Compare commits

..

23 Commits

Author SHA1 Message Date
Joel Challis 12139903ce Require --keyboard for some CLI subcommands (#26308) 2026-07-08 01:41:47 +01:00
QMK Bot 817bbaa5f9 Merge remote-tracking branch 'origin/master' into develop 2026-07-07 22:15:29 +00:00
Alexis "Horgix" Chotard 2dc5e39798 docs(features): Add missing inline code syntax for KC_ESC (#26314) 2026-07-07 23:14:50 +01:00
QMK Bot da481f5cc4 Merge remote-tracking branch 'origin/master' into develop 2026-07-06 20:09:23 +00:00
Harry Cutts 7a15cd2482 Add "handwired" TwentyPad macro pad (#26264)
* Add "handwired" TwentyPad macro pad

TwentyPad is 20-key macro pad I created as a hobby project. Its
configuration is based on ez_maker/directpins/teensy_2, with the
bootloader and layout changed.

* Host the image on Imgur

Co-authored-by: Joel Challis <git@zvecr.com>

---------

Co-authored-by: Joel Challis <git@zvecr.com>
2026-07-06 13:08:39 -07:00
Harrison 428b1cd568 Use memmove for overlapping copies in RGB/LED matrix last-hit tracker (#26306)
Use memmove for overlapping copies in RGB/LED matrix last-hit tracker
2026-07-06 12:30:13 -07:00
QMK Bot e38f3097cb Merge remote-tracking branch 'origin/master' into develop 2026-07-03 03:49:08 +00:00
Pascal Getreuer cf93bbb78f [Docs] Tap-hold doc improvements and suggest an HRMs starter recipe (#26284)
* Enhance tap-hold docs.

* Minor edits.

* Move note on Quick Tap to a sub bullet for visibility.

Co-authored-by: Drashna Jaelre <drashna@live.com>

---------

Co-authored-by: Drashna Jaelre <drashna@live.com>
2026-07-03 11:48:28 +08:00
QMK Bot 9f75ab2c92 Merge remote-tracking branch 'origin/master' into develop 2026-06-26 13:20:50 +00:00
Trent Piepho b1093e9da5 Fix VERBOSE make flag (#26289)
The docs say set this to true to enable verbose output, but setting it to
anything, even "false", would enable verbose mode.

The qmk python build program actually does this, supplying "VERBOSE=false"
to make, which turns verbose mode on, not off!  The reason it's not verbose
is that the wrapper also adds the "-s" switch that has the same effect as
turning verbose mode back off.

After fixing the flag, there's no reason to add the "-s", so remove that code.
2026-06-26 14:20:10 +01:00
Nick Brassel 5734360a86 Restrict the EXTRAKEY_ENABLE System Control HID usage range. (#26295) 2026-06-25 16:29:47 +10:00
Joel Challis 0ec0cdde81 Consistently handle datablock init (#26282) 2026-06-24 20:36:51 +01:00
QMK Bot ee9354d36e Merge remote-tracking branch 'origin/master' into develop 2026-06-23 20:31:27 +00:00
dependabot[bot] 0cb6461c6a Bump actions/cache from 5 to 6 (#26293)
Bumps [actions/cache](https://github.com/actions/cache) from 5 to 6.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-23 21:30:44 +01:00
Joel Challis dd905c9531 Split ducky/one2sf/1967st into ansi/iso variants (#26277) 2026-06-23 15:31:31 +01:00
Joel Challis 963986c475 Automatically handle duplicate matrix LED mappings (#26278) 2026-06-22 18:31:14 +01:00
QMK Bot aae4189aa4 Merge remote-tracking branch 'origin/master' into develop 2026-06-22 17:28:58 +00:00
Benoit Brummer 198026cf27 ploopyco: fix bitwise typos in opt_encoder_tiny state definitions (#26288)
Fixes a bug in the state machine definitions within `opt_encoder_tiny.c` that caused severely delayed or unresponsive scrolling.
2026-06-22 18:28:13 +01:00
Joel Challis fd624d016b Fix nifty_numpad issues (#26283)
* eeconfig_init_kb_datablock should not call eeconfig_init_user_datablock

* Fix lint warnings
2026-06-21 10:49:42 +01:00
gitaen 6741f9dc26 Add converter/thinkpad_t6x/pico_t61 keyboard (#26266)
This adds support for Frank Adams pico_t61 board which is similar to
the currently supported converter/thinkpad_t6x/rpi_pico one.

Common options and shared default keymap have been moved to the upper
directory (keyboards/converter/thinkpad_t6x).
2026-06-19 19:40:51 +01:00
QMK Bot f8910d3a60 Merge remote-tracking branch 'origin/master' into develop 2026-06-19 16:32:31 +00:00
dependabot[bot] c638100030 Bump actions/checkout from 6 to 7 (#26274)
Bumps [actions/checkout](https://github.com/actions/checkout) from 6 to 7.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-19 17:30:08 +01:00
Arca Artem 1d2f52e407 process_key_lock: clear entire key state in cancel_key_lock() (#26269)
cancel_key_lock() called UNSET_KEY_STATE(0x0), which expands to clearing
only bit 0 of key_state[0]. The lock state is a 256-bit map spread across
key_state[0..3], so every locked key other than keycode 0x00 stayed
latched after a cancel.

Zero all four words so cancel_key_lock() releases every locked key, as
its name and its public declaration in process_key_lock.h imply.
2026-06-19 17:24:11 +01:00
166 changed files with 812 additions and 8307 deletions
+1 -1
View File
@@ -25,7 +25,7 @@ jobs:
if: github.repository == 'qmk/qmk_firmware'
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
with:
fetch-depth: 1
persist-credentials: false
+1 -1
View File
@@ -28,7 +28,7 @@ jobs:
if: github.repository == 'qmk/qmk_firmware'
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
with:
fetch-depth: 0
+3 -3
View File
@@ -123,7 +123,7 @@ jobs:
echo 'Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"' >> /etc/sudoers
- name: Checkout repository
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
fetch-depth: 1
submodules: recursive
@@ -201,7 +201,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
fetch-depth: 1
submodules: recursive
@@ -258,7 +258,7 @@ jobs:
git:
- name: Checkout repository
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
fetch-depth: 1
submodules: recursive
+2 -2
View File
@@ -41,7 +41,7 @@ jobs:
git config --global --add safe.directory '*'
- name: Checkout QMK Firmware
uses: actions/checkout@v6
uses: actions/checkout@v7
- name: Install dependencies
run: pip3 install -r requirements-dev.txt
@@ -89,7 +89,7 @@ jobs:
git config --global --add safe.directory '*'
- name: Checkout QMK Firmware
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
fetch-depth: 0
@@ -32,7 +32,7 @@ jobs:
git config --global --add safe.directory '*'
- name: Checkout QMK Firmware
uses: actions/checkout@v6
uses: actions/checkout@v7
- name: Install dependencies
run: pip3 install -r requirements-dev.txt
@@ -86,7 +86,7 @@ jobs:
git config --global --add safe.directory '*'
- name: Checkout QMK Firmware
uses: actions/checkout@v6
uses: actions/checkout@v7
with:
submodules: recursive
@@ -105,7 +105,7 @@ jobs:
- name: Restore Cache
id: cache
uses: actions/cache/restore@v5
uses: actions/cache/restore@v6
with:
path: ${{ env.CCACHE_CONFIGPATH }}
key: compile-${{ inputs.keymap }}-${{ matrix.target }}
@@ -136,7 +136,7 @@ jobs:
fi
- name: Save Cache
uses: actions/cache/save@v5
uses: actions/cache/save@v6
with:
path: ${{ env.CCACHE_CONFIGPATH }}
key: compile-${{ inputs.keymap }}-${{ matrix.target }}
@@ -166,7 +166,7 @@ jobs:
steps:
- name: Checkout QMK Firmware
uses: actions/checkout@v6
uses: actions/checkout@v7
- name: Download firmwares
uses: actions/download-artifact@v8
+1 -1
View File
@@ -24,7 +24,7 @@ jobs:
- name: Disable safe.directory check
run : git config --global --add safe.directory '*'
- uses: actions/checkout@v6
- uses: actions/checkout@v7
with:
submodules: recursive
+1 -1
View File
@@ -15,7 +15,7 @@ jobs:
if: github.repository == 'qmk/qmk_firmware'
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
with:
token: ${{ secrets.QMK_BOT_TOKEN }}
fetch-depth: 0
+1 -1
View File
@@ -30,7 +30,7 @@ jobs:
container: ghcr.io/qmk/qmk_cli
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
with:
fetch-depth: 1
+1 -1
View File
@@ -21,7 +21,7 @@ jobs:
- riot
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
with:
token: ${{ secrets.QMK_BOT_TOKEN }}
fetch-depth: 0
+1 -1
View File
@@ -26,7 +26,7 @@ jobs:
- name: Disable safe.directory check
run : git config --global --add safe.directory '*'
- uses: actions/checkout@v6
- uses: actions/checkout@v7
with:
fetch-depth: 0
+1 -1
View File
@@ -19,7 +19,7 @@ jobs:
- name: Disable safe.directory check
run : git config --global --add safe.directory '*'
- uses: actions/checkout@v6
- uses: actions/checkout@v7
with:
fetch-depth: 0
+1 -1
View File
@@ -18,7 +18,7 @@ jobs:
- name: Disable safe.directory check
run : git config --global --add safe.directory '*'
- uses: actions/checkout@v6
- uses: actions/checkout@v7
with:
fetch-depth: 0
+1 -1
View File
@@ -22,7 +22,7 @@ jobs:
- name: Disable safe.directory check
run : git config --global --add safe.directory '*'
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- name: Install dependencies
run: pip3 install -r requirements-dev.txt
+1 -1
View File
@@ -19,7 +19,7 @@ jobs:
- name: Disable safe.directory check
run : git config --global --add safe.directory '*'
- uses: actions/checkout@v6
- uses: actions/checkout@v7
- name: Install dependencies
run: pip3 install -r requirements-dev.txt
+1 -1
View File
@@ -27,7 +27,7 @@ jobs:
container: ghcr.io/qmk/qmk_cli
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
with:
submodules: recursive
-1
View File
@@ -111,7 +111,6 @@ secrets.tar
# Python things
__pycache__
.python-version
*.egg-info
.venv
# Prerequisites for updating ChibiOS
+1 -1
View File
@@ -1,4 +1,4 @@
ifndef VERBOSE
ifneq ($(VERBOSE),true)
.SILENT:
endif
+1 -1
View File
@@ -4,7 +4,7 @@
# responsible for determining which folder is being used and doing the
# corresponding environment setup.
ifndef VERBOSE
ifneq ($(VERBOSE),true)
.SILENT:
endif
+1 -1
View File
@@ -1,4 +1,4 @@
ifndef VERBOSE
ifneq ($(VERBOSE),true)
.SILENT:
endif
-20
View File
@@ -49,10 +49,6 @@ else ifeq ($(strip $(DEBUG_MATRIX_SCAN_RATE_ENABLE)), api)
OPT_DEFS += -DDEBUG_MATRIX_SCAN_RATE
endif
ifeq ($(strip $(XAP_ENABLE)), yes)
include $(BUILDDEFS_PATH)/xap.mk
endif
AUDIO_ENABLE ?= no
ifeq ($(strip $(AUDIO_ENABLE)), yes)
ifeq ($(PLATFORM),CHIBIOS)
@@ -649,22 +645,6 @@ ifeq ($(strip $(VIA_ENABLE)), yes)
endif
endif
ifeq ($(strip $(XAP_ENABLE)), yes)
ifeq ($(strip $(VIA_ENABLE)), yes)
$(error 'XAP_ENABLE = $(XAP_ENABLE)' deprecates 'VIA_ENABLE = $(VIA_ENABLE)'. Please set 'VIA_ENABLE = no')
endif
DYNAMIC_KEYMAP_ENABLE := yes
FNV_ENABLE := yes
SECURE_ENABLE := yes
BOOTMAGIC_ENABLE := yes
OPT_DEFS += -DXAP_ENABLE
OPT_DEFS += -DBOOTLOADER_JUMP_SUPPORTED
VPATH += $(QUANTUM_DIR)/xap
SRC += $(QUANTUM_DIR)/xap/xap.c $(QUANTUM_DIR)/xap/xap_handlers.c
endif
ifeq ($(strip $(RAW_ENABLE)), yes)
OPT_DEFS += -DRAW_ENABLE
SRC += raw_hid.c
-44
View File
@@ -1,44 +0,0 @@
# Copyright 2022 Nick Brassel (@tzarc)
# SPDX-License-Identifier: GPL-2.0-or-later
XAP_FILES := $(shell ls -1 data/xap/* | sort | xargs echo)
ifneq ("$(wildcard $(KEYBOARD_PATH_1)/xap.hjson)","")
XAP_FILES += $(KEYBOARD_PATH_1)/xap.hjson
endif
ifneq ("$(wildcard $(KEYBOARD_PATH_2)/xap.hjson)","")
XAP_FILES += $(KEYBOARD_PATH_2)/xap.hjson
endif
ifneq ("$(wildcard $(KEYBOARD_PATH_3)/xap.hjson)","")
XAP_FILES += $(KEYBOARD_PATH_3)/xap.hjson
endif
ifneq ("$(wildcard $(KEYBOARD_PATH_4)/xap.hjson)","")
XAP_FILES += $(KEYBOARD_PATH_4)/xap.hjson
endif
ifneq ("$(wildcard $(KEYBOARD_PATH_5)/xap.hjson)","")
XAP_FILES += $(KEYBOARD_PATH_5)/xap.hjson
endif
ifneq ("$(wildcard $(KEYMAP_PATH)/xap.hjson)","")
XAP_FILES += $(KEYMAP_PATH)/xap.hjson
endif
ifneq ("$(wildcard $(USER_NAME)/xap.hjson)","")
XAP_FILES += $(USER_NAME)/xap.hjson
endif
$(INTERMEDIATE_OUTPUT)/src/config_blob_gz.h: $(INFO_JSON_FILES)
@$(SILENT) || printf "$(MSG_GENERATING) $@" | $(AWK_CMD)
$(eval CMD=$(QMK_BIN) xap-generate-qmk-blob-h -o "$(INTERMEDIATE_OUTPUT)/src/config_blob_gz.h" -kb $(KEYBOARD) -km $(KEYMAP))
@$(BUILD_CMD)
$(INTERMEDIATE_OUTPUT)/src/xap_generated.inl: $(XAP_FILES)
@$(SILENT) || printf "$(MSG_GENERATING) $@" | $(AWK_CMD)
$(eval CMD=$(QMK_BIN) xap-generate-qmk-inc -o "$(INTERMEDIATE_OUTPUT)/src/xap_generated.inl" -kb $(KEYBOARD) -km $(KEYMAP))
@$(BUILD_CMD)
$(INTERMEDIATE_OUTPUT)/src/xap_generated.h: $(XAP_FILES)
@$(SILENT) || printf "$(MSG_GENERATING) $@" | $(AWK_CMD)
$(eval CMD=$(QMK_BIN) xap-generate-qmk-h -o "$(INTERMEDIATE_OUTPUT)/src/xap_generated.h" -kb $(KEYBOARD) -km $(KEYMAP))
@$(BUILD_CMD)
generated-files: $(INTERMEDIATE_OUTPUT)/src/config_blob_gz.h $(INTERMEDIATE_OUTPUT)/src/xap_generated.inl $(INTERMEDIATE_OUTPUT)/src/xap_generated.h
VPATH += $(INTERMEDIATE_OUTPUT)/src
@@ -1,82 +0,0 @@
{
"groups": {
"reactive": {
"define": "LED_MATRIX_KEYREACTIVE_ENABLED"
}
},
"effects": {
"0x00": {
"key": "SOLID"
},
"0x01": {
"key": "ALPHAS_MODS"
},
"0x02": {
"key": "BREATHING"
},
"0x03": {
"key": "BAND"
},
"0x04": {
"key": "BAND_PINWHEEL"
},
"0x05": {
"key": "BAND_SPIRAL"
},
"0x06": {
"key": "CYCLE_LEFT_RIGHT"
},
"0x07": {
"key": "CYCLE_UP_DOWN"
},
"0x08": {
"key": "CYCLE_OUT_IN"
},
"0x09": {
"key": "DUAL_BEACON"
},
"0x0A": {
"key": "WAVE_LEFT_RIGHT"
},
"0x0B": {
"key": "WAVE_UP_DOWN"
},
"0x0C": {
"key": "SOLID_REACTIVE_SIMPLE",
"group": "reactive"
},
"0x0D": {
"key": "SOLID_REACTIVE_WIDE",
"group": "reactive"
},
"0x0E": {
"key": "SOLID_REACTIVE_MULTIWIDE",
"group": "reactive"
},
"0x0F": {
"key": "SOLID_REACTIVE_CROSS",
"group": "reactive"
},
"0x10": {
"key": "SOLID_REACTIVE_MULTICROSS",
"group": "reactive"
},
"0x11": {
"key": "SOLID_REACTIVE_NEXUS",
"group": "reactive"
},
"0x12": {
"key": "SOLID_REACTIVE_MULTINEXUS",
"group": "reactive"
},
"0x13": {
"key": "SOLID_SPLASH",
"group": "reactive"
},
"0x14": {
"key": "SOLID_MULTISPLASH",
"group": "reactive"
}
}
}
@@ -1,175 +0,0 @@
{
"groups": {
"framebuffer": {
"define": "RGB_MATRIX_FRAMEBUFFER_EFFECTS"
},
"reactive": {
"define": "RGB_MATRIX_KEYREACTIVE_ENABLED"
}
},
"effects": {
"0x00": {
"key": "SOLID_COLOR"
},
"0x01": {
"key": "ALPHAS_MODS"
},
"0x02": {
"key": "GRADIENT_UP_DOWN"
},
"0x03": {
"key": "GRADIENT_LEFT_RIGHT"
},
"0x04": {
"key": "BREATHING"
},
"0x05": {
"key": "BAND_SAT"
},
"0x06": {
"key": "BAND_VAL"
},
"0x07": {
"key": "BAND_PINWHEEL_SAT"
},
"0x08": {
"key": "BAND_PINWHEEL_VAL"
},
"0x09": {
"key": "BAND_SPIRAL_SAT"
},
"0x0A": {
"key": "BAND_SPIRAL_VAL"
},
"0x0B": {
"key": "CYCLE_ALL"
},
"0x0C": {
"key": "CYCLE_LEFT_RIGHT"
},
"0x0D": {
"key": "CYCLE_UP_DOWN"
},
"0x0E": {
"key": "CYCLE_OUT_IN"
},
"0x0F": {
"key": "CYCLE_OUT_IN_DUAL"
},
"0x10": {
"key": "RAINBOW_MOVING_CHEVRON"
},
"0x11": {
"key": "CYCLE_PINWHEEL"
},
"0x12": {
"key": "CYCLE_SPIRAL"
},
"0x13": {
"key": "DUAL_BEACON"
},
"0x14": {
"key": "RAINBOW_BEACON"
},
"0x15": {
"key": "RAINBOW_PINWHEELS"
},
"0x16": {
"key": "RAINDROPS"
},
"0x17": {
"key": "JELLYBEAN_RAINDROPS"
},
"0x18": {
"key": "HUE_BREATHING"
},
"0x19": {
"key": "HUE_PENDULUM"
},
"0x1A": {
"key": "HUE_WAVE"
},
"0x1B": {
"key": "PIXEL_FRACTAL"
},
"0x1C": {
"key": "PIXEL_FLOW"
},
"0x1D": {
"key": "PIXEL_RAIN"
},
"0x1E": {
"key": "TYPING_HEATMAP",
"group": "framebuffer"
},
"0x1F": {
"key": "DIGITAL_RAIN",
"group": "framebuffer"
},
"0x20": {
"key": "SOLID_REACTIVE_SIMPLE",
"group": "reactive"
},
"0x21": {
"key": "SOLID_REACTIVE",
"group": "reactive"
},
"0x22": {
"key": "SOLID_REACTIVE_WIDE",
"group": "reactive"
},
"0x23": {
"key": "SOLID_REACTIVE_MULTIWIDE",
"group": "reactive"
},
"0x24": {
"key": "SOLID_REACTIVE_CROSS",
"group": "reactive"
},
"0x25": {
"key": "SOLID_REACTIVE_MULTICROSS",
"group": "reactive"
},
"0x26": {
"key": "SOLID_REACTIVE_NEXUS",
"group": "reactive"
},
"0x27": {
"key": "SOLID_REACTIVE_MULTINEXUS",
"group": "reactive"
},
"0x28": {
"key": "SPLASH",
"group": "reactive"
},
"0x29": {
"key": "MULTISPLASH",
"group": "reactive"
},
"0x2A": {
"key": "SOLID_SPLASH",
"group": "reactive"
},
"0x2B": {
"key": "SOLID_MULTISPLASH",
"group": "reactive"
},
"0x2C": {
"key": "FLOWER_BLOOMING"
},
"0x2D": {
"key": "STARLIGHT"
},
"0x2E": {
"key": "STARLIGHT_DUAL_SAT"
},
"0x2F": {
"key": "STARLIGHT_DUAL_HUE"
},
"0x30": {
"key": "RIVERFLOW"
}
}
}
@@ -1,130 +0,0 @@
{
"effects": {
"0x00": {
"key": "STATIC_LIGHT"
},
"0x01": {
"key": "BREATHING"
},
"0x02": {
"key": "BREATHING_2"
},
"0x03": {
"key": "BREATHING_3"
},
"0x04": {
"key": "BREATHING_4"
},
"0x05": {
"key": "RAINBOW_MOOD"
},
"0x06": {
"key": "RAINBOW_MOOD_2"
},
"0x07": {
"key": "RAINBOW_MOOD_3"
},
"0x08": {
"key": "RAINBOW_SWIRL"
},
"0x09": {
"key": "RAINBOW_SWIRL_2"
},
"0x0A": {
"key": "RAINBOW_SWIRL_3"
},
"0x0B": {
"key": "RAINBOW_SWIRL_4"
},
"0x0C": {
"key": "RAINBOW_SWIRL_5"
},
"0x0D": {
"key": "RAINBOW_SWIRL_6"
},
"0x0E": {
"key": "SNAKE"
},
"0x0F": {
"key": "SNAKE_2"
},
"0x10": {
"key": "SNAKE_3"
},
"0x11": {
"key": "SNAKE_4"
},
"0x12": {
"key": "SNAKE_5"
},
"0x13": {
"key": "SNAKE_6"
},
"0x14": {
"key": "KNIGHT"
},
"0x15": {
"key": "KNIGHT_2"
},
"0x16": {
"key": "KNIGHT_3"
},
"0x17": {
"key": "CHRISTMAS"
},
"0x18": {
"key": "STATIC_GRADIENT"
},
"0x19": {
"key": "STATIC_GRADIENT_2"
},
"0x1A": {
"key": "STATIC_GRADIENT_3"
},
"0x1B": {
"key": "STATIC_GRADIENT_4"
},
"0x1C": {
"key": "STATIC_GRADIENT_5"
},
"0x1D": {
"key": "STATIC_GRADIENT_6"
},
"0x1E": {
"key": "STATIC_GRADIENT_7"
},
"0x1F": {
"key": "STATIC_GRADIENT_8"
},
"0x20": {
"key": "STATIC_GRADIENT_9"
},
"0x21": {
"key": "STATIC_GRADIENT_10"
},
"0x22": {
"key": "RGB_TEST"
},
"0x23": {
"key": "ALTERNATING"
},
"0x24": {
"key": "TWINKLE"
},
"0x25": {
"key": "TWINKLE_2"
},
"0x26": {
"key": "TWINKLE_3"
},
"0x27": {
"key": "TWINKLE_4"
},
"0x28": {
"key": "TWINKLE_5"
},
"0x29": {
"key": "TWINKLE_6"
}
}
}
+4 -1
View File
@@ -1741,7 +1741,10 @@
"target": "ducky/one2mini/1861st"
},
"ducky/one2sf": {
"target": "ducky/one2sf/1967st"
"target": "ducky/one2sf/1967st/ansi"
},
"ducky/one2sf/1967st": {
"target": "ducky/one2sf/1967st/ansi"
},
"dumbpad": {
"target": "dumbpad/v0x"
-7
View File
@@ -1,7 +0,0 @@
{
"secure": {
"unlock_sequence": [ [0,0] ],
"unlock_timeout": 5000,
"idle_timeout": 60000
}
}
-16
View File
@@ -16,18 +16,6 @@
"type": "object",
"additionalProperties": {"type": "boolean"}
},
"build_target": {
"oneOf": [
{"$ref": "#/keyboard_keymap_tuple"},
{"$ref": "#/json_file_path"}
]
},
"define": {
"type": "string",
"minLength": 2,
"maxLength": 50,
"pattern": "^[A-Z_]*$"
},
"filename": {
"type": "string",
"minLength": 1,
@@ -199,10 +187,6 @@
"minLength": 1,
"maxLength": 250
},
"text_unsigned_int": {
"type": "string",
"pattern": "^[0-8]+$"
},
"unsigned_decimal": {
"type": "number",
"minimum": 0
-255
View File
@@ -1,255 +0,0 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "qmk.xap.v1",
"title": "XAP Spec",
"definitions": {
"data_type": {
"oneOf": [
{
"enum": [
"bool",
"u8",
"u16",
"u32",
"u64",
"struct",
"string"
]
},
{
"type": "string",
"pattern": "^u\\d{1,2}\\[\\d{1,2}\\]*$"
}
]
},
"router_type": {
"enum": [
"command",
"router"
]
},
"permission": {
"enum": [
"secure"
]
},
"struct": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"required": [
"name",
"type"
],
"properties": {
"name": {
"type": "string"
},
"type": {
"type": "string"
}
}
}
},
"route": {
"type": "object",
"propertyNames": {
"$ref": "qmk.definitions.v1#/hex_number_2d"
},
"additionalProperties": {
"type": "object",
"required": [
"type",
"define"
],
"additionalProperties": false,
"properties": {
"type": {
"$ref": "#/definitions/router_type"
},
"name": {
"type": "string"
},
"description": {
"type": "string"
},
"define": {
"$ref": "qmk.definitions.v1#/define"
},
"permissions": {
"$ref": "#/definitions/permission"
},
"enable_if_preprocessor": {
"type": "string"
},
"request_type": {
"$ref": "#/definitions/data_type"
},
"request_struct_length": {
"type": "number"
},
"request_purpose": {
"type": "string"
},
"return_type": {
"$ref": "#/definitions/data_type"
},
"request_struct_members": {
"$ref": "#definitions/struct"
},
"return_struct_length": {
"type": "number"
},
"return_constant": {
"type": [
"array",
"string"
]
},
"return_struct_members": {
"$ref": "#definitions/struct"
},
"return_purpose": {
"type": "string"
},
"return_execute": {
"type": "string"
},
"routes": {
"$ref": "#/definitions/route"
}
}
}
}
},
"type": "object",
"additionalProperties": false,
"required": [
"version"
],
"properties": {
"version": {
"$ref": "qmk.definitions.v1#/bcd_version"
},
"define": {
"$ref": "qmk.definitions.v1#/define"
},
"documentation": {
"type": "object",
"properties": {
"order": {
"type": "array",
"items": {
"type": "string"
}
}
},
"additionalProperties": {
"type": "string"
}
},
"term_definitions": {
"type": "object",
"additionalProperties": {
"type": "string"
}
},
"type_docs": {
"type": "object",
"additionalProperties": {
"type": "string"
}
},
"type_definitions": {
"type": "object",
"additionalProperties": {
"type": "object",
"additionalProperties": false,
"properties": {
"name": {
"type": "string"
},
"description": {
"type": "string"
},
"type": {
"$ref": "#/definitions/data_type"
},
"struct_length": {
"type": "number"
},
"struct_members": {
"$ref": "#definitions/struct"
}
}
}
},
"response_flags": {
"type": "object",
"additionalProperties": false,
"properties": {
"define_prefix": {
"$ref": "qmk.definitions.v1#/define"
},
"bits": {
"type": "object",
"propertyNames": {
"$ref": "qmk.definitions.v1#/text_unsigned_int"
},
"additionalProperties": {
"type": "object",
"additionalProperties": false,
"properties": {
"name": {
"type": "string"
},
"define": {
"$ref": "qmk.definitions.v1#/define"
},
"description": {
"type": "string"
}
}
}
}
}
},
"broadcast_messages": {
"type": "object",
"additionalProperties": false,
"properties": {
"define_prefix": {
"$ref": "qmk.definitions.v1#/define"
},
"messages": {
"type": "object",
"propertyNames": {
"$ref": "qmk.definitions.v1#/hex_number_2d"
},
"additionalProperties": {
"type": "object",
"additionalProperties": false,
"properties": {
"name": {
"type": "string"
},
"define": {
"$ref": "qmk.definitions.v1#/define"
},
"description": {
"type": "string"
},
"return_type": {
"$ref": "#/definitions/data_type"
}
}
}
}
}
},
"routes": {
"$ref": "#/definitions/route"
}
}
}
@@ -1,19 +0,0 @@
{{ constants.GPL2_HEADER_SH_LIKE }}
{{ constants.GENERATED_HEADER_SH_LIKE }}
from enum import IntEnum
# version: 0.0.1
class RgblightModes(IntEnum):
{% for id, effect in specs.rgblight.effects | dictsort %}
{{ effect.key }} = {{ id }}
{% endfor %}
# version: 0.0.1
class RgbMatrixModes(IntEnum):
{% for id, effect in specs.rgb_matrix.effects | dictsort %}
{{ effect.key }} = {{ id }}
{% endfor %}
# noqa: W391
@@ -1,22 +0,0 @@
{{ constants.GPL2_HEADER_SH_LIKE }}
{{ constants.GENERATED_HEADER_SH_LIKE }}
class XAPRouteError(Exception):
pass
class XAPRoutes():
{% for id, route in xap.routes | dictsort %}
{% if route.routes %}
# {{route.define}}
{% for subid, subroute in route.routes | dictsort %}
{{route.define}}_{{subroute.define}} = b'\x{{ '%02d' % id|int(base=16) }}\x{{ '%02d' % subid|int(base=16) }}'
{% if subroute.routes %}
{% for subsubid, subsubroute in subroute.routes | dictsort %}
{{route.define}}_{{subroute.define}}_{{subsubroute.define}} = b'\x{{ '%02d' % id|int(base=16) }}\x{{ '%02d' % subid|int(base=16) }}\x{{ '%02d' % subsubid|int(base=16) }}'
{% endfor %}
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
# noqa: W391
@@ -1,68 +0,0 @@
{{ constants.GPL2_HEADER_SH_LIKE }}
{{ constants.GENERATED_HEADER_SH_LIKE }}
from collections import namedtuple
from enum import IntFlag, IntEnum
from struct import Struct
{% macro gen_struct(name, members, fmt) -%}
class {{ name }}(namedtuple('{{ name }}', '{{ members }}')):
fmt = Struct('{{ fmt }}')
def __new__(cls, *args):
return super().__new__(cls, *args)
@classmethod
def from_bytes(cls, data):
return cls._make(cls.fmt.unpack(data))
def to_bytes(self):
return self.fmt.pack(*list(self))
{% endmacro -%}
{% set type_definitions = [
{'name':'XAPRequest', 'members': 'token length data', 'fmt':'<HB61s'},
{'name':'XAPResponse', 'members': 'token flags length data', 'fmt':'<HBB60s'},
{'name':'XAPBroadcast', 'members': 'token event length data', 'fmt':'<HBB60s'},
{'name':'XAPConfigBacklight', 'members': 'enable mode val', 'fmt':'<BBB'},
{'name':'XAPConfigRgblight', 'members': 'enable mode hue sat val speed', 'fmt':'<BBBBBB'},
{'name':'XAPConfigRgbMatrix', 'members': 'enable mode hue sat val speed flags', 'fmt':'<BBBBBBB'}
] %}
{% for item in type_definitions -%}{{ gen_struct(item.name, item.members, item.fmt) }}{% endfor -%}
# Spec structs
{% for item in xap.routes.values() recursive %}
{%- if item.routes -%}
{{ loop(item.routes.values()) }}
{%- endif -%}
{%- if item.request_struct_members %}
# TODO: gen inbound object for {{ item.define | to_snake }}
{% endif -%}
{%- if item.return_struct_members %}
# TODO: gen outbound object for {{ item.define | to_snake }}
{% endif %}
{%- endfor %}
class XAPSecureStatus(IntEnum):
LOCKED = 0x00
UNLOCKING = 0x01
UNLOCKED = 0x02
class XAPEventType(IntEnum):
{% for id, message in xap.broadcast_messages.messages | dictsort %}
{{ message.define }} = {{ id }}
{% endfor %}
class XAPFlags(IntFlag):
{% for bitnum, bitinfo in xap.response_flags.bits | dictsort %}
{% if bitinfo.define != "-" %}
{{ bitinfo.define }} = 1 << {{ bitnum }}
{% endif %}
{% endfor %}
# noqa: W391
@@ -1,4 +0,0 @@
{% for id, message in xap.broadcast_messages.messages | dictsort %}
### {{ message.name }} - `{{ id }}`
{{ message.description }}
{% endfor %}
-11
View File
@@ -1,11 +0,0 @@
{{ constants.GPL2_HEADER_XML_LIKE }}
{{ constants.GENERATED_HEADER_XML_LIKE }}
{%- for item in xap.documentation.order %}
{% if not item[0:1] == '!' %}
{{ xap.documentation.get(item) }}
{% else %}
{% include item[1:] %}
{% endif %}
{% endfor %}
@@ -1,12 +0,0 @@
|{% for bitnum, bitinfo in xap.response_flags.bits | dictsort | reverse %} Bit {{ bitnum }} |{% endfor %}
|{% for bitnum, bitinfo in xap.response_flags.bits | dictsort | reverse %} -- |{% endfor %}
|{% for bitnum, bitinfo in xap.response_flags.bits | dictsort | reverse %} `{{ bitinfo.define }}` |{% endfor %}
{% for bitnum, bitinfo in xap.response_flags.bits | dictsort | reverse %}
{% if bitinfo.define != "-" -%}
* Bit {{ bitnum }} (`{{ bitinfo.define }}`): {{ bitinfo.description }}
{% endif %}
{% endfor %}
-52
View File
@@ -1,52 +0,0 @@
{%- macro gen_payload(name, type, purpose, members) -%}
{%- if type == 'struct' -%}
__{{ name }}:__
{%- for member in members -%}
<br>{{ "&nbsp;"|safe*4 }}* {{ member.name }}: `{{ member.type }}`
{%- endfor -%}
{%- elif purpose -%}
__{{ name }}:__<br>{{ "&nbsp;"|safe*4 }}* {{ purpose }}: `{{ type }}`
{%- elif type -%}
__{{ name }}:__ `{{ type }}`
{%- endif -%}
{%- endmacro -%}
{%- macro gen_payloads(route) -%}
{{ gen_payload('Request', route.request_type, route.request_purpose, route.request_struct_members) }}{%- if route.return_type and route.request_type -%}<br><br>{% endif %}{{ gen_payload('Response', route.return_type, null, route.return_struct_members) }}
{%- endmacro -%}
{%- macro gen_tags(route) -%}
{% if 'secure' == route.permissions %}__Secure__{% endif %}
{%- endmacro -%}
{% for id, route in xap.routes | dictsort %}
### {{ route.name }} - `{{ id }}`
{{ route.description }}
{% if route.routes %}
| Name | Route | Tags | Payloads | Description |
| -- | -- | -- | -- | -- |
{% for subid, subroute in route.routes | dictsort %}
{% if not subroute.routes %}
| {{ subroute.name }} | `{{ id }} {{ subid }}` | {{ gen_tags(subroute) }} | {{ gen_payloads(subroute) }} | {{ subroute.description | newline_to_br }}|
{% endif %}
{% endfor %}
{% for subid, subroute in route.routes | dictsort %}
{%- if subroute.routes %}
#### {{ subroute.name }} - `{{ id }} {{ subid }}`
{{ subroute.description }}
| Name | Route | Tags | Payloads | Description |
| -- | -- | -- | -- | -- |
{% for subsubid, subsubroute in subroute.routes | dictsort %}
{% if not subsubroute.routes %}
| {{ subsubroute.name }} | `{{ id }} {{ subid }} {{ subsubid }}` | {{ gen_tags(subsubroute) }} | {{ gen_payloads(subsubroute) }} | {{ subsubroute.description | newline_to_br }}|
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
{% endif %}
{% endfor %}
@@ -1,8 +0,0 @@
| Name | Definition |
| -- | -- |
{% for type, definition in xap.term_definitions | dictsort %}
| _{{ type }}_ | {{ definition }} |
{% endfor %}
{% for type, definition in xap.type_definitions | dictsort %}
| _{{ definition.name }}_ | {{ definition.description }}{% if 'struct' == definition.type %} Takes the format:{% for item in definition.struct_members %}<br>`{{ item.type }}` - {{ item.name }}{%- endfor %}{% endif %} |
{% endfor %}
-5
View File
@@ -1,5 +0,0 @@
| Name | Definition |
| -- | -- |
{% for type, definition in xap.type_docs | dictsort %}
| _{{ type }}_ | {{ definition }} |
{% endfor %}
-6
View File
@@ -1,6 +0,0 @@
{{ constants.GPL2_HEADER_XML_LIKE }}
{{ constants.GENERATED_HEADER_XML_LIKE }}
{%- for ver in versions | reverse -%}
* [XAP Version {{ ver }}](xap_{{ ver }}.md)
{% endfor %}
@@ -1,171 +0,0 @@
{{ constants.GPL2_HEADER_C_LIKE }}
{{ constants.GENERATED_HEADER_C_LIKE }}
#pragma once
#include <stdint.h>
#include <stdbool.h>
////////////////////////////////////////////////////////////////////////////////
// Versions and identifiers
#define XAP_BCD_VERSION UINT32_C({{ xap.version | triplet_to_bcd }})
#define QMK_BCD_VERSION UINT32_C({{ qmk_version | triplet_to_bcd }})
#define XAP_KEYBOARD_IDENTIFIER UINT32_C({{ keyboard | fnv1a_32 }})
////////////////////////////////////////////////////////////////////////////////
// Response flag definitions
{% for bit,data in xap.response_flags.bits | dictsort %}
#define {{ xap.response_flags.define_prefix }}_{{ data.define | to_snake | upper }} (UINT32_C(1) << ({{ bit }}))
{% endfor %}
#define {{ xap.response_flags.define_prefix }}_FAILED 0x00
////////////////////////////////////////////////////////////////////////////////
// Broadcast message definitions
{% for message_id,data in xap.broadcast_messages.messages | dictsort %}
#define {{ xap.broadcast_messages.define_prefix }}_{{ data.define | to_snake | upper }} {{ message_id }}
{% if 'return_type' in data %}
void {{ xap.broadcast_messages.define_prefix | lower }}_{{ data.define | to_snake | lower }}({{ data.return_type | type_to_c('value') }});
{% else %}
void {{ xap.broadcast_messages.define_prefix | lower }}_{{ data.define | to_snake | lower }}(const void *data, size_t length);
{% endif %}
{% endfor %}
#define XAP_BROADCAST_TOKEN 0xFFFF
////////////////////////////////////////////////////////////////////////////////
// Type definitions
{% for name,data in xap.type_definitions | dictsort %}
{% if data.type != 'struct' %}
typedef {{ data.type | type_to_c('xap_'+(name|to_snake|lower)+'_t') }};
{% endif %}
{% endfor %}
{% for name,data in xap.type_definitions | dictsort %}
{% if data.type == 'struct' %}
typedef struct {
{% for member in data.struct_members %}
{{ member.type | type_to_c(member.name) }};
{% endfor %}
} __attribute__((__packed__)) xap_{{ name | to_snake | lower }}_t{{ data.type | type_to_c_after }};
_Static_assert(sizeof(xap_{{ name | to_snake | lower }}_t) == {{ data.struct_length }}, "xap_{{ name | to_snake | lower }}_t needs to be {{ data.struct_length }} bytes in size");
{% endif %}
{% endfor %}
////////////////////////////////////////////////////////////////////////////////
// Route definitions
{% macro export_route_types(prefix, container) %}
{% if 'routes' in container %}
{% for route, data in container.routes | dictsort %}
{% set this_prefix_uc = (prefix + '_' + data.define) | upper %}
{% set this_prefix_lc = this_prefix_uc | lower %}
{% if 'request_struct_members' in data %}
typedef struct {
{% for member in data.request_struct_members %}
{{ member.type | type_to_c(member.name|lower) }};
{% endfor %}
} __attribute__((__packed__)) {{ this_prefix_lc | to_snake | lower }}_arg_t;
_Static_assert(sizeof({{ this_prefix_lc | to_snake | lower }}_arg_t) == {{ data.request_struct_length }}, "{{ this_prefix_lc | to_snake | lower }}_arg_t needs to be {{ data.request_struct_length }} bytes in size");
{% elif 'request_type' in data %}
{% if '[' in data.request_type %}
typedef struct __attribute__((__packed__)) { {{ data.request_type | type_to_c('x') }}; } {{ this_prefix_lc }}_arg_t;
{% else %}
typedef {{ data.request_type | type_to_c(this_prefix_lc+'_arg_t') }};
{% endif %}
{% endif %}
{% if 'return_struct_members' in data %}
typedef struct {
{% for member in data.return_struct_members %}
{{ member.type | type_to_c(member.name|lower) }};
{% endfor %}
} __attribute__((__packed__)) {{ this_prefix_lc | to_snake | lower }}_t;
_Static_assert(sizeof({{ this_prefix_lc | to_snake | lower }}_t) == {{ data.return_struct_length }}, "{{ this_prefix_lc | to_snake | lower }}_t needs to be {{ data.return_struct_length }} bytes in size");
{% elif 'return_type' in data %}
{% if '[' in data.return_type %}
typedef struct __attribute__((__packed__)) { {{ data.return_type | type_to_c('x') }}; } {{ this_prefix_lc }}_t;
{% else %}
typedef {{ data.return_type | type_to_c(this_prefix_lc+'_t') }};
{% endif %}
{% endif %}
{{ export_route_types(this_prefix_lc, data) }}
{% endfor %}
{% endif %}
{% endmacro %}
{{ export_route_types('xap_route', xap) }}
////////////////////////////////////////////////////////////////////////////////
// Capabilities IDs
{% macro export_route_ids(prefix, container) %}
{% if 'routes' in container %}
{% for route, data in container.routes | dictsort %}
{% set this_prefix_uc = (prefix + '_' + data.define) | upper %}
{% set this_prefix_lc = this_prefix_uc | lower %}
#define {{ this_prefix_uc }} {{ route }}
{{ export_route_ids(this_prefix_uc, data) }}
{% endfor %}
{% endif %}
{% endmacro %}
{{ export_route_ids('XAP_ROUTE', xap) }}
////////////////////////////////////////////////////////////////////////////////
// Capabilities Masks
{% macro export_route_masks(prefix, container, preprocessor_condition) %}
{% if 'routes' in container %}
{% for route, data in container.routes | dictsort %}
{% set this_prefix_uc = (prefix + '_' + data.define) | upper %}
{% set this_prefix_lc = this_prefix_uc | lower %}
{% if 'enable_if_preprocessor' in data %}
{% if preprocessor_condition == 'TRUE' %}
{% set condition = "(" + data.enable_if_preprocessor + ")" %}
{% else %}
{% set condition = "(" + preprocessor_condition + " && (" + data.enable_if_preprocessor + "))" %}
{% endif %}
{% else %}
{% set condition = preprocessor_condition %}
{% endif %}
{% if condition == 'TRUE' %}
#define {{ this_prefix_uc }}_MASK (UINT32_C(1) << ({{ this_prefix_uc }}))
{% else %}
#if ({{ condition }})
#define {{ this_prefix_uc }}_MASK (UINT32_C(1) << ({{ this_prefix_uc }}))
#else // ({{ condition }})
#define {{ this_prefix_uc }}_MASK 0
#endif // ({{ condition }})
{% endif %}
{{ export_route_masks(this_prefix_uc, data, condition) }}
{% endfor %}
{% endif %}
{% endmacro %}
{{ export_route_masks('XAP_ROUTE', xap, 'TRUE') }}
////////////////////////////////////////////////////////////////////////////////
// Capabilities Values
{% macro export_route_capabilities(prefix, container) %}
{% if 'routes' in container %}
#define {{ prefix }}_CAPABILITIES (0 \
{% for route, data in container.routes | dictsort %}
{% set this_prefix_uc = (prefix + '_' + data.define) | upper %}
| ({{ this_prefix_uc }}_MASK) \
{% endfor %}
)
{% for route, data in container.routes | dictsort %}
{% set this_prefix_uc = (prefix + '_' + data.define) | upper %}
{{ export_route_capabilities(this_prefix_uc, data) }}
{% endfor %}
{% endif %}
{% endmacro %}
{{ export_route_capabilities('XAP_ROUTE', xap) }}
@@ -1,166 +0,0 @@
{{ constants.GPL2_HEADER_C_LIKE }}
{{ constants.GENERATED_HEADER_C_LIKE }}
{% macro route_conditions(route_stack) %}
{% set conditions = [] %}
{% for data in route_stack %}
{% if 'enable_if_preprocessor' in data %}
{{ conditions.append(data.enable_if_preprocessor) or '' }}
{% endif %}
{% endfor %}
{% if conditions %}
#if ({{ conditions | join(' && ') }})
{% endif %}
{{ caller() }}
{%- if conditions %}
#endif // ({{ conditions | join(' && ') }})
{% endif %}
{% endmacro %}
////////////////////////////////////////////////////////////////////////////////
// Broadcast
{% for message_id,data in xap.broadcast_messages.messages | dictsort %}
{% if 'return_type' in data %}
void {{ xap.broadcast_messages.define_prefix | lower }}_{{ data.define | to_snake | lower }}({{ data.return_type | type_to_c('value') }}) { xap_broadcast({{ message_id }}, &value, sizeof(value)); }
{% else %}
void {{ xap.broadcast_messages.define_prefix | lower }}_{{ data.define | to_snake | lower }}(const void *data, size_t length) { xap_broadcast({{ message_id }}, data, length); }
{% endif %}
{% endfor %}
////////////////////////////////////////////////////////////////////////////////
// Decl
{% macro export_route_declaration(prefix, container) %}
{% if 'routes' in container %}
{% for route, data in container.routes | dictsort %}
{% set this_prefix_uc = (prefix + '_' + data.define) | upper %}
{% set this_prefix_lc = this_prefix_uc | lower %}
{% if 'return_execute' in data %}
{% if 'request_struct_members' in data %}
{% set arg_type = ( this_prefix_lc | to_snake | lower ) + '_arg_t' %}
{% set arg_var = arg_type + ' arg' %}
{% elif 'request_type' in data %}
{% set arg_type = data.request_type | type_to_c() %}
{% set arg_var = data.request_type | type_to_c('arg') %}
{% endif %}
__attribute__((weak)) bool xap_execute_{{ data.return_execute }}(xap_token_t token{% if arg_type %}, {{ (arg_type + '* arg') if 'xap_route' in arg_type else arg_var }}{% endif %}) { return false; }
__attribute__((weak)) bool xap_respond_{{ data.return_execute }}(xap_token_t token, const uint8_t *data, size_t data_len) {
{% if arg_type %}
if (data_len != sizeof({{ arg_type }})) {
return false;
}
{{ arg_var }};
memcpy(&arg, data, sizeof({{ arg_type }}));
{% endif %}
return xap_execute_{{ data.return_execute }}(token{% if arg_type %}, {{ '&' if 'xap_route' in arg_type else '' }}arg{% endif %});
}
{% endif %}
{{ export_route_declaration(this_prefix_lc, data) }}
{% endfor %}
{% endif %}
{% endmacro %}
{{ export_route_declaration('xap_route', xap) }}
////////////////////////////////////////////////////////////////////////////////
// Data
{% macro export_route_data(prefix, container, route_stack) %}
{% set this_route_stack = route_stack.copy() %}
{{ this_route_stack.append(container) or '' }}
{% if 'routes' in container %}
{% for route, data in container.routes | dictsort %}
{% set this_prefix_uc = (prefix + '_' + data.define) | upper %}
{% set this_prefix_lc = this_prefix_uc | lower %}
{% if 'return_constant' in data %}
{% if data.return_type == 'struct' %}
{% call route_conditions(this_route_stack) %}
static const {{ this_prefix_lc }}_t {{ this_prefix_lc }}_data PROGMEM = {
{% for member in data.return_constant %}
{{ member }},
{% endfor %}
};
{% endcall %}
{% elif data.return_type == 'string' %}
{% call route_conditions(this_route_stack) %}
static const char {{ this_prefix_lc }}_str[] PROGMEM = {{ data.return_constant }};
{% endcall %}
{% else %}
{% call route_conditions(this_route_stack) %}
static const {{ data.return_type | type_to_c_before }} {{ this_prefix_lc }}_data PROGMEM = {{ data.return_constant }};
{% endcall %}
{% endif %}
{% endif %}
{{ export_route_data(this_prefix_lc, data, this_route_stack) }}
{% endfor %}
{% endif %}
{% endmacro %}
{{ export_route_data('XAP_ROUTE', xap, []) }}
////////////////////////////////////////////////////////////////////////////////
// Routes
{% macro append_routing_table(prefix, container, route_stack) %}
{% set this_route_stack = route_stack.copy() %}
{{ this_route_stack.append(container) or '' }}
{% if 'routes' in container %}
{% for route, data in container.routes | dictsort %}
{% set this_prefix_uc = (prefix + '_' + data.define) | upper %}
{% set this_prefix_lc = this_prefix_uc | lower %}
{{ append_routing_table(this_prefix_lc, data, this_route_stack) }}
{% endfor %}
{% call route_conditions(this_route_stack) %}
static const xap_route_t {{ prefix | lower}}_table[] PROGMEM = {
{% for route, data in container.routes | dictsort %}
{% set inner_route_stack = this_route_stack.copy() %}
{{ inner_route_stack.append(data) or '' }}
{% if 'permissions' in data %}
{% set secure_status = 'ROUTE_PERMISSIONS_SECURE' %}
{% else %}
{% set secure_status = 'ROUTE_PERMISSIONS_INSECURE' %}
{% endif %}
{% call route_conditions(inner_route_stack) %}
[{{ prefix | upper }}_{{ data.define }}] = {
{% if 'routes' in data %}
.flags = {
.type = XAP_ROUTE,
.secure = {{ secure_status }},
},
.child_routes = {{ prefix | lower }}_{{ data.define | lower }}_table,
.child_routes_len = sizeof({{ prefix | lower }}_{{ data.define | lower }}_table)/sizeof(xap_route_t),
{% elif 'return_execute' in data %}
.flags = {
.type = XAP_EXECUTE,
.secure = {{ secure_status }},
},
.handler = xap_respond_{{ data.return_execute | lower }},
{% elif 'return_constant' in data and data.return_type == 'string' %}
.flags = {
.type = XAP_CONST_MEM,
.secure = {{ secure_status }},
},
.const_data = {{ prefix | lower }}_{{ data.define | lower }}_str,
.const_data_len = sizeof({{ prefix | lower }}_{{ data.define | lower }}_str) - 1,
{% elif 'return_constant' in data %}
.flags = {
.type = XAP_CONST_MEM,
.secure = {{ secure_status }},
},
.const_data = &{{ prefix | lower }}_{{ data.define | lower }}_data,
.const_data_len = sizeof({{ prefix | lower }}_{{ data.define | lower }}_data),
{% endif %}
},
{% endcall %}
{% endfor %}
};
{% endcall %}
{% endif %}
{% endmacro %}
{{ append_routing_table("xap_route", xap, []) }}
-237
View File
@@ -1,237 +0,0 @@
{
version: 0.0.1
// Needed for table generation
define: XAP_ROUTE
// Documentation section is used purely for `qmk xap-generate-docs`.
documentation: {
order: [
page_header
type_docs
!type_docs.md.j2
term_definitions
!term_definitions.md.j2
request_response
reserved_tokens
response_flags
!response_flags.md.j2
example_conversation
routes
!routes.md.j2
]
page_header:
'''
# QMK Firmware XAP Specs
This document describes the requirements of the QMK XAP ("extensible application protocol") API.
'''
type_docs:
'''
## Types
**All integral types are little-endian.**
'''
term_definitions:
'''
## Definitions
This list defines the terms used across the entire set of XAP protocol documentation.
'''
request_response:
'''
## Requests and Responses
Communication generally follows a request/response pattern.
Each request needs to include a _token_ -- this `u16` value prefixes each outbound request from the host application and its corresponding response.
This allows response messages to be correlated with their request, even if multiple host applications are communicating with the firmware simultaneously.
Host applications should randomly generate a token ID for **every** outbound request, unless using a reserved token defined below.
To ensure host interoperability, valid token values are within the range `0x0100`-`0xFFFF`.
This token is followed by a `u8` signifying the length of data in the request.
'''
// This documentation section reserved for next version
reserved_tokens: ''
response_flags:
'''
Response messages will always be prefixed by the originating request _token_, directly followed by that request's _response flags_, then the response payload length:
'''
example_conversation:
'''
### Example "conversation":
**Request** -- version query:
| Byte | 0 | 1 | 2 | 3 | 4 |
| --- | --- | --- | --- | --- | --- |
| **Purpose** | Token | Token | Payload Length | Route | Route |
| **Value** | `0x43` | `0x2B` | `0x02` | `0x00` | `0x00` |
**Response** -- matching token, successful flag, payload of `0x03170192` = 3.17.192:
| Byte | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| **Purpose** | Token | Token | Response Flags | Payload Length | Payload | Payload | Payload | Payload |
| **Value** | `0x43` | `0x2B` | `0x01` | `0x04` | `0x92` | `0x01` | `0x17` | `0x03` |
'''
routes:
'''
## Routes
Subsystem validity should be queried through the “Enabled-in-firmware subsystem query” under the QMK subsystem (route=0x00,0x01).
This is the primary method for determining if a subsystem has been enabled in the running firmware.
'''
}
type_docs: {
u8:
'''
An unsigned 8-bit integral (octet, or byte), commonly seen as `uint8_t` from _stdint.h_.
'''
u16:
'''
An unsigned 16-bit integral, commonly seen as `uint16_t` from _stdint.h_.
'''
u32:
'''
An unsigned 32-bit integral, commonly seen as `uint32_t` from _stdint.h_.
'''
"type[n]":
'''
An array of `type`, with array extent of `N` -- e.g. `u8[2]` signifies two consecutive octets.
'''
}
term_definitions: {
Subsystem:
'''
A high-level area of functionality within XAP.
'''
Route:
'''
A sequence of _IDs_ describing the route to invoke a _handler_.
'''
Handler:
'''
A piece of code that is executed when a specific _route_ is received.
'''
Response:
'''
The data sent back to the host during execution of a _handler_.
'''
Payload:
'''
Any received data appended to the _route_, which gets delivered to the _handler_ when received.
'''
}
type_definitions: {
identifier: {
name: ID
description: A single octet / 8-bit byte, representing Subsystem or Route index.
type: u8
}
response_flags: {
name: Response Flags
description: An `u8` containing the status of the request.
type: u8
}
token: {
name: Token
description: A `u16` associated with a specific request as well as its corresponding response. Valid token values are within the range `0x0100`-`0xFFFF`.
type: u16
}
request_header: {
name: Request Header
description: Packet format for inbound data.
type: struct
struct_length: 3
struct_members: [
{
type: token
name: token
},
{
type: u8
name: length
}
]
}
response_header: {
name: Response Header
description: Packet format for outbound data.
type: struct
struct_length: 4
struct_members: [
{
type: token
name: token
},
{
type: response_flags
name: flags
},
{
type: u8
name: length
}
]
}
}
response_flags: {
define_prefix: XAP_RESPONSE_FLAG
bits: {
0: {
name: Success
define: SUCCESS
description:
'''
When this bit is set, the request was successfully handled. If not set, all payload data should be disregarded, and the request retried if appropriate (with a new token).
'''
}
}
}
routes: {
0x00: {
type: router
name: XAP
define: XAP
description:
'''
This subsystem is always present, and provides the ability to query information about the XAP protocol of the connected device.
'''
routes: {
0x00: {
type: command
name: Version Query
define: VERSION_QUERY
description:
'''
XAP protocol version query.
* Returns the BCD-encoded version in the format of XX.YY.ZZZZ => `0xXXYYZZZZ`
* e.g. 3.2.115 will match `0x03020115`, or bytes {0x15,0x01,0x02,0x03}.
'''
return_type: u32
return_purpose: bcd-version
return_constant: XAP_BCD_VERSION
}
}
}
}
}
-385
View File
@@ -1,385 +0,0 @@
{
version: 0.1.0
documentation: {
order: [
broadcast_messages
!broadcast_messages.md.j2
]
reserved_tokens:
'''
Two token values are reserved: `0xFFFE` and `0xFFFF`:
* `0xFFFE`: A message sent by a host application may use this token if no response is to be sent -- a "fire and forget" message.
* `0xFFFF`: Signifies a "broadcast" message sent by the firmware without prompting from the host application. Broadcast messages are defined later in this document.
Any request will generate at least one corresponding response, with the exception of messages using reserved tokens. Maximum total message length is 128 bytes due to RAM constraints.
'''
broadcast_messages:
'''
## Broadcast messages
Broadcast messages may be sent by the firmware to the host, without a corresponding inbound request. Each broadcast message uses the token `0xFFFF`, and does not expect a response from the host. Tokens are followed by an _ID_ signifying the type of broadcast, then the response _payload_ length, and finally the corresponding _payload_.
'''
}
response_flags: {
bits: {
1: {
name: Secure Failure
define: SECURE_FAILURE
description:
'''
When this bit is set, the requested _route_ was marked _secure_ but an _unlock sequence_ has not completed.
'''
}
}
}
type_docs: {
bool:
'''
Data type that contains values 0 and 1. Implemented as an alias of `u8`.
'''
u64:
'''
An unsigned 64-bit integral, commonly seen as `uint64_t` from _stdint.h_.
'''
"struct{}":
'''
A structure of data, packing different objects together. Data is "compacted" -- there are no padding bytes between fields. Equivalent to a packed C-style `struct`. The order in which they're defined matches the order of the data in the response packet.
'''
}
term_definitions: {
Capability:
'''
A way to determine if certain functionality is enabled in the firmware. Any _subsystem_ that provides build-time restriction of functionality must provide a _route_ for a _capabilities query_.
'''
"Secure Route":
'''
A _route_ which has potentially destructive consequences, necessitating prior approval by the user before executing.
'''
"Unlock sequence":
'''
A physical sequence initiated by the user to enable execution of _secure routes_.
'''
}
type_definitions: {
broadcast_header: {
name: Broadcast Header
description: Packet format for broadcast messages.
type: struct
struct_length: 4
struct_members: [
{
type: token
name: token
},
{
type: u8
name: type
},
{
type: u8
name: length
}
]
}
}
broadcast_messages: {
define_prefix: XAP_BROADCAST
messages: {
0x00: {
name: Log message
define: LOG_MESSAGE
description:
'''
Replicates and replaces the same functionality as if using the standard QMK `CONSOLE_ENABLE = yes` in `rules.mk`. Normal prints within the firmware will manifest as log messages broadcast to the host. `hid_listen` will not be functional with XAP enabled.
Log message payloads include `u8[Length]` containing the text, where the length of the text is the _broadcast_header.length_ field.
**Example Log Broadcast** -- log message "Hello QMK!"
| Byte | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| **Purpose** | Token | Token | Broadcast Type | Length | Payload | Payload | Payload | Payload | Payload | Payload | Payload | Payload | Payload | Payload |
| **Value** | `0xFF` | `0xFF` | `0x00` | `0x0A`(10) | `0x48`(H) | `0x65`(e) | `0x6C`(l) | `0x6C`(l) | `0x6F`(o) | `0x20`(&nbsp;) | `0x51`(Q) | `0x4D`(M) | `0x4B`(K) | `0x21`(!) |
'''
}
0x01: {
name: Secure Status
define: SECURE_STATUS
description:
'''
Secure status has changed. Payloads include a `u8` matching a 'Secure Status' request.
**Example Secure Status Broadcast** -- secure "Unlocking"
| Byte | 0 | 1 | 2 | 3 | 4 |
| --- | --- | --- | --- | --- | --- |
| **Purpose** | Token | Token | Broadcast Type | Length | Secure Status |
| **Value** | `0xFF` | `0xFF` | `0x01` | `0x01` | `0x01` |
'''
return_type: u8
}
0x02: {
name: Keyboard
define: KB
description:
'''
Reserved for vendor-specific functionality. No messages are defined by XAP.
'''
},
0x03: {
name: User
define: USER
description:
'''
Reserved for user-specific functionality. No messages are defined by XAP.
'''
}
}
}
routes: {
0x00: {
routes: {
0x01: {
type: command
name: Capabilities Query
define: CAPABILITIES_QUERY
description:
'''
XAP subsystem capabilities query. Each bit should be considered as a "usable" route within this subsystem.
'''
return_type: u32
return_purpose: capabilities
return_constant: XAP_ROUTE_XAP_CAPABILITIES
}
0x02: {
type: command
name: Enabled subsystem query
define: SUBSYSTEM_QUERY
description:
'''
XAP protocol subsystem query. Each bit should be considered as a "usable" subsystem. For example, checking `(value & (1 << XAP_ROUTE_QMK) != 0)` means the QMK subsystem is enabled and available for querying.
'''
return_type: u32
return_purpose: capabilities
return_constant: XAP_ROUTE_CAPABILITIES
}
0x03: {
type: command
name: Secure Status
define: SECURE_STATUS
description:
'''
Query secure route status
* 0 means secure routes are disabled
* 1 means unlock sequence initiated but incomplete
* 2 means secure routes are allowed
* any other value should be interpreted as disabled
'''
return_type: u8
return_execute: secure_status
}
0x04: {
type: command
name: Secure Unlock
define: SECURE_UNLOCK
description: Initiate secure route unlock sequence
return_execute: secure_unlock
}
0x05: {
type: command
name: Secure Lock
define: SECURE_LOCK
description: Disable secure routes
return_execute: secure_lock
}
}
},
0x01: {
type: router
name: QMK
define: QMK
description:
'''
This subsystem is always present, and provides the ability to address QMK-specific functionality.
'''
routes: {
0x00: {
type: command
name: Version Query
define: VERSION_QUERY
description:
'''
QMK protocol version query.
* Returns the BCD-encoded version in the format of XX.YY.ZZZZ => `0xXXYYZZZZ`
* e.g. 3.2.115 will match `0x03020115`, or bytes {0x15,0x01,0x02,0x03}.
'''
return_type: u32
return_purpose: bcd-version
return_constant: QMK_BCD_VERSION
}
0x01: {
type: command
name: Capabilities Query
define: CAPABILITIES_QUERY
description:
'''
QMK subsystem capabilities query. Each bit should be considered as a "usable" route within this subsystem.
'''
return_type: u32
return_purpose: capabilities
return_constant: XAP_ROUTE_QMK_CAPABILITIES
}
0x02: {
type: command
name: Board identifiers
define: BOARD_IDENTIFIERS
description:
'''
Retrieves the set of identifying information for the board.
'''
return_type: struct
return_struct_length: 10
return_struct_members: [
{
type: u16
name: Vendor ID
},
{
type: u16
name: Product ID
},
{
type: u16
name: Product Version
},
{
type: u32
name: QMK Unique Identifier
}
]
return_constant: [
VENDOR_ID
PRODUCT_ID
DEVICE_VER
XAP_KEYBOARD_IDENTIFIER
]
}
0x03: {
type: command
name: Board Manufacturer
define: BOARD_MANUFACTURER
description: Retrieves the name of the manufacturer
return_type: string
return_constant: QSTR(MANUFACTURER)
}
0x04: {
type: command
name: Product Name
define: PRODUCT_NAME
description: Retrieves the product name
return_type: string
return_constant: QSTR(PRODUCT)
}
0x05: {
type: command
name: Config Blob Length
define: CONFIG_BLOB_LEN
description: Retrieves the length of the configuration data bundled within the firmware
return_type: u16
return_constant: CONFIG_BLOB_GZ_LEN
}
0x06: {
type: command
name: Config Blob Chunk
define: CONFIG_BLOB_CHUNK
description: Retrieves a chunk of the configuration data bundled within the firmware
request_type: u16
request_purpose: offset
return_type: u8[32]
return_execute: get_config_blob_chunk
}
0x07: {
type: command
name: Jump to bootloader
define: BOOTLOADER_JUMP
permissions: secure
enable_if_preprocessor: defined(BOOTLOADER_JUMP_SUPPORTED)
description:
'''
Jump to bootloader
May not be present - if QMK capabilities query returns “true”, then jump to bootloader is supported
* 0 means secure routes are disabled, and should be considered as a failure
* 1 means successful, board will jump to bootloader
'''
return_type: u8
return_execute: request_bootloader_jump
}
0x08: {
type: command
name: Hardware Identifier
define: HARDWARE_ID
description: Retrieves a unique identifier for the board.
return_type: u32[4]
return_execute: get_hardware_id
}
0x09: {
type: command
name: Reinitialize EEPROM
define: EEPROM_RESET
permissions: secure
enable_if_preprocessor: !defined(NO_RESET)
description:
'''
Reinitializes the keyboard's EEPROM (persistent memory)
May not be present - if QMK capabilities query returns “true”, then reinitialize is supported
* 0 means secure routes are disabled, and should be considered as a failure
* 1 means successful, board will reinitialize and then reboot
'''
return_type: u8
return_execute: request_eeprom_reset
}
}
},
0x02: {
type: router
name: Keyboard
define: KB
description:
'''
This subsystem is always present, and reserved for vendor-specific functionality. No routes are defined by XAP.
'''
routes: {
}
},
0x03: {
type: router
name: User
define: USER
description:
'''
This subsystem is always present, and reserved for user-specific functionality. No routes are defined by XAP.
'''
routes: {
}
}
}
}
-200
View File
@@ -1,200 +0,0 @@
{
version: 0.2.0
routes: {
0x04: {
type: router
name: Keymap
define: KEYMAP
description:
'''
This subsystem allows for query of currently configured keycodes.
'''
routes: {
0x01: {
type: command
name: Capabilities Query
define: CAPABILITIES_QUERY
description:
'''
Keymap subsystem capabilities query. Each bit should be considered as a "usable" route within this subsystem.
'''
return_type: u32
return_purpose: capabilities
return_constant: XAP_ROUTE_KEYMAP_CAPABILITIES
}
0x02: {
type: command
name: Get Layer Count
define: GET_LAYER_COUNT
description: Query maximum number of layers that can be addressed within the keymap.
return_type: u8
return_execute: keymap_get_layer_count
}
0x03: {
type: command
name: Get Keycode
define: GET_KEYMAP_KEYCODE
description: Query the Keycode at the requested location.
request_type: struct
request_struct_length: 3
request_struct_members: [
{
type: u8
name: Layer
},
{
type: u8
name: Row
},
{
type: u8
name: Column
}
]
return_type: u16
return_execute: get_keymap_keycode
}
0x04: {
type: command
name: Get Encoder Keycode
define: GET_ENCODER_KEYCODE
description: Query the Keycode at the requested location.
enable_if_preprocessor: defined(ENCODER_MAP_ENABLE)
request_type: struct
request_struct_length: 3
request_struct_members: [
{
type: u8
name: Layer
},
{
type: u8
name: Encoder
},
{
type: u8
name: Clockwise
}
]
return_type: u16
return_execute: get_encoder_keycode
}
}
}
0x05: {
type: router
name: Remapping
define: REMAPPING
description:
'''
This subsystem allows for live reassignment of keycodes without rebuilding the firmware.
'''
enable_if_preprocessor: defined(DYNAMIC_KEYMAP_ENABLE)
routes: {
0x01: {
type: command
name: Capabilities Query
define: CAPABILITIES_QUERY
description:
'''
Remapping subsystem capabilities query. Each bit should be considered as a "usable" route within this subsystem.
'''
return_type: u32
return_purpose: capabilities
return_constant: XAP_ROUTE_REMAPPING_CAPABILITIES
}
0x02: {
type: command
name: Get Layer Count
define: GET_DYNAMIC_LAYER_COUNT
description: Query maximum number of layers that can be addressed within the keymap.
return_type: u8
return_constant: DYNAMIC_KEYMAP_LAYER_COUNT
}
0x03: {
type: command
name: Set Keycode
define: SET_KEYMAP_KEYCODE
description: Modify the Keycode at the requested location.
permissions: secure
request_type: struct
request_struct_length: 5
request_struct_members: [
{
type: u8
name: Layer
},
{
type: u8
name: Row
},
{
type: u8
name: Column
},
{
type: u16
name: Keycode
}
]
return_execute: dynamic_keymap_set_keycode
}
0x04: {
type: command
name: Set Encoder Keycode
define: SET_ENCODER_KEYCODE
permissions: secure
description: Modify the Keycode at the requested location.
enable_if_preprocessor: defined(ENCODER_MAP_ENABLE)
request_type: struct
request_struct_length: 5
request_struct_members: [
{
type: u8
name: Layer
},
{
type: u8
name: Encoder
},
{
type: u8
name: Clockwise
},
{
type: u16
name: Keycode
}
]
return_execute: dynamic_encoder_set_keycode
}
}
}
0x06: {
type: router
name: Lighting
define: LIGHTING
description:
'''
This subsystem allows for control over the lighting subsystem.
'''
routes: {
0x01: {
type: command
name: Capabilities Query
define: CAPABILITIES_QUERY
description:
'''
Lighting subsystem capabilities query. Each bit should be considered as a "usable" route within this subsystem.
'''
return_type: u32
return_purpose: capabilities
return_constant: XAP_ROUTE_LIGHTING_CAPABILITIES
}
}
}
}
}
-396
View File
@@ -1,396 +0,0 @@
{
version: 0.3.0
routes: {
0x06: {
routes: {
0x02: {
type: router
name: backlight
define: BACKLIGHT
description:
'''
This subsystem allows for control over the backlight subsystem.
'''
enable_if_preprocessor: defined(BACKLIGHT_ENABLE)
routes: {
0x01: {
type: command
name: Capabilities Query
define: CAPABILITIES_QUERY
description:
'''
backlight subsystem capabilities query. Each bit should be considered as a "usable" route within this subsystem.
'''
return_type: u32
return_purpose: capabilities
return_constant: XAP_ROUTE_LIGHTING_BACKLIGHT_CAPABILITIES
}
0x02: {
type: command
name: Get Enabled Effects
define: GET_ENABLED_EFFECTS
description: Each bit should be considered as a "usable" effect id
return_type: u8
return_constant: ENABLED_BACKLIGHT_EFFECTS
}
0x03: {
type: command
name: Get Config
define: GET_CONFIG
description: Query the current config.
return_type: struct
return_struct_length: 3
return_struct_members: [
{
type: u8
name: enable
},
{
type: u8
name: mode
},
{
type: u8
name: val
},
]
return_execute: get_backlight_config
}
0x04: {
type: command
name: Set Config
define: SET_CONFIG
description: Set the current config.
request_type: struct
request_struct_length: 3
request_struct_members: [
{
type: u8
name: enable
},
{
type: u8
name: mode
},
{
type: u8
name: val
},
]
return_execute: set_backlight_config
}
0x05: {
type: command
name: Save Config
define: SAVE_CONFIG
description: Save the current config.
return_execute: save_backlight_config
}
}
}
0x03: {
type: router
name: rgblight
define: RGBLIGHT
description:
'''
This subsystem allows for control over the rgblight subsystem.
'''
enable_if_preprocessor: defined(RGBLIGHT_ENABLE)
routes: {
0x01: {
type: command
name: Capabilities Query
define: CAPABILITIES_QUERY
description:
'''
rgblight subsystem capabilities query. Each bit should be considered as a "usable" route within this subsystem.
'''
return_type: u32
return_purpose: capabilities
return_constant: XAP_ROUTE_LIGHTING_RGBLIGHT_CAPABILITIES
}
0x02: {
type: command
name: Get Enabled Effects
define: GET_ENABLED_EFFECTS
description: Each bit should be considered as a "usable" effect id
return_type: u64
return_constant: ENABLED_RGBLIGHT_EFFECTS
}
0x03: {
type: command
name: Get Config
define: GET_CONFIG
description: Query the current config.
return_type: struct
return_struct_length: 6
return_struct_members: [
{
type: u8
name: enable
},
{
type: u8
name: mode
},
{
type: u8
name: hue
},
{
type: u8
name: sat
},
{
type: u8
name: val
},
{
type: u8
name: speed
},
]
return_execute: get_rgblight_config
}
0x04: {
type: command
name: Set Config
define: SET_CONFIG
description: Set the current config.
request_type: struct
request_struct_length: 6
request_struct_members: [
{
type: u8
name: enable
},
{
type: u8
name: mode
},
{
type: u8
name: hue
},
{
type: u8
name: sat
},
{
type: u8
name: val
},
{
type: u8
name: speed
},
]
return_execute: set_rgblight_config
}
0x05: {
type: command
name: Save Config
define: SAVE_CONFIG
description: Save the current config.
return_execute: save_rgblight_config
}
}
}
0x04: {
type: router
name: rgbmatrix
define: RGB_MATRIX
description:
'''
This subsystem allows for control over the rgb matrix subsystem.
'''
enable_if_preprocessor: defined(RGB_MATRIX_ENABLE)
routes: {
0x01: {
type: command
name: Capabilities Query
define: CAPABILITIES_QUERY
description:
'''
rgb matrix subsystem capabilities query. Each bit should be considered as a "usable" route within this subsystem.
'''
return_type: u32
return_purpose: capabilities
return_constant: XAP_ROUTE_LIGHTING_RGB_MATRIX_CAPABILITIES
}
0x02: {
type: command
name: Get Enabled Effects
define: GET_ENABLED_EFFECTS
description: Each bit should be considered as a "usable" effect id
return_type: u64
return_constant: ENABLED_RGB_MATRIX_EFFECTS
}
0x03: {
type: command
name: Get Config
define: GET_CONFIG
description: Query the current config.
return_type: struct
return_struct_length: 7
return_struct_members: [
{
type: u8
name: enable
},
{
type: u8
name: mode
},
{
type: u8
name: hue
},
{
type: u8
name: sat
},
{
type: u8
name: val
},
{
type: u8
name: speed
},
{
type: u8
name: flags
},
]
return_execute: get_rgb_matrix_config
}
0x04: {
type: command
name: Set Config
define: SET_CONFIG
description: Set the current config.
request_type: struct
request_struct_length: 7
request_struct_members: [
{
type: u8
name: enable
},
{
type: u8
name: mode
},
{
type: u8
name: hue
},
{
type: u8
name: sat
},
{
type: u8
name: val
},
{
type: u8
name: speed
},
{
type: u8
name: flags
},
]
return_execute: set_rgb_matrix_config
}
0x05: {
type: command
name: Save Config
define: SAVE_CONFIG
description: Save the current config.
return_execute: save_rgb_matrix_config
}
}
}
}
}
0x07: {
type: router
name: Audio
define: AUDIO
description:
'''
This subsystem allows for control over the audio subsystem.
'''
enable_if_preprocessor: defined(AUDIO_ENABLE)
routes: {
0x01: {
type: command
name: Capabilities Query
define: CAPABILITIES_QUERY
description:
'''
Audio subsystem capabilities query. Each bit should be considered as a "usable" route within this subsystem.
'''
return_type: u32
return_purpose: capabilities
return_constant: XAP_ROUTE_AUDIO_CAPABILITIES
}
0x03: {
type: command
name: Get Config
define: GET_CONFIG
description: Query the current config.
return_type: struct
return_struct_length: 2
return_struct_members: [
{
type: u8
name: enable
},
{
type: u8
name: clicky_enable
},
]
return_execute: get_audio_config
}
0x04: {
type: command
name: Set Config
define: SET_CONFIG
description: Set the current config.
request_type: struct
request_struct_length: 2
request_struct_members: [
{
type: u8
name: enable
},
{
type: u8
name: clicky_enable
},
]
return_execute: set_audio_config
}
0x05: {
type: command
name: Save Config
define: SAVE_CONFIG
description: Save the current config.
return_execute: save_audio_config
}
}
}
}
}
+1 -2
View File
@@ -144,8 +144,7 @@
{ "text": "Tri Layer", "link": "/features/tri_layer" },
{ "text": "Unicode", "link": "/features/unicode" },
{ "text": "Userspace", "link": "/feature_userspace" },
{ "text": "WPM Calculation", "link": "/features/wpm" },
{ "text": "XAP", "link": "/xap" }
{ "text": "WPM Calculation", "link": "/features/wpm" }
]
},
{
+4
View File
@@ -340,6 +340,10 @@ There are a few different ways to set handedness for split keyboards (listed in
* `#define SPLIT_TRANSACTION_IDS_USER .....`
* Allows for custom data sync with the slave when using the QMK-provided split transport. See [custom data sync between sides](features/split_keyboard#custom-data-sync) for more information.
* `#define SYSTEM_CONTROL_USAGE_MINIMUM 0x0081`
* `#define SYSTEM_CONTROL_USAGE_MAXIMUM 0x008F`
* Sets the usage range reported by the System Control collection that `EXTRAKEY_ENABLE` adds. The default range covers the System Control usages QMK can send and stops below the Generic Desktop D-pad usages (`0x90` and up). Raising the maximum into that range makes some hosts detect the keyboard as a gamepad, so only widen it if you need the extra usages and know your host handles them. The minimum must not be greater than the maximum.
# The `rules.mk` File
This is a [make](https://www.gnu.org/software/make/manual/make.html) file that is included by the top-level `Makefile`. It is used to set some information about the MCU that we will be compiling for as well as enabling and disabling certain features.
+20 -5
View File
@@ -191,7 +191,9 @@ void eeconfig_init_user_datablock(void);
:::::
### Example
### Examples
#### Basic
This is an example of how to add settings, and read and write it. We're using the user keymap for the example here.
@@ -215,10 +217,6 @@ typedef struct my_config_t {
static my_config_t config;
void keyboard_post_init_user(void) {
if (!eeconfig_is_user_datablock_valid()) {
eeconfig_init_user_datablock();
}
eeconfig_read_user_datablock(&config, 0, sizeof(my_config_t));
}
@@ -240,3 +238,20 @@ void housekeeping_task_user(void) {
}
}
```
#### Default Values
Extending the above example, a default value for the datablock can be configured as follows:
```c
void eeconfig_init_user_datablock(void) {
my_config_t default_config = {
.data = 42,
};
eeconfig_update_user_datablock(&default_config, 0, sizeof(my_config_t));
}
```
::: tip
For large datablocks, you might need to manually update in chunks to avoid memory issues.
:::
+2 -1
View File
@@ -16,7 +16,8 @@ These functions allow you to activate layers in various ways. Note that layers a
* `OSL(layer)` - momentarily activates *layer* until the next key is pressed. See [One Shot Keys](one_shot_keys) for details and additional functionality.
* `TG(layer)` - toggles *layer*, activating it if it's inactive and vice versa
* `TO(layer)` - activates *layer* and de-activates all other layers (except your default layer). This function is special, because instead of just adding/removing one layer to your active layer stack, it will completely replace your current active layers, uniquely allowing you to replace higher layers with a lower one. This is activated on keydown (as soon as the key is pressed).
* `TT(layer)` - Layer Tap-Toggle. If you hold the key down, *layer* is activated, and then is de-activated when you let go (like `MO`). If you repeatedly tap it, the layer will be toggled on or off (like `TG`). It needs 5 taps by default, but you can change this by defining `TAPPING_TOGGLE` -- for example, `#define TAPPING_TOGGLE 2` to toggle on just two taps.
* `TT(layer)` - Layer Tap-Toggle. If you hold the key down, *layer* is activated, and then is de-activated when you let go (like `MO`). If you repeatedly tap it, the layer will be toggled on or off (like `TG`). It needs 5 taps by default, but you can change this by defining `TAPPING_TOGGLE` -- for example, `#define TAPPING_TOGGLE 2` to toggle on just two taps.
* Note: toggling behavior requires that [Quick Tap](tap_hold#quick-tap-term) is enabled (`QUICK_TAP_TERM` not set to `0`), or if `QUICK_TAP_TERM_PER_KEY` is defined, that `get_quick_tap_term()` returns a non-zero value for the `TT` key.
See also the [Layer Lock key](features/layer_lock), which locks the highest
active layer until pressed again.
+1 -1
View File
@@ -8,7 +8,7 @@ Replace the `KC_GRV` key in your keymap (usually to the left of the `1` key) wit
## What Your OS Sees
If Mary presses `QK_GESC` on her keyboard, the OS will see an KC_ESC character. Now if Mary holds Shift down and presses `QK_GESC` it will output `~`, or a shifted backtick. Now if she holds GUI/CMD/WIN, it will output a simple <code>&#96;</code> character.
If Mary presses `QK_GESC` on her keyboard, the OS will see an `KC_ESC` character. Now if Mary holds Shift down and presses `QK_GESC` it will output `~`, or a shifted backtick. Now if she holds GUI/CMD/WIN, it will output a simple <code>&#96;</code> character.
## Keycodes
+4
View File
@@ -375,6 +375,10 @@ In this configuration "hold" takes place **after** tap dance timeout. To achieve
Tap dance can be used to emulate `MT()` and `LT()` behavior when the tapped code is not a basic keycode. This is useful to send tapped keycodes that normally require `Shift`, such as parentheses or curly braces—or other modified keycodes, such as `Control + X`.
::: tip
For simply sending a non-basic keycode on tap while functioning as a modifier or layer switch on hold, a simpler (and often superior) alternative is to use a Mod-Tap or Layer-Tap key and intercept its tap function in `process_record_user()`. This avoids the complexity of Tap Dance, and allows the key to benefit from advanced Tap-Hold options. See [Intercepting Mod-Taps](../mod_tap#intercepting-mod-taps) for details.
:::
Below your layers and custom keycodes, add the following:
```c
+3 -1
View File
@@ -72,9 +72,11 @@ It can also be mitigated by increasing [`TAP_CODE_DELAY`](config_options#behavio
## Intercepting Mod-Taps
This technique works for both Mod-Tap (`MT`) and Layer-Tap (`LT`) keys.
### Changing tap function
The basic keycode limitation with Mod-Tap can be worked around by intercepting it in `process_record_user`. For example, shifted keycode `KC_DQUO` cannot be used with `MT()` because it is a 16-bit keycode alias of `LSFT(KC_QUOT)`. Modifiers on `KC_DQUO` will be masked by `MT()`. But the following custom code can be used to intercept the "tap" function to manually send `KC_DQUO`:
The basic keycode limitation with Mod-Tap and Layer-Tap can be worked around by intercepting it in `process_record_user`. For example, shifted keycode `KC_DQUO` cannot be used with `MT()` because it is a 16-bit keycode alias of `LSFT(KC_QUOT)`. Modifiers on `KC_DQUO` will be masked by `MT()`. But the following custom code can be used to intercept the "tap" function to manually send `KC_DQUO`:
```c
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
+25 -2
View File
@@ -1,8 +1,12 @@
# Tap-Hold Configuration Options
These options let you modify the behavior of the tap-hold keys, applying primarily to Mod-Tap `MT` and Layer-Tap `LT` keys. They also affect layer tap-toggle `TT`, one-shot `OSM`, `OSL`, and Swap Hands `SH_T`, `SH_TT` keys.
While Tap-Hold options are fantastic, they are not without their issues. We have tried to configure them with reasonable defaults, but that may still cause issues for some people.
These options let you modify the behavior of the tap-hold keys.
::: info
Besides the tapping term, tap-hold options do **not** apply to Tap Dance keys. Tap Dance implements a separate, simpler decision logic to track when keys are tapped vs. held, and it does not support advanced tap-hold configurations like Permissive Hold, Chordal Hold, etc.
:::
## Tapping Term
@@ -148,6 +152,25 @@ uint16_t get_tapping_term(uint16_t keycode, keyrecord_t *record) {
The reason is that `TAPPING_TERM` is a macro that expands to a constant integer and thus cannot be changed at runtime, whereas `g_tapping_term` is a variable whose value can be changed at runtime. If you want, you can temporarily enable `DYNAMIC_TAPPING_TERM_ENABLE` to find a suitable tapping term value and then disable that feature and revert back to using the classic syntax for per-key tapping term settings. In case you need to access the tapping term from elsewhere in your code, you can use the `GET_TAPPING_TERM(keycode, record)` macro. This macro will expand to whatever is the appropriate access pattern given the current configuration.
## Configuring Home Row Mods
"Home row mods" (HRMs) is a popular layout technique where modifiers are placed as Mod-Tap keys on the home row (<kbd>A</kbd>, <kbd>S</kbd>, <kbd>D</kbd>, <kbd>F</kbd> and <kbd>J</kbd>, <kbd>K</kbd>, <kbd>L</kbd>, <kbd>;</kbd>, supposing QWERTY layout). This reduces hand movement and can increase comfort. However, because these keys are also used for fast typing, they are prone to accidental modifier triggers (when rolling keys) or accidental typed letters (when trying to use a modifier).
There is no single perfect configuration for home row mods, as it depends heavily on your typing speed and habits. However, a good starting point in QMK is (added in your `config.h`):
```c
#define TAPPING_TERM 250
#define PERMISSIVE_HOLD // Triggers mod if you tap another key while holding.
#define CHORDAL_HOLD // Constrains holds to opposite-hand combinations.
// Consider also:
// #define FLOW_TAP_TERM 150 // Disables holds when typing quickly.
```
See [Permissive Hold](#permissive-hold), [Chordal Hold](#chordal-hold), and [Flow Tap](#flow-tap) below for details on what they do and how to fine-tune them.
Additionally, [Speculative Hold](#speculative-hold) is useful to eliminate lag when combining a home row mod with mouse clicks (e.g., Shift + Click), as standard mod-tap keys do not send the modifier until the tap-hold decision is finalized.
## Tap-Or-Hold Decision Modes
The code which decides between the tap and hold actions of dual-role keys supports three different modes, in increasing order of preference for the hold action:
@@ -824,7 +847,7 @@ bool get_speculative_hold(uint16_t keycode, keyrecord_t* record) {
}
```
Some operating systems or applications assign actions to tapping a modifier key by itself, e.g., tapping GUI to open a start menu. Because Speculative Hold sometimes sends a lone modifier key press, it can falsely trigger these actions (known as the "flashing mods" problem). How such an input is handled depends on the OS and application, so unfortunately, there is no universal solution.
Some operating systems or applications assign actions to tapping a modifier key by itself, e.g., tapping GUI to open a start menu. Because Speculative Hold sends a lone modifier key press in some cases, it can falsely trigger these actions (known as the "flashing mods" problem). How such an input is handled depends on the OS and application, so unfortunately, there is no universal solution.
To mitigate this issue, you can set `DUMMY_MOD_NEUTRALIZER_KEYCODE` (and optionally `MODS_TO_NEUTRALIZE`) in your `config.h`, as described above for [Retro Tapping](#retro-tapping).
-95
View File
@@ -1,95 +0,0 @@
# XAP
XAP (“extensible application protocol”) API intends to provide access to various QMK subsystems.
## Overview
```mermaid
%%{init: {'themeVariables': { 'fontSize': '24px'}}}%%
flowchart LR
dev[QMK Device] <-- XAP --> host[Host Computer]
```
The intention is to provide access to QMK subsystems through a versioned and documented protocol.
## Protocol Reference
[protocol_versions](xap_protocol.md ':include')
## Clients
TODO
## CLI
The QMK CLI provides a few XAP specific commands for diagnosis purposes.
### List Connected Devices
Simple
```
$ qmk xap --list
Ψ Available devices:
Ψ 7844:8450 KPrepublic XD84 Pro [API:0.2.0] LOCKED
```
Verbose
```
$ qmk --verbose xap --list
Ψ Available devices:
Ψ 7844:8450 KPrepublic XD84 Pro [API:0.2.0] LOCKED
_id: 553831323538150A2113000000000000
backlight.pin: F5
bootloader: atmel-dfu
community_layouts: 75_ansi, 75_iso
debounce: 5
diode_direction: COL2ROW
features.audio: False
features.backlight: True
features.bootmagic: True
features.command: False
features.console: False
features.extrakey: True
features.mousekey: False
features.nkro: True
features.rgblight: True
indicators.caps_lock: B2
keyboard_folder: xiudi/xd84pro
keyboard_name: XD84 Pro
layouts: LAYOUT_75_ansi, LAYOUT_75_iso, LAYOUT_all
maintainer: qmk
manufacturer: KPrepublic
matrix_pins.cols: B1, B3, B4, B5, B6, B7, C6, C7, D4, D6, D7, E6, F0, F1, F7
matrix_pins.rows: D0, D1, D2, D3, D5, F4
matrix_pins.unused: B0, E2
matrix_size.cols: 15
matrix_size.rows: 6
mouse_key.enabled: False
platform: unknown
processor: atmega32u4
processor_type: avr
protocol: LUFA
rgblight.animations.all: False
rgblight.led_count: 12
rgblight.pin: F6
rgblight.sleep: False
url:
usb.device_ver: 0x0001
usb.device_version: 0.0.1
usb.pid: 0x8450
usb.vid: 0x7844
```
### Interactive shell
```
$ qmk xap -i
Ψ Connected to:7844:8450 KPrepublic XD84 Pro
Welcome to the XAP shell. Type help or ? to list commands.
Ψ> help
Documented commands (type help <topic>):
========================================
EOF about exit help keycode keymap layer listen unlock
Ψ>
```
-108
View File
@@ -1,108 +0,0 @@
<!--- Copyright 2024 QMK --->
<!--- SPDX-License-Identifier: GPL-2.0-or-later --->
<!---
*******************************************************************************
88888888888 888 d8b .d888 d8b 888 d8b
888 888 Y8P d88P" Y8P 888 Y8P
888 888 888 888
888 88888b. 888 .d8888b 888888 888 888 .d88b. 888 .d8888b
888 888 "88b 888 88K 888 888 888 d8P Y8b 888 88K
888 888 888 888 "Y8888b. 888 888 888 88888888 888 "Y8888b.
888 888 888 888 X88 888 888 888 Y8b. 888 X88
888 888 888 888 88888P' 888 888 888 "Y8888 888 88888P'
888 888
888 888
888 888
.d88b. .d88b. 88888b. .d88b. 888d888 8888b. 888888 .d88b. .d88888
d88P"88b d8P Y8b 888 "88b d8P Y8b 888P" "88b 888 d8P Y8b d88" 888
888 888 88888888 888 888 88888888 888 .d888888 888 88888888 888 888
Y88b 888 Y8b. 888 888 Y8b. 888 888 888 Y88b. Y8b. Y88b 888
"Y88888 "Y8888 888 888 "Y8888 888 "Y888888 "Y888 "Y8888 "Y88888
888
Y8b d88P
"Y88P"
*******************************************************************************
--->
# QMK Firmware XAP Specs
This document describes the requirements of the QMK XAP ("extensible application protocol") API.
## Types
**All integral types are little-endian.**
| Name | Definition |
| -- | -- |
| _type[n]_ | An array of `type`, with array extent of `N` -- e.g. `u8[2]` signifies two consecutive octets. |
| _u16_ | An unsigned 16-bit integral, commonly seen as `uint16_t` from _stdint.h_. |
| _u32_ | An unsigned 32-bit integral, commonly seen as `uint32_t` from _stdint.h_. |
| _u8_ | An unsigned 8-bit integral (octet, or byte), commonly seen as `uint8_t` from _stdint.h_. |
## Definitions
This list defines the terms used across the entire set of XAP protocol documentation.
| Name | Definition |
| -- | -- |
| _Handler_ | A piece of code that is executed when a specific _route_ is received. |
| _Payload_ | Any received data appended to the _route_, which gets delivered to the _handler_ when received. |
| _Response_ | The data sent back to the host during execution of a _handler_. |
| _Route_ | A sequence of _IDs_ describing the route to invoke a _handler_. |
| _Subsystem_ | A high-level area of functionality within XAP. |
| _ID_ | A single octet / 8-bit byte, representing Subsystem or Route index. |
| _Request Header_ | Packet format for inbound data. Takes the format:<br>`token` - token<br>`u8` - length |
| _Response Flags_ | An `u8` containing the status of the request. |
| _Response Header_ | Packet format for outbound data. Takes the format:<br>`token` - token<br>`response_flags` - flags<br>`u8` - length |
| _Token_ | A `u16` associated with a specific request as well as its corresponding response. Valid token values are within the range `0x0100`-`0xFFFF`. |
## Requests and Responses
Communication generally follows a request/response pattern.
Each request needs to include a _token_ -- this `u16` value prefixes each outbound request from the host application and its corresponding response.
This allows response messages to be correlated with their request, even if multiple host applications are communicating with the firmware simultaneously.
Host applications should randomly generate a token ID for **every** outbound request, unless using a reserved token defined below.
To ensure host interoperability, valid token values are within the range `0x0100`-`0xFFFF`.
This token is followed by a `u8` signifying the length of data in the request.
Response messages will always be prefixed by the originating request _token_, directly followed by that request's _response flags_, then the response payload length:
| Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 |
| -- | -- | -- | -- | -- | -- | -- | -- |
| `-` | `-` | `-` | `-` | `-` | `-` | `-` | `SUCCESS` |
* Bit 0 (`SUCCESS`): When this bit is set, the request was successfully handled. If not set, all payload data should be disregarded, and the request retried if appropriate (with a new token).
### Example "conversation":
**Request** -- version query:
| Byte | 0 | 1 | 2 | 3 | 4 |
| --- | --- | --- | --- | --- | --- |
| **Purpose** | Token | Token | Payload Length | Route | Route |
| **Value** | `0x43` | `0x2B` | `0x02` | `0x00` | `0x00` |
**Response** -- matching token, successful flag, payload of `0x03170192` = 3.17.192:
| Byte | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| **Purpose** | Token | Token | Response Flags | Payload Length | Payload | Payload | Payload | Payload |
| **Value** | `0x43` | `0x2B` | `0x01` | `0x04` | `0x92` | `0x01` | `0x17` | `0x03` |
## Routes
Subsystem validity should be queried through the “Enabled-in-firmware subsystem query” under the QMK subsystem (route=0x00,0x01).
This is the primary method for determining if a subsystem has been enabled in the running firmware.
### XAP - `0x00`
This subsystem is always present, and provides the ability to query information about the XAP protocol of the connected device.
| Name | Route | Tags | Payloads | Description |
| -- | -- | -- | -- | -- |
| Version Query | `0x00 0x00` | | __Response:__ `u32` | XAP protocol version query.<br><br>* Returns the BCD-encoded version in the format of XX.YY.ZZZZ => `0xXXYYZZZZ`<br> * e.g. 3.2.115 will match `0x03020115`, or bytes {0x15,0x01,0x02,0x03}.|
-176
View File
@@ -1,176 +0,0 @@
<!--- Copyright 2024 QMK --->
<!--- SPDX-License-Identifier: GPL-2.0-or-later --->
<!---
*******************************************************************************
88888888888 888 d8b .d888 d8b 888 d8b
888 888 Y8P d88P" Y8P 888 Y8P
888 888 888 888
888 88888b. 888 .d8888b 888888 888 888 .d88b. 888 .d8888b
888 888 "88b 888 88K 888 888 888 d8P Y8b 888 88K
888 888 888 888 "Y8888b. 888 888 888 88888888 888 "Y8888b.
888 888 888 888 X88 888 888 888 Y8b. 888 X88
888 888 888 888 88888P' 888 888 888 "Y8888 888 88888P'
888 888
888 888
888 888
.d88b. .d88b. 88888b. .d88b. 888d888 8888b. 888888 .d88b. .d88888
d88P"88b d8P Y8b 888 "88b d8P Y8b 888P" "88b 888 d8P Y8b d88" 888
888 888 88888888 888 888 88888888 888 .d888888 888 88888888 888 888
Y88b 888 Y8b. 888 888 Y8b. 888 888 888 Y88b. Y8b. Y88b 888
"Y88888 "Y8888 888 888 "Y8888 888 "Y888888 "Y888 "Y8888 "Y88888
888
Y8b d88P
"Y88P"
*******************************************************************************
--->
# QMK Firmware XAP Specs
This document describes the requirements of the QMK XAP ("extensible application protocol") API.
## Types
**All integral types are little-endian.**
| Name | Definition |
| -- | -- |
| _bool_ | Data type that contains values 0 and 1. Implemented as an alias of `u8`. |
| _struct{}_ | A structure of data, packing different objects together. Data is "compacted" -- there are no padding bytes between fields. Equivalent to a packed C-style `struct`. The order in which they're defined matches the order of the data in the response packet. |
| _type[n]_ | An array of `type`, with array extent of `N` -- e.g. `u8[2]` signifies two consecutive octets. |
| _u16_ | An unsigned 16-bit integral, commonly seen as `uint16_t` from _stdint.h_. |
| _u32_ | An unsigned 32-bit integral, commonly seen as `uint32_t` from _stdint.h_. |
| _u64_ | An unsigned 64-bit integral, commonly seen as `uint64_t` from _stdint.h_. |
| _u8_ | An unsigned 8-bit integral (octet, or byte), commonly seen as `uint8_t` from _stdint.h_. |
## Definitions
This list defines the terms used across the entire set of XAP protocol documentation.
| Name | Definition |
| -- | -- |
| _Capability_ | A way to determine if certain functionality is enabled in the firmware. Any _subsystem_ that provides build-time restriction of functionality must provide a _route_ for a _capabilities query_. |
| _Handler_ | A piece of code that is executed when a specific _route_ is received. |
| _Payload_ | Any received data appended to the _route_, which gets delivered to the _handler_ when received. |
| _Response_ | The data sent back to the host during execution of a _handler_. |
| _Route_ | A sequence of _IDs_ describing the route to invoke a _handler_. |
| _Secure Route_ | A _route_ which has potentially destructive consequences, necessitating prior approval by the user before executing. |
| _Subsystem_ | A high-level area of functionality within XAP. |
| _Unlock sequence_ | A physical sequence initiated by the user to enable execution of _secure routes_. |
| _Broadcast Header_ | Packet format for broadcast messages. Takes the format:<br>`token` - token<br>`u8` - type<br>`u8` - length |
| _ID_ | A single octet / 8-bit byte, representing Subsystem or Route index. |
| _Request Header_ | Packet format for inbound data. Takes the format:<br>`token` - token<br>`u8` - length |
| _Response Flags_ | An `u8` containing the status of the request. |
| _Response Header_ | Packet format for outbound data. Takes the format:<br>`token` - token<br>`response_flags` - flags<br>`u8` - length |
| _Token_ | A `u16` associated with a specific request as well as its corresponding response. Valid token values are within the range `0x0100`-`0xFFFF`. |
## Requests and Responses
Communication generally follows a request/response pattern.
Each request needs to include a _token_ -- this `u16` value prefixes each outbound request from the host application and its corresponding response.
This allows response messages to be correlated with their request, even if multiple host applications are communicating with the firmware simultaneously.
Host applications should randomly generate a token ID for **every** outbound request, unless using a reserved token defined below.
To ensure host interoperability, valid token values are within the range `0x0100`-`0xFFFF`.
This token is followed by a `u8` signifying the length of data in the request.
Two token values are reserved: `0xFFFE` and `0xFFFF`:
* `0xFFFE`: A message sent by a host application may use this token if no response is to be sent -- a "fire and forget" message.
* `0xFFFF`: Signifies a "broadcast" message sent by the firmware without prompting from the host application. Broadcast messages are defined later in this document.
Any request will generate at least one corresponding response, with the exception of messages using reserved tokens. Maximum total message length is 128 bytes due to RAM constraints.
Response messages will always be prefixed by the originating request _token_, directly followed by that request's _response flags_, then the response payload length:
| Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 |
| -- | -- | -- | -- | -- | -- | -- | -- |
| `-` | `-` | `-` | `-` | `-` | `-` | `SECURE_FAILURE` | `SUCCESS` |
* Bit 1 (`SECURE_FAILURE`): When this bit is set, the requested _route_ was marked _secure_ but an _unlock sequence_ has not completed.
* Bit 0 (`SUCCESS`): When this bit is set, the request was successfully handled. If not set, all payload data should be disregarded, and the request retried if appropriate (with a new token).
### Example "conversation":
**Request** -- version query:
| Byte | 0 | 1 | 2 | 3 | 4 |
| --- | --- | --- | --- | --- | --- |
| **Purpose** | Token | Token | Payload Length | Route | Route |
| **Value** | `0x43` | `0x2B` | `0x02` | `0x00` | `0x00` |
**Response** -- matching token, successful flag, payload of `0x03170192` = 3.17.192:
| Byte | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| **Purpose** | Token | Token | Response Flags | Payload Length | Payload | Payload | Payload | Payload |
| **Value** | `0x43` | `0x2B` | `0x01` | `0x04` | `0x92` | `0x01` | `0x17` | `0x03` |
## Routes
Subsystem validity should be queried through the “Enabled-in-firmware subsystem query” under the QMK subsystem (route=0x00,0x01).
This is the primary method for determining if a subsystem has been enabled in the running firmware.
### XAP - `0x00`
This subsystem is always present, and provides the ability to query information about the XAP protocol of the connected device.
| Name | Route | Tags | Payloads | Description |
| -- | -- | -- | -- | -- |
| Version Query | `0x00 0x00` | | __Response:__ `u32` | XAP protocol version query.<br><br>* Returns the BCD-encoded version in the format of XX.YY.ZZZZ => `0xXXYYZZZZ`<br> * e.g. 3.2.115 will match `0x03020115`, or bytes {0x15,0x01,0x02,0x03}.|
| Capabilities Query | `0x00 0x01` | | __Response:__ `u32` | XAP subsystem capabilities query. Each bit should be considered as a "usable" route within this subsystem.|
| Enabled subsystem query | `0x00 0x02` | | __Response:__ `u32` | XAP protocol subsystem query. Each bit should be considered as a "usable" subsystem. For example, checking `(value & (1 << XAP_ROUTE_QMK) != 0)` means the QMK subsystem is enabled and available for querying.|
| Secure Status | `0x00 0x03` | | __Response:__ `u8` | Query secure route status<br><br>* 0 means secure routes are disabled<br>* 1 means unlock sequence initiated but incomplete<br>* 2 means secure routes are allowed<br>* any other value should be interpreted as disabled|
| Secure Unlock | `0x00 0x04` | | | Initiate secure route unlock sequence|
| Secure Lock | `0x00 0x05` | | | Disable secure routes|
### QMK - `0x01`
This subsystem is always present, and provides the ability to address QMK-specific functionality.
| Name | Route | Tags | Payloads | Description |
| -- | -- | -- | -- | -- |
| Version Query | `0x01 0x00` | | __Response:__ `u32` | QMK protocol version query.<br><br>* Returns the BCD-encoded version in the format of XX.YY.ZZZZ => `0xXXYYZZZZ`<br> * e.g. 3.2.115 will match `0x03020115`, or bytes {0x15,0x01,0x02,0x03}.|
| Capabilities Query | `0x01 0x01` | | __Response:__ `u32` | QMK subsystem capabilities query. Each bit should be considered as a "usable" route within this subsystem.|
| Board identifiers | `0x01 0x02` | | __Response:__<br>&nbsp;&nbsp;&nbsp;&nbsp;* Vendor ID: `u16`<br>&nbsp;&nbsp;&nbsp;&nbsp;* Product ID: `u16`<br>&nbsp;&nbsp;&nbsp;&nbsp;* Product Version: `u16`<br>&nbsp;&nbsp;&nbsp;&nbsp;* QMK Unique Identifier: `u32` | Retrieves the set of identifying information for the board.|
| Board Manufacturer | `0x01 0x03` | | __Response:__ `string` | Retrieves the name of the manufacturer|
| Product Name | `0x01 0x04` | | __Response:__ `string` | Retrieves the product name|
| Config Blob Length | `0x01 0x05` | | __Response:__ `u16` | Retrieves the length of the configuration data bundled within the firmware|
| Config Blob Chunk | `0x01 0x06` | | __Request:__ `u16`<br><br>__Response:__ `u8[32]` | Retrieves a chunk of the configuration data bundled within the firmware|
| Jump to bootloader | `0x01 0x07` | __Secure__ | __Response:__ `u8` | Jump to bootloader<br><br>May not be present - if QMK capabilities query returns “true”, then jump to bootloader is supported<br><br>* 0 means secure routes are disabled, and should be considered as a failure<br>* 1 means successful, board will jump to bootloader|
| Hardware Identifier | `0x01 0x08` | | __Response:__ `u32[4]` | Retrieves a unique identifier for the board.|
| Reinitialize EEPROM | `0x01 0x09` | __Secure__ | __Response:__ `u8` | Reinitializes the keyboard's EEPROM (persistent memory)<br><br>May not be present - if QMK capabilities query returns “true”, then reinitialize is supported<br><br>* 0 means secure routes are disabled, and should be considered as a failure<br>* 1 means successful, board will reinitialize and then reboot|
### Keyboard - `0x02`
This subsystem is always present, and reserved for vendor-specific functionality. No routes are defined by XAP.
### User - `0x03`
This subsystem is always present, and reserved for user-specific functionality. No routes are defined by XAP.
## Broadcast messages
Broadcast messages may be sent by the firmware to the host, without a corresponding inbound request. Each broadcast message uses the token `0xFFFF`, and does not expect a response from the host. Tokens are followed by an _ID_ signifying the type of broadcast, then the response _payload_ length, and finally the corresponding _payload_.
### Log message - `0x00`
Replicates and replaces the same functionality as if using the standard QMK `CONSOLE_ENABLE = yes` in `rules.mk`. Normal prints within the firmware will manifest as log messages broadcast to the host. `hid_listen` will not be functional with XAP enabled.
Log message payloads include `u8[Length]` containing the text, where the length of the text is the _broadcast_header.length_ field.
**Example Log Broadcast** -- log message "Hello QMK!"
| Byte | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| **Purpose** | Token | Token | Broadcast Type | Length | Payload | Payload | Payload | Payload | Payload | Payload | Payload | Payload | Payload | Payload |
| **Value** | `0xFF` | `0xFF` | `0x00` | `0x0A`(10) | `0x48`(H) | `0x65`(e) | `0x6C`(l) | `0x6C`(l) | `0x6F`(o) | `0x20`(&nbsp;) | `0x51`(Q) | `0x4D`(M) | `0x4B`(K) | `0x21`(!) |
### Secure Status - `0x01`
Secure status has changed. Payloads include a `u8` matching a 'Secure Status' request.
**Example Secure Status Broadcast** -- secure "Unlocking"
| Byte | 0 | 1 | 2 | 3 | 4 |
| --- | --- | --- | --- | --- | --- |
| **Purpose** | Token | Token | Broadcast Type | Length | Secure Status |
| **Value** | `0xFF` | `0xFF` | `0x01` | `0x01` | `0x01` |
### Keyboard - `0x02`
Reserved for vendor-specific functionality. No messages are defined by XAP.
### User - `0x03`
Reserved for user-specific functionality. No messages are defined by XAP.
-203
View File
@@ -1,203 +0,0 @@
<!--- Copyright 2024 QMK --->
<!--- SPDX-License-Identifier: GPL-2.0-or-later --->
<!---
*******************************************************************************
88888888888 888 d8b .d888 d8b 888 d8b
888 888 Y8P d88P" Y8P 888 Y8P
888 888 888 888
888 88888b. 888 .d8888b 888888 888 888 .d88b. 888 .d8888b
888 888 "88b 888 88K 888 888 888 d8P Y8b 888 88K
888 888 888 888 "Y8888b. 888 888 888 88888888 888 "Y8888b.
888 888 888 888 X88 888 888 888 Y8b. 888 X88
888 888 888 888 88888P' 888 888 888 "Y8888 888 88888P'
888 888
888 888
888 888
.d88b. .d88b. 88888b. .d88b. 888d888 8888b. 888888 .d88b. .d88888
d88P"88b d8P Y8b 888 "88b d8P Y8b 888P" "88b 888 d8P Y8b d88" 888
888 888 88888888 888 888 88888888 888 .d888888 888 88888888 888 888
Y88b 888 Y8b. 888 888 Y8b. 888 888 888 Y88b. Y8b. Y88b 888
"Y88888 "Y8888 888 888 "Y8888 888 "Y888888 "Y888 "Y8888 "Y88888
888
Y8b d88P
"Y88P"
*******************************************************************************
--->
# QMK Firmware XAP Specs
This document describes the requirements of the QMK XAP ("extensible application protocol") API.
## Types
**All integral types are little-endian.**
| Name | Definition |
| -- | -- |
| _bool_ | Data type that contains values 0 and 1. Implemented as an alias of `u8`. |
| _struct{}_ | A structure of data, packing different objects together. Data is "compacted" -- there are no padding bytes between fields. Equivalent to a packed C-style `struct`. The order in which they're defined matches the order of the data in the response packet. |
| _type[n]_ | An array of `type`, with array extent of `N` -- e.g. `u8[2]` signifies two consecutive octets. |
| _u16_ | An unsigned 16-bit integral, commonly seen as `uint16_t` from _stdint.h_. |
| _u32_ | An unsigned 32-bit integral, commonly seen as `uint32_t` from _stdint.h_. |
| _u64_ | An unsigned 64-bit integral, commonly seen as `uint64_t` from _stdint.h_. |
| _u8_ | An unsigned 8-bit integral (octet, or byte), commonly seen as `uint8_t` from _stdint.h_. |
## Definitions
This list defines the terms used across the entire set of XAP protocol documentation.
| Name | Definition |
| -- | -- |
| _Capability_ | A way to determine if certain functionality is enabled in the firmware. Any _subsystem_ that provides build-time restriction of functionality must provide a _route_ for a _capabilities query_. |
| _Handler_ | A piece of code that is executed when a specific _route_ is received. |
| _Payload_ | Any received data appended to the _route_, which gets delivered to the _handler_ when received. |
| _Response_ | The data sent back to the host during execution of a _handler_. |
| _Route_ | A sequence of _IDs_ describing the route to invoke a _handler_. |
| _Secure Route_ | A _route_ which has potentially destructive consequences, necessitating prior approval by the user before executing. |
| _Subsystem_ | A high-level area of functionality within XAP. |
| _Unlock sequence_ | A physical sequence initiated by the user to enable execution of _secure routes_. |
| _Broadcast Header_ | Packet format for broadcast messages. Takes the format:<br>`token` - token<br>`u8` - type<br>`u8` - length |
| _ID_ | A single octet / 8-bit byte, representing Subsystem or Route index. |
| _Request Header_ | Packet format for inbound data. Takes the format:<br>`token` - token<br>`u8` - length |
| _Response Flags_ | An `u8` containing the status of the request. |
| _Response Header_ | Packet format for outbound data. Takes the format:<br>`token` - token<br>`response_flags` - flags<br>`u8` - length |
| _Token_ | A `u16` associated with a specific request as well as its corresponding response. Valid token values are within the range `0x0100`-`0xFFFF`. |
## Requests and Responses
Communication generally follows a request/response pattern.
Each request needs to include a _token_ -- this `u16` value prefixes each outbound request from the host application and its corresponding response.
This allows response messages to be correlated with their request, even if multiple host applications are communicating with the firmware simultaneously.
Host applications should randomly generate a token ID for **every** outbound request, unless using a reserved token defined below.
To ensure host interoperability, valid token values are within the range `0x0100`-`0xFFFF`.
This token is followed by a `u8` signifying the length of data in the request.
Two token values are reserved: `0xFFFE` and `0xFFFF`:
* `0xFFFE`: A message sent by a host application may use this token if no response is to be sent -- a "fire and forget" message.
* `0xFFFF`: Signifies a "broadcast" message sent by the firmware without prompting from the host application. Broadcast messages are defined later in this document.
Any request will generate at least one corresponding response, with the exception of messages using reserved tokens. Maximum total message length is 128 bytes due to RAM constraints.
Response messages will always be prefixed by the originating request _token_, directly followed by that request's _response flags_, then the response payload length:
| Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 |
| -- | -- | -- | -- | -- | -- | -- | -- |
| `-` | `-` | `-` | `-` | `-` | `-` | `SECURE_FAILURE` | `SUCCESS` |
* Bit 1 (`SECURE_FAILURE`): When this bit is set, the requested _route_ was marked _secure_ but an _unlock sequence_ has not completed.
* Bit 0 (`SUCCESS`): When this bit is set, the request was successfully handled. If not set, all payload data should be disregarded, and the request retried if appropriate (with a new token).
### Example "conversation":
**Request** -- version query:
| Byte | 0 | 1 | 2 | 3 | 4 |
| --- | --- | --- | --- | --- | --- |
| **Purpose** | Token | Token | Payload Length | Route | Route |
| **Value** | `0x43` | `0x2B` | `0x02` | `0x00` | `0x00` |
**Response** -- matching token, successful flag, payload of `0x03170192` = 3.17.192:
| Byte | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| **Purpose** | Token | Token | Response Flags | Payload Length | Payload | Payload | Payload | Payload |
| **Value** | `0x43` | `0x2B` | `0x01` | `0x04` | `0x92` | `0x01` | `0x17` | `0x03` |
## Routes
Subsystem validity should be queried through the “Enabled-in-firmware subsystem query” under the QMK subsystem (route=0x00,0x01).
This is the primary method for determining if a subsystem has been enabled in the running firmware.
### XAP - `0x00`
This subsystem is always present, and provides the ability to query information about the XAP protocol of the connected device.
| Name | Route | Tags | Payloads | Description |
| -- | -- | -- | -- | -- |
| Version Query | `0x00 0x00` | | __Response:__ `u32` | XAP protocol version query.<br><br>* Returns the BCD-encoded version in the format of XX.YY.ZZZZ => `0xXXYYZZZZ`<br> * e.g. 3.2.115 will match `0x03020115`, or bytes {0x15,0x01,0x02,0x03}.|
| Capabilities Query | `0x00 0x01` | | __Response:__ `u32` | XAP subsystem capabilities query. Each bit should be considered as a "usable" route within this subsystem.|
| Enabled subsystem query | `0x00 0x02` | | __Response:__ `u32` | XAP protocol subsystem query. Each bit should be considered as a "usable" subsystem. For example, checking `(value & (1 << XAP_ROUTE_QMK) != 0)` means the QMK subsystem is enabled and available for querying.|
| Secure Status | `0x00 0x03` | | __Response:__ `u8` | Query secure route status<br><br>* 0 means secure routes are disabled<br>* 1 means unlock sequence initiated but incomplete<br>* 2 means secure routes are allowed<br>* any other value should be interpreted as disabled|
| Secure Unlock | `0x00 0x04` | | | Initiate secure route unlock sequence|
| Secure Lock | `0x00 0x05` | | | Disable secure routes|
### QMK - `0x01`
This subsystem is always present, and provides the ability to address QMK-specific functionality.
| Name | Route | Tags | Payloads | Description |
| -- | -- | -- | -- | -- |
| Version Query | `0x01 0x00` | | __Response:__ `u32` | QMK protocol version query.<br><br>* Returns the BCD-encoded version in the format of XX.YY.ZZZZ => `0xXXYYZZZZ`<br> * e.g. 3.2.115 will match `0x03020115`, or bytes {0x15,0x01,0x02,0x03}.|
| Capabilities Query | `0x01 0x01` | | __Response:__ `u32` | QMK subsystem capabilities query. Each bit should be considered as a "usable" route within this subsystem.|
| Board identifiers | `0x01 0x02` | | __Response:__<br>&nbsp;&nbsp;&nbsp;&nbsp;* Vendor ID: `u16`<br>&nbsp;&nbsp;&nbsp;&nbsp;* Product ID: `u16`<br>&nbsp;&nbsp;&nbsp;&nbsp;* Product Version: `u16`<br>&nbsp;&nbsp;&nbsp;&nbsp;* QMK Unique Identifier: `u32` | Retrieves the set of identifying information for the board.|
| Board Manufacturer | `0x01 0x03` | | __Response:__ `string` | Retrieves the name of the manufacturer|
| Product Name | `0x01 0x04` | | __Response:__ `string` | Retrieves the product name|
| Config Blob Length | `0x01 0x05` | | __Response:__ `u16` | Retrieves the length of the configuration data bundled within the firmware|
| Config Blob Chunk | `0x01 0x06` | | __Request:__ `u16`<br><br>__Response:__ `u8[32]` | Retrieves a chunk of the configuration data bundled within the firmware|
| Jump to bootloader | `0x01 0x07` | __Secure__ | __Response:__ `u8` | Jump to bootloader<br><br>May not be present - if QMK capabilities query returns “true”, then jump to bootloader is supported<br><br>* 0 means secure routes are disabled, and should be considered as a failure<br>* 1 means successful, board will jump to bootloader|
| Hardware Identifier | `0x01 0x08` | | __Response:__ `u32[4]` | Retrieves a unique identifier for the board.|
| Reinitialize EEPROM | `0x01 0x09` | __Secure__ | __Response:__ `u8` | Reinitializes the keyboard's EEPROM (persistent memory)<br><br>May not be present - if QMK capabilities query returns “true”, then reinitialize is supported<br><br>* 0 means secure routes are disabled, and should be considered as a failure<br>* 1 means successful, board will reinitialize and then reboot|
### Keyboard - `0x02`
This subsystem is always present, and reserved for vendor-specific functionality. No routes are defined by XAP.
### User - `0x03`
This subsystem is always present, and reserved for user-specific functionality. No routes are defined by XAP.
### Keymap - `0x04`
This subsystem allows for query of currently configured keycodes.
| Name | Route | Tags | Payloads | Description |
| -- | -- | -- | -- | -- |
| Capabilities Query | `0x04 0x01` | | __Response:__ `u32` | Keymap subsystem capabilities query. Each bit should be considered as a "usable" route within this subsystem.|
| Get Layer Count | `0x04 0x02` | | __Response:__ `u8` | Query maximum number of layers that can be addressed within the keymap.|
| Get Keycode | `0x04 0x03` | | __Request:__<br>&nbsp;&nbsp;&nbsp;&nbsp;* Layer: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* Row: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* Column: `u8`<br><br>__Response:__ `u16` | Query the Keycode at the requested location.|
| Get Encoder Keycode | `0x04 0x04` | | __Request:__<br>&nbsp;&nbsp;&nbsp;&nbsp;* Layer: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* Encoder: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* Clockwise: `u8`<br><br>__Response:__ `u16` | Query the Keycode at the requested location.|
### Remapping - `0x05`
This subsystem allows for live reassignment of keycodes without rebuilding the firmware.
| Name | Route | Tags | Payloads | Description |
| -- | -- | -- | -- | -- |
| Capabilities Query | `0x05 0x01` | | __Response:__ `u32` | Remapping subsystem capabilities query. Each bit should be considered as a "usable" route within this subsystem.|
| Get Layer Count | `0x05 0x02` | | __Response:__ `u8` | Query maximum number of layers that can be addressed within the keymap.|
| Set Keycode | `0x05 0x03` | __Secure__ | __Request:__<br>&nbsp;&nbsp;&nbsp;&nbsp;* Layer: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* Row: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* Column: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* Keycode: `u16` | Modify the Keycode at the requested location.|
| Set Encoder Keycode | `0x05 0x04` | __Secure__ | __Request:__<br>&nbsp;&nbsp;&nbsp;&nbsp;* Layer: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* Encoder: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* Clockwise: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* Keycode: `u16` | Modify the Keycode at the requested location.|
### Lighting - `0x06`
This subsystem allows for control over the lighting subsystem.
| Name | Route | Tags | Payloads | Description |
| -- | -- | -- | -- | -- |
| Capabilities Query | `0x06 0x01` | | __Response:__ `u32` | Lighting subsystem capabilities query. Each bit should be considered as a "usable" route within this subsystem.|
## Broadcast messages
Broadcast messages may be sent by the firmware to the host, without a corresponding inbound request. Each broadcast message uses the token `0xFFFF`, and does not expect a response from the host. Tokens are followed by an _ID_ signifying the type of broadcast, then the response _payload_ length, and finally the corresponding _payload_.
### Log message - `0x00`
Replicates and replaces the same functionality as if using the standard QMK `CONSOLE_ENABLE = yes` in `rules.mk`. Normal prints within the firmware will manifest as log messages broadcast to the host. `hid_listen` will not be functional with XAP enabled.
Log message payloads include `u8[Length]` containing the text, where the length of the text is the _broadcast_header.length_ field.
**Example Log Broadcast** -- log message "Hello QMK!"
| Byte | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| **Purpose** | Token | Token | Broadcast Type | Length | Payload | Payload | Payload | Payload | Payload | Payload | Payload | Payload | Payload | Payload |
| **Value** | `0xFF` | `0xFF` | `0x00` | `0x0A`(10) | `0x48`(H) | `0x65`(e) | `0x6C`(l) | `0x6C`(l) | `0x6F`(o) | `0x20`(&nbsp;) | `0x51`(Q) | `0x4D`(M) | `0x4B`(K) | `0x21`(!) |
### Secure Status - `0x01`
Secure status has changed. Payloads include a `u8` matching a 'Secure Status' request.
**Example Secure Status Broadcast** -- secure "Unlocking"
| Byte | 0 | 1 | 2 | 3 | 4 |
| --- | --- | --- | --- | --- | --- |
| **Purpose** | Token | Token | Broadcast Type | Length | Secure Status |
| **Value** | `0xFF` | `0xFF` | `0x01` | `0x01` | `0x01` |
### Keyboard - `0x02`
Reserved for vendor-specific functionality. No messages are defined by XAP.
### User - `0x03`
Reserved for user-specific functionality. No messages are defined by XAP.
-249
View File
@@ -1,249 +0,0 @@
<!--- Copyright 2024 QMK --->
<!--- SPDX-License-Identifier: GPL-2.0-or-later --->
<!---
*******************************************************************************
88888888888 888 d8b .d888 d8b 888 d8b
888 888 Y8P d88P" Y8P 888 Y8P
888 888 888 888
888 88888b. 888 .d8888b 888888 888 888 .d88b. 888 .d8888b
888 888 "88b 888 88K 888 888 888 d8P Y8b 888 88K
888 888 888 888 "Y8888b. 888 888 888 88888888 888 "Y8888b.
888 888 888 888 X88 888 888 888 Y8b. 888 X88
888 888 888 888 88888P' 888 888 888 "Y8888 888 88888P'
888 888
888 888
888 888
.d88b. .d88b. 88888b. .d88b. 888d888 8888b. 888888 .d88b. .d88888
d88P"88b d8P Y8b 888 "88b d8P Y8b 888P" "88b 888 d8P Y8b d88" 888
888 888 88888888 888 888 88888888 888 .d888888 888 88888888 888 888
Y88b 888 Y8b. 888 888 Y8b. 888 888 888 Y88b. Y8b. Y88b 888
"Y88888 "Y8888 888 888 "Y8888 888 "Y888888 "Y888 "Y8888 "Y88888
888
Y8b d88P
"Y88P"
*******************************************************************************
--->
# QMK Firmware XAP Specs
This document describes the requirements of the QMK XAP ("extensible application protocol") API.
## Types
**All integral types are little-endian.**
| Name | Definition |
| -- | -- |
| _bool_ | Data type that contains values 0 and 1. Implemented as an alias of `u8`. |
| _struct{}_ | A structure of data, packing different objects together. Data is "compacted" -- there are no padding bytes between fields. Equivalent to a packed C-style `struct`. The order in which they're defined matches the order of the data in the response packet. |
| _type[n]_ | An array of `type`, with array extent of `N` -- e.g. `u8[2]` signifies two consecutive octets. |
| _u16_ | An unsigned 16-bit integral, commonly seen as `uint16_t` from _stdint.h_. |
| _u32_ | An unsigned 32-bit integral, commonly seen as `uint32_t` from _stdint.h_. |
| _u64_ | An unsigned 64-bit integral, commonly seen as `uint64_t` from _stdint.h_. |
| _u8_ | An unsigned 8-bit integral (octet, or byte), commonly seen as `uint8_t` from _stdint.h_. |
## Definitions
This list defines the terms used across the entire set of XAP protocol documentation.
| Name | Definition |
| -- | -- |
| _Capability_ | A way to determine if certain functionality is enabled in the firmware. Any _subsystem_ that provides build-time restriction of functionality must provide a _route_ for a _capabilities query_. |
| _Handler_ | A piece of code that is executed when a specific _route_ is received. |
| _Payload_ | Any received data appended to the _route_, which gets delivered to the _handler_ when received. |
| _Response_ | The data sent back to the host during execution of a _handler_. |
| _Route_ | A sequence of _IDs_ describing the route to invoke a _handler_. |
| _Secure Route_ | A _route_ which has potentially destructive consequences, necessitating prior approval by the user before executing. |
| _Subsystem_ | A high-level area of functionality within XAP. |
| _Unlock sequence_ | A physical sequence initiated by the user to enable execution of _secure routes_. |
| _Broadcast Header_ | Packet format for broadcast messages. Takes the format:<br>`token` - token<br>`u8` - type<br>`u8` - length |
| _ID_ | A single octet / 8-bit byte, representing Subsystem or Route index. |
| _Request Header_ | Packet format for inbound data. Takes the format:<br>`token` - token<br>`u8` - length |
| _Response Flags_ | An `u8` containing the status of the request. |
| _Response Header_ | Packet format for outbound data. Takes the format:<br>`token` - token<br>`response_flags` - flags<br>`u8` - length |
| _Token_ | A `u16` associated with a specific request as well as its corresponding response. Valid token values are within the range `0x0100`-`0xFFFF`. |
## Requests and Responses
Communication generally follows a request/response pattern.
Each request needs to include a _token_ -- this `u16` value prefixes each outbound request from the host application and its corresponding response.
This allows response messages to be correlated with their request, even if multiple host applications are communicating with the firmware simultaneously.
Host applications should randomly generate a token ID for **every** outbound request, unless using a reserved token defined below.
To ensure host interoperability, valid token values are within the range `0x0100`-`0xFFFF`.
This token is followed by a `u8` signifying the length of data in the request.
Two token values are reserved: `0xFFFE` and `0xFFFF`:
* `0xFFFE`: A message sent by a host application may use this token if no response is to be sent -- a "fire and forget" message.
* `0xFFFF`: Signifies a "broadcast" message sent by the firmware without prompting from the host application. Broadcast messages are defined later in this document.
Any request will generate at least one corresponding response, with the exception of messages using reserved tokens. Maximum total message length is 128 bytes due to RAM constraints.
Response messages will always be prefixed by the originating request _token_, directly followed by that request's _response flags_, then the response payload length:
| Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 |
| -- | -- | -- | -- | -- | -- | -- | -- |
| `-` | `-` | `-` | `-` | `-` | `-` | `SECURE_FAILURE` | `SUCCESS` |
* Bit 1 (`SECURE_FAILURE`): When this bit is set, the requested _route_ was marked _secure_ but an _unlock sequence_ has not completed.
* Bit 0 (`SUCCESS`): When this bit is set, the request was successfully handled. If not set, all payload data should be disregarded, and the request retried if appropriate (with a new token).
### Example "conversation":
**Request** -- version query:
| Byte | 0 | 1 | 2 | 3 | 4 |
| --- | --- | --- | --- | --- | --- |
| **Purpose** | Token | Token | Payload Length | Route | Route |
| **Value** | `0x43` | `0x2B` | `0x02` | `0x00` | `0x00` |
**Response** -- matching token, successful flag, payload of `0x03170192` = 3.17.192:
| Byte | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| **Purpose** | Token | Token | Response Flags | Payload Length | Payload | Payload | Payload | Payload |
| **Value** | `0x43` | `0x2B` | `0x01` | `0x04` | `0x92` | `0x01` | `0x17` | `0x03` |
## Routes
Subsystem validity should be queried through the “Enabled-in-firmware subsystem query” under the QMK subsystem (route=0x00,0x01).
This is the primary method for determining if a subsystem has been enabled in the running firmware.
### XAP - `0x00`
This subsystem is always present, and provides the ability to query information about the XAP protocol of the connected device.
| Name | Route | Tags | Payloads | Description |
| -- | -- | -- | -- | -- |
| Version Query | `0x00 0x00` | | __Response:__ `u32` | XAP protocol version query.<br><br>* Returns the BCD-encoded version in the format of XX.YY.ZZZZ => `0xXXYYZZZZ`<br> * e.g. 3.2.115 will match `0x03020115`, or bytes {0x15,0x01,0x02,0x03}.|
| Capabilities Query | `0x00 0x01` | | __Response:__ `u32` | XAP subsystem capabilities query. Each bit should be considered as a "usable" route within this subsystem.|
| Enabled subsystem query | `0x00 0x02` | | __Response:__ `u32` | XAP protocol subsystem query. Each bit should be considered as a "usable" subsystem. For example, checking `(value & (1 << XAP_ROUTE_QMK) != 0)` means the QMK subsystem is enabled and available for querying.|
| Secure Status | `0x00 0x03` | | __Response:__ `u8` | Query secure route status<br><br>* 0 means secure routes are disabled<br>* 1 means unlock sequence initiated but incomplete<br>* 2 means secure routes are allowed<br>* any other value should be interpreted as disabled|
| Secure Unlock | `0x00 0x04` | | | Initiate secure route unlock sequence|
| Secure Lock | `0x00 0x05` | | | Disable secure routes|
### QMK - `0x01`
This subsystem is always present, and provides the ability to address QMK-specific functionality.
| Name | Route | Tags | Payloads | Description |
| -- | -- | -- | -- | -- |
| Version Query | `0x01 0x00` | | __Response:__ `u32` | QMK protocol version query.<br><br>* Returns the BCD-encoded version in the format of XX.YY.ZZZZ => `0xXXYYZZZZ`<br> * e.g. 3.2.115 will match `0x03020115`, or bytes {0x15,0x01,0x02,0x03}.|
| Capabilities Query | `0x01 0x01` | | __Response:__ `u32` | QMK subsystem capabilities query. Each bit should be considered as a "usable" route within this subsystem.|
| Board identifiers | `0x01 0x02` | | __Response:__<br>&nbsp;&nbsp;&nbsp;&nbsp;* Vendor ID: `u16`<br>&nbsp;&nbsp;&nbsp;&nbsp;* Product ID: `u16`<br>&nbsp;&nbsp;&nbsp;&nbsp;* Product Version: `u16`<br>&nbsp;&nbsp;&nbsp;&nbsp;* QMK Unique Identifier: `u32` | Retrieves the set of identifying information for the board.|
| Board Manufacturer | `0x01 0x03` | | __Response:__ `string` | Retrieves the name of the manufacturer|
| Product Name | `0x01 0x04` | | __Response:__ `string` | Retrieves the product name|
| Config Blob Length | `0x01 0x05` | | __Response:__ `u16` | Retrieves the length of the configuration data bundled within the firmware|
| Config Blob Chunk | `0x01 0x06` | | __Request:__ `u16`<br><br>__Response:__ `u8[32]` | Retrieves a chunk of the configuration data bundled within the firmware|
| Jump to bootloader | `0x01 0x07` | __Secure__ | __Response:__ `u8` | Jump to bootloader<br><br>May not be present - if QMK capabilities query returns “true”, then jump to bootloader is supported<br><br>* 0 means secure routes are disabled, and should be considered as a failure<br>* 1 means successful, board will jump to bootloader|
| Hardware Identifier | `0x01 0x08` | | __Response:__ `u32[4]` | Retrieves a unique identifier for the board.|
| Reinitialize EEPROM | `0x01 0x09` | __Secure__ | __Response:__ `u8` | Reinitializes the keyboard's EEPROM (persistent memory)<br><br>May not be present - if QMK capabilities query returns “true”, then reinitialize is supported<br><br>* 0 means secure routes are disabled, and should be considered as a failure<br>* 1 means successful, board will reinitialize and then reboot|
### Keyboard - `0x02`
This subsystem is always present, and reserved for vendor-specific functionality. No routes are defined by XAP.
### User - `0x03`
This subsystem is always present, and reserved for user-specific functionality. No routes are defined by XAP.
### Keymap - `0x04`
This subsystem allows for query of currently configured keycodes.
| Name | Route | Tags | Payloads | Description |
| -- | -- | -- | -- | -- |
| Capabilities Query | `0x04 0x01` | | __Response:__ `u32` | Keymap subsystem capabilities query. Each bit should be considered as a "usable" route within this subsystem.|
| Get Layer Count | `0x04 0x02` | | __Response:__ `u8` | Query maximum number of layers that can be addressed within the keymap.|
| Get Keycode | `0x04 0x03` | | __Request:__<br>&nbsp;&nbsp;&nbsp;&nbsp;* Layer: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* Row: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* Column: `u8`<br><br>__Response:__ `u16` | Query the Keycode at the requested location.|
| Get Encoder Keycode | `0x04 0x04` | | __Request:__<br>&nbsp;&nbsp;&nbsp;&nbsp;* Layer: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* Encoder: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* Clockwise: `u8`<br><br>__Response:__ `u16` | Query the Keycode at the requested location.|
### Remapping - `0x05`
This subsystem allows for live reassignment of keycodes without rebuilding the firmware.
| Name | Route | Tags | Payloads | Description |
| -- | -- | -- | -- | -- |
| Capabilities Query | `0x05 0x01` | | __Response:__ `u32` | Remapping subsystem capabilities query. Each bit should be considered as a "usable" route within this subsystem.|
| Get Layer Count | `0x05 0x02` | | __Response:__ `u8` | Query maximum number of layers that can be addressed within the keymap.|
| Set Keycode | `0x05 0x03` | __Secure__ | __Request:__<br>&nbsp;&nbsp;&nbsp;&nbsp;* Layer: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* Row: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* Column: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* Keycode: `u16` | Modify the Keycode at the requested location.|
| Set Encoder Keycode | `0x05 0x04` | __Secure__ | __Request:__<br>&nbsp;&nbsp;&nbsp;&nbsp;* Layer: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* Encoder: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* Clockwise: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* Keycode: `u16` | Modify the Keycode at the requested location.|
### Lighting - `0x06`
This subsystem allows for control over the lighting subsystem.
| Name | Route | Tags | Payloads | Description |
| -- | -- | -- | -- | -- |
| Capabilities Query | `0x06 0x01` | | __Response:__ `u32` | Lighting subsystem capabilities query. Each bit should be considered as a "usable" route within this subsystem.|
#### backlight - `0x06 0x02`
This subsystem allows for control over the backlight subsystem.
| Name | Route | Tags | Payloads | Description |
| -- | -- | -- | -- | -- |
| Capabilities Query | `0x06 0x02 0x01` | | __Response:__ `u32` | backlight subsystem capabilities query. Each bit should be considered as a "usable" route within this subsystem.|
| Get Enabled Effects | `0x06 0x02 0x02` | | __Response:__ `u8` | Each bit should be considered as a "usable" effect id|
| Get Config | `0x06 0x02 0x03` | | __Response:__<br>&nbsp;&nbsp;&nbsp;&nbsp;* enable: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* mode: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* val: `u8` | Query the current config.|
| Set Config | `0x06 0x02 0x04` | | __Request:__<br>&nbsp;&nbsp;&nbsp;&nbsp;* enable: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* mode: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* val: `u8` | Set the current config.|
| Save Config | `0x06 0x02 0x05` | | | Save the current config.|
#### rgblight - `0x06 0x03`
This subsystem allows for control over the rgblight subsystem.
| Name | Route | Tags | Payloads | Description |
| -- | -- | -- | -- | -- |
| Capabilities Query | `0x06 0x03 0x01` | | __Response:__ `u32` | rgblight subsystem capabilities query. Each bit should be considered as a "usable" route within this subsystem.|
| Get Enabled Effects | `0x06 0x03 0x02` | | __Response:__ `u64` | Each bit should be considered as a "usable" effect id|
| Get Config | `0x06 0x03 0x03` | | __Response:__<br>&nbsp;&nbsp;&nbsp;&nbsp;* enable: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* mode: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* hue: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* sat: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* val: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* speed: `u8` | Query the current config.|
| Set Config | `0x06 0x03 0x04` | | __Request:__<br>&nbsp;&nbsp;&nbsp;&nbsp;* enable: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* mode: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* hue: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* sat: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* val: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* speed: `u8` | Set the current config.|
| Save Config | `0x06 0x03 0x05` | | | Save the current config.|
#### rgbmatrix - `0x06 0x04`
This subsystem allows for control over the rgb matrix subsystem.
| Name | Route | Tags | Payloads | Description |
| -- | -- | -- | -- | -- |
| Capabilities Query | `0x06 0x04 0x01` | | __Response:__ `u32` | rgb matrix subsystem capabilities query. Each bit should be considered as a "usable" route within this subsystem.|
| Get Enabled Effects | `0x06 0x04 0x02` | | __Response:__ `u64` | Each bit should be considered as a "usable" effect id|
| Get Config | `0x06 0x04 0x03` | | __Response:__<br>&nbsp;&nbsp;&nbsp;&nbsp;* enable: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* mode: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* hue: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* sat: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* val: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* speed: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* flags: `u8` | Query the current config.|
| Set Config | `0x06 0x04 0x04` | | __Request:__<br>&nbsp;&nbsp;&nbsp;&nbsp;* enable: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* mode: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* hue: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* sat: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* val: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* speed: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* flags: `u8` | Set the current config.|
| Save Config | `0x06 0x04 0x05` | | | Save the current config.|
### Audio - `0x07`
This subsystem allows for control over the audio subsystem.
| Name | Route | Tags | Payloads | Description |
| -- | -- | -- | -- | -- |
| Capabilities Query | `0x07 0x01` | | __Response:__ `u32` | Audio subsystem capabilities query. Each bit should be considered as a "usable" route within this subsystem.|
| Get Config | `0x07 0x03` | | __Response:__<br>&nbsp;&nbsp;&nbsp;&nbsp;* enable: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* clicky_enable: `u8` | Query the current config.|
| Set Config | `0x07 0x04` | | __Request:__<br>&nbsp;&nbsp;&nbsp;&nbsp;* enable: `u8`<br>&nbsp;&nbsp;&nbsp;&nbsp;* clicky_enable: `u8` | Set the current config.|
| Save Config | `0x07 0x05` | | | Save the current config.|
## Broadcast messages
Broadcast messages may be sent by the firmware to the host, without a corresponding inbound request. Each broadcast message uses the token `0xFFFF`, and does not expect a response from the host. Tokens are followed by an _ID_ signifying the type of broadcast, then the response _payload_ length, and finally the corresponding _payload_.
### Log message - `0x00`
Replicates and replaces the same functionality as if using the standard QMK `CONSOLE_ENABLE = yes` in `rules.mk`. Normal prints within the firmware will manifest as log messages broadcast to the host. `hid_listen` will not be functional with XAP enabled.
Log message payloads include `u8[Length]` containing the text, where the length of the text is the _broadcast_header.length_ field.
**Example Log Broadcast** -- log message "Hello QMK!"
| Byte | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| **Purpose** | Token | Token | Broadcast Type | Length | Payload | Payload | Payload | Payload | Payload | Payload | Payload | Payload | Payload | Payload |
| **Value** | `0xFF` | `0xFF` | `0x00` | `0x0A`(10) | `0x48`(H) | `0x65`(e) | `0x6C`(l) | `0x6C`(l) | `0x6F`(o) | `0x20`(&nbsp;) | `0x51`(Q) | `0x4D`(M) | `0x4B`(K) | `0x21`(!) |
### Secure Status - `0x01`
Secure status has changed. Payloads include a `u8` matching a 'Secure Status' request.
**Example Secure Status Broadcast** -- secure "Unlocking"
| Byte | 0 | 1 | 2 | 3 | 4 |
| --- | --- | --- | --- | --- | --- |
| **Purpose** | Token | Token | Broadcast Type | Length | Secure Status |
| **Value** | `0xFF` | `0xFF` | `0x01` | `0x01` | `0x01` |
### Keyboard - `0x02`
Reserved for vendor-specific functionality. No messages are defined by XAP.
### User - `0x03`
Reserved for user-specific functionality. No messages are defined by XAP.
-30
View File
@@ -1,30 +0,0 @@
<!--- Copyright 2024 QMK --->
<!--- SPDX-License-Identifier: GPL-2.0-or-later --->
<!---
*******************************************************************************
88888888888 888 d8b .d888 d8b 888 d8b
888 888 Y8P d88P" Y8P 888 Y8P
888 888 888 888
888 88888b. 888 .d8888b 888888 888 888 .d88b. 888 .d8888b
888 888 "88b 888 88K 888 888 888 d8P Y8b 888 88K
888 888 888 888 "Y8888b. 888 888 888 88888888 888 "Y8888b.
888 888 888 888 X88 888 888 888 Y8b. 888 X88
888 888 888 888 88888P' 888 888 888 "Y8888 888 88888P'
888 888
888 888
888 888
.d88b. .d88b. 88888b. .d88b. 888d888 8888b. 888888 .d88b. .d88888
d88P"88b d8P Y8b 888 "88b d8P Y8b 888P" "88b 888 d8P Y8b d88" 888
888 888 88888888 888 888 88888888 888 .d888888 888 88888888 888 888
Y88b 888 Y8b. 888 888 Y8b. 888 888 888 Y88b. Y8b. Y88b 888
"Y88888 "Y8888 888 888 "Y8888 888 "Y888888 "Y888 "Y8888 "Y88888
888
Y8b d88P
"Y88P"
*******************************************************************************
--->
* [XAP Version 0.3.0](xap_0.3.0.md)
* [XAP Version 0.2.0](xap_0.2.0.md)
* [XAP Version 0.1.0](xap_0.1.0.md)
* [XAP Version 0.0.1](xap_0.0.1.md)
+116
View File
@@ -0,0 +1,116 @@
{
"board": "GENERIC_RP_RP2040",
"bootloader": "rp2040",
"diode_direction": "COL2ROW",
"features": {
"bootmagic": true,
"extrakey": true,
"mousekey": true
},
"processor": "RP2040",
"ps2": {
"driver": "vendor",
"enabled": true,
"mouse_enabled": true
},
"layouts": {
"LAYOUT_iso": {
"layout": [
{"label": "Esc", "matrix": [5, 0], "x": 0, "y": 0, "w": 0.9, "h": 0.75},
{"label": "Mute", "matrix": [4, 10], "x": 0.9, "y": 0, "w": 0.75, "h": 0.5},
{"label": "Vol -", "matrix": [3, 10], "x": 1.65, "y": 0, "w": 0.75, "h": 0.5},
{"label": "Vol +", "matrix": [2, 10], "x": 2.4, "y": 0, "w": 0.75, "h": 0.5},
{"label": "ThinkVantage", "matrix": [5, 10], "x": 3.5, "y": 0, "w": 1.25, "h": 0.5},
{"label": "PrtSc", "matrix": [1, 13], "x": 8.9, "y": 0, "w": 0.9, "h": 0.65},
{"label": "ScrLk", "matrix": [2, 13], "x": 9.8, "y": 0, "w": 0.9, "h": 0.65},
{"label": "Pause", "matrix": [6, 12], "x": 10.7, "y": 0, "w": 0.9, "h": 0.65},
{"label": "Insert", "matrix": [0, 9], "x": 12, "y": 0, "w": 0.9, "h": 0.65},
{"label": "Home", "matrix": [0, 12], "x": 12.9, "y": 0, "w": 0.9, "h": 0.65},
{"label": "PgUp", "matrix": [0, 11], "x": 13.8, "y": 0, "w": 0.9, "h": 0.65},
{"label": "F1", "matrix": [0, 1], "x": 0, "y": 0.75, "w": 0.9, "h": 0.65},
{"label": "F2", "matrix": [0, 2], "x": 0.9, "y": 0.75, "w": 0.9, "h": 0.65},
{"label": "F3", "matrix": [3, 2], "x": 1.8, "y": 0.75, "w": 0.9, "h": 0.65},
{"label": "F4", "matrix": [5, 2], "x": 2.7, "y": 0.75, "w": 0.9, "h": 0.65},
{"label": "F5", "matrix": [5, 8], "x": 4, "y": 0.75, "w": 0.9, "h": 0.65},
{"label": "F6", "matrix": [5, 5], "x": 4.9, "y": 0.75, "w": 0.9, "h": 0.65},
{"label": "F7", "matrix": [3, 6], "x": 5.8, "y": 0.75, "w": 0.9, "h": 0.65},
{"label": "F8", "matrix": [0, 6], "x": 6.7, "y": 0.75, "w": 0.9, "h": 0.65},
{"label": "F9", "matrix": [0, 8], "x": 8, "y": 0.75, "w": 0.9, "h": 0.65},
{"label": "F10", "matrix": [1, 8], "x": 8.9, "y": 0.75, "w": 0.9, "h": 0.65},
{"label": "F11", "matrix": [1, 10], "x": 9.8, "y": 0.75, "w": 0.9, "h": 0.65},
{"label": "F12", "matrix": [1, 9], "x": 10.7, "y": 0.75, "w": 0.9, "h": 0.65},
{"label": "Delete", "matrix": [0, 10], "x": 12, "y": 0.75, "w": 0.9, "h": 0.65},
{"label": "End", "matrix": [1, 12], "x": 12.9, "y": 0.75, "w": 0.9, "h": 0.65},
{"label": "PgDn", "matrix": [1, 11], "x": 13.8, "y": 0.75, "w": 0.9, "h": 0.65},
{"label": "`\u00ac", "matrix": [0, 0], "x": 0, "y": 1.4},
{"label": "1!", "matrix": [1, 0], "x": 1, "y": 1.4},
{"label": "2\"", "matrix": [1, 1], "x": 2, "y": 1.4},
{"label": "3\u00a3", "matrix": [1, 2], "x": 3, "y": 1.4},
{"label": "4$", "matrix": [1, 3], "x": 4, "y": 1.4},
{"label": "5%", "matrix": [0, 3], "x": 5, "y": 1.4},
{"label": "6^", "matrix": [0, 4], "x": 6, "y": 1.4},
{"label": "7&", "matrix": [1, 4], "x": 7, "y": 1.4},
{"label": "8*", "matrix": [1, 5], "x": 8, "y": 1.4},
{"label": "9(", "matrix": [1, 6], "x": 9, "y": 1.4},
{"label": "0)", "matrix": [1, 7], "x": 10, "y": 1.4},
{"label": "-_", "matrix": [0, 7], "x": 11, "y": 1.4},
{"label": "=+", "matrix": [0, 5], "x": 12, "y": 1.4},
{"label": "Bksp", "matrix": [3, 8], "x": 13, "y": 1.4, "w": 2},
{"label": "Tab", "matrix": [3, 0], "x": 0, "y": 2.4, "w": 1.5},
{"label": "Q", "matrix": [2, 0], "x": 1.5, "y": 2.4},
{"label": "W", "matrix": [2, 1], "x": 2.5, "y": 2.4},
{"label": "E", "matrix": [2, 2], "x": 3.5, "y": 2.4},
{"label": "R", "matrix": [2, 3], "x": 4.5, "y": 2.4},
{"label": "T", "matrix": [3, 3], "x": 5.5, "y": 2.4},
{"label": "Y", "matrix": [3, 4], "x": 6.5, "y": 2.4},
{"label": "U", "matrix": [2, 4], "x": 7.5, "y": 2.4},
{"label": "I", "matrix": [2, 5], "x": 8.5, "y": 2.4},
{"label": "O", "matrix": [2, 6], "x": 9.5, "y": 2.4},
{"label": "P", "matrix": [2, 7], "x": 10.5, "y": 2.4},
{"label": "[{", "matrix": [3, 7], "x": 11.5, "y": 2.4},
{"label": "]}", "matrix": [3, 5], "x": 12.5, "y": 2.4},
{"label": "Caps Lock", "matrix": [3, 1], "x": 0, "y": 3.4, "w": 1.75},
{"label": "A", "matrix": [4, 0], "x": 1.75, "y": 3.4},
{"label": "S", "matrix": [4, 1], "x": 2.75, "y": 3.4},
{"label": "D", "matrix": [4, 2], "x": 3.75, "y": 3.4},
{"label": "F", "matrix": [4, 3], "x": 4.75, "y": 3.4},
{"label": "G", "matrix": [5, 3], "x": 5.75, "y": 3.4},
{"label": "H", "matrix": [5, 4], "x": 6.75, "y": 3.4},
{"label": "J", "matrix": [4, 4], "x": 7.75, "y": 3.4},
{"label": "K", "matrix": [4, 5], "x": 8.75, "y": 3.4},
{"label": "L", "matrix": [4, 6], "x": 9.75, "y": 3.4},
{"label": ";:", "matrix": [4, 7], "x": 10.75, "y": 3.4},
{"label": "'@", "matrix": [5, 7], "x": 11.75, "y": 3.4},
{"label": "#~", "matrix": [6, 7], "x": 12.75, "y": 3.4},
{"label": "Enter", "matrix": [6, 8], "x": 13.75, "y": 2.4, "w": 1.25, "h": 2},
{"label": "Shift", "matrix": [3, 14], "x": 0, "y": 4.4, "w": 1.25},
{"label": "\\|", "matrix": [5, 1], "x": 1.25, "y": 4.4},
{"label": "Z", "matrix": [6, 0], "x": 2.25, "y": 4.4},
{"label": "X", "matrix": [6, 1], "x": 3.25, "y": 4.4},
{"label": "C", "matrix": [6, 2], "x": 4.25, "y": 4.4},
{"label": "V", "matrix": [6, 3], "x": 5.25, "y": 4.4},
{"label": "B", "matrix": [7, 3], "x": 6.25, "y": 4.4},
{"label": "N", "matrix": [7, 4], "x": 7.25, "y": 4.4},
{"label": "M", "matrix": [6, 4], "x": 8.25, "y": 4.4},
{"label": ",<", "matrix": [6, 5], "x": 9.25, "y": 4.4},
{"label": ".>", "matrix": [6, 6], "x": 10.25, "y": 4.4},
{"label": "/?", "matrix": [7, 7], "x": 11.25, "y": 4.4},
{"label": "Shift", "matrix": [6, 14], "x": 12.25, "y": 4.4, "w": 2.75},
{"label": "Fn", "matrix": [4, 9], "x": 0, "y": 5.4},
{"label": "Ctrl", "matrix": [0, 15], "x": 1, "y": 5.4, "w": 1.25},
{"label": "Left OS", "matrix": [2, 11], "x": 2.25, "y": 5.4, "w": 0.9},
{"label": "Alt", "matrix": [5, 13], "x": 3.15, "y": 5.4},
{"label": "Space", "matrix": [7, 8], "x": 4.15, "y": 5.4, "w": 5},
{"label": "AltGr", "matrix": [7, 13], "x": 9.25, "y": 5.4},
{"label": "Menu", "matrix": [4, 11], "x": 10.25, "y": 5.4},
{"label": "Ctrl", "matrix": [6, 15], "x": 11.25, "y": 5.4},
{"label": "Browser Back", "matrix": [6, 11], "x": 12.25, "y": 5.4, "w": 0.9, "h": 0.75},
{"label": "Up", "matrix": [5, 12], "x": 13.15, "y": 5.4, "w": 0.9, "h": 0.75},
{"label": "Browser Forward", "matrix": [7, 11], "x": 14.05, "y": 5.4, "w": 0.9, "h": 0.75},
{"label": "Left", "matrix": [7, 12], "x": 12.25, "y": 6.15, "w": 0.9, "h": 0.75},
{"label": "Down", "matrix": [7, 10], "x": 13.15, "y": 6.15, "w": 0.9, "h": 0.75},
{"label": "Right", "matrix": [7, 9], "x": 14.05, "y": 6.15, "w": 0.9, "h": 0.75}
]
}
}
}
@@ -0,0 +1,19 @@
{
"manufacturer": "Frank Adams",
"keyboard_name": "converter/thinkpad_t6x/pico_t61",
"maintainer": "Al En",
"matrix_pins": {
"cols": ["GP27", "GP26", "GP17", "GP14", "GP12", "GP19", "GP18", "GP15", "GP13", "GP6", "GP16", "GP5", "GP28", "GP2", "GP4", "GP3"],
"rows": ["GP11", "GP22", "GP10", "GP21", "GP9", "GP20", "GP8", "GP7"]
},
"ps2": {
"clock_pin": "GP0",
"data_pin": "GP1"
},
"url": "https://github.com/thedalles77/USB_Laptop_Keyboard_Controller/tree/master/Example_Keyboards/Pico_T61_Keyboard",
"usb": {
"device_version": "1.0.0",
"pid": "0xBACA",
"vid": "0xFEED"
}
}
@@ -0,0 +1,27 @@
# converter/thinkpad_t6x/pico_t61
![converter/thinkpad_t6x/pico_t61](https://i.imgur.com/KDouWIc.jpeg)
This is a converter PCB for Lenovo Thinkpad keyboards from T60, T400 and X200 series, based on the Raspberry Pi Pico W. The QMK implementation here is specific to the converter in the link below. Similar PCB designs to convert a Thinkpad keyboard to USB exist, but they use a different microcontroller and wiring of the keyboard connector with the MCU.
* Keyboard Maintainer: [Al En](https://github.com/gitaen)
* Hardware Supported: The linked converter PCB with keyboards from various Thinkpad models
* Hardware Availability: [Custom PCB](https://github.com/thedalles77/USB_Laptop_Keyboard_Controller/tree/master/Example_Keyboards/Pico_T61_Keyboard)
Make example for this keyboard (after setting up your build environment):
make converter/thinkpad_t6x/pico_t61:default
Flashing example for this keyboard:
make converter/thinkpad_t6x/pico_t61:default:flash
See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_tools) and the [make instructions](https://docs.qmk.fm/#/getting_started_make_guide) for more information. Brand new to QMK? Start with our [Complete Newbs Guide](https://docs.qmk.fm/#/newbs).
## Bootloader
Enter the bootloader in 3 ways:
* **Bootmagic reset**: Hold down the key at (0,0) in the matrix (\`~) and plug in the keyboard
* **Physical BOOTSEL button**: Hold down the BOOTSEL button on the Raspberry PiPico W and plug the keyboard
* **Keycode in layout**: Press the key mapped to `QK_BOOT` if it is available
@@ -2,130 +2,18 @@
"manufacturer": "strobo5",
"keyboard_name": "converter/thinkpad_t6x/rpi_pico",
"maintainer": "strobo5",
"board": "GENERIC_RP_RP2040",
"bootloader": "rp2040",
"diode_direction": "COL2ROW",
"features": {
"bootmagic": true,
"extrakey": true,
"mousekey": true
},
"matrix_pins": {
"cols": ["GP7", "GP9", "GP11", "GP13", "GP17", "GP16", "GP14", "GP12", "GP15", "GP8", "GP10", "GP6", "GP4", "GP2", "GP5", "GP3"],
"rows": ["GP20", "GP26", "GP22", "GP21", "GP18", "GP19", "GP27", "GP28"]
},
"processor": "RP2040",
"ps2": {
"clock_pin": "GP1",
"data_pin": "GP0",
"driver": "vendor",
"enabled": true,
"mouse_enabled": true
"data_pin": "GP0"
},
"url": "https://github.com/strobo5/T61_PiPico_Scanner",
"usb": {
"device_version": "1.0.0",
"pid": "0x0000",
"vid": "0xFEED"
},
"layouts": {
"LAYOUT_iso": {
"layout": [
{"label": "Esc", "matrix": [5, 0], "x": 0, "y": 0, "w": 0.9, "h": 0.75},
{"label": "Mute", "matrix": [4, 10], "x": 0.9, "y": 0, "w": 0.75, "h": 0.5},
{"label": "Vol -", "matrix": [3, 10], "x": 1.65, "y": 0, "w": 0.75, "h": 0.5},
{"label": "Vol +", "matrix": [2, 10], "x": 2.4, "y": 0, "w": 0.75, "h": 0.5},
{"label": "ThinkVantage", "matrix": [5, 10], "x": 3.5, "y": 0, "w": 1.25, "h": 0.5},
{"label": "PrtSc", "matrix": [1, 13], "x": 8.9, "y": 0, "w": 0.9, "h": 0.65},
{"label": "ScrLk", "matrix": [2, 13], "x": 9.8, "y": 0, "w": 0.9, "h": 0.65},
{"label": "Pause", "matrix": [6, 12], "x": 10.7, "y": 0, "w": 0.9, "h": 0.65},
{"label": "Insert", "matrix": [0, 9], "x": 12, "y": 0, "w": 0.9, "h": 0.65},
{"label": "Home", "matrix": [0, 12], "x": 12.9, "y": 0, "w": 0.9, "h": 0.65},
{"label": "PgUp", "matrix": [0, 11], "x": 13.8, "y": 0, "w": 0.9, "h": 0.65},
{"label": "F1", "matrix": [0, 1], "x": 0, "y": 0.75, "w": 0.9, "h": 0.65},
{"label": "F2", "matrix": [0, 2], "x": 0.9, "y": 0.75, "w": 0.9, "h": 0.65},
{"label": "F3", "matrix": [3, 2], "x": 1.8, "y": 0.75, "w": 0.9, "h": 0.65},
{"label": "F4", "matrix": [5, 2], "x": 2.7, "y": 0.75, "w": 0.9, "h": 0.65},
{"label": "F5", "matrix": [5, 8], "x": 4, "y": 0.75, "w": 0.9, "h": 0.65},
{"label": "F6", "matrix": [5, 5], "x": 4.9, "y": 0.75, "w": 0.9, "h": 0.65},
{"label": "F7", "matrix": [3, 6], "x": 5.8, "y": 0.75, "w": 0.9, "h": 0.65},
{"label": "F8", "matrix": [0, 6], "x": 6.7, "y": 0.75, "w": 0.9, "h": 0.65},
{"label": "F9", "matrix": [0, 8], "x": 8, "y": 0.75, "w": 0.9, "h": 0.65},
{"label": "F10", "matrix": [1, 8], "x": 8.9, "y": 0.75, "w": 0.9, "h": 0.65},
{"label": "F11", "matrix": [1, 10], "x": 9.8, "y": 0.75, "w": 0.9, "h": 0.65},
{"label": "F12", "matrix": [1, 9], "x": 10.7, "y": 0.75, "w": 0.9, "h": 0.65},
{"label": "Delete", "matrix": [0, 10], "x": 12, "y": 0.75, "w": 0.9, "h": 0.65},
{"label": "End", "matrix": [1, 12], "x": 12.9, "y": 0.75, "w": 0.9, "h": 0.65},
{"label": "PgDn", "matrix": [1, 11], "x": 13.8, "y": 0.75, "w": 0.9, "h": 0.65},
{"label": "`\u00ac", "matrix": [0, 0], "x": 0, "y": 1.4},
{"label": "1!", "matrix": [1, 0], "x": 1, "y": 1.4},
{"label": "2\"", "matrix": [1, 1], "x": 2, "y": 1.4},
{"label": "3\u00a3", "matrix": [1, 2], "x": 3, "y": 1.4},
{"label": "4$", "matrix": [1, 3], "x": 4, "y": 1.4},
{"label": "5%", "matrix": [0, 3], "x": 5, "y": 1.4},
{"label": "6^", "matrix": [0, 4], "x": 6, "y": 1.4},
{"label": "7&", "matrix": [1, 4], "x": 7, "y": 1.4},
{"label": "8*", "matrix": [1, 5], "x": 8, "y": 1.4},
{"label": "9(", "matrix": [1, 6], "x": 9, "y": 1.4},
{"label": "0)", "matrix": [1, 7], "x": 10, "y": 1.4},
{"label": "-_", "matrix": [0, 7], "x": 11, "y": 1.4},
{"label": "=+", "matrix": [0, 5], "x": 12, "y": 1.4},
{"label": "Bksp", "matrix": [3, 8], "x": 13, "y": 1.4, "w": 2},
{"label": "Tab", "matrix": [3, 0], "x": 0, "y": 2.4, "w": 1.5},
{"label": "Q", "matrix": [2, 0], "x": 1.5, "y": 2.4},
{"label": "W", "matrix": [2, 1], "x": 2.5, "y": 2.4},
{"label": "E", "matrix": [2, 2], "x": 3.5, "y": 2.4},
{"label": "R", "matrix": [2, 3], "x": 4.5, "y": 2.4},
{"label": "T", "matrix": [3, 3], "x": 5.5, "y": 2.4},
{"label": "Y", "matrix": [3, 4], "x": 6.5, "y": 2.4},
{"label": "U", "matrix": [2, 4], "x": 7.5, "y": 2.4},
{"label": "I", "matrix": [2, 5], "x": 8.5, "y": 2.4},
{"label": "O", "matrix": [2, 6], "x": 9.5, "y": 2.4},
{"label": "P", "matrix": [2, 7], "x": 10.5, "y": 2.4},
{"label": "[{", "matrix": [3, 7], "x": 11.5, "y": 2.4},
{"label": "]}", "matrix": [3, 5], "x": 12.5, "y": 2.4},
{"label": "Caps Lock", "matrix": [3, 1], "x": 0, "y": 3.4, "w": 1.75},
{"label": "A", "matrix": [4, 0], "x": 1.75, "y": 3.4},
{"label": "S", "matrix": [4, 1], "x": 2.75, "y": 3.4},
{"label": "D", "matrix": [4, 2], "x": 3.75, "y": 3.4},
{"label": "F", "matrix": [4, 3], "x": 4.75, "y": 3.4},
{"label": "G", "matrix": [5, 3], "x": 5.75, "y": 3.4},
{"label": "H", "matrix": [5, 4], "x": 6.75, "y": 3.4},
{"label": "J", "matrix": [4, 4], "x": 7.75, "y": 3.4},
{"label": "K", "matrix": [4, 5], "x": 8.75, "y": 3.4},
{"label": "L", "matrix": [4, 6], "x": 9.75, "y": 3.4},
{"label": ";:", "matrix": [4, 7], "x": 10.75, "y": 3.4},
{"label": "'@", "matrix": [5, 7], "x": 11.75, "y": 3.4},
{"label": "#~", "matrix": [6, 7], "x": 12.75, "y": 3.4},
{"label": "Enter", "matrix": [6, 8], "x": 13.75, "y": 2.4, "w": 1.25, "h": 2},
{"label": "Shift", "matrix": [3, 14], "x": 0, "y": 4.4, "w": 1.25},
{"label": "\\|", "matrix": [5, 1], "x": 1.25, "y": 4.4},
{"label": "Z", "matrix": [6, 0], "x": 2.25, "y": 4.4},
{"label": "X", "matrix": [6, 1], "x": 3.25, "y": 4.4},
{"label": "C", "matrix": [6, 2], "x": 4.25, "y": 4.4},
{"label": "V", "matrix": [6, 3], "x": 5.25, "y": 4.4},
{"label": "B", "matrix": [7, 3], "x": 6.25, "y": 4.4},
{"label": "N", "matrix": [7, 4], "x": 7.25, "y": 4.4},
{"label": "M", "matrix": [6, 4], "x": 8.25, "y": 4.4},
{"label": ",<", "matrix": [6, 5], "x": 9.25, "y": 4.4},
{"label": ".>", "matrix": [6, 6], "x": 10.25, "y": 4.4},
{"label": "/?", "matrix": [7, 7], "x": 11.25, "y": 4.4},
{"label": "Shift", "matrix": [6, 14], "x": 12.25, "y": 4.4, "w": 2.75},
{"label": "Fn", "matrix": [4, 9], "x": 0, "y": 5.4},
{"label": "Ctrl", "matrix": [0, 15], "x": 1, "y": 5.4, "w": 1.25},
{"label": "Left OS", "matrix": [2, 11], "x": 2.25, "y": 5.4, "w": 0.9},
{"label": "Alt", "matrix": [5, 13], "x": 3.15, "y": 5.4},
{"label": "Space", "matrix": [7, 8], "x": 4.15, "y": 5.4, "w": 5},
{"label": "AltGr", "matrix": [7, 13], "x": 9.25, "y": 5.4},
{"label": "Menu", "matrix": [4, 11], "x": 10.25, "y": 5.4},
{"label": "Ctrl", "matrix": [6, 15], "x": 11.25, "y": 5.4},
{"label": "Browser Back", "matrix": [6, 11], "x": 12.25, "y": 5.4, "w": 0.9, "h": 0.75},
{"label": "Up", "matrix": [5, 12], "x": 13.15, "y": 5.4, "w": 0.9, "h": 0.75},
{"label": "Browser Forward", "matrix": [7, 11], "x": 14.05, "y": 5.4, "w": 0.9, "h": 0.75},
{"label": "Left", "matrix": [7, 12], "x": 12.25, "y": 6.15, "w": 0.9, "h": 0.75},
{"label": "Down", "matrix": [7, 10], "x": 13.15, "y": 6.15, "w": 0.9, "h": 0.75},
{"label": "Right", "matrix": [7, 9], "x": 14.05, "y": 6.15, "w": 0.9, "h": 0.75}
]
}
}
}
+9
View File
@@ -0,0 +1,9 @@
// Copyright 2022 Nick Brassel (@tzarc)
// SPDX-License-Identifier: GPL-2.0-or-later
#include "quantum.h"
void bootloader_jump(void) {
// TODO: Work out how to jump to LDROM, for now just reset the board.
NVIC_SystemReset();
}
@@ -0,0 +1,90 @@
{
"keyboard_name": "One 2 SF ANSI",
"usb": {
"pid": "0x07AF",
"device_version": "0.0.1"
},
"layout_aliases": {
"LAYOUT_ansi": "LAYOUT"
},
"layouts": {
"LAYOUT": {
"layout": [
{"label": "Esc", "matrix": [0, 0], "x": 0, "y": 0},
{"label": "1", "matrix": [0, 1], "x": 1, "y": 0},
{"label": "2", "matrix": [0, 2], "x": 2, "y": 0},
{"label": "3", "matrix": [0, 3], "x": 3, "y": 0},
{"label": "4", "matrix": [0, 4], "x": 4, "y": 0},
{"label": "5", "matrix": [0, 5], "x": 5, "y": 0},
{"label": "6", "matrix": [0, 6], "x": 6, "y": 0},
{"label": "7", "matrix": [0, 7], "x": 7, "y": 0},
{"label": "8", "matrix": [0, 8], "x": 8, "y": 0},
{"label": "9", "matrix": [0, 9], "x": 9, "y": 0},
{"label": "0", "matrix": [0, 10], "x": 10, "y": 0},
{"label": "-", "matrix": [0, 11], "x": 11, "y": 0},
{"label": "=", "matrix": [0, 12], "x": 12, "y": 0},
{"label": "Backspace", "matrix": [0, 13], "x": 13, "y": 0, "w": 2},
{"label": "Delete", "matrix": [0, 14], "x": 15.25, "y": 0},
{"label": "Tab", "matrix": [1, 0], "x": 0, "y": 1, "w": 1.5},
{"label": "Q", "matrix": [1, 1], "x": 1.5, "y": 1},
{"label": "W", "matrix": [1, 2], "x": 2.5, "y": 1},
{"label": "E", "matrix": [1, 3], "x": 3.5, "y": 1},
{"label": "R", "matrix": [1, 4], "x": 4.5, "y": 1},
{"label": "T", "matrix": [1, 5], "x": 5.5, "y": 1},
{"label": "Y", "matrix": [1, 6], "x": 6.5, "y": 1},
{"label": "U", "matrix": [1, 7], "x": 7.5, "y": 1},
{"label": "I", "matrix": [1, 8], "x": 8.5, "y": 1},
{"label": "O", "matrix": [1, 9], "x": 9.5, "y": 1},
{"label": "P", "matrix": [1, 10], "x": 10.5, "y": 1},
{"label": "[", "matrix": [1, 11], "x": 11.5, "y": 1},
{"label": "]", "matrix": [1, 12], "x": 12.5, "y": 1},
{"label": "\\", "matrix": [1, 13], "x": 13.5, "y": 1, "w": 1.5},
{"label": "Page Up", "matrix": [1, 14], "x": 15.25, "y": 1},
{"label": "Caps Lock", "matrix": [2, 0], "x": 0, "y": 2, "w": 1.75},
{"label": "A", "matrix": [2, 1], "x": 1.75, "y": 2},
{"label": "S", "matrix": [2, 2], "x": 2.75, "y": 2},
{"label": "D", "matrix": [2, 3], "x": 3.75, "y": 2},
{"label": "F", "matrix": [2, 4], "x": 4.75, "y": 2},
{"label": "G", "matrix": [2, 5], "x": 5.75, "y": 2},
{"label": "H", "matrix": [2, 6], "x": 6.75, "y": 2},
{"label": "J", "matrix": [2, 7], "x": 7.75, "y": 2},
{"label": "K", "matrix": [2, 8], "x": 8.75, "y": 2},
{"label": "L", "matrix": [2, 9], "x": 9.75, "y": 2},
{"label": ";", "matrix": [2, 10], "x": 10.75, "y": 2},
{"label": "'", "matrix": [2, 11], "x": 11.75, "y": 2},
{"label": "Enter", "matrix": [2, 13], "x": 12.75, "y": 2, "w": 2.25},
{"label": "Page Down", "matrix": [2, 14], "x": 15.25, "y": 2},
{"label": "Shift", "matrix": [3, 0], "x": 0, "y": 3, "w": 2.25},
{"label": "Z", "matrix": [3, 2], "x": 2.25, "y": 3},
{"label": "X", "matrix": [3, 3], "x": 3.25, "y": 3},
{"label": "C", "matrix": [3, 4], "x": 4.25, "y": 3},
{"label": "V", "matrix": [3, 5], "x": 5.25, "y": 3},
{"label": "B", "matrix": [3, 6], "x": 6.25, "y": 3},
{"label": "N", "matrix": [3, 7], "x": 7.25, "y": 3},
{"label": "M", "matrix": [3, 8], "x": 8.25, "y": 3},
{"label": ",", "matrix": [3, 9], "x": 9.25, "y": 3},
{"label": ".", "matrix": [3, 10], "x": 10.25, "y": 3},
{"label": "/", "matrix": [3, 11], "x": 11.25, "y": 3},
{"label": "Shift", "matrix": [3, 12], "x": 12.25, "y": 3, "w": 2},
{"label": "\u2191", "matrix": [3, 13], "x": 14.25, "y": 3},
{"label": "Ctrl", "matrix": [4, 0], "x": 0, "y": 4, "w": 1.25},
{"label": "GUI", "matrix": [4, 1], "x": 1.25, "y": 4, "w": 1.25},
{"label": "Alt", "matrix": [4, 2], "x": 2.5, "y": 4, "w": 1.25},
{"label": "Space", "matrix": [4, 5], "x": 3.75, "y": 4, "w": 6.25},
{"label": "Alt", "matrix": [4, 9], "x": 10, "y": 4},
{"label": "Fn", "matrix": [4, 10], "x": 11, "y": 4},
{"label": "Ctrl", "matrix": [4, 11], "x": 12, "y": 4, "w": 1.25},
{"label": "\u2190", "matrix": [4, 12], "x": 13.25, "y": 4},
{"label": "\u2193", "matrix": [4, 13], "x": 14.25, "y": 4},
{"label": "\u2192", "matrix": [4, 14], "x": 15.25, "y": 4}
]
}
}
}
@@ -0,0 +1,12 @@
// Copyright 2019 /u/KeepItUnder
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
// place overrides here
#define GRAVE_ESC_GUI_OVERRIDE
#define MK_3_SPEED
#define MK_C_OFFSET_UNMOD 400 /* Cursor offset per movement (unmodified) */
#define MK_C_INTERVAL_UNMOD 5 /* Time between cursor movements (unmodified) */
#define MK_W_OFFSET_UNMOD 100 /* Scroll steps per scroll action (unmodified) */
#define MK_W_INTERVAL_UNMOD 10 /* Time between scroll steps (unmodified) */
@@ -1,34 +1,17 @@
/* Copyright 2019 /u/KeepItUnder
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// Copyright 2019 /u/KeepItUnder
// SPDX-License-Identifier: GPL-2.0-or-later
#include QMK_KEYBOARD_H
// LAYERS
enum Layer {
_QWERTY = 0, // Standard QWERTY layer
_FUNCTION, // Function key layer
_COLOUR // RGB key layer
_QWERTY,
_FUNCTION,
_COLOUR
};
#define _QW _QWERTY
#define _FN _FUNCTION
#define _CLR _COLOUR
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[_QWERTY] = LAYOUT_ansi(
// 2 3 4 5 6 7 8 9 10 11 12 13 14 15
[_QWERTY] = LAYOUT(
QK_GESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, KC_DEL,
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, KC_PGUP,
KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, KC_PGDN,
@@ -36,15 +19,15 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
KC_LCTL, KC_LGUI, KC_LALT, KC_SPC, KC_RALT, MO(1), KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT
),
[_FUNCTION] = LAYOUT_ansi(
[_FUNCTION] = LAYOUT(
KC_GRV, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_DEL, _______,
_______, MS_BTN1, MS_UP, MS_BTN2, MS_WHLU, _______, KC_INS, _______, KC_UP, KC_PAUS, KC_PGUP, KC_HOME, KC_PSCR, _______, KC_HOME,
_______, MS_LEFT, MS_DOWN, MS_RGHT, MS_WHLD, _______, KC_SCRL, KC_LEFT, KC_DOWN, KC_RGHT, KC_PGDN, KC_END, _______, KC_END,
_______, RM_TOGG, RM_NEXT, RM_HUEU, RM_HUED, RM_SATU, RM_SATD, KC_MUTE, KC_VOLD, KC_VOLU, _______, _______, _______,
_______, _______, _______, _______, MO(2), _______, _______, _______, _______, _______
_______, _______, _______, QK_BOOT, MO(2), _______, _______, _______, _______, _______
),
[_COLOUR] = LAYOUT_ansi(
[_COLOUR] = LAYOUT(
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
+2 -15
View File
@@ -1,18 +1,5 @@
/* Copyright 2020 QMK
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// Copyright 2020 QMK
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
+2 -16
View File
@@ -1,19 +1,5 @@
/*
Copyright 2019 /u/KeepItUnder
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// Copyright 2019 /u/KeepItUnder
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
+23
View File
@@ -0,0 +1,23 @@
{
"manufacturer": "Ducky",
"maintainer": "f7urry",
"bootloader": "custom",
"usb": {
"vid": "0x445B"
},
"host": {
"default": {
"nkro": true
}
},
"matrix_pins": {
"cols": ["B10", "B9", "C13", "C12", "C11", "C10", "C9", "C8", "A15", "A14", "A13", "D0", "D1", "D2", "B15"],
"rows": ["D11", "B4", "B5", "B6", "B7"]
},
"diode_direction": "COL2ROW",
"features": {
"mousekey": true,
"extrakey": true,
"nkro": true
}
}
@@ -0,0 +1,91 @@
{
"keyboard_name": "One 2 SF ISO",
"usb": {
"pid": "0x07AE",
"device_version": "0.0.1"
},
"layout_aliases": {
"LAYOUT_iso": "LAYOUT"
},
"layouts": {
"LAYOUT": {
"layout": [
{"label": "Esc", "matrix": [0, 0], "x": 0, "y": 0},
{"label": "1", "matrix": [0, 1], "x": 1, "y": 0},
{"label": "2", "matrix": [0, 2], "x": 2, "y": 0},
{"label": "3", "matrix": [0, 3], "x": 3, "y": 0},
{"label": "4", "matrix": [0, 4], "x": 4, "y": 0},
{"label": "5", "matrix": [0, 5], "x": 5, "y": 0},
{"label": "6", "matrix": [0, 6], "x": 6, "y": 0},
{"label": "7", "matrix": [0, 7], "x": 7, "y": 0},
{"label": "8", "matrix": [0, 8], "x": 8, "y": 0},
{"label": "9", "matrix": [0, 9], "x": 9, "y": 0},
{"label": "0", "matrix": [0, 10], "x": 10, "y": 0},
{"label": "-", "matrix": [0, 11], "x": 11, "y": 0},
{"label": "=", "matrix": [0, 12], "x": 12, "y": 0},
{"label": "Backspace", "matrix": [0, 13], "x": 13, "y": 0, "w": 2},
{"label": "Delete", "matrix": [0, 14], "x": 15.25, "y": 0},
{"label": "Tab", "matrix": [1, 0], "x": 0, "y": 1, "w": 1.5},
{"label": "Q", "matrix": [1, 1], "x": 1.5, "y": 1},
{"label": "W", "matrix": [1, 2], "x": 2.5, "y": 1},
{"label": "E", "matrix": [1, 3], "x": 3.5, "y": 1},
{"label": "R", "matrix": [1, 4], "x": 4.5, "y": 1},
{"label": "T", "matrix": [1, 5], "x": 5.5, "y": 1},
{"label": "Y", "matrix": [1, 6], "x": 6.5, "y": 1},
{"label": "U", "matrix": [1, 7], "x": 7.5, "y": 1},
{"label": "I", "matrix": [1, 8], "x": 8.5, "y": 1},
{"label": "O", "matrix": [1, 9], "x": 9.5, "y": 1},
{"label": "P", "matrix": [1, 10], "x": 10.5, "y": 1},
{"label": "[", "matrix": [1, 11], "x": 11.5, "y": 1},
{"label": "]", "matrix": [1, 12], "x": 12.5, "y": 1},
{"label": "Page Up", "matrix": [1, 14], "x": 15.25, "y": 1},
{"label": "Caps Lock", "matrix": [2, 0], "x": 0, "y": 2, "w": 1.75},
{"label": "A", "matrix": [2, 1], "x": 1.75, "y": 2},
{"label": "S", "matrix": [2, 2], "x": 2.75, "y": 2},
{"label": "D", "matrix": [2, 3], "x": 3.75, "y": 2},
{"label": "F", "matrix": [2, 4], "x": 4.75, "y": 2},
{"label": "G", "matrix": [2, 5], "x": 5.75, "y": 2},
{"label": "H", "matrix": [2, 6], "x": 6.75, "y": 2},
{"label": "J", "matrix": [2, 7], "x": 7.75, "y": 2},
{"label": "K", "matrix": [2, 8], "x": 8.75, "y": 2},
{"label": "L", "matrix": [2, 9], "x": 9.75, "y": 2},
{"label": ";", "matrix": [2, 10], "x": 10.75, "y": 2},
{"label": "'", "matrix": [2, 11], "x": 11.75, "y": 2},
{"label": "#", "matrix": [2, 12], "x": 12.75, "y": 2},
{"label": "Enter", "matrix": [2, 13], "x": 13.75, "y": 1, "w": 1.25, "h": 2},
{"label": "Page Down", "matrix": [2, 14], "x": 15.25, "y": 2},
{"label": "Shift", "matrix": [3, 0], "x": 0, "y": 3, "w": 1.25},
{"label": "\\", "matrix": [3, 1], "x": 1.25, "y": 3},
{"label": "Z", "matrix": [3, 2], "x": 2.25, "y": 3},
{"label": "X", "matrix": [3, 3], "x": 3.25, "y": 3},
{"label": "C", "matrix": [3, 4], "x": 4.25, "y": 3},
{"label": "V", "matrix": [3, 5], "x": 5.25, "y": 3},
{"label": "B", "matrix": [3, 6], "x": 6.25, "y": 3},
{"label": "N", "matrix": [3, 7], "x": 7.25, "y": 3},
{"label": "M", "matrix": [3, 8], "x": 8.25, "y": 3},
{"label": ",", "matrix": [3, 9], "x": 9.25, "y": 3},
{"label": ".", "matrix": [3, 10], "x": 10.25, "y": 3},
{"label": "/", "matrix": [3, 11], "x": 11.25, "y": 3},
{"label": "Shift", "matrix": [3, 12], "x": 12.25, "y": 3, "w": 2},
{"label": "\u2191", "matrix": [3, 13], "x": 14.25, "y": 3},
{"label": "Ctrl", "matrix": [4, 0], "x": 0, "y": 4, "w": 1.25},
{"label": "GUI", "matrix": [4, 1], "x": 1.25, "y": 4, "w": 1.25},
{"label": "Alt", "matrix": [4, 2], "x": 2.5, "y": 4, "w": 1.25},
{"label": "Space", "matrix": [4, 5], "x": 3.75, "y": 4, "w": 6.25},
{"label": "Alt", "matrix": [4, 9], "x": 10, "y": 4},
{"label": "Fn", "matrix": [4, 10], "x": 11, "y": 4},
{"label": "Ctrl", "matrix": [4, 11], "x": 12, "y": 4, "w": 1.25},
{"label": "\u2190", "matrix": [4, 12], "x": 13.25, "y": 4},
{"label": "\u2193", "matrix": [4, 13], "x": 14.25, "y": 4},
{"label": "\u2192", "matrix": [4, 14], "x": 15.25, "y": 4}
]
}
}
}
@@ -0,0 +1,12 @@
// Copyright 2019 /u/KeepItUnder
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
// place overrides here
#define GRAVE_ESC_GUI_OVERRIDE
#define MK_3_SPEED
#define MK_C_OFFSET_UNMOD 400 /* Cursor offset per movement (unmodified) */
#define MK_C_INTERVAL_UNMOD 5 /* Time between cursor movements (unmodified) */
#define MK_W_OFFSET_UNMOD 100 /* Scroll steps per scroll action (unmodified) */
#define MK_W_INTERVAL_UNMOD 10 /* Time between scroll steps (unmodified) */
@@ -1,34 +1,17 @@
/* Copyright 2019 /u/KeepItUnder
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// Copyright 2019 /u/KeepItUnder
// SPDX-License-Identifier: GPL-2.0-or-later
#include QMK_KEYBOARD_H
// LAYERS
enum Layer {
_QWERTY = 0, // Standard QWERTY layer
_FUNCTION, // Function key layer
_COLOUR // RGB key layer
_QWERTY,
_FUNCTION,
_COLOUR
};
#define _QW _QWERTY
#define _FN _FUNCTION
#define _CLR _COLOUR
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[_QWERTY] = LAYOUT_iso(
// 2 3 4 5 6 7 8 9 10 11 12 13 14 15
[_QWERTY] = LAYOUT(
QK_GESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, KC_DEL,
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_PGUP,
KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_NUHS, KC_ENT, KC_PGDN,
@@ -36,15 +19,15 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
KC_LCTL, KC_LGUI, KC_LALT, KC_SPC, KC_RALT, MO(1), KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT
),
[_FUNCTION] = LAYOUT_iso(
[_FUNCTION] = LAYOUT(
KC_GRV, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_DEL, _______,
_______, MS_BTN1, MS_UP, MS_BTN2, MS_WHLU, _______, KC_INS, _______, KC_UP, KC_PAUS, KC_PGUP, KC_HOME, KC_PSCR, KC_HOME,
_______, MS_LEFT, MS_DOWN, MS_RGHT, MS_WHLD, _______, KC_SCRL, KC_LEFT, KC_DOWN, KC_RGHT, KC_PGDN, KC_END, _______, _______, KC_END,
_______, _______, RM_TOGG, RM_NEXT, RM_HUEU, RM_HUED, RM_SATU, RM_SATD, KC_MUTE, KC_VOLD, KC_VOLU, _______, _______, _______,
_______, _______, _______, _______, MO(2), _______, _______, _______, _______, _______
_______, _______, _______, QK_BOOT, MO(2), _______, _______, _______, _______, _______
),
[_COLOUR] = LAYOUT_iso(
[_COLOUR] = LAYOUT(
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
-269
View File
@@ -1,269 +0,0 @@
{
"keyboard_name": "One 2 SF",
"manufacturer": "Ducky",
"maintainer": "f7urry",
"usb": {
"vid": "0x445B",
"pid": "0x07AF",
"device_version": "0.0.1"
},
"host": {
"default": {
"nkro": true
}
},
"matrix_pins": {
"cols": ["B10", "B9", "C13", "C12", "C11", "C10", "C9", "C8", "A15", "A14", "A13", "D0", "D1", "D2", "B15", "B8"],
"rows": ["D11", "B4", "B5", "B6", "B7"]
},
"diode_direction": "COL2ROW",
"dip_switch": {
"matrix_grid": [ [0,14], [1,14], [2,14], [3,14] ]
},
"features": {
"bootmagic": true,
"mousekey": true,
"extrakey": true,
"nkro": true,
"dip_switch": true
},
"layouts": {
"LAYOUT_all": {
"layout": [
{"label": "Esc", "matrix": [0, 0], "x": 0, "y": 0},
{"label": "1", "matrix": [0, 1], "x": 1, "y": 0},
{"label": "2", "matrix": [0, 2], "x": 2, "y": 0},
{"label": "3", "matrix": [0, 3], "x": 3, "y": 0},
{"label": "4", "matrix": [0, 4], "x": 4, "y": 0},
{"label": "5", "matrix": [0, 5], "x": 5, "y": 0},
{"label": "6", "matrix": [0, 6], "x": 6, "y": 0},
{"label": "7", "matrix": [0, 7], "x": 7, "y": 0},
{"label": "8", "matrix": [0, 8], "x": 8, "y": 0},
{"label": "9", "matrix": [0, 9], "x": 9, "y": 0},
{"label": "0", "matrix": [0, 10], "x": 10, "y": 0},
{"label": "-", "matrix": [0, 11], "x": 11, "y": 0},
{"label": "=", "matrix": [0, 12], "x": 12, "y": 0},
{"label": "Backspace", "matrix": [0, 13], "x": 13, "y": 0, "w": 2},
{"label": "Delete", "matrix": [0, 14], "x": 15.25, "y": 0},
{"label": "Tab", "matrix": [1, 0], "x": 0, "y": 1, "w": 1.5},
{"label": "Q", "matrix": [1, 1], "x": 1.5, "y": 1},
{"label": "W", "matrix": [1, 2], "x": 2.5, "y": 1},
{"label": "E", "matrix": [1, 3], "x": 3.5, "y": 1},
{"label": "R", "matrix": [1, 4], "x": 4.5, "y": 1},
{"label": "T", "matrix": [1, 5], "x": 5.5, "y": 1},
{"label": "Y", "matrix": [1, 6], "x": 6.5, "y": 1},
{"label": "U", "matrix": [1, 7], "x": 7.5, "y": 1},
{"label": "I", "matrix": [1, 8], "x": 8.5, "y": 1},
{"label": "O", "matrix": [1, 9], "x": 9.5, "y": 1},
{"label": "P", "matrix": [1, 10], "x": 10.5, "y": 1},
{"label": "[", "matrix": [1, 11], "x": 11.5, "y": 1},
{"label": "]", "matrix": [1, 12], "x": 12.5, "y": 1},
{"label": "\\", "matrix": [1, 13], "x": 13.5, "y": 1, "w": 1.5},
{"label": "Page Up", "matrix": [1, 14], "x": 15.25, "y": 1},
{"label": "Caps Lock", "matrix": [2, 0], "x": 0, "y": 2, "w": 1.75},
{"label": "A", "matrix": [2, 1], "x": 1.75, "y": 2},
{"label": "S", "matrix": [2, 2], "x": 2.75, "y": 2},
{"label": "D", "matrix": [2, 3], "x": 3.75, "y": 2},
{"label": "F", "matrix": [2, 4], "x": 4.75, "y": 2},
{"label": "G", "matrix": [2, 5], "x": 5.75, "y": 2},
{"label": "H", "matrix": [2, 6], "x": 6.75, "y": 2},
{"label": "J", "matrix": [2, 7], "x": 7.75, "y": 2},
{"label": "K", "matrix": [2, 8], "x": 8.75, "y": 2},
{"label": "L", "matrix": [2, 9], "x": 9.75, "y": 2},
{"label": ";", "matrix": [2, 10], "x": 10.75, "y": 2},
{"label": "'", "matrix": [2, 11], "x": 11.75, "y": 2},
{"label": "#", "matrix": [2, 12], "x": 12.75, "y": 2},
{"label": "Enter", "matrix": [2, 13], "x": 13.75, "y": 2, "w": 1.25},
{"label": "Page Down", "matrix": [2, 14], "x": 15.25, "y": 2},
{"label": "Shift", "matrix": [3, 0], "x": 0, "y": 3, "w": 1.25},
{"label": "\\", "matrix": [3, 1], "x": 1.25, "y": 3},
{"label": "Z", "matrix": [3, 2], "x": 2.25, "y": 3},
{"label": "X", "matrix": [3, 3], "x": 3.25, "y": 3},
{"label": "C", "matrix": [3, 4], "x": 4.25, "y": 3},
{"label": "V", "matrix": [3, 5], "x": 5.25, "y": 3},
{"label": "B", "matrix": [3, 6], "x": 6.25, "y": 3},
{"label": "N", "matrix": [3, 7], "x": 7.25, "y": 3},
{"label": "M", "matrix": [3, 8], "x": 8.25, "y": 3},
{"label": ",", "matrix": [3, 9], "x": 9.25, "y": 3},
{"label": ".", "matrix": [3, 10], "x": 10.25, "y": 3},
{"label": "/", "matrix": [3, 11], "x": 11.25, "y": 3},
{"label": "Shift", "matrix": [3, 12], "x": 12.25, "y": 3, "w": 2},
{"label": "\u2191", "matrix": [3, 13], "x": 14.25, "y": 3},
{"label": "Ctrl", "matrix": [4, 0], "x": 0, "y": 4, "w": 1.25},
{"label": "GUI", "matrix": [4, 1], "x": 1.25, "y": 4, "w": 1.25},
{"label": "Alt", "matrix": [4, 2], "x": 2.5, "y": 4, "w": 1.25},
{"label": "Space", "matrix": [4, 5], "x": 3.75, "y": 4, "w": 6.25},
{"label": "Alt", "matrix": [4, 9], "x": 10, "y": 4},
{"label": "Fn", "matrix": [4, 10], "x": 11, "y": 4},
{"label": "Ctrl", "matrix": [4, 11], "x": 12, "y": 4, "w": 1.25},
{"label": "\u2190", "matrix": [4, 12], "x": 13.25, "y": 4},
{"label": "\u2193", "matrix": [4, 13], "x": 14.25, "y": 4},
{"label": "\u2192", "matrix": [4, 14], "x": 15.25, "y": 4}
]
},
"LAYOUT_ansi": {
"layout": [
{"label": "Esc", "matrix": [0, 0], "x": 0, "y": 0},
{"label": "1", "matrix": [0, 1], "x": 1, "y": 0},
{"label": "2", "matrix": [0, 2], "x": 2, "y": 0},
{"label": "3", "matrix": [0, 3], "x": 3, "y": 0},
{"label": "4", "matrix": [0, 4], "x": 4, "y": 0},
{"label": "5", "matrix": [0, 5], "x": 5, "y": 0},
{"label": "6", "matrix": [0, 6], "x": 6, "y": 0},
{"label": "7", "matrix": [0, 7], "x": 7, "y": 0},
{"label": "8", "matrix": [0, 8], "x": 8, "y": 0},
{"label": "9", "matrix": [0, 9], "x": 9, "y": 0},
{"label": "0", "matrix": [0, 10], "x": 10, "y": 0},
{"label": "-", "matrix": [0, 11], "x": 11, "y": 0},
{"label": "=", "matrix": [0, 12], "x": 12, "y": 0},
{"label": "Backspace", "matrix": [0, 13], "x": 13, "y": 0, "w": 2},
{"label": "Delete", "matrix": [0, 14], "x": 15.25, "y": 0},
{"label": "Tab", "matrix": [1, 0], "x": 0, "y": 1, "w": 1.5},
{"label": "Q", "matrix": [1, 1], "x": 1.5, "y": 1},
{"label": "W", "matrix": [1, 2], "x": 2.5, "y": 1},
{"label": "E", "matrix": [1, 3], "x": 3.5, "y": 1},
{"label": "R", "matrix": [1, 4], "x": 4.5, "y": 1},
{"label": "T", "matrix": [1, 5], "x": 5.5, "y": 1},
{"label": "Y", "matrix": [1, 6], "x": 6.5, "y": 1},
{"label": "U", "matrix": [1, 7], "x": 7.5, "y": 1},
{"label": "I", "matrix": [1, 8], "x": 8.5, "y": 1},
{"label": "O", "matrix": [1, 9], "x": 9.5, "y": 1},
{"label": "P", "matrix": [1, 10], "x": 10.5, "y": 1},
{"label": "[", "matrix": [1, 11], "x": 11.5, "y": 1},
{"label": "]", "matrix": [1, 12], "x": 12.5, "y": 1},
{"label": "\\", "matrix": [1, 13], "x": 13.5, "y": 1, "w": 1.5},
{"label": "Page Up", "matrix": [1, 14], "x": 15.25, "y": 1},
{"label": "Caps Lock", "matrix": [2, 0], "x": 0, "y": 2, "w": 1.75},
{"label": "A", "matrix": [2, 1], "x": 1.75, "y": 2},
{"label": "S", "matrix": [2, 2], "x": 2.75, "y": 2},
{"label": "D", "matrix": [2, 3], "x": 3.75, "y": 2},
{"label": "F", "matrix": [2, 4], "x": 4.75, "y": 2},
{"label": "G", "matrix": [2, 5], "x": 5.75, "y": 2},
{"label": "H", "matrix": [2, 6], "x": 6.75, "y": 2},
{"label": "J", "matrix": [2, 7], "x": 7.75, "y": 2},
{"label": "K", "matrix": [2, 8], "x": 8.75, "y": 2},
{"label": "L", "matrix": [2, 9], "x": 9.75, "y": 2},
{"label": ";", "matrix": [2, 10], "x": 10.75, "y": 2},
{"label": "'", "matrix": [2, 11], "x": 11.75, "y": 2},
{"label": "Enter", "matrix": [2, 13], "x": 12.75, "y": 2, "w": 2.25},
{"label": "Page Down", "matrix": [2, 14], "x": 15.25, "y": 2},
{"label": "Shift", "matrix": [3, 0], "x": 0, "y": 3, "w": 2.25},
{"label": "Z", "matrix": [3, 2], "x": 2.25, "y": 3},
{"label": "X", "matrix": [3, 3], "x": 3.25, "y": 3},
{"label": "C", "matrix": [3, 4], "x": 4.25, "y": 3},
{"label": "V", "matrix": [3, 5], "x": 5.25, "y": 3},
{"label": "B", "matrix": [3, 6], "x": 6.25, "y": 3},
{"label": "N", "matrix": [3, 7], "x": 7.25, "y": 3},
{"label": "M", "matrix": [3, 8], "x": 8.25, "y": 3},
{"label": ",", "matrix": [3, 9], "x": 9.25, "y": 3},
{"label": ".", "matrix": [3, 10], "x": 10.25, "y": 3},
{"label": "/", "matrix": [3, 11], "x": 11.25, "y": 3},
{"label": "Shift", "matrix": [3, 12], "x": 12.25, "y": 3, "w": 2},
{"label": "\u2191", "matrix": [3, 13], "x": 14.25, "y": 3},
{"label": "Ctrl", "matrix": [4, 0], "x": 0, "y": 4, "w": 1.25},
{"label": "GUI", "matrix": [4, 1], "x": 1.25, "y": 4, "w": 1.25},
{"label": "Alt", "matrix": [4, 2], "x": 2.5, "y": 4, "w": 1.25},
{"label": "Space", "matrix": [4, 5], "x": 3.75, "y": 4, "w": 6.25},
{"label": "Alt", "matrix": [4, 9], "x": 10, "y": 4},
{"label": "Fn", "matrix": [4, 10], "x": 11, "y": 4},
{"label": "Ctrl", "matrix": [4, 11], "x": 12, "y": 4, "w": 1.25},
{"label": "\u2190", "matrix": [4, 12], "x": 13.25, "y": 4},
{"label": "\u2193", "matrix": [4, 13], "x": 14.25, "y": 4},
{"label": "\u2192", "matrix": [4, 14], "x": 15.25, "y": 4}
]
},
"LAYOUT_iso": {
"layout": [
{"label": "Esc", "matrix": [0, 0], "x": 0, "y": 0},
{"label": "1", "matrix": [0, 1], "x": 1, "y": 0},
{"label": "2", "matrix": [0, 2], "x": 2, "y": 0},
{"label": "3", "matrix": [0, 3], "x": 3, "y": 0},
{"label": "4", "matrix": [0, 4], "x": 4, "y": 0},
{"label": "5", "matrix": [0, 5], "x": 5, "y": 0},
{"label": "6", "matrix": [0, 6], "x": 6, "y": 0},
{"label": "7", "matrix": [0, 7], "x": 7, "y": 0},
{"label": "8", "matrix": [0, 8], "x": 8, "y": 0},
{"label": "9", "matrix": [0, 9], "x": 9, "y": 0},
{"label": "0", "matrix": [0, 10], "x": 10, "y": 0},
{"label": "-", "matrix": [0, 11], "x": 11, "y": 0},
{"label": "=", "matrix": [0, 12], "x": 12, "y": 0},
{"label": "Backspace", "matrix": [0, 13], "x": 13, "y": 0, "w": 2},
{"label": "Delete", "matrix": [0, 14], "x": 15.25, "y": 0},
{"label": "Tab", "matrix": [1, 0], "x": 0, "y": 1, "w": 1.5},
{"label": "Q", "matrix": [1, 1], "x": 1.5, "y": 1},
{"label": "W", "matrix": [1, 2], "x": 2.5, "y": 1},
{"label": "E", "matrix": [1, 3], "x": 3.5, "y": 1},
{"label": "R", "matrix": [1, 4], "x": 4.5, "y": 1},
{"label": "T", "matrix": [1, 5], "x": 5.5, "y": 1},
{"label": "Y", "matrix": [1, 6], "x": 6.5, "y": 1},
{"label": "U", "matrix": [1, 7], "x": 7.5, "y": 1},
{"label": "I", "matrix": [1, 8], "x": 8.5, "y": 1},
{"label": "O", "matrix": [1, 9], "x": 9.5, "y": 1},
{"label": "P", "matrix": [1, 10], "x": 10.5, "y": 1},
{"label": "[", "matrix": [1, 11], "x": 11.5, "y": 1},
{"label": "]", "matrix": [1, 12], "x": 12.5, "y": 1},
{"label": "Page Up", "matrix": [1, 14], "x": 15.25, "y": 1},
{"label": "Caps Lock", "matrix": [2, 0], "x": 0, "y": 2, "w": 1.75},
{"label": "A", "matrix": [2, 1], "x": 1.75, "y": 2},
{"label": "S", "matrix": [2, 2], "x": 2.75, "y": 2},
{"label": "D", "matrix": [2, 3], "x": 3.75, "y": 2},
{"label": "F", "matrix": [2, 4], "x": 4.75, "y": 2},
{"label": "G", "matrix": [2, 5], "x": 5.75, "y": 2},
{"label": "H", "matrix": [2, 6], "x": 6.75, "y": 2},
{"label": "J", "matrix": [2, 7], "x": 7.75, "y": 2},
{"label": "K", "matrix": [2, 8], "x": 8.75, "y": 2},
{"label": "L", "matrix": [2, 9], "x": 9.75, "y": 2},
{"label": ";", "matrix": [2, 10], "x": 10.75, "y": 2},
{"label": "'", "matrix": [2, 11], "x": 11.75, "y": 2},
{"label": "#", "matrix": [2, 12], "x": 12.75, "y": 2},
{"label": "Enter", "matrix": [2, 13], "x": 13.75, "y": 1, "w": 1.25, "h": 2},
{"label": "Page Down", "matrix": [2, 14], "x": 15.25, "y": 2},
{"label": "Shift", "matrix": [3, 0], "x": 0, "y": 3, "w": 1.25},
{"label": "\\", "matrix": [3, 1], "x": 1.25, "y": 3},
{"label": "Z", "matrix": [3, 2], "x": 2.25, "y": 3},
{"label": "X", "matrix": [3, 3], "x": 3.25, "y": 3},
{"label": "C", "matrix": [3, 4], "x": 4.25, "y": 3},
{"label": "V", "matrix": [3, 5], "x": 5.25, "y": 3},
{"label": "B", "matrix": [3, 6], "x": 6.25, "y": 3},
{"label": "N", "matrix": [3, 7], "x": 7.25, "y": 3},
{"label": "M", "matrix": [3, 8], "x": 8.25, "y": 3},
{"label": ",", "matrix": [3, 9], "x": 9.25, "y": 3},
{"label": ".", "matrix": [3, 10], "x": 10.25, "y": 3},
{"label": "/", "matrix": [3, 11], "x": 11.25, "y": 3},
{"label": "Shift", "matrix": [3, 12], "x": 12.25, "y": 3, "w": 2},
{"label": "\u2191", "matrix": [3, 13], "x": 14.25, "y": 3},
{"label": "Ctrl", "matrix": [4, 0], "x": 0, "y": 4, "w": 1.25},
{"label": "GUI", "matrix": [4, 1], "x": 1.25, "y": 4, "w": 1.25},
{"label": "Alt", "matrix": [4, 2], "x": 2.5, "y": 4, "w": 1.25},
{"label": "Space", "matrix": [4, 5], "x": 3.75, "y": 4, "w": 6.25},
{"label": "Alt", "matrix": [4, 9], "x": 10, "y": 4},
{"label": "Fn", "matrix": [4, 10], "x": 11, "y": 4},
{"label": "Ctrl", "matrix": [4, 11], "x": 12, "y": 4, "w": 1.25},
{"label": "\u2190", "matrix": [4, 12], "x": 13.25, "y": 4},
{"label": "\u2193", "matrix": [4, 13], "x": 14.25, "y": 4},
{"label": "\u2192", "matrix": [4, 14], "x": 15.25, "y": 4}
]
}
}
}
@@ -1,18 +0,0 @@
# Matrix Diagram for Ducky One 2 SF
```
┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐┌───┐
│00 │01 │02 │03 │04 │05 │06 │07 │08 │09 │0A │0B │0C │0D ││0E │
├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤├───┤ ┌─────┐
│10 │11 │12 │13 │14 │15 │16 │17 │18 │19 │1A │1B │1C │1D ││1E │ │ │
├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┤├───┤ ┌──┴┐2D │
│20 │21 │22 │23 │24 │25 │26 │27 │28 │29 │2A │2B │2D ││2E │ │2C │ │
├────┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─────┬──┴┼───┘ └───┴────┘
│30 │31 │32 │33 │34 │35 │36 │37 │38 │39 │3A │3B │3C │3D │ ISO Enter
├────┼───┴┬──┴─┬─┴───┴───┴───┴───┴───┴──┬┴──┬┴──┬┴───┬───┼───┼───┐
│40 │41 │42 │45 │49 │4A │4B │4C │4D │4E │
└────┴────┴────┴────────────────────────┴───┴───┴────┴───┴───┴───┘
┌────────┐
│30 │ 2.25u LShift
└────────┘
```
+1 -1
View File
@@ -43,7 +43,7 @@
#define NUC123_USB_USE_USB0 TRUE
#define NUC123_USB_USE_USB1 TRUE
#define NUC123_SERIAL_USE_UART0 TRUE
#define NUC123_SERIAL_USE_UART0 FALSE
#define NUC123_SERIAL_CLKSRC NUC123_SERIAL_CLKSRC_HSI
#define NUC123_MCUCONF
+10 -7
View File
@@ -2,18 +2,16 @@
A 65% keyboard by Ducky.
This firmware was tested on the Ducky One 2 SF 1967ST version.
* Keyboard Maintainer: [f7urry](https://github.com/f7urry)
* Hardware Supported: Ducky One 2 SF RGB (DKON1967ST), NUC123SD4AN0 + MBI5043GP
* Only ANSI layout is supported at this time
* ISO compiles but is **untested**
* VIA still WIP.
* RGB LEDs are currently disabled until the driver is merged.
* DIP switches are disabled due to hardware incompatibilities
## Compiling the Firmware:
make ducky/one2sf/1967st:default
make ducky/one2sf/1967st/ansi:default
make ducky/one2sf/1967st/iso:default
## Accessing Bootloader Mode
@@ -24,11 +22,16 @@ To enter the 1967ST bootloader to flash, boot the keyboard while holding D+L.
There are then two ways to flash the keyboard:
pip install --user nuvoton-isp
nuvoisp -f ducky_one2sf_ansi.bin
nuvoisp -f ducky_one2sf_1967st_ansi_default.bin
Alternatively you can use elfmimi's [nu-isp-cli](https://lib.rs/crates/nu-isp-cli) which is more complete than nuvoisp and allows flashing .hex files as well.
cargo install nu-isp-cli
nu-isp-cli flash ducky_one2sf_ansi.bin
nu-isp-cli flash ducky_one2sf_1967st_ansi_default.bin
or
make ducky/one2sf/1967st/ansi:default:flash
make ducky/one2sf/1967st/iso:default:flash
See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_tools) and the [make instructions](https://docs.qmk.fm/#/getting_started_make_guide) for more information. Brand new to QMK? Start with our [Complete Newbs Guide](https://docs.qmk.fm/#/newbs).
+3
View File
@@ -15,3 +15,6 @@ BOARD = NUC123SD4AN0
MCU = cortex-m0
# ARM version, CORTEX-M0/M1 are 6, CORTEX-M3/M4/M7 are 7
ARMV = 6
# Needs elevated access to 0416:3f00 on Linux
PROGRAM_CMD = nu-isp-cli flash $(BUILD_DIR)/$(TARGET).bin
@@ -1,25 +0,0 @@
/* Copyright 2019 /u/KeepItUnder
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
// place overrides here
#define GRAVE_ESC_GUI_OVERRIDE
#define MK_3_SPEED
#define MK_C_OFFSET_UNMOD 400 /* Cursor offset per movement (unmodified) */
#define MK_C_INTERVAL_UNMOD 5 /* Time between cursor movements (unmodified) */
#define MK_W_OFFSET_UNMOD 100 /* Scroll steps per scroll action (unmodified) */
#define MK_W_INTERVAL_UNMOD 10 /* Time between scroll steps (unmodified) */
@@ -1,55 +0,0 @@
/* Copyright 2019 /u/KeepItUnder
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include QMK_KEYBOARD_H
// LAYERS
enum Layer {
_QWERTY = 0, // Standard QWERTY layer
_FUNCTION, // Function key layer
_COLOUR // RGB key layer
};
#define _QW _QWERTY
#define _FN _FUNCTION
#define _CLR _COLOUR
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[_QWERTY] = LAYOUT_all(
// 2 3 4 5 6 7 8 9 10 11 12 13 14 15
QK_GESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, KC_DEL,
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, KC_PGUP,
KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_NUHS, KC_ENT, KC_PGDN,
KC_LSFT, KC_NUBS, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, KC_UP,
KC_LCTL, KC_LGUI, KC_LALT, KC_SPC, KC_RALT, MO(1), KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT
),
[_FUNCTION] = LAYOUT_all(
KC_GRV, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_DEL, _______,
_______, MS_BTN1, MS_UP, MS_BTN2, MS_WHLU, _______, KC_INS, _______, KC_UP, KC_PAUSE, KC_PGUP, KC_HOME, KC_PSCR, _______, KC_HOME,
_______, MS_LEFT, MS_DOWN, MS_RGHT, MS_WHLD, _______, KC_SCRL, KC_LEFT, KC_DOWN, KC_RIGHT, KC_PGDN, KC_END, _______, _______, KC_END,
_______, _______, RM_TOGG, RM_NEXT, RM_HUEU, RM_HUED, RM_SATU, RM_SATD, KC_MUTE, KC_VOLD, KC_VOLU, _______, _______, _______,
_______, _______, _______, _______, MO(2), _______, _______, _______, _______, _______
),
[_COLOUR] = LAYOUT_all(
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, RM_TOGG, RM_NEXT, RM_HUEU, RM_HUED, RM_SATU, RM_SATD, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______
),
};
@@ -1,25 +0,0 @@
/* Copyright 2019 /u/KeepItUnder
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
// place overrides here
#define GRAVE_ESC_GUI_OVERRIDE
#define MK_3_SPEED
#define MK_C_OFFSET_UNMOD 400 /* Cursor offset per movement (unmodified) */
#define MK_C_INTERVAL_UNMOD 5 /* Time between cursor movements (unmodified) */
#define MK_W_OFFSET_UNMOD 100 /* Scroll steps per scroll action (unmodified) */
#define MK_W_INTERVAL_UNMOD 10 /* Time between scroll steps (unmodified) */
@@ -1,25 +0,0 @@
/* Copyright 2019 /u/KeepItUnder
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
// place overrides here
#define GRAVE_ESC_GUI_OVERRIDE
#define MK_3_SPEED
#define MK_C_OFFSET_UNMOD 400 /* Cursor offset per movement (unmodified) */
#define MK_C_INTERVAL_UNMOD 5 /* Time between cursor movements (unmodified) */
#define MK_W_OFFSET_UNMOD 100 /* Scroll steps per scroll action (unmodified) */
#define MK_W_INTERVAL_UNMOD 10 /* Time between scroll steps (unmodified) */
@@ -0,0 +1,54 @@
{
"manufacturer": "Harry Cutts",
"keyboard_name": "TwentyPad",
"maintainer": "HarryCutts",
"bootloader": "atmel-dfu",
"features": {
"bootmagic": true,
"extrakey": true,
"mousekey": true
},
"matrix_pins": {
"direct": [
["B7", "D5", "B5", "F6"],
["B3", "D3", "B4", "F7"],
["B2", "D2", "D7", "C7"],
["B1", "D1", "D6", "C6"],
["B0", "D0", "D4", "B6"]
]
},
"processor": "atmega32u4",
"url": "https://github.com/HarryCutts/twentypad/",
"usb": {
"device_version": "1.0.0",
"pid": "0x209D",
"vid": "0xFEED"
},
"community_layouts": ["ortho_5x4"],
"layouts": {
"LAYOUT_ortho_5x4": {
"layout": [
{"label": "B7", "matrix": [0, 0], "x": 0, "y": 0},
{"label": "D5", "matrix": [0, 1], "x": 1, "y": 0},
{"label": "B5", "matrix": [0, 2], "x": 2, "y": 0},
{"label": "F6", "matrix": [0, 3], "x": 3, "y": 0},
{"label": "B3", "matrix": [1, 0], "x": 0, "y": 1},
{"label": "D3", "matrix": [1, 1], "x": 1, "y": 1},
{"label": "B4", "matrix": [1, 2], "x": 2, "y": 1},
{"label": "F7", "matrix": [1, 3], "x": 3, "y": 1},
{"label": "B2", "matrix": [2, 0], "x": 0, "y": 2},
{"label": "D2", "matrix": [2, 1], "x": 1, "y": 2},
{"label": "D7", "matrix": [2, 2], "x": 2, "y": 2},
{"label": "C7", "matrix": [2, 3], "x": 3, "y": 2},
{"label": "B1", "matrix": [3, 0], "x": 0, "y": 3},
{"label": "D1", "matrix": [3, 1], "x": 1, "y": 3},
{"label": "D6", "matrix": [3, 2], "x": 2, "y": 3},
{"label": "C6", "matrix": [3, 3], "x": 3, "y": 3},
{"label": "B0", "matrix": [4, 0], "x": 0, "y": 4},
{"label": "D0", "matrix": [4, 1], "x": 1, "y": 4},
{"label": "D4", "matrix": [4, 2], "x": 2, "y": 4},
{"label": "B6", "matrix": [4, 3], "x": 3, "y": 4}
]
}
}
}
@@ -0,0 +1,14 @@
{
"keyboard": "handwired/twentypad",
"keymap": "default",
"layout": "LAYOUT_ortho_5x4",
"layers": [
[
"KC_CALCULATOR", "KC_KP_SLASH", "KC_KP_ASTERISK", "KC_KP_MINUS",
"KC_KP_7", "KC_KP_8", "KC_KP_9", "KC_KP_PLUS",
"KC_KP_4", "KC_KP_5", "KC_KP_6", "KC_LEFT_PAREN",
"KC_KP_1", "KC_KP_2", "KC_KP_3", "KC_RIGHT_PAREN",
"KC_KP_0", "KC_KP_DOT", "KC_KP_EQUAL", "KC_KP_ENTER"
]
]
}
+26
View File
@@ -0,0 +1,26 @@
# TwentyPad
![TwentyPad](https://i.imgur.com/e1Bsg1M.jpeg)
A simple twenty-key macro pad, built to learn PCB design.
* Keyboard Maintainer: [Harry Cutts](https://github.com/HarryCutts)
* Hardware Supported: ATMEGA32U4 on a [custom PCB](https://github.com/HarryCutts/twentypad/)
Make example for this keyboard (after setting up your build environment):
qmk compile -kb handwired/twentypad -km default
Flashing example for this keyboard:
qmk flash -kb handwired/twentypad -km default
See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_tools) and the [make instructions](https://docs.qmk.fm/#/getting_started_make_guide) for more information. Brand new to QMK? Start with our [Complete Newbs Guide](https://docs.qmk.fm/#/newbs).
## Bootloader
Enter the bootloader in 3 ways:
* **Bootmagic reset**: Hold down the key at (0,0) in the matrix (the top left key) and plug in the keyboard
* **Physical reset button**: Press the button marked `SWR1` in the top-left of the PCB
* **Keycode in layout**: Press the key mapped to `QK_BOOT` if it is available
-2
View File
@@ -6,8 +6,6 @@
"diode_direction": "ROW2COL",
"features": {
"bootmagic": true,
"command": false,
"console": false,
"extrakey": true,
"mousekey": true,
"nkro": true,
-4
View File
@@ -221,9 +221,5 @@ void eeconfig_init_kb_datablock(void) {
config.idle_rgb_matrix = default_idle_rgb_matrix;
eeconfig_update_kb_datablock(&config, 0, EECONFIG_KB_DATA_SIZE);
# if (EECONFIG_USER_DATA_SIZE) > 0
eeconfig_init_user_datablock();
# endif // EECONFIG_USER_DATA_SIZE
#endif // RGB_IDLE_ENABLE
}
+1 -1
View File
@@ -98,7 +98,7 @@
{"matrix": [3, 3], "x": 61, "y": 63, "flags": 1},
{"matrix": [3, 4], "x": 81, "y": 63, "flags": 1},
{"matrix": [3, 5], "x": 101, "y": 63, "flags": 4},
{"x": 111, "y": 63, "flags": 4},
{"matrix": [3, 5], "x": 111, "y": 63, "flags": 4},
{"matrix": [3, 6], "x": 122, "y": 63, "flags": 4},
{"matrix": [3, 7], "x": 142, "y": 63, "flags": 1},
{"matrix": [3, 8], "x": 162, "y": 63, "flags": 1},
-10
View File
@@ -86,16 +86,6 @@ void matrix_init_kb(void) {
matrix_init_user();
}
uint8_t rgb_matrix_map_row_column_to_led_kb(uint8_t row, uint8_t column, uint8_t *led_i) {
// Spacebar has 2 leds 41 & 42, so add 42 to the array here, and 41 will be added
// by the default lookup code that runs after this
if (row == 3 && column == 5) {
led_i[0] = 42;
return 1;
}
return 0;
}
#ifdef SWAP_HANDS_ENABLE
__attribute__ ((weak))
const keypos_t PROGMEM hand_swap_config[MATRIX_ROWS][MATRIX_COLS] = {
+2 -2
View File
@@ -78,9 +78,9 @@ typedef enum {
UP_BEGIN_MID,
STATE_MASK = 0xf, /* 0b1111 */
EMIT_UP = 0x10,
EMIT_UP_MID = EMIT_UP & START_MID,
EMIT_UP_MID = EMIT_UP | START_MID,
EMIT_DOWN = 0x80,
EMIT_DOWN_MID = EMIT_DOWN & START_MID,
EMIT_DOWN_MID = EMIT_DOWN | START_MID,
EMIT_MASK = 0xf0
} encoder_state_t;
-113
View File
@@ -1,113 +0,0 @@
// Copyright 2024 zvecr <git@zvecr.com>
// SPDX-License-Identifier: GPL-2.0-or-later
#include QMK_KEYBOARD_H
enum layer_names {
_QWERTY,
_LOWER,
_RAISE,
_ADJUST,
};
#define LOWER MO(_LOWER)
#define RAISE MO(_RAISE)
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
/* Qwerty
* ,-----------------------------------------------------------------------------------.
* | Esc | Q | W | E | R | T | Y | U | I | O | P | Bksp |
* |------+------+------+------+------+-------------+------+------+------+------+------|
* | Tab | A | S | D | F | G | H | J | K | L | ; | " |
* |------+------+------+------+------+------|------+------+------+------+------+------|
* | Shift| Z | X | C | V | B | N | M | , | . | / |Enter |
* |------+------+------+------+------+------+------+------+------+------+------+------|
* | Ctrl | GUI | Alt | App |Lower | Space |Raise | Left | Down | Up |Right |
* `-----------------------------------------------------------------------------------'
*/
[_QWERTY] = LAYOUT_ortho_4x12(
KC_ESC, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_BSPC,
KC_TAB, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT,
KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_ENT,
KC_LCTL, KC_LGUI, KC_LALT, KC_APP, LOWER, KC_SPC, KC_SPC, RAISE, KC_LEFT, KC_DOWN, KC_UP, KC_RGHT
),
/* Lower
* ,-----------------------------------------------------------------------------------.
* | ~ | ! | @ | # | $ | % | ^ | & | * | ( | ) | Del |
* |------+------+------+------+------+-------------+------+------+------+------+------|
* | Del | F1 | F2 | F3 | F4 | F5 | F6 | _ | + | { | } | | |
* |------+------+------+------+------+------|------+------+------+------+------+------|
* | | F7 | F8 | F9 | F10 | F11 | F12 |ISO ~ |ISO | | | | |
* |------+------+------+------+------+------+------+------+------+------+------+------|
* | | | | | | | | | Next | Vol- | Vol+ | Play |
* `-----------------------------------------------------------------------------------'
*/
[_LOWER] = LAYOUT_ortho_4x12(
KC_TILD, KC_EXLM, KC_AT, KC_HASH, KC_DLR, KC_PERC, KC_CIRC, KC_AMPR, KC_ASTR, KC_LPRN, KC_RPRN, KC_DEL,
KC_DEL, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_UNDS, KC_PLUS, KC_LCBR, KC_RCBR, KC_PIPE,
_______, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12,S(KC_NUHS),S(KC_NUBS),_______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, KC_MNXT, KC_VOLD, KC_VOLU, KC_MPLY
),
/* Raise
* ,-----------------------------------------------------------------------------------.
* | ` | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | Del |
* |------+------+------+------+------+-------------+------+------+------+------+------|
* | Del | F1 | F2 | F3 | F4 | F5 | F6 | - | = | [ | ] | \ |
* |------+------+------+------+------+------|------+------+------+------+------+------|
* | | F7 | F8 | F9 | F10 | F11 | F12 |ISO # |ISO / | | | |
* |------+------+------+------+------+------+------+------+------+------+------+------|
* | | | | | | | | | Next | Vol- | Vol+ | Play |
* `-----------------------------------------------------------------------------------'
*/
[_RAISE] = LAYOUT_ortho_4x12(
KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_DEL,
KC_DEL, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_MINS, KC_EQL, KC_LBRC, KC_RBRC, KC_BSLS,
_______, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_NUHS, KC_NUBS, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, KC_MNXT, KC_VOLD, KC_VOLU, KC_MPLY
),
/* Adjust (Lower + Raise)
* ,-----------------------------------------------------------------------------------.
* | | Reset| | | | |R Tog |R Mode|R Rev |R Grad| Reset| |
* |------+------+------+------+------+-------------+------+------+------+------+------|
* | | | | | | |R HUI|R SAI|R VAI| | | |
* |------+------+------+------+------+------|------+------+------+------+------+------|
* | | | | | | |R HUD|R SAD|R VAD| | | |
* |------+------+------+------+------+------+------+------+------+------+------+------|
* | | | | | | | | | | | | |
* `-----------------------------------------------------------------------------------'
*/
[_ADJUST] = LAYOUT_ortho_4x12(
_______, QK_BOOT, _______, _______, _______, _______, UG_TOGG, UG_NEXT, UG_PREV, RGB_M_G, QK_BOOT, _______,
_______, _______, _______, _______, _______, _______, UG_HUEU, UG_SATU, UG_VALU, _______, _______, _______,
_______, _______, _______, _______, _______, _______, UG_HUED, UG_SATD, UG_VALD, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______
)
};
layer_state_t layer_state_set_user(layer_state_t state) {
return update_tri_layer_state(state, _LOWER, _RAISE, _ADJUST);
}
#if defined(ENCODER_MAP_ENABLE)
const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][NUM_DIRECTIONS] = {
[_QWERTY] = { ENCODER_CCW_CW(MS_WHLD, MS_WHLU), ENCODER_CCW_CW(KC_VOLD, KC_VOLU) },
[_LOWER] = { ENCODER_CCW_CW(UG_HUED, UG_HUEU), ENCODER_CCW_CW(UG_SATD, UG_SATU) },
[_RAISE] = { ENCODER_CCW_CW(UG_SATD, UG_SATU), ENCODER_CCW_CW(UG_SPDD, UG_SPDU) },
[_ADJUST] = { ENCODER_CCW_CW(UG_PREV, UG_NEXT), ENCODER_CCW_CW(KC_RGHT, KC_LEFT) },
};
#endif
void housekeeping_task_user(void) {
static uint32_t timer = 0;
static uint8_t count = 0;
if (timer_elapsed32(timer) > 1000) {
timer = timer_read32();
count++;
xap_broadcast(0x03, &count, 1);
}
}
@@ -1,2 +0,0 @@
ENCODER_MAP_ENABLE = yes
XAP_ENABLE = yes
@@ -1,16 +0,0 @@
{
routes: {
0x01: {
type: command
name: Capabilities Query
define: CAPABILITIES_QUERY_USER
description:
'''
USER subsystem capabilities query. Each bit should be considered as a "usable" route within this subsystem.
'''
return_type: u32
return_purpose: capabilities
return_constant: XAP_ROUTE_USER_CAPABILITIES
}
}
}
-16
View File
@@ -1,16 +0,0 @@
{
routes: {
0x01: {
type: command
name: Capabilities Query
define: CAPABILITIES_QUERY_KB
description:
'''
KB subsystem capabilities query. Each bit should be considered as a "usable" route within this subsystem.
'''
return_type: u32
return_purpose: capabilities
return_constant: XAP_ROUTE_KB_CAPABILITIES
}
}
}
-3
View File
@@ -113,9 +113,6 @@ class BuildTarget:
'builddefs/build_keyboard.mk',
]
if not cli.config.general.verbose:
compile_args.append('-s')
verbose = 'true' if cli.config.general.verbose else 'false'
color = 'true' if cli.config.general.color else 'false'
-65
View File
@@ -1,65 +0,0 @@
"""This script handles conversion between snake and camel casing.
"""
import re
_words_expr = re.compile(r"([a-zA-Z][^A-Z0-9]*|[0-9]+)")
_lower_snake_case_expr = re.compile(r'^[a-z][a-z0-9_]*$')
_upper_snake_case_expr = re.compile(r'^[A-Z][A-Z0-9_]*$')
def _is_snake_case(str):
"""Checks if the supplied string is already in snake case.
"""
match = _lower_snake_case_expr.match(str)
if match:
return True
match = _upper_snake_case_expr.match(str)
if match:
return True
return False
def _split_snake_case(str):
"""Splits up a string based on underscores, if it's in snake casing.
"""
if _is_snake_case(str):
return [s.lower() for s in str.split("_")]
return str
def _split_camel_case(str):
"""Splits up a string based on capitalised camel casing.
"""
return _words_expr.findall(str)
def _split_cased_words(str):
return _split_snake_case(str) if _is_snake_case(str) else _split_camel_case(str)
def to_snake(str):
str = "_".join([word.strip().lower() for word in _split_cased_words(str)])
# Fix acronyms
str = str.replace('i_d', 'id')
str = str.replace('x_a_p', 'xap')
str = str.replace('q_m_k', 'qmk')
return str
def to_upper_snake(str):
return to_snake(str).upper()
def to_camel(str):
def _acronym(w):
if w.strip().lower() == 'qmk':
return 'QMK'
elif w.strip().lower() == 'xap':
return 'XAP'
elif w.strip().lower() == 'id':
return 'ID'
return w.title()
return "".join([_acronym(word) for word in _split_cased_words(str)])
+1 -8
View File
@@ -42,8 +42,7 @@ import_names = {
'pyserial': 'serial',
'pyusb': 'usb.core',
'qmk-dotty-dict': 'dotty_dict',
'pillow': 'PIL',
'Jinja2': 'jinja2'
'pillow': 'PIL'
}
safe_commands = [
@@ -84,7 +83,6 @@ subcommands = [
'qmk.cli.generate.keyboard_c',
'qmk.cli.generate.keyboard_h',
'qmk.cli.generate.keycodes',
'qmk.cli.generate.lighting_map',
'qmk.cli.generate.keymap_h',
'qmk.cli.generate.make_dependencies',
'qmk.cli.generate.rgb_breathe_table',
@@ -118,11 +116,6 @@ subcommands = [
'qmk.cli.userspace.path',
'qmk.cli.userspace.remove',
'qmk.cli.via2json',
'qmk.cli.xap',
'qmk.cli.xap.generate_docs',
'qmk.cli.xap.generate_json',
'qmk.cli.xap.generate_python',
'qmk.cli.xap.generate_qmk',
]
+1 -1
View File
@@ -12,7 +12,7 @@ py_dirs = ['lib/python', 'util/ci']
def yapf_run(files):
edit = '--diff' if cli.args.dry_run else '--in-place'
yapf_cmd = ['yapf', '-vv', '--exclude', '**/xap_client/*', '--recursive', edit, *files]
yapf_cmd = ['yapf', '-vv', '--recursive', edit, *files]
try:
cli.run(yapf_cmd, check=True, capture_output=False, stdin=DEVNULL)
cli.log.info('Successfully formatted the python code.')
+9 -2
View File
@@ -1,11 +1,11 @@
"""Ensure text files have the proper line endings.
"""
from itertools import islice
from subprocess import DEVNULL
from milc import cli
from qmk.path import normpath, is_relative_to
from qmk.commands import get_chunks
IGNORE_SUFFIXES = [
'hex',
@@ -21,6 +21,13 @@ IGNORE_DIRS = [
]
def _get_chunks(it, size):
"""Break down a collection into smaller parts
"""
it = iter(it)
return iter(lambda: tuple(islice(it, size)), ())
def _check_dos2unix():
"""Check for a 'valid' dos2unix executable
"""
@@ -31,7 +38,7 @@ def _check_dos2unix():
def dos2unix_run(files):
"""Spawn multiple dos2unix subprocess avoiding too long commands on formatting everything
"""
for chunk in get_chunks([normpath(file).as_posix() for file in files], 10):
for chunk in _get_chunks([normpath(file).as_posix() for file in files], 10):
dos2unix = cli.run(['dos2unix', '--add-eol', *chunk])
if dos2unix.returncode:
-19
View File
@@ -2,7 +2,6 @@
"""
from pathlib import Path
import shutil
import hjson
import json
from milc import cli
@@ -14,7 +13,6 @@ from qmk.json_schema import json_load
from qmk.keymap import list_keymaps
from qmk.keyboard import find_readme, list_keyboards, keyboard_alias_definitions
from qmk.keycodes import load_spec, list_versions, list_languages
from qmk.xap.common import get_xap_definition_files, update_xap_definitions
DATA_PATH = Path('data')
TEMPLATE_PATH = DATA_PATH / 'templates/api/'
@@ -91,22 +89,6 @@ def _filtered_keyboard_list():
return keyboard_list
def _resolve_xap_specs(output_folder):
"""To make it easier for consumers, publish pre-merged spec files
"""
overall = None
for file in get_xap_definition_files():
overall = update_xap_definitions(overall, hjson.load(file.open(encoding='utf-8')))
# Inject dummy bits for unspecified response flags
for n in range(0, 8):
if str(n) not in overall['response_flags']['bits']:
overall['response_flags']['bits'][str(n)] = {'name': '', 'description': '', 'define': '-'}
output_file = output_folder / (file.stem + ".json")
output_file.write_text(json.dumps(overall, indent=4), encoding='utf-8')
@cli.argument('-n', '--dry-run', arg_only=True, action='store_true', help="Don't write the data to disk.")
@cli.argument('-f', '--filter', arg_only=True, action='append', default=[], help="Filter the list of keyboards based on partial name matches the supplied value. May be passed multiple times.")
@cli.subcommand('Generate QMK API data', hidden=False if cli.config.user.developer else True)
@@ -204,7 +186,6 @@ def generate_api(cli):
# Feature specific handling
_resolve_keycode_specs(v1_dir)
_resolve_xap_specs(v1_dir / 'xap')
# Write the global JSON files
keyboard_all_json = json.dumps({'last_updated': current_datetime(), 'keyboards': kb_all}, separators=(',', ':'))

Some files were not shown because too many files have changed in this diff Show More