Compare commits

..

28 Commits

Author SHA1 Message Date
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
Jack Sangdahl 746eff22db Add additional layouts for mkh_studio/bully (#26271)
* Add extra spacebar layouts

- Rename LAYOUT -> LAYOUT_all
  - Resize keys to not be 0.5u tall
- Add layout alias for the above
- Add LAYOUT_split_space
- Add LAYOUT_full_space

* Remove whitepsace
2026-06-18 15:59:10 -07:00
Joel Challis d36397fdd4 Implement Plover HID for VUSB (#26267) 2026-06-19 06:55:21 +10:00
Joel Challis 8522bb342d Enable modules to persist data (#26201) 2026-06-18 18:43:32 +01:00
precondition 721affff7b repeat_key.c: add implementation for get_last_record (#26263)
The `get_last_record` signature was present in repeat_key.h but without
any implementation in repeat_key.c which caused compilation errors for
any user of `get_last_record`.
2026-06-18 18:41:12 +01:00
gitaen 4f6c5d2745 Remove pin ordering restriction in RP2040 ps2 driver (#26256) 2026-06-15 09:36:02 +10:00
Nick Brassel 92dc82ae08 Plover HID cleanup. (#26262) 2026-06-15 08:33:35 +10:00
Graham Held b64014d5df Custom plover HID report type (#26018)
Co-authored-by: Nick Brassel <nick@tzarc.org>
Co-authored-by: dnaq <dnaq@users.noreply.github.com>
2026-06-14 12:38:34 +10:00
Puneet Dixit 0d401d1182 Preserve Azoteq mouse buttons (#26248)
Co-authored-by: Deepak kudi <deepakkudi23@adsl-172-10-9-116.dsl.sndg02.sbcglobal.net>
2026-06-14 09:04:01 +10:00
QMK Bot 6ada0933db Merge remote-tracking branch 'origin/master' into develop 2026-06-13 21:20:24 +00:00
Nick Brassel 85886db43b Fixup make format-core, make pytest, make format-and-pytest. (#26259) 2026-06-13 22:19:43 +01:00
QMK Bot 0515002e7d Merge remote-tracking branch 'origin/master' into develop 2026-06-13 12:29:41 +00:00
mellanslag-de d8c8872753 Key Overrides: Fix Ghost Modifier Bug on macOS (with Karabiner Elements) (#25886) 2026-06-13 22:28:41 +10:00
QMK Bot 7f702d2262 Merge remote-tracking branch 'origin/master' into develop 2026-06-13 12:06:29 +00:00
yiancar 520b726b5c Float65 Keyboard (#26197)
Co-authored-by: Drashna Jaelre <drashna@live.com>
Co-authored-by: yiancar <yiancar@gmail.com>
2026-06-13 22:00:51 +10:00
QMK Bot 6a0e2a8868 Merge remote-tracking branch 'origin/master' into develop 2026-06-13 11:30:00 +00:00
Samuel Baumgartner 4dc0a6e9e3 Feature/owlab link65 (#26163)
Co-authored-by: Joel Challis <git@zvecr.com>
2026-06-13 21:29:19 +10:00
QMK Bot 90082403de Merge remote-tracking branch 'origin/master' into develop 2026-06-10 23:54:21 +00:00
QMK Bot cffafbbdc7 Merge remote-tracking branch 'origin/master' into develop 2026-06-09 18:27:28 +00:00
QMK Bot 55be8f2c2b Merge remote-tracking branch 'origin/master' into develop 2026-06-08 00:37:23 +00:00
QMK Bot df94ffcc66 Merge remote-tracking branch 'origin/master' into develop 2026-06-03 21:49:34 +00:00
QMK Bot ee74da3a4d Merge remote-tracking branch 'origin/master' into develop 2026-06-01 11:34:14 +00:00
QMK Bot 480d808683 Merge remote-tracking branch 'origin/master' into develop 2026-06-01 08:08:15 +00:00
zvecr 62a8db33a3 Branch point for 2026q3 Breaking Change 2026-06-01 07:59:12 +01:00
85 changed files with 2222 additions and 222 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
@@ -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
+7 -6
View File
@@ -118,7 +118,7 @@ endef
TRY_TO_MATCH_RULE_FROM_LIST = $(eval $(call TRY_TO_MATCH_RULE_FROM_LIST_HELPER,$1))$(RULE_FOUND)
# As TRY_TO_MATCH_RULE_FROM_LIST_HELPER, but with additional
# resolution of keyboard_aliases.hjson for provided rule
# resolution of keyboard_aliases.hjson for provided rule
define TRY_TO_MATCH_RULE_FROM_LIST_HELPER_KB
# Split on ":", padding with empty strings to avoid indexing issues
TOKEN1:=$$(shell python3 -c "import sys; print((sys.argv[1].split(':',1)+[''])[0])" $$(RULE))
@@ -452,16 +452,17 @@ distclean_userspace: clean
endif
# Extra targets for formatting and/or pytest, running within the qmk/qmk_cli container to match GHA.
CONTAINER_PREAMBLE := export HOME="/tmp"; export PATH="/tmp/.local/bin:\$$PATH"; python3 -m pip install --upgrade pip; python3 -m pip install -r requirements-dev.txt
.PHONY: format-core
format-core:
RUNTIME=docker ./util/docker_cmd.sh bash -lic "$(CONTAINER_PREAMBLE); qmk format-c --core-only -a && qmk format-python -a"
RUNTIME=docker ./util/docker_cmd.sh qmk format-c --core-only -a
RUNTIME=docker ./util/docker_cmd.sh qmk format-python -a
.PHONY: pytest
pytest:
RUNTIME=docker ./util/docker_cmd.sh bash -lic "$(CONTAINER_PREAMBLE); qmk pytest"
RUNTIME=docker ./util/docker_cmd.sh qmk pytest
.PHONY: format-and-pytest
format-and-pytest:
RUNTIME=docker ./util/docker_cmd.sh bash -lic "$(CONTAINER_PREAMBLE); qmk format-c --core-only -a && qmk format-python -a && qmk pytest"
RUNTIME=docker ./util/docker_cmd.sh qmk format-c --core-only -a
RUNTIME=docker ./util/docker_cmd.sh qmk format-python -a
RUNTIME=docker ./util/docker_cmd.sh qmk pytest
+8 -8
View File
@@ -187,9 +187,9 @@ include $(COMMUNITY_RULES_MK)
ifneq ($(COMMUNITY_MODULES),)
$(INTERMEDIATE_OUTPUT)/src/community_config.h: $(KEYMAP_JSON) $(DD_CONFIG_FILES)
$(INTERMEDIATE_OUTPUT)/src/community_post_config.h: $(KEYMAP_JSON) $(DD_CONFIG_FILES)
@$(SILENT) || printf "$(MSG_GENERATING) $@" | $(AWK_CMD)
$(eval CMD=$(QMK_BIN) generate-community-config-h -kb $(KEYBOARD) --quiet --output $(INTERMEDIATE_OUTPUT)/src/community_config.h $(KEYMAP_JSON))
$(eval CMD=$(QMK_BIN) generate-community-post-config-h -kb $(KEYBOARD) --quiet --output $(INTERMEDIATE_OUTPUT)/src/community_post_config.h $(KEYMAP_JSON))
@$(BUILD_CMD)
$(INTERMEDIATE_OUTPUT)/src/community_modules.h: $(KEYMAP_JSON) $(DD_CONFIG_FILES)
@@ -227,10 +227,10 @@ $(INTERMEDIATE_OUTPUT)/src/split_transaction_id_community_modules.inc: $(KEYMAP_
$(eval CMD=$(QMK_BIN) generate-split-transaction-id-community-modules-inc -kb $(KEYBOARD) --quiet --output $(INTERMEDIATE_OUTPUT)/src/split_transaction_id_community_modules.inc $(KEYMAP_JSON))
@$(BUILD_CMD)
COMMUNITY_CONFIG_H = $(INTERMEDIATE_OUTPUT)/src/community_config.h
COMMUNITY_POST_CONFIG_H = $(INTERMEDIATE_OUTPUT)/src/community_post_config.h
SRC += $(INTERMEDIATE_OUTPUT)/src/community_modules.c
generated-files: $(INTERMEDIATE_OUTPUT)/src/community_config.h $(INTERMEDIATE_OUTPUT)/src/community_modules.h $(INTERMEDIATE_OUTPUT)/src/community_modules.c $(INTERMEDIATE_OUTPUT)/src/community_modules_introspection.c $(INTERMEDIATE_OUTPUT)/src/community_modules_introspection.h $(INTERMEDIATE_OUTPUT)/src/led_matrix_community_modules.inc $(INTERMEDIATE_OUTPUT)/src/rgb_matrix_community_modules.inc $(INTERMEDIATE_OUTPUT)/src/split_transaction_id_community_modules.inc
generated-files: $(INTERMEDIATE_OUTPUT)/src/community_post_config.h $(INTERMEDIATE_OUTPUT)/src/community_modules.h $(INTERMEDIATE_OUTPUT)/src/community_modules.c $(INTERMEDIATE_OUTPUT)/src/community_modules_introspection.c $(INTERMEDIATE_OUTPUT)/src/community_modules_introspection.h $(INTERMEDIATE_OUTPUT)/src/led_matrix_community_modules.inc $(INTERMEDIATE_OUTPUT)/src/rgb_matrix_community_modules.inc $(INTERMEDIATE_OUTPUT)/src/split_transaction_id_community_modules.inc
endif
@@ -331,10 +331,6 @@ define config_h_community_module_appender
endef
$(foreach module,$(COMMUNITY_MODULE_PATHS),$(eval $(call config_h_community_module_appender,$(module))))
ifneq ($(COMMUNITY_CONFIG_H),)
CONFIG_H += $(COMMUNITY_CONFIG_H)
endif
ifneq ("$(wildcard $(KEYBOARD_PATH_5)/config.h)","")
CONFIG_H += $(KEYBOARD_PATH_5)/config.h
endif
@@ -376,6 +372,10 @@ ifneq ("$(wildcard $(KEYBOARD_PATH_5)/post_config.h)","")
POST_CONFIG_H += $(KEYBOARD_PATH_5)/post_config.h
endif
ifneq ($(COMMUNITY_POST_CONFIG_H),)
POST_CONFIG_H += $(COMMUNITY_POST_CONFIG_H)
endif
CONFIG_H += $(INTERMEDIATE_OUTPUT)/src/info_config.h
KEYBOARD_SRC += $(INTERMEDIATE_OUTPUT)/src/default_keyboard.c
+1
View File
@@ -98,6 +98,7 @@ endif
VALID_STENO_PROTOCOL_TYPES := geminipr txbolt all
STENO_PROTOCOL ?= all
ifeq ($(strip $(STENO_ENABLE)), yes)
ifeq ($(filter $(STENO_PROTOCOL),$(VALID_STENO_PROTOCOL_TYPES)),)
$(call CATASTROPHIC_ERROR,Invalid STENO_PROTOCOL,STENO_PROTOCOL="$(STENO_PROTOCOL)" is not a valid stenography protocol)
+1
View File
@@ -45,6 +45,7 @@ GENERIC_FEATURES = \
MOUSEKEY \
MUSIC \
OS_DETECTION \
PLOVER_HID \
PROGRAMMABLE_BUTTON \
REPEAT_KEY \
SECURE \
+1
View File
@@ -63,6 +63,7 @@ OTHER_OPTION_NAMES = \
LCD_BACKLIGHT_ENABLE \
MACROS_ENABLED \
PS2_ENABLE \
PLOVER_HID_ENABLE \
PS2_MOUSE_ENABLE \
PS2_DRIVER \
RAW_ENABLE \
@@ -0,0 +1,265 @@
{
"ranges": {
"0x5A40/0x003F": {
"define": "QK_PLOVER_HID"
}
},
"keycodes": {
"0x5A40": {
"group": "plover_hid",
"key": "PLV_S1"
},
"0x5A41": {
"group": "plover_hid",
"key": "PLV_TL"
},
"0x5A42": {
"group": "plover_hid",
"key": "PLV_KL"
},
"0x5A43": {
"group": "plover_hid",
"key": "PLV_PL"
},
"0x5A44": {
"group": "plover_hid",
"key": "PLV_WL"
},
"0x5A45": {
"group": "plover_hid",
"key": "PLV_HL"
},
"0x5A46": {
"group": "plover_hid",
"key": "PLV_RL"
},
"0x5A47": {
"group": "plover_hid",
"key": "PLV_A"
},
"0x5A48": {
"group": "plover_hid",
"key": "PLV_O"
},
"0x5A49": {
"group": "plover_hid",
"key": "PLV_ST1"
},
"0x5A4A": {
"group": "plover_hid",
"key": "PLV_E"
},
"0x5A4B": {
"group": "plover_hid",
"key": "PLV_U"
},
"0x5A4C": {
"group": "plover_hid",
"key": "PLV_FR"
},
"0x5A4D": {
"group": "plover_hid",
"key": "PLV_RR"
},
"0x5A4E": {
"group": "plover_hid",
"key": "PLV_PR"
},
"0x5A4F": {
"group": "plover_hid",
"key": "PLV_BR"
},
"0x5A50": {
"group": "plover_hid",
"key": "PLV_LR"
},
"0x5A51": {
"group": "plover_hid",
"key": "PLV_GR"
},
"0x5A52": {
"group": "plover_hid",
"key": "PLV_TR"
},
"0x5A53": {
"group": "plover_hid",
"key": "PLV_SR"
},
"0x5A54": {
"group": "plover_hid",
"key": "PLV_DR"
},
"0x5A55": {
"group": "plover_hid",
"key": "PLV_ZR"
},
"0x5A56": {
"group": "plover_hid",
"key": "PLV_N1"
},
"0x5A57": {
"group": "plover_hid",
"key": "PLV_S2"
},
"0x5A58": {
"group": "plover_hid",
"key": "PLV_ST2"
},
"0x5A59": {
"group": "plover_hid",
"key": "PLV_ST3"
},
"0x5A5A": {
"group": "plover_hid",
"key": "PLV_ST4"
},
"0x5A5B": {
"group": "plover_hid",
"key": "PLV_N2"
},
"0x5A5C": {
"group": "plover_hid",
"key": "PLV_N3"
},
"0x5A5D": {
"group": "plover_hid",
"key": "PLV_N4"
},
"0x5A5E": {
"group": "plover_hid",
"key": "PLV_N5"
},
"0x5A5F": {
"group": "plover_hid",
"key": "PLV_N6"
},
"0x5A60": {
"group": "plover_hid",
"key": "PLV_N7"
},
"0x5A61": {
"group": "plover_hid",
"key": "PLV_N8"
},
"0x5A62": {
"group": "plover_hid",
"key": "PLV_N9"
},
"0x5A63": {
"group": "plover_hid",
"key": "PLV_NA"
},
"0x5A64": {
"group": "plover_hid",
"key": "PLV_NB"
},
"0x5A65": {
"group": "plover_hid",
"key": "PLV_NC"
},
"0x5A66": {
"group": "plover_hid",
"key": "PLV_X1"
},
"0x5A67": {
"group": "plover_hid",
"key": "PLV_X2"
},
"0x5A68": {
"group": "plover_hid",
"key": "PLV_X3"
},
"0x5A69": {
"group": "plover_hid",
"key": "PLV_X4"
},
"0x5A6A": {
"group": "plover_hid",
"key": "PLV_X5"
},
"0x5A6B": {
"group": "plover_hid",
"key": "PLV_X6"
},
"0x5A6C": {
"group": "plover_hid",
"key": "PLV_X7"
},
"0x5A6D": {
"group": "plover_hid",
"key": "PLV_X8"
},
"0x5A6E": {
"group": "plover_hid",
"key": "PLV_X9"
},
"0x5A6F": {
"group": "plover_hid",
"key": "PLV_X10"
},
"0x5A70": {
"group": "plover_hid",
"key": "PLV_X11"
},
"0x5A71": {
"group": "plover_hid",
"key": "PLV_X12"
},
"0x5A72": {
"group": "plover_hid",
"key": "PLV_X13"
},
"0x5A73": {
"group": "plover_hid",
"key": "PLV_X14"
},
"0x5A74": {
"group": "plover_hid",
"key": "PLV_X15"
},
"0x5A75": {
"group": "plover_hid",
"key": "PLV_X16"
},
"0x5A76": {
"group": "plover_hid",
"key": "PLV_X17"
},
"0x5A77": {
"group": "plover_hid",
"key": "PLV_X18"
},
"0x5A78": {
"group": "plover_hid",
"key": "PLV_X19"
},
"0x5A79": {
"group": "plover_hid",
"key": "PLV_X20"
},
"0x5A7A": {
"group": "plover_hid",
"key": "PLV_X21"
},
"0x5A7B": {
"group": "plover_hid",
"key": "PLV_X22"
},
"0x5A7C": {
"group": "plover_hid",
"key": "PLV_X23"
},
"0x5A7D": {
"group": "plover_hid",
"key": "PLV_X24"
},
"0x5A7E": {
"group": "plover_hid",
"key": "PLV_X25"
},
"0x5A7F": {
"group": "plover_hid",
"key": "PLV_X26"
}
}
}
+3
View File
@@ -0,0 +1,3 @@
{
// This version exists to signify addition of eeconfig support.
}
+33 -17
View File
@@ -135,28 +135,45 @@ This file defines LED matrix effects in the same form as used with `led_matrix_k
This file defines RGB matrix effects in the same form as used with `rgb_matrix_kb.inc` and `rgb_matrix_user.inc` (see [Custom RGB Matrix Effects](rgb_matrix#custom-rgb-matrix-effects)). Effect mode names are prepended with `RGB_MATRIX_COMMUNITY_MODULE_`.
### Custom split keyboard data sync
### Additional Customization
Defines follow the convention, `SPLIT_TRANSACTION_IDS_MODULE_<MODULE>` (see [Custom data sync](split_keyboard#custom-data-sync)).
#### Split Keyboard Data Sync
Defines follow the convention, `SPLIT_TRANSACTION_IDS_MODULE_<MODULE>` (see [Custom data sync](split_keyboard#custom-data-sync)).
#### Persistent Configuration
Defines follow the convention, `EECONFIG_MODULE_<MODULE>_DATA_SIZE` and `EECONFIG_MODULE_<MODULE>_DATA_VERSION` (see [Custom Persistent Configuration](../feature_eeprom#datablock)).
When configured, the following APIs are available:
| API Format | Example (`hello_world` module) | API Version |
|--------------------------------------------|-----------------------------------------------|-------------|
| `eeconfig_is_<module>_datablock_valid` | `eeconfig_is_hello_world_datablock_valid` | `1.1.3` |
| `eeconfig_read_<module>_datablock` | `eeconfig_read_hello_world_datablock` | `1.1.3` |
| `eeconfig_update_<module>_datablock` | `eeconfig_update_hello_world_datablock` | `1.1.3` |
| `eeconfig_init_<module>_datablock` | `eeconfig_init_hello_world_datablock` | `1.1.3` |
| `eeconfig_read_<module>_datablock_field` | `eeconfig_read_hello_world_datablock_field` | `1.1.3` |
| `eeconfig_update_<module>_datablock_field` | `eeconfig_update_hello_world_datablock_field` | `1.1.3` |
### Compatible APIs
Community Modules may provide specializations for the following APIs:
| Base API | API Format | Example (`hello_world` module) | API Version |
|----------------------------------|-------------------------------------------|---------------------------------------------|-------------|
| `keyboard_pre_init` | `keyboard_pre_init_<module>` | `keyboard_pre_init_hello_world` | `0.1.0` |
| `keyboard_post_init` | `keyboard_post_init_<module>` | `keyboard_post_init_hello_world` | `0.1.0` |
| `pre_process_record` | `pre_process_record_<module>` | `pre_process_record_hello_world` | `0.1.0` |
| `process_record` | `process_record_<module>` | `process_record_hello_world` | `0.1.0` |
| `post_process_record` | `post_process_record_<module>` | `post_process_record_hello_world` | `0.1.0` |
| `housekeeping_task` | `housekeeping_task_<module>` | `housekeeping_task_hello_world` | `1.0.0` |
| `suspend_power_down` | `suspend_power_down_<module>` | `suspend_power_down_hello_world` | `1.0.0` |
| `suspend_wakeup_init` | `suspend_wakeup_init_<module>` | `suspend_wakeup_init_hello_world` | `1.0.0` |
| `shutdown` | `shutdown_<module>` | `shutdown_hello_world` | `1.0.0` |
| `process_detected_host_os` | `process_detected_host_os_<module>` | `process_detected_host_os_hello_world` | `1.0.0` |
| `default_layer_state_set` | `default_layer_state_set_<module>` | `default_layer_state_set_hello_world` | `1.1.0` |
| `layer_state_set` | `layer_state_set_<module>` | `layer_state_set_hello_world` | `1.1.0` |
| Base API | API Format | Example (`hello_world` module) | API Version |
|----------------------------------|-------------------------------------------|----------------------------------------------|-------------|
| `keyboard_pre_init` | `keyboard_pre_init_<module>` | `keyboard_pre_init_hello_world` | `0.1.0` |
| `keyboard_post_init` | `keyboard_post_init_<module>` | `keyboard_post_init_hello_world` | `0.1.0` |
| `pre_process_record` | `pre_process_record_<module>` | `pre_process_record_hello_world` | `0.1.0` |
| `process_record` | `process_record_<module>` | `process_record_hello_world` | `0.1.0` |
| `post_process_record` | `post_process_record_<module>` | `post_process_record_hello_world` | `0.1.0` |
| `housekeeping_task` | `housekeeping_task_<module>` | `housekeeping_task_hello_world` | `1.0.0` |
| `suspend_power_down` | `suspend_power_down_<module>` | `suspend_power_down_hello_world` | `1.0.0` |
| `suspend_wakeup_init` | `suspend_wakeup_init_<module>` | `suspend_wakeup_init_hello_world` | `1.0.0` |
| `shutdown` | `shutdown_<module>` | `shutdown_hello_world` | `1.0.0` |
| `process_detected_host_os` | `process_detected_host_os_<module>` | `process_detected_host_os_hello_world` | `1.0.0` |
| `default_layer_state_set` | `default_layer_state_set_<module>` | `default_layer_state_set_hello_world` | `1.1.0` |
| `layer_state_set` | `layer_state_set_<module>` | `layer_state_set_hello_world` | `1.1.0` |
| `led_matrix_indicators` | `led_matrix_indicators_<module>` | `led_matrix_indicators_hello_world` | `1.1.0` |
| `led_matrix_indicators_advanced` | `led_matrix_indicators_advanced_<module>` | `led_matrix_indicators_advanced_hello_world` | `1.1.0` |
| `rgb_matrix_indicators` | `rgb_matrix_indicators_<module>` | `rgb_matrix_indicators_hello_world` | `1.1.0` |
@@ -164,7 +181,6 @@ Community Modules may provide specializations for the following APIs:
| `pointing_device_init` | `pointing_device_init_<module>` | `pointing_device_init_hello_world` | `1.1.0` |
| `pointing_device_task` | `pointing_device_task_<module>` | `pointing_device_task_hello_world` | `1.1.0` |
::: info
An unspecified API is disregarded if a Community Module does not provide a specialization for it.
:::
+1 -1
View File
@@ -166,7 +166,7 @@ In your keyboard config.h:
The `PIO` subsystem is a Raspberry Pi RP2040 specific implementation, using the integrated PIO peripheral and is therefore only available on this MCU.
There are strict requirements for pin ordering but any pair of GPIO pins can be used. The GPIO used for clock must be directly after data, see the included info.json snippet for an example of correct order.
The GPIOs used for clock and data must be consecutive (in either order).
You may optionally switch the PIO peripheral used with the following define in config.h:
```c
+18 -1
View File
@@ -6,11 +6,12 @@ The [Open Steno Project](https://www.openstenoproject.org/) has built an open-so
## Steno Support in QMK
There are three ways that QMK keyboards can support steno, with varying degrees of configuration required:
There are four ways that QMK keyboards can support steno, with varying degrees of configuration required:
1. Plover with [Arpeggiation](https://plover.wiki/index.php/Glossary#Arpeggiate) requires no changes to any keyboard and is supported by QMK as well as any other QWERTY keyboard.
2. Plover with [NKRO](https://plover.wiki/index.php/Using_a_standard_keyboard_with_Plover#NKRO). If your keyboard supports NKRO in hardware and you have NKRO enabled as a USB endpoint, you can chord with the keyboard. Many devices will arrive stock like this and will require no changes.
3. Steno Machine Protocols. This requires the most configuration, but this has the advantage of allowing you to use your keyboard keys normally (either on another layer or another piece of hardware) without enabling and disabling your steno software.
4. Plover HID Protocol. This is a custom HID protocol that Plover can understand, but does not require a COM port. It is robust to device disconnects and saves an interface over the COM-based alternatives.
## Plover with QWERTY Keyboard {#plover-with-qwerty-keyboard}
@@ -92,6 +93,22 @@ Examples of steno strokes and the associated packet:
- `WAZ` = `10000000 00000010 00100000 00000000 00000000 00000001`
- `PHAPBGS` = `10000000 00000101 00100000 00000000 01101010 00000000`
## Plover HID Protocol {#plover-hid-protocol}
This mode operates independently of the other Steno "official" machine protocols. Like any other mouse or keyboard, it uses the USB HID protocol to communicate with Plover by sending an 8 byte (64 bit) packet representing a bitfield for all the possible keys on a steno machine plus a number of additional general purpose keys for custom use. This protocol is only understood by Plover as of [5.1.0](https://github.com/opensteno/plover/releases/tag/v5.1.0).
Add
```make
PLOVER_HID_ENABLE = yes
```
to your `rules.mk` file. This does **not** require `STENO_ENABLE` to be set.
All of the possible keycodes are defined with the `PLV_` prefix and are available without any additional includes.
More details can be found here: https://github.com/dnaq/plover-machine-hid
### Switching protocols on the fly {#switching-protocols-on-the-fly}
If you wish to switch the serial protocol used to transfer the steno chords without having to recompile your keyboard firmware every time, you can press the `QK_STENO_BOLT` and `QK_STENO_GEMINI` keycodes in order to switch protocols on the fly.
+1 -1
View File
@@ -354,7 +354,7 @@ bool azoteq_iqs5xx_init(void) {
};
report_mouse_t azoteq_iqs5xx_get_report(report_mouse_t mouse_report) {
report_mouse_t temp_report = {0};
report_mouse_t temp_report = {.buttons = mouse_report.buttons};
azoteq_iqs5xx_base_data_t base_data = {0};
i2c_status_t status = azoteq_iqs5xx_get_base_data(&base_data);
+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}
]
}
}
}
@@ -0,0 +1,13 @@
// Copyright 2026 QMK
// SPDX-License-Identifier: GPL-2.0-or-later
#include QMK_KEYBOARD_H
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {LAYOUT_ortho_1x1(KC_A)};
void keyboard_post_init_user(void) {
// Customise these values to desired behaviour
debug_enable = true;
debug_matrix = true;
// debug_keyboard=true;
// debug_mouse=true;
}
@@ -0,0 +1,10 @@
{
"config": {
"features": {
"console": true
}
},
"modules": [
"qmk/nvm_test"
]
}
+105 -4
View File
@@ -26,8 +26,11 @@
"resync": true
}
},
"layout_aliases": {
"LAYOUT": "LAYOUT_all"
},
"layouts": {
"LAYOUT": {
"LAYOUT_all": {
"layout": [
{"matrix": [0, 0], "w": 1.5, "x": 0, "y": 0},
{"matrix": [0, 1], "x": 1.5, "y": 0},
@@ -69,9 +72,107 @@
{"matrix": [3, 0], "w": 1.25, "x": 0, "y": 3},
{"matrix": [3, 1], "w": 1.25, "x": 1.25, "y": 3},
{"matrix": [3, 2], "w": 1.25, "x": 2.5, "y": 3},
{"matrix": [3, 3], "w": 3, "x": 3.75, "y": 3, "h": 0.5},
{"matrix": [3, 5], "w": 6, "x": 3.75, "y": 3.5, "h": 0.5},
{"matrix": [3, 6], "w": 3, "x": 6.75, "y": 3, "h": 0.5},
{"matrix": [3, 3], "w": 2.5, "x": 3.75, "y": 3},
{"matrix": [3, 5], "w": 1, "x": 6.25, "y": 3},
{"matrix": [3, 6], "w": 2.5, "x": 7.25, "y": 3},
{"matrix": [3, 8], "w": 1.25, "x": 9.75, "y": 3},
{"matrix": [3, 9], "w": 1.25, "x": 11, "y": 3},
{"matrix": [3, 10], "w": 1.25, "x": 12.25, "y": 3}
]
},
"LAYOUT_split_space": {
"layout": [
{"matrix": [0, 0], "w": 1.5, "x": 0, "y": 0},
{"matrix": [0, 1], "x": 1.5, "y": 0},
{"matrix": [0, 2], "x": 2.5, "y": 0},
{"matrix": [0, 3], "x": 3.5, "y": 0},
{"matrix": [0, 4], "x": 4.5, "y": 0},
{"matrix": [0, 5], "x": 5.5, "y": 0},
{"matrix": [0, 6], "x": 6.5, "y": 0},
{"matrix": [0, 7], "x": 7.5, "y": 0},
{"matrix": [0, 8], "x": 8.5, "y": 0},
{"matrix": [0, 9], "x": 9.5, "y": 0},
{"matrix": [0, 10], "x": 10.5, "y": 0},
{"matrix": [0, 11], "x": 11.5, "y": 0},
{"matrix": [3, 11], "x": 12.5, "y": 0},
{"matrix": [1, 0], "w": 1.75, "x": 0, "y": 1},
{"matrix": [1, 1], "x": 1.75, "y": 1},
{"matrix": [1, 2], "x": 2.75, "y": 1},
{"matrix": [1, 3], "x": 3.75, "y": 1},
{"matrix": [1, 4], "x": 4.75, "y": 1},
{"matrix": [1, 5], "x": 5.75, "y": 1},
{"matrix": [1, 6], "x": 6.75, "y": 1},
{"matrix": [1, 7], "x": 7.75, "y": 1},
{"matrix": [1, 8], "x": 8.75, "y": 1},
{"matrix": [1, 9], "x": 9.75, "y": 1},
{"matrix": [1, 10], "x": 10.75, "y": 1},
{"matrix": [1, 11], "w": 1.75, "x": 11.75, "y": 1},
{"matrix": [2, 0], "w": 2.25, "x": 0, "y": 2},
{"matrix": [2, 1], "x": 2.25, "y": 2},
{"matrix": [2, 2], "x": 3.25, "y": 2},
{"matrix": [2, 3], "x": 4.25, "y": 2},
{"matrix": [2, 4], "x": 5.25, "y": 2},
{"matrix": [2, 5], "x": 6.25, "y": 2},
{"matrix": [2, 6], "x": 7.25, "y": 2},
{"matrix": [2, 7], "x": 8.25, "y": 2},
{"matrix": [2, 8], "x": 9.25, "y": 2},
{"matrix": [2, 9], "x": 10.25, "y": 2},
{"matrix": [2, 10], "x": 11.25, "y": 2},
{"matrix": [2, 11], "w": 1.25, "x": 12.25, "y": 2},
{"matrix": [3, 0], "w": 1.25, "x": 0, "y": 3},
{"matrix": [3, 1], "w": 1.25, "x": 1.25, "y": 3},
{"matrix": [3, 2], "w": 1.25, "x": 2.5, "y": 3},
{"matrix": [3, 3], "w": 3, "x": 3.75, "y": 3},
{"matrix": [3, 6], "w": 3, "x": 6.75, "y": 3},
{"matrix": [3, 8], "w": 1.25, "x": 9.75, "y": 3},
{"matrix": [3, 9], "w": 1.25, "x": 11, "y": 3},
{"matrix": [3, 10], "w": 1.25, "x": 12.25, "y": 3}
]
},
"LAYOUT_full_space": {
"layout": [
{"matrix": [0, 0], "w": 1.5, "x": 0, "y": 0},
{"matrix": [0, 1], "x": 1.5, "y": 0},
{"matrix": [0, 2], "x": 2.5, "y": 0},
{"matrix": [0, 3], "x": 3.5, "y": 0},
{"matrix": [0, 4], "x": 4.5, "y": 0},
{"matrix": [0, 5], "x": 5.5, "y": 0},
{"matrix": [0, 6], "x": 6.5, "y": 0},
{"matrix": [0, 7], "x": 7.5, "y": 0},
{"matrix": [0, 8], "x": 8.5, "y": 0},
{"matrix": [0, 9], "x": 9.5, "y": 0},
{"matrix": [0, 10], "x": 10.5, "y": 0},
{"matrix": [0, 11], "x": 11.5, "y": 0},
{"matrix": [3, 11], "x": 12.5, "y": 0},
{"matrix": [1, 0], "w": 1.75, "x": 0, "y": 1},
{"matrix": [1, 1], "x": 1.75, "y": 1},
{"matrix": [1, 2], "x": 2.75, "y": 1},
{"matrix": [1, 3], "x": 3.75, "y": 1},
{"matrix": [1, 4], "x": 4.75, "y": 1},
{"matrix": [1, 5], "x": 5.75, "y": 1},
{"matrix": [1, 6], "x": 6.75, "y": 1},
{"matrix": [1, 7], "x": 7.75, "y": 1},
{"matrix": [1, 8], "x": 8.75, "y": 1},
{"matrix": [1, 9], "x": 9.75, "y": 1},
{"matrix": [1, 10], "x": 10.75, "y": 1},
{"matrix": [1, 11], "w": 1.75, "x": 11.75, "y": 1},
{"matrix": [2, 0], "w": 2.25, "x": 0, "y": 2},
{"matrix": [2, 1], "x": 2.25, "y": 2},
{"matrix": [2, 2], "x": 3.25, "y": 2},
{"matrix": [2, 3], "x": 4.25, "y": 2},
{"matrix": [2, 4], "x": 5.25, "y": 2},
{"matrix": [2, 5], "x": 6.25, "y": 2},
{"matrix": [2, 6], "x": 7.25, "y": 2},
{"matrix": [2, 7], "x": 8.25, "y": 2},
{"matrix": [2, 8], "x": 9.25, "y": 2},
{"matrix": [2, 9], "x": 10.25, "y": 2},
{"matrix": [2, 10], "x": 11.25, "y": 2},
{"matrix": [2, 11], "w": 1.25, "x": 12.25, "y": 2},
{"matrix": [3, 0], "w": 1.25, "x": 0, "y": 3},
{"matrix": [3, 1], "w": 1.25, "x": 1.25, "y": 3},
{"matrix": [3, 2], "w": 1.25, "x": 2.5, "y": 3},
{"matrix": [3, 5], "w": 6, "x": 3.75, "y": 3},
{"matrix": [3, 8], "w": 1.25, "x": 9.75, "y": 3},
{"matrix": [3, 9], "w": 1.25, "x": 11, "y": 3},
{"matrix": [3, 10], "w": 1.25, "x": 12.25, "y": 3}
@@ -4,19 +4,19 @@
#include QMK_KEYBOARD_H
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[0] = LAYOUT(
[0] = LAYOUT_all(
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_DEL, KC_BSPC,
LT(2, KC_ESC), 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, LT(1, KC_SPC), KC_SPC, KC_SPC, KC_RALT, KC_RGUI, KC_RCTL
),
[1] = LAYOUT(
[1] = LAYOUT_all(
KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_TRNS, QK_BOOT,
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_MINS, KC_EQL, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_BSLS,
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_LBRC, KC_RBRC, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_PGUP, KC_TRNS,
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, LT(2, KC_SPC), KC_HOME, KC_PGDN, KC_END
),
[2] = LAYOUT(
[2] = LAYOUT_all(
KC_TRNS, KC_TRNS, KC_UP, KC_TRNS, KC_PGUP, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_TRNS, KC_TRNS,
KC_TRNS, KC_LEFT, KC_DOWN, KC_RGHT, KC_PGDN, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_TRNS,
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
-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
}
@@ -0,0 +1,107 @@
{
"manufacturer": "Owlab",
"keyboard_name": "LINK Hotswap",
"maintainer": "Owlab",
"bootloader": "custom",
"diode_direction": "COL2ROW",
"features": {
"bootmagic": true,
"extrakey": true,
"mousekey": true,
"nkro": true
},
"host": {
"default": {
"nkro": true
}
},
"indicators": {
"caps_lock": "A0",
"on_state": 0
},
"matrix_pins": {
"cols": ["A7", "B0", "B1", "B2", "B10", "B11", "B12", "B13", "B14", "B15", "A8", "A9", "A10", "A6", "A15"],
"rows": ["A1", "A2", "A3", "A4", "A5"]
},
"processor": "STM32F103",
"url": "https://owlab.store",
"usb": {
"device_version": "0.0.1",
"pid": "0x4C49",
"vid": "0x4F53"
},
"community_layouts": ["65_ansi_blocker"],
"layouts": {
"LAYOUT_65_ansi_blocker": {
"layout": [
{"matrix": [0, 0], "x": 0, "y": 0},
{"matrix": [0, 1], "x": 1, "y": 0},
{"matrix": [0, 2], "x": 2, "y": 0},
{"matrix": [0, 3], "x": 3, "y": 0},
{"matrix": [0, 4], "x": 4, "y": 0},
{"matrix": [0, 5], "x": 5, "y": 0},
{"matrix": [0, 6], "x": 6, "y": 0},
{"matrix": [0, 7], "x": 7, "y": 0},
{"matrix": [0, 8], "x": 8, "y": 0},
{"matrix": [0, 9], "x": 9, "y": 0},
{"matrix": [0, 10], "x": 10, "y": 0},
{"matrix": [0, 11], "x": 11, "y": 0},
{"matrix": [0, 12], "x": 12, "y": 0},
{"matrix": [0, 13], "x": 13, "y": 0, "w": 2},
{"matrix": [0, 14], "x": 15, "y": 0},
{"matrix": [1, 0], "x": 0, "y": 1, "w": 1.5},
{"matrix": [1, 1], "x": 1.5, "y": 1},
{"matrix": [1, 2], "x": 2.5, "y": 1},
{"matrix": [1, 3], "x": 3.5, "y": 1},
{"matrix": [1, 4], "x": 4.5, "y": 1},
{"matrix": [1, 5], "x": 5.5, "y": 1},
{"matrix": [1, 6], "x": 6.5, "y": 1},
{"matrix": [1, 7], "x": 7.5, "y": 1},
{"matrix": [1, 8], "x": 8.5, "y": 1},
{"matrix": [1, 9], "x": 9.5, "y": 1},
{"matrix": [1, 10], "x": 10.5, "y": 1},
{"matrix": [1, 11], "x": 11.5, "y": 1},
{"matrix": [1, 12], "x": 12.5, "y": 1},
{"matrix": [1, 13], "x": 13.5, "y": 1, "w": 1.5},
{"matrix": [1, 14], "x": 15, "y": 1},
{"matrix": [2, 0], "x": 0, "y": 2, "w": 1.75},
{"matrix": [2, 1], "x": 1.75, "y": 2},
{"matrix": [2, 2], "x": 2.75, "y": 2},
{"matrix": [2, 3], "x": 3.75, "y": 2},
{"matrix": [2, 4], "x": 4.75, "y": 2},
{"matrix": [2, 5], "x": 5.75, "y": 2},
{"matrix": [2, 6], "x": 6.75, "y": 2},
{"matrix": [2, 7], "x": 7.75, "y": 2},
{"matrix": [2, 8], "x": 8.75, "y": 2},
{"matrix": [2, 9], "x": 9.75, "y": 2},
{"matrix": [2, 10], "x": 10.75, "y": 2},
{"matrix": [2, 11], "x": 11.75, "y": 2},
{"matrix": [2, 13], "x": 12.75, "y": 2, "w": 2.25},
{"matrix": [2, 14], "x": 15, "y": 2},
{"matrix": [3, 0], "x": 0, "y": 3, "w": 2.25},
{"matrix": [3, 1], "x": 2.25, "y": 3},
{"matrix": [3, 2], "x": 3.25, "y": 3},
{"matrix": [3, 3], "x": 4.25, "y": 3},
{"matrix": [3, 4], "x": 5.25, "y": 3},
{"matrix": [3, 5], "x": 6.25, "y": 3},
{"matrix": [3, 6], "x": 7.25, "y": 3},
{"matrix": [3, 7], "x": 8.25, "y": 3},
{"matrix": [3, 8], "x": 9.25, "y": 3},
{"matrix": [3, 9], "x": 10.25, "y": 3},
{"matrix": [3, 10], "x": 11.25, "y": 3},
{"matrix": [3, 11], "x": 12.25, "y": 3, "w": 1.75},
{"matrix": [3, 13], "x": 14, "y": 3},
{"matrix": [3, 14], "x": 15, "y": 3},
{"matrix": [4, 0], "x": 0, "y": 4, "w": 1.25},
{"matrix": [4, 1], "x": 1.25, "y": 4, "w": 1.25},
{"matrix": [4, 2], "x": 2.5, "y": 4, "w": 1.25},
{"matrix": [4, 4], "x": 3.75, "y": 4, "w": 6.25},
{"matrix": [4, 7], "x": 10, "y": 4, "w": 1.25},
{"matrix": [4, 8], "x": 11.25, "y": 4, "w": 1.25},
{"matrix": [4, 12], "x": 13, "y": 4},
{"matrix": [4, 13], "x": 14, "y": 4},
{"matrix": [4, 14], "x": 15, "y": 4}
]
}
}
}
@@ -0,0 +1,37 @@
/*
Copyright 2022 Owlab
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
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[0] = LAYOUT_65_ansi_blocker(
KC_ESC, 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,
KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, KC_UP, MO(1),
KC_LCTL, KC_LGUI, KC_LALT, KC_SPC, KC_RALT, KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT
),
[1] = LAYOUT_65_ansi_blocker(
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_TRNS, KC_TRNS,
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_HOME,
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_END,
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS
),
};
@@ -0,0 +1,89 @@
/*
ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
* STM32F103x8 memory setup for use with the STM32Duino bootloader.
*/
f103_flash_size = 128k;
MEMORY
{
/*Here we give 22K flash to bootloader*/
/*0x08005800 : the application bin start address*/
flash0 : org = 0x08006000, len = f103_flash_size - 0x6000
flash1 : org = 0x00000000, len = 0
flash2 : org = 0x00000000, len = 0
flash3 : org = 0x00000000, len = 0
flash4 : org = 0x00000000, len = 0
flash5 : org = 0x00000000, len = 0
flash6 : org = 0x00000000, len = 0
flash7 : org = 0x00000000, len = 0
ram0 : org = 0x20000000, len = 20k
ram1 : org = 0x00000000, len = 0
ram2 : org = 0x00000000, len = 0
ram3 : org = 0x00000000, len = 0
ram4 : org = 0x00000000, len = 0
ram5 : org = 0x00000000, len = 0
ram6 : org = 0x00000000, len = 0
ram7 : org = 0x00000000, len = 0
}
/* For each data/text section two region are defined, a virtual region
and a load region (_LMA suffix).*/
/* Flash region to be used for exception vectors.*/
REGION_ALIAS("VECTORS_FLASH", flash0);
REGION_ALIAS("VECTORS_FLASH_LMA", flash0);
/* Flash region to be used for constructors and destructors.*/
REGION_ALIAS("XTORS_FLASH", flash0);
REGION_ALIAS("XTORS_FLASH_LMA", flash0);
/* Flash region to be used for code text.*/
REGION_ALIAS("TEXT_FLASH", flash0);
REGION_ALIAS("TEXT_FLASH_LMA", flash0);
/* Flash region to be used for read only data.*/
REGION_ALIAS("RODATA_FLASH", flash0);
REGION_ALIAS("RODATA_FLASH_LMA", flash0);
/* Flash region to be used for various.*/
REGION_ALIAS("VARIOUS_FLASH", flash0);
REGION_ALIAS("VARIOUS_FLASH_LMA", flash0);
/* Flash region to be used for RAM(n) initialization data.*/
REGION_ALIAS("RAM_INIT_FLASH_LMA", flash0);
/* RAM region to be used for Main stack. This stack accommodates the processing
of all exceptions and interrupts.*/
REGION_ALIAS("MAIN_STACK_RAM", ram0);
/* RAM region to be used for the process stack. This is the stack used by
the main() function.*/
REGION_ALIAS("PROCESS_STACK_RAM", ram0);
/* RAM region to be used for data segment.*/
REGION_ALIAS("DATA_RAM", ram0);
REGION_ALIAS("DATA_RAM_LMA", flash0);
/* RAM region to be used for BSS segment.*/
REGION_ALIAS("BSS_RAM", ram0);
/* RAM region to be used for the default heap.*/
REGION_ALIAS("HEAP_RAM", ram0);
/* Generic rules inclusion.*/
INCLUDE rules.ld
+23
View File
@@ -0,0 +1,23 @@
# LINK65 - Hotswap PCB
![LINK65](https://i.imgur.com/tbeeWsph.jpeg)
A 65% keyboard made by Owlab.
* Keyboard Maintainer: [Owlab](https://github.com/owlab-git)
* Hardware Supported: LINK65 Hotswap PCB
* Hardware Availability: https://owlab.store
Make example for this keyboard (after setting up your build environment):
make owlab/link65/hotswap:default
Flashing example for this keyboard:
make owlab/link65/hotswap:default:flash
**Bootloader:** This PCB uses the stm32duino bootloader with firmware starting at address `0x08006000`. To enter bootloader mode, hold the `B` key while plugging in USB.
> ⚠️ **QMK Toolbox is not supported.** It flashes to the wrong address (`0x08000000`) and will overwrite the bootloader, bricking the board. Use `qmk flash` or `dfu-util` directly with `-s 0x08006000:leave`.
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).
+7
View File
@@ -0,0 +1,7 @@
MCU_LDSCRIPT = STM32F103x8_0x08006000_bootloader
BOARD = STM32_F103_STM32DUINO
DFU_ARGS = -d 1688:2220 -a 0 -s 0x08006000
# PID
DFU_SUFFIX_ARGS = -v 1688 -p 2220
OPT_DEFS += -DBOOTLOADER_STM32DUINO
+24
View File
@@ -0,0 +1,24 @@
/* Copyright 2024 Yiancar-Designs
*
* 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
/* RGB options */
#define WS2812_SPI_DRIVER SPID2
#define WS2812_SPI_MOSI_PAL_MODE 0
#define WS2812_SPI_SCK_PAL_MODE 0
#define WS2812_SPI_SCK_PIN B13
@@ -0,0 +1,21 @@
/* Copyright 2024 Yiancar-Designs
*
* 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
#define HAL_USE_SPI TRUE
#include_next <halconf.h>
@@ -0,0 +1,333 @@
{
"manufacturer": "Yiancar-Designs",
"keyboard_name": "Float 65",
"maintainer": "Yiancar",
"bootloader": "stm32-dfu",
"diode_direction": "COL2ROW",
"features": {
"bootmagic": true,
"extrakey": true,
"mousekey": true,
"nkro": true,
"rgblight": true
},
"matrix_pins": {
"cols": ["A13", "A10", "A9", "A14", "A15", "B8", "B9", "B2", "B1", "B0", "A0", "A1", "A2", "A3", "A5"],
"rows": ["B3", "B4", "B5", "A8", "A4"]
},
"processor": "STM32F072",
"rgblight": {
"animations": {
"alternating": true,
"breathing": true,
"christmas": true,
"knight": true,
"rainbow_mood": true,
"rainbow_swirl": true,
"snake": true,
"static_gradient": true,
"twinkle": true
},
"led_count": 8
},
"url": "https://yiancar-designs.com",
"usb": {
"device_version": "0.0.1",
"pid": "0x5334",
"vid": "0x8968"
},
"ws2812": {
"driver": "spi",
"pin": "B15"
},
"community_layouts": ["65_ansi_blocker", "65_ansi_blocker_split_bs", "65_ansi_blocker_tsangan", "65_ansi_blocker_tsangan_split_bs"],
"layout_aliases": {
"LAYOUT": "LAYOUT_65_ansi_blocker_split_bs"
},
"layouts": {
"LAYOUT_65_ansi_blocker": {
"layout": [
{"matrix": [0, 0], "x": 0, "y": 0},
{"matrix": [0, 1], "x": 1, "y": 0},
{"matrix": [0, 2], "x": 2, "y": 0},
{"matrix": [0, 3], "x": 3, "y": 0},
{"matrix": [0, 4], "x": 4, "y": 0},
{"matrix": [0, 5], "x": 5, "y": 0},
{"matrix": [0, 6], "x": 6, "y": 0},
{"matrix": [0, 7], "x": 7, "y": 0},
{"matrix": [0, 8], "x": 8, "y": 0},
{"matrix": [0, 9], "x": 9, "y": 0},
{"matrix": [0, 10], "x": 10, "y": 0},
{"matrix": [0, 11], "x": 11, "y": 0},
{"matrix": [0, 12], "x": 12, "y": 0},
{"matrix": [0, 13], "x": 13, "y": 0, "w": 2},
{"matrix": [0, 14], "x": 15, "y": 0},
{"matrix": [1, 0], "x": 0, "y": 1, "w": 1.5},
{"matrix": [1, 1], "x": 1.5, "y": 1},
{"matrix": [1, 2], "x": 2.5, "y": 1},
{"matrix": [1, 3], "x": 3.5, "y": 1},
{"matrix": [1, 4], "x": 4.5, "y": 1},
{"matrix": [1, 5], "x": 5.5, "y": 1},
{"matrix": [1, 6], "x": 6.5, "y": 1},
{"matrix": [1, 7], "x": 7.5, "y": 1},
{"matrix": [1, 8], "x": 8.5, "y": 1},
{"matrix": [1, 9], "x": 9.5, "y": 1},
{"matrix": [1, 10], "x": 10.5, "y": 1},
{"matrix": [1, 11], "x": 11.5, "y": 1},
{"matrix": [1, 12], "x": 12.5, "y": 1},
{"matrix": [2, 12], "x": 13.5, "y": 1, "w": 1.5},
{"matrix": [1, 14], "x": 15, "y": 1},
{"matrix": [2, 0], "x": 0, "y": 2, "w": 1.75},
{"matrix": [2, 1], "x": 1.75, "y": 2},
{"matrix": [2, 2], "x": 2.75, "y": 2},
{"matrix": [2, 3], "x": 3.75, "y": 2},
{"matrix": [2, 4], "x": 4.75, "y": 2},
{"matrix": [2, 5], "x": 5.75, "y": 2},
{"matrix": [2, 6], "x": 6.75, "y": 2},
{"matrix": [2, 7], "x": 7.75, "y": 2},
{"matrix": [2, 8], "x": 8.75, "y": 2},
{"matrix": [2, 9], "x": 9.75, "y": 2},
{"matrix": [2, 10], "x": 10.75, "y": 2},
{"matrix": [2, 11], "x": 11.75, "y": 2},
{"matrix": [2, 13], "x": 12.75, "y": 2, "w": 2.25},
{"matrix": [2, 14], "x": 15, "y": 2},
{"matrix": [3, 0], "x": 0, "y": 3, "w": 2.25},
{"matrix": [3, 2], "x": 2.25, "y": 3},
{"matrix": [3, 3], "x": 3.25, "y": 3},
{"matrix": [3, 4], "x": 4.25, "y": 3},
{"matrix": [3, 5], "x": 5.25, "y": 3},
{"matrix": [3, 6], "x": 6.25, "y": 3},
{"matrix": [3, 7], "x": 7.25, "y": 3},
{"matrix": [3, 8], "x": 8.25, "y": 3},
{"matrix": [3, 9], "x": 9.25, "y": 3},
{"matrix": [3, 10], "x": 10.25, "y": 3},
{"matrix": [3, 11], "x": 11.25, "y": 3},
{"matrix": [3, 12], "x": 12.25, "y": 3, "w": 1.75},
{"matrix": [3, 13], "x": 14, "y": 3},
{"matrix": [3, 14], "x": 15, "y": 3},
{"matrix": [4, 0], "x": 0, "y": 4, "w": 1.25},
{"matrix": [4, 1], "x": 1.25, "y": 4, "w": 1.25},
{"matrix": [4, 2], "x": 2.5, "y": 4, "w": 1.25},
{"matrix": [4, 6], "x": 3.75, "y": 4, "w": 6.25},
{"matrix": [4, 9], "x": 10, "y": 4, "w": 1.25},
{"matrix": [4, 11], "x": 11.25, "y": 4, "w": 1.25},
{"matrix": [4, 12], "x": 13, "y": 4},
{"matrix": [4, 13], "x": 14, "y": 4},
{"matrix": [4, 14], "x": 15, "y": 4}
]
},
"LAYOUT_65_ansi_blocker_split_bs": {
"layout": [
{"matrix": [0, 0], "x": 0, "y": 0},
{"matrix": [0, 1], "x": 1, "y": 0},
{"matrix": [0, 2], "x": 2, "y": 0},
{"matrix": [0, 3], "x": 3, "y": 0},
{"matrix": [0, 4], "x": 4, "y": 0},
{"matrix": [0, 5], "x": 5, "y": 0},
{"matrix": [0, 6], "x": 6, "y": 0},
{"matrix": [0, 7], "x": 7, "y": 0},
{"matrix": [0, 8], "x": 8, "y": 0},
{"matrix": [0, 9], "x": 9, "y": 0},
{"matrix": [0, 10], "x": 10, "y": 0},
{"matrix": [0, 11], "x": 11, "y": 0},
{"matrix": [0, 12], "x": 12, "y": 0},
{"matrix": [1, 13], "x": 13, "y": 0},
{"matrix": [0, 13], "x": 14, "y": 0},
{"matrix": [0, 14], "x": 15, "y": 0},
{"matrix": [1, 0], "x": 0, "y": 1, "w": 1.5},
{"matrix": [1, 1], "x": 1.5, "y": 1},
{"matrix": [1, 2], "x": 2.5, "y": 1},
{"matrix": [1, 3], "x": 3.5, "y": 1},
{"matrix": [1, 4], "x": 4.5, "y": 1},
{"matrix": [1, 5], "x": 5.5, "y": 1},
{"matrix": [1, 6], "x": 6.5, "y": 1},
{"matrix": [1, 7], "x": 7.5, "y": 1},
{"matrix": [1, 8], "x": 8.5, "y": 1},
{"matrix": [1, 9], "x": 9.5, "y": 1},
{"matrix": [1, 10], "x": 10.5, "y": 1},
{"matrix": [1, 11], "x": 11.5, "y": 1},
{"matrix": [1, 12], "x": 12.5, "y": 1},
{"matrix": [2, 12], "x": 13.5, "y": 1, "w": 1.5},
{"matrix": [1, 14], "x": 15, "y": 1},
{"matrix": [2, 0], "x": 0, "y": 2, "w": 1.75},
{"matrix": [2, 1], "x": 1.75, "y": 2},
{"matrix": [2, 2], "x": 2.75, "y": 2},
{"matrix": [2, 3], "x": 3.75, "y": 2},
{"matrix": [2, 4], "x": 4.75, "y": 2},
{"matrix": [2, 5], "x": 5.75, "y": 2},
{"matrix": [2, 6], "x": 6.75, "y": 2},
{"matrix": [2, 7], "x": 7.75, "y": 2},
{"matrix": [2, 8], "x": 8.75, "y": 2},
{"matrix": [2, 9], "x": 9.75, "y": 2},
{"matrix": [2, 10], "x": 10.75, "y": 2},
{"matrix": [2, 11], "x": 11.75, "y": 2},
{"matrix": [2, 13], "x": 12.75, "y": 2, "w": 2.25},
{"matrix": [2, 14], "x": 15, "y": 2},
{"matrix": [3, 0], "x": 0, "y": 3, "w": 2.25},
{"matrix": [3, 2], "x": 2.25, "y": 3},
{"matrix": [3, 3], "x": 3.25, "y": 3},
{"matrix": [3, 4], "x": 4.25, "y": 3},
{"matrix": [3, 5], "x": 5.25, "y": 3},
{"matrix": [3, 6], "x": 6.25, "y": 3},
{"matrix": [3, 7], "x": 7.25, "y": 3},
{"matrix": [3, 8], "x": 8.25, "y": 3},
{"matrix": [3, 9], "x": 9.25, "y": 3},
{"matrix": [3, 10], "x": 10.25, "y": 3},
{"matrix": [3, 11], "x": 11.25, "y": 3},
{"matrix": [3, 12], "x": 12.25, "y": 3, "w": 1.75},
{"matrix": [3, 13], "x": 14, "y": 3},
{"matrix": [3, 14], "x": 15, "y": 3},
{"matrix": [4, 0], "x": 0, "y": 4, "w": 1.25},
{"matrix": [4, 1], "x": 1.25, "y": 4, "w": 1.25},
{"matrix": [4, 2], "x": 2.5, "y": 4, "w": 1.25},
{"matrix": [4, 6], "x": 3.75, "y": 4, "w": 6.25},
{"matrix": [4, 9], "x": 10, "y": 4, "w": 1.25},
{"matrix": [4, 11], "x": 11.25, "y": 4, "w": 1.25},
{"matrix": [4, 12], "x": 13, "y": 4},
{"matrix": [4, 13], "x": 14, "y": 4},
{"matrix": [4, 14], "x": 15, "y": 4}
]
},
"LAYOUT_65_ansi_blocker_tsangan": {
"layout": [
{"matrix": [0, 0], "x": 0, "y": 0},
{"matrix": [0, 1], "x": 1, "y": 0},
{"matrix": [0, 2], "x": 2, "y": 0},
{"matrix": [0, 3], "x": 3, "y": 0},
{"matrix": [0, 4], "x": 4, "y": 0},
{"matrix": [0, 5], "x": 5, "y": 0},
{"matrix": [0, 6], "x": 6, "y": 0},
{"matrix": [0, 7], "x": 7, "y": 0},
{"matrix": [0, 8], "x": 8, "y": 0},
{"matrix": [0, 9], "x": 9, "y": 0},
{"matrix": [0, 10], "x": 10, "y": 0},
{"matrix": [0, 11], "x": 11, "y": 0},
{"matrix": [0, 12], "x": 12, "y": 0},
{"matrix": [0, 13], "x": 13, "y": 0, "w": 2},
{"matrix": [0, 14], "x": 15, "y": 0},
{"matrix": [1, 0], "x": 0, "y": 1, "w": 1.5},
{"matrix": [1, 1], "x": 1.5, "y": 1},
{"matrix": [1, 2], "x": 2.5, "y": 1},
{"matrix": [1, 3], "x": 3.5, "y": 1},
{"matrix": [1, 4], "x": 4.5, "y": 1},
{"matrix": [1, 5], "x": 5.5, "y": 1},
{"matrix": [1, 6], "x": 6.5, "y": 1},
{"matrix": [1, 7], "x": 7.5, "y": 1},
{"matrix": [1, 8], "x": 8.5, "y": 1},
{"matrix": [1, 9], "x": 9.5, "y": 1},
{"matrix": [1, 10], "x": 10.5, "y": 1},
{"matrix": [1, 11], "x": 11.5, "y": 1},
{"matrix": [1, 12], "x": 12.5, "y": 1},
{"matrix": [2, 12], "x": 13.5, "y": 1, "w": 1.5},
{"matrix": [1, 14], "x": 15, "y": 1},
{"matrix": [2, 0], "x": 0, "y": 2, "w": 1.75},
{"matrix": [2, 1], "x": 1.75, "y": 2},
{"matrix": [2, 2], "x": 2.75, "y": 2},
{"matrix": [2, 3], "x": 3.75, "y": 2},
{"matrix": [2, 4], "x": 4.75, "y": 2},
{"matrix": [2, 5], "x": 5.75, "y": 2},
{"matrix": [2, 6], "x": 6.75, "y": 2},
{"matrix": [2, 7], "x": 7.75, "y": 2},
{"matrix": [2, 8], "x": 8.75, "y": 2},
{"matrix": [2, 9], "x": 9.75, "y": 2},
{"matrix": [2, 10], "x": 10.75, "y": 2},
{"matrix": [2, 11], "x": 11.75, "y": 2},
{"matrix": [2, 13], "x": 12.75, "y": 2, "w": 2.25},
{"matrix": [2, 14], "x": 15, "y": 2},
{"matrix": [3, 0], "x": 0, "y": 3, "w": 2.25},
{"matrix": [3, 2], "x": 2.25, "y": 3},
{"matrix": [3, 3], "x": 3.25, "y": 3},
{"matrix": [3, 4], "x": 4.25, "y": 3},
{"matrix": [3, 5], "x": 5.25, "y": 3},
{"matrix": [3, 6], "x": 6.25, "y": 3},
{"matrix": [3, 7], "x": 7.25, "y": 3},
{"matrix": [3, 8], "x": 8.25, "y": 3},
{"matrix": [3, 9], "x": 9.25, "y": 3},
{"matrix": [3, 10], "x": 10.25, "y": 3},
{"matrix": [3, 11], "x": 11.25, "y": 3},
{"matrix": [3, 12], "x": 12.25, "y": 3, "w": 1.75},
{"matrix": [3, 13], "x": 14, "y": 3},
{"matrix": [3, 14], "x": 15, "y": 3},
{"matrix": [4, 0], "x": 0, "y": 4, "w": 1.5},
{"matrix": [4, 1], "x": 1.5, "y": 4},
{"matrix": [4, 2], "x": 2.5, "y": 4, "w": 1.5},
{"matrix": [4, 6], "x": 4, "y": 4, "w": 7},
{"matrix": [4, 11], "x": 11, "y": 4, "w": 1.5},
{"matrix": [4, 12], "x": 13, "y": 4},
{"matrix": [4, 13], "x": 14, "y": 4},
{"matrix": [4, 14], "x": 15, "y": 4}
]
},
"LAYOUT_65_ansi_blocker_tsangan_split_bs": {
"layout": [
{"matrix": [0, 0], "x": 0, "y": 0},
{"matrix": [0, 1], "x": 1, "y": 0},
{"matrix": [0, 2], "x": 2, "y": 0},
{"matrix": [0, 3], "x": 3, "y": 0},
{"matrix": [0, 4], "x": 4, "y": 0},
{"matrix": [0, 5], "x": 5, "y": 0},
{"matrix": [0, 6], "x": 6, "y": 0},
{"matrix": [0, 7], "x": 7, "y": 0},
{"matrix": [0, 8], "x": 8, "y": 0},
{"matrix": [0, 9], "x": 9, "y": 0},
{"matrix": [0, 10], "x": 10, "y": 0},
{"matrix": [0, 11], "x": 11, "y": 0},
{"matrix": [0, 12], "x": 12, "y": 0},
{"matrix": [1, 13], "x": 13, "y": 0},
{"matrix": [0, 13], "x": 14, "y": 0},
{"matrix": [0, 14], "x": 15, "y": 0},
{"matrix": [1, 0], "x": 0, "y": 1, "w": 1.5},
{"matrix": [1, 1], "x": 1.5, "y": 1},
{"matrix": [1, 2], "x": 2.5, "y": 1},
{"matrix": [1, 3], "x": 3.5, "y": 1},
{"matrix": [1, 4], "x": 4.5, "y": 1},
{"matrix": [1, 5], "x": 5.5, "y": 1},
{"matrix": [1, 6], "x": 6.5, "y": 1},
{"matrix": [1, 7], "x": 7.5, "y": 1},
{"matrix": [1, 8], "x": 8.5, "y": 1},
{"matrix": [1, 9], "x": 9.5, "y": 1},
{"matrix": [1, 10], "x": 10.5, "y": 1},
{"matrix": [1, 11], "x": 11.5, "y": 1},
{"matrix": [1, 12], "x": 12.5, "y": 1},
{"matrix": [2, 12], "x": 13.5, "y": 1, "w": 1.5},
{"matrix": [1, 14], "x": 15, "y": 1},
{"matrix": [2, 0], "x": 0, "y": 2, "w": 1.75},
{"matrix": [2, 1], "x": 1.75, "y": 2},
{"matrix": [2, 2], "x": 2.75, "y": 2},
{"matrix": [2, 3], "x": 3.75, "y": 2},
{"matrix": [2, 4], "x": 4.75, "y": 2},
{"matrix": [2, 5], "x": 5.75, "y": 2},
{"matrix": [2, 6], "x": 6.75, "y": 2},
{"matrix": [2, 7], "x": 7.75, "y": 2},
{"matrix": [2, 8], "x": 8.75, "y": 2},
{"matrix": [2, 9], "x": 9.75, "y": 2},
{"matrix": [2, 10], "x": 10.75, "y": 2},
{"matrix": [2, 11], "x": 11.75, "y": 2},
{"matrix": [2, 13], "x": 12.75, "y": 2, "w": 2.25},
{"matrix": [2, 14], "x": 15, "y": 2},
{"matrix": [3, 0], "x": 0, "y": 3, "w": 2.25},
{"matrix": [3, 2], "x": 2.25, "y": 3},
{"matrix": [3, 3], "x": 3.25, "y": 3},
{"matrix": [3, 4], "x": 4.25, "y": 3},
{"matrix": [3, 5], "x": 5.25, "y": 3},
{"matrix": [3, 6], "x": 6.25, "y": 3},
{"matrix": [3, 7], "x": 7.25, "y": 3},
{"matrix": [3, 8], "x": 8.25, "y": 3},
{"matrix": [3, 9], "x": 9.25, "y": 3},
{"matrix": [3, 10], "x": 10.25, "y": 3},
{"matrix": [3, 11], "x": 11.25, "y": 3},
{"matrix": [3, 12], "x": 12.25, "y": 3, "w": 1.75},
{"matrix": [3, 13], "x": 14, "y": 3},
{"matrix": [3, 14], "x": 15, "y": 3},
{"matrix": [4, 0], "x": 0, "y": 4, "w": 1.5},
{"matrix": [4, 1], "x": 1.5, "y": 4},
{"matrix": [4, 2], "x": 2.5, "y": 4, "w": 1.5},
{"matrix": [4, 6], "x": 4, "y": 4, "w": 7},
{"matrix": [4, 11], "x": 11, "y": 4, "w": 1.5},
{"matrix": [4, 12], "x": 13, "y": 4},
{"matrix": [4, 13], "x": 14, "y": 4},
{"matrix": [4, 14], "x": 15, "y": 4}
]
}
}
}
@@ -0,0 +1,32 @@
/* Copyright 2024 Yiancar-Designs
*
* 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
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[0] = LAYOUT_65_ansi_blocker_split_bs( /* Base */
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_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,
KC_LSFT, 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_END,
KC_LCTL, KC_LGUI, KC_LALT, KC_SPC, KC_RCTL, MO(1), KC_LEFT, KC_DOWN, KC_RGHT),
[1] = LAYOUT_65_ansi_blocker_split_bs( /* FN */
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, KC_DEL, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, UG_NEXT, UG_HUEU, UG_SATU, UG_VALU, UG_SPDU, _______, _______, _______, _______, _______, _______, _______, _______,
KC_VOLU, KC_VOLD, KC_MUTE, _______, _______, _______, _______, _______, _______)
};
@@ -0,0 +1,22 @@
/* Copyright 2024 Yiancar-Designs
*
* 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
#include_next <mcuconf.h>
#undef STM32_SPI_USE_SPI2
#define STM32_SPI_USE_SPI2 TRUE
@@ -0,0 +1,32 @@
# Float 65
This is a 65% layout PCB. It supports VIA.
* Keyboard Maintainer: [Yiancar](http://yiancar-designs.com/) and on [GitHub](https://github.com/yiancar)
* Hardware Supported: A 65% keyboard with STM32F072CB
* Hardware Availability: https://omnitype.com
## Instructions
### Build
Make example for this keyboard (after setting up your build environment):
make yiancardesigns/float65: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).
### Reset
- Unplug
- Hold Escape
- Plug In
- Unplug
- Release Escape
### Flash
- Unplug
- Hold Escape
- Plug In
- Flash using QMK Toolbox or CLI (`make yiancardesigns/float65:<keymap>:flash`)
@@ -169,6 +169,139 @@ def _generate_modules_rules(keyboard, filename):
return lines
def _module_slugs(modules):
return [Path(m).name.lower() for m in modules]
def _render_eeconfig_declarations(modules):
lines = []
lines.append('')
lines.append('// nvm eeconfig')
for module_slug in _module_slugs(modules):
lines.extend([
f'#if (EECONFIG_MODULE_{module_slug.upper()}_DATA_SIZE) > 0',
f'bool eeconfig_is_{module_slug}_datablock_valid(void);',
f'uint32_t eeconfig_read_{module_slug}_datablock(void *data, uint32_t offset, uint32_t length) __attribute__((nonnull));',
f'uint32_t eeconfig_update_{module_slug}_datablock(const void *data, uint32_t offset, uint32_t length) __attribute__((nonnull));',
f'void eeconfig_init_{module_slug}_datablock(void);',
f'# define eeconfig_read_{module_slug}_datablock_field(__object, __field) eeconfig_read_{module_slug}_datablock(&(__object.__field), offsetof(typeof(__object), __field), sizeof(__object.__field))',
f'# define eeconfig_update_{module_slug}_datablock_field(__object, __field) eeconfig_update_{module_slug}_datablock(&(__object.__field), offsetof(typeof(__object), __field), sizeof(__object.__field))',
'',
f'bool nvm_eeconfig_is_{module_slug}_datablock_valid(void);',
f'uint32_t nvm_eeconfig_read_{module_slug}_datablock(void *data, uint32_t offset, uint32_t length);',
f'uint32_t nvm_eeconfig_update_{module_slug}_datablock(const void *data, uint32_t offset, uint32_t length);',
f'void nvm_eeconfig_init_{module_slug}_datablock(void);',
f'#endif // (EECONFIG_MODULE_{module_slug.upper()}_DATA_SIZE) > 0',
'',
])
lines.append('typedef struct PACKED {')
for module_slug in _module_slugs(modules):
lines.extend([
f'#if (EECONFIG_MODULE_{module_slug.upper()}_DATA_SIZE) > 0',
f' uint32_t {module_slug}_version;',
f' uint8_t {module_slug}[EECONFIG_MODULE_{module_slug.upper()}_DATA_SIZE];',
f'#endif // (EECONFIG_MODULE_{module_slug.upper()}_DATA_SIZE) > 0',
])
lines.append('} eeprom_modules_t;')
lines.append('')
for module_slug in _module_slugs(modules):
lines.append(f'#define EECONFIG_MODULE_{module_slug.upper()}_VERSION (uint32_t *)(EECONFIG_MODULES_DATABLOCK + (offsetof(eeprom_modules_t, {module_slug}_version)))')
lines.append(f'#define EECONFIG_MODULE_{module_slug.upper()}_DATABLOCK (uint8_t *)(EECONFIG_MODULES_DATABLOCK + (offsetof(eeprom_modules_t, {module_slug})))')
lines.append('')
lines.append('bool eeconfig_is_modules_datablock_valid(void);')
lines.append('void eeconfig_init_modules_datablock(void);')
lines.append('')
return lines
def _render_eeconfig_implementation(modules):
lines = []
lines.append('')
lines.append('// nvm eeconfig')
lines.append('#if defined(NVM_DRIVER_EEPROM)'),
lines.append('# include "nvm_eeprom_eeconfig_internal.h"')
lines.append('# include "eeprom.h"')
lines.append('#endif // defined(NVM_DRIVER_EEPROM)'),
lines.append('')
for module_slug in _module_slugs(modules):
lines.extend([
f'#if (EECONFIG_MODULE_{module_slug.upper()}_DATA_SIZE) > 0',
f'bool eeconfig_is_{module_slug}_datablock_valid(void) {{ return nvm_eeconfig_is_{module_slug}_datablock_valid(); }}',
f'uint32_t eeconfig_read_{module_slug}_datablock(void *data, uint32_t offset, uint32_t length) {{ return nvm_eeconfig_read_{module_slug}_datablock(data, offset, length); }}',
f'uint32_t eeconfig_update_{module_slug}_datablock(const void *data, uint32_t offset, uint32_t length) {{ return nvm_eeconfig_update_{module_slug}_datablock(data, offset, length); }}',
f'void eeconfig_init_{module_slug}_datablock(void) {{ nvm_eeconfig_init_{module_slug}_datablock(); }}',
'',
'# if defined(NVM_DRIVER_EEPROM)',
f'bool nvm_eeconfig_is_{module_slug}_datablock_valid(void) {{',
f' return eeprom_read_dword(EECONFIG_MODULE_{module_slug.upper()}_VERSION) == (EECONFIG_MODULE_{module_slug.upper()}_DATA_VERSION);',
'}',
f'uint32_t nvm_eeconfig_read_{module_slug}_datablock(void *data, uint32_t offset, uint32_t length) {{',
f' if (eeconfig_is_{module_slug}_datablock_valid()) {{',
f' void *ee_start = (void *)(uintptr_t)(EECONFIG_MODULE_{module_slug.upper()}_DATABLOCK + offset);',
f' void *ee_end = (void *)(uintptr_t)(EECONFIG_MODULE_{module_slug.upper()}_DATABLOCK + MIN((EECONFIG_MODULE_{module_slug.upper()}_DATA_SIZE), offset + length));',
' eeprom_read_block(data, ee_start, ee_end - ee_start);',
' return ee_end - ee_start;',
' } else {',
' memset(data, 0, length);',
' return length;',
' }',
'}',
f'uint32_t nvm_eeconfig_update_{module_slug}_datablock(const void *data, uint32_t offset, uint32_t length) {{',
f' eeprom_update_dword(EECONFIG_MODULE_{module_slug.upper()}_VERSION, (EECONFIG_MODULE_{module_slug.upper()}_DATA_VERSION));',
f' void *ee_start = (void *)(uintptr_t)(EECONFIG_MODULE_{module_slug.upper()}_DATABLOCK + offset);',
f' void *ee_end = (void *)(uintptr_t)(EECONFIG_MODULE_{module_slug.upper()}_DATABLOCK + MIN((EECONFIG_MODULE_{module_slug.upper()}_DATA_SIZE), offset + length));',
' eeprom_update_block(data, ee_start, ee_end - ee_start);',
' return ee_end - ee_start;',
'}',
f'void nvm_eeconfig_init_{module_slug}_datablock(void) {{',
f' eeprom_update_dword(EECONFIG_MODULE_{module_slug.upper()}_VERSION, (EECONFIG_MODULE_{module_slug.upper()}_DATA_VERSION));',
f' void *start = (void *)(uintptr_t)(EECONFIG_MODULE_{module_slug.upper()}_DATABLOCK);',
f' void *end = (void *)(uintptr_t)(EECONFIG_MODULE_{module_slug.upper()}_DATABLOCK + (EECONFIG_MODULE_{module_slug.upper()}_DATA_SIZE));',
' long remaining = end - start;',
' uint8_t dummy[16] = {0};',
f' for (int i = 0; i < EECONFIG_MODULE_{module_slug.upper()}_DATA_SIZE; i += sizeof(dummy)) {{',
' int this_loop = remaining < sizeof(dummy) ? remaining : sizeof(dummy);',
' eeprom_update_block(dummy, start, this_loop);',
' start += this_loop;',
' remaining -= this_loop;',
' }',
'}',
'# endif // defined(NVM_DRIVER_EEPROM)',
f'#endif // (EECONFIG_MODULE_{module_slug.upper()}_DATA_SIZE) > 0',
'',
])
lines.append('bool eeconfig_is_modules_datablock_valid(void) {')
lines.append(' return true')
for module_slug in _module_slugs(modules):
lines.extend([
f'#if (EECONFIG_MODULE_{module_slug.upper()}_DATA_SIZE) > 0',
f' && eeconfig_is_{module_slug}_datablock_valid()',
f'#endif // (EECONFIG_MODULE_{module_slug.upper()}_DATA_SIZE) > 0',
])
lines.append(' ;')
lines.append('}')
lines.append('')
lines.append('void eeconfig_init_modules_datablock(void) {'),
for module_slug in _module_slugs(modules):
lines.extend([
f'#if (EECONFIG_MODULE_{module_slug.upper()}_DATA_SIZE) > 0',
f' eeconfig_init_{module_slug}_datablock();',
f'#endif // (EECONFIG_MODULE_{module_slug.upper()}_DATA_SIZE) > 0',
])
lines.append('}')
lines.append('')
return lines
@cli.argument('-o', '--output', arg_only=True, type=qmk.path.normpath, help='File to write to')
@cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages")
@cli.argument('-e', '--escape', arg_only=True, action='store_true', help="Escape spaces in quiet mode")
@@ -196,11 +329,11 @@ def generate_community_modules_rules_mk(cli):
@cli.argument('-o', '--output', arg_only=True, type=qmk.path.normpath, help='File to write to')
@cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages")
@cli.argument('-kb', '--keyboard', arg_only=True, type=keyboard_folder, completer=keyboard_completer, help='Keyboard to generate community_config.h for.')
@cli.argument('-kb', '--keyboard', arg_only=True, type=keyboard_folder, completer=keyboard_completer, help='Keyboard to generate community_post_config.h for.')
@cli.argument('filename', nargs='?', type=qmk.path.FileType('r'), arg_only=True, completer=FilesCompleter('.json'), help='Configurator JSON file')
@cli.subcommand('Creates a community_config.h from a keymap.json file.')
def generate_community_config_h(cli):
"""Creates a community_config.h from a keymap.json file
@cli.subcommand('Creates a community_post_config.h from a keymap.json file.')
def generate_community_post_config_h(cli):
"""Creates a community_post_config.h from a keymap.json file
"""
if cli.args.output and cli.args.output.name == '-':
cli.args.output = None
@@ -215,14 +348,29 @@ def generate_community_config_h(cli):
modules = get_modules(cli.args.keyboard, cli.args.filename)
if len(modules) > 0:
lines.append('// Split transactions')
for module in modules:
for module_slug in _module_slugs(modules):
lines.extend([
f'#ifdef SPLIT_TRANSACTION_IDS_MODULE_{Path(module).name.upper()}',
f'#ifdef SPLIT_TRANSACTION_IDS_MODULE_{module_slug.upper()}',
'# define SPLIT_TRANSACTION_RPC',
'#endif',
])
lines.append('')
lines.append('// nvm eeconfig')
for module_slug in _module_slugs(modules):
lines.extend([
f'#ifndef EECONFIG_MODULE_{module_slug.upper()}_DATA_SIZE',
f'# define EECONFIG_MODULE_{module_slug.upper()}_DATA_SIZE 0',
'#endif',
f'#ifndef EECONFIG_MODULE_{module_slug.upper()}_DATA_VERSION',
f'# define EECONFIG_MODULE_{module_slug.upper()}_DATA_VERSION (EECONFIG_MODULE_{module_slug.upper()}_DATA_SIZE)',
'#endif',
'',
])
module_size = " + ".join([f'(4 + (EECONFIG_MODULE_{module_slug.upper()}_DATA_SIZE))' for module_slug in _module_slugs(modules)])
lines.append(f'#define EECONFIG_MODULE_DATA_SIZE ({module_size})')
lines.append('')
dump_lines(cli.args.output, lines, cli.args.quiet, remove_repeated_newlines=True)
@@ -245,6 +393,7 @@ def generate_community_modules_h(cli):
'#pragma once',
'#include <stdint.h>',
'#include <stdbool.h>',
'#include <string.h>',
'#include <keycodes.h>',
'',
'#include "compiler_support.h"',
@@ -272,6 +421,8 @@ def generate_community_modules_h(cli):
lines.extend(_render_api_declarations(api, Path(module).name))
lines.append('')
lines.extend(_render_eeconfig_declarations(modules))
lines.append('// Core wrapper')
for api in api_list:
lines.extend(_render_api_declarations(api, 'modules', user_kb=False))
@@ -309,6 +460,8 @@ def generate_community_modules_c(cli):
for api in api_list:
lines.extend(_render_core_implementation(api, modules))
lines.extend(_render_eeconfig_implementation(modules))
dump_lines(cli.args.output, lines, cli.args.quiet, remove_repeated_newlines=True)
+5
View File
@@ -0,0 +1,5 @@
// Copyright 2026 QMK
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#define EECONFIG_MODULE_NVM_TEST_DATA_SIZE 4
+53
View File
@@ -0,0 +1,53 @@
// Copyright 2026 QMK
// SPDX-License-Identifier: GPL-2.0-or-later
#include <stdint.h>
#include "community_modules.h"
#include "debug.h"
#include "timer.h"
#include "eeconfig.h"
ASSERT_COMMUNITY_MODULES_MIN_API_VERSION(1, 1, 3);
typedef struct my_config_t {
uint32_t data;
} my_config_t;
static my_config_t config;
// Helpers required to bind to debounce helper
void eeconfig_read_my_config(my_config_t *value) {
eeconfig_read_nvm_test_datablock(value, 0, sizeof(my_config_t));
}
void eeconfig_update_my_config(my_config_t *value) {
eeconfig_update_nvm_test_datablock(value, 0, sizeof(my_config_t));
}
EECONFIG_DEBOUNCE_HELPER(my_config, config);
void keyboard_post_init_nvm_test(void) {
if (!eeconfig_is_nvm_test_datablock_valid()) {
eeconfig_init_nvm_test_datablock();
}
eeconfig_init_my_config();
}
bool process_record_nvm_test(uint16_t keycode, keyrecord_t *record) {
if (!record->event.pressed) {
config.data += 1;
eeconfig_flag_my_config(true);
}
return true;
}
void housekeeping_task_nvm_test(void) {
eeconfig_flush_my_config(false);
static uint32_t last_sync = 0;
if (timer_elapsed32(last_sync) > 1000) {
last_sync = timer_read32();
dprintf("Config: %ld\n", config.data);
}
}
+5
View File
@@ -0,0 +1,5 @@
{
"module_name": "Example nvm persistence",
"maintainer": "QMK Maintainers",
"license": "GPL-2.0-or-later"
}
+35 -27
View File
@@ -21,8 +21,16 @@
# endif
#endif
#if PS2_DATA_PIN + 1 != PS2_CLOCK_PIN
# error PS/2 clock pin must be data pin + 1!
#if PS2_DATA_PIN + 1 == PS2_CLOCK_PIN
# define PS2_FIRST_PIN PS2_DATA_PIN
# define PS2_DATA_PINDIR_BIT 1
# define PS2_CLOCK_PINDIR_BIT 2
#elif PS2_DATA_PIN - 1 == PS2_CLOCK_PIN
# define PS2_FIRST_PIN PS2_CLOCK_PIN
# define PS2_DATA_PINDIR_BIT 2
# define PS2_CLOCK_PINDIR_BIT 1
#else
# error PS/2 clock and data pin must be consecutive!
#endif
static inline void pio_serve_interrupt(void);
@@ -50,29 +58,29 @@ OSAL_IRQ_HANDLER(RP_PIO0_IRQ_0_HANDLER) {
// clang-format off
static const uint16_t ps2_program_instructions[] = {
// .wrap_target
0x00c7, // 0: jmp pin, 7
0xe02a, // 1: set x, 10
0x2021, // 2: wait 0 pin, 1
0x4001, // 3: in pins, 1
0x20a1, // 4: wait 1 pin, 1
0x0042, // 5: jmp x--, 2
0x0000, // 6: jmp 0
0x00e9, // 7: jmp !osre, 9
0x0000, // 8: jmp 0
0xff81, // 9: set pindirs, 1 [31]
0xe280, // 10: set pindirs, 0 [2]
0xe082, // 11: set pindirs, 2
0x2021, // 12: wait 0 pin, 1
0xe029, // 13: set x, 9
0x6081, // 14: out pindirs, 1
0x20a1, // 15: wait 1 pin, 1
0x2021, // 16: wait 0 pin, 1
0x004e, // 17: jmp x--, 14
0xe083, // 18: set pindirs, 3
0x2021, // 19: wait 0 pin, 1
0x20a1, // 20: wait 1 pin, 1
// .wrap
// .wrap_target
0x00c7, // 0: jmp pin, 7
0xe02a, // 1: set x, 10
0x2000 | PS2_CLOCK_PIN, // 2: wait 0 gpio, CLK
0x4001, // 3: in pins, 1
0x2080 | PS2_CLOCK_PIN, // 4: wait 1 gpio, CLK
0x0042, // 5: jmp x--, 2
0x0000, // 6: jmp 0
0x00e9, // 7: jmp !osre, 9
0x0000, // 8: jmp 0
0xff80 | PS2_DATA_PINDIR_BIT, // 9: set pindirs, DATA [31]
0xe280, // 10: set pindirs, 0 [2]
0xe080 | PS2_CLOCK_PINDIR_BIT, // 11: set pindirs, CLK
0x2000 | PS2_CLOCK_PIN, // 12: wait 0 gpio, CLK
0xe029, // 13: set x, 9
0x6081, // 14: out pindirs, 1
0x2080 | PS2_CLOCK_PIN, // 15: wait 1 gpio, CLK
0x2000 | PS2_CLOCK_PIN, // 16: wait 0 gpio, CLK
0x004e, // 17: jmp x--, 14
0xe083, // 18: set pindirs, 3
0x2000 | PS2_CLOCK_PIN, // 19: wait 0 gpio, CLK
0x2080 | PS2_CLOCK_PIN, // 20: wait 1 gpio, CLK
// .wrap
};
// clang-format on
@@ -133,9 +141,9 @@ void ps2_host_init(void) {
sm_config_set_wrap(&c, offset + PS2_WRAP_TARGET, offset + PS2_WRAP);
// Set pindirs to input (output enable is inverted below)
pio_sm_set_consecutive_pindirs(pio, state_machine, PS2_DATA_PIN, 2, true);
pio_sm_set_consecutive_pindirs(pio, state_machine, PS2_FIRST_PIN, 2, true);
sm_config_set_clkdiv(&c, (float)clock_get_hz(clk_sys) / (200.0f * KHZ));
sm_config_set_set_pins(&c, PS2_DATA_PIN, 2);
sm_config_set_set_pins(&c, PS2_FIRST_PIN, 2);
sm_config_set_out_pins(&c, PS2_DATA_PIN, 1);
sm_config_set_out_shift(&c, true, true, 10);
sm_config_set_in_shift(&c, true, true, 11);
+8
View File
@@ -39,6 +39,10 @@
# include "connection.h"
#endif // CONNECTION_ENABLE
#ifdef COMMUNITY_MODULES_ENABLE
# include "community_modules.h"
#endif
#ifdef VIA_ENABLE
bool via_eeprom_is_valid(void);
void via_eeprom_set_valid(bool valid);
@@ -148,6 +152,10 @@ void eeconfig_init_quantum(void) {
eeconfig_init_user_datablock();
#endif // (EECONFIG_USER_DATA_SIZE) > 0
#ifdef COMMUNITY_MODULES_ENABLE
eeconfig_init_modules_datablock();
#endif // COMMUNITY_MODULES_ENABLE
#if defined(VIA_ENABLE)
// Invalidate VIA eeprom config, and then reset.
// Just in case if power is lost mid init, this makes sure that it gets
+72 -3
View File
@@ -26,11 +26,11 @@
#pragma once
// clang-format off
#define QMK_KEYCODES_VERSION "0.0.8"
#define QMK_KEYCODES_VERSION_BCD 0x00000008
#define QMK_KEYCODES_VERSION "0.0.9"
#define QMK_KEYCODES_VERSION_BCD 0x00000009
#define QMK_KEYCODES_VERSION_MAJOR 0
#define QMK_KEYCODES_VERSION_MINOR 0
#define QMK_KEYCODES_VERSION_PATCH 8
#define QMK_KEYCODES_VERSION_PATCH 9
enum qk_keycode_ranges {
// Ranges
@@ -64,6 +64,8 @@ enum qk_keycode_ranges {
QK_SWAP_HANDS_MAX = 0x56FF,
QK_TAP_DANCE = 0x5700,
QK_TAP_DANCE_MAX = 0x57FF,
QK_PLOVER_HID = 0x5A40,
QK_PLOVER_HID_MAX = 0x5A7F,
QK_MAGIC = 0x7000,
QK_MAGIC_MAX = 0x70FF,
QK_MIDI = 0x7100,
@@ -329,6 +331,70 @@ enum qk_keycode_defines {
QK_SWAP_HANDS_OFF = 0x56F4,
QK_SWAP_HANDS_ON = 0x56F5,
QK_SWAP_HANDS_ONE_SHOT = 0x56F6,
PLV_S1 = 0x5A40,
PLV_TL = 0x5A41,
PLV_KL = 0x5A42,
PLV_PL = 0x5A43,
PLV_WL = 0x5A44,
PLV_HL = 0x5A45,
PLV_RL = 0x5A46,
PLV_A = 0x5A47,
PLV_O = 0x5A48,
PLV_ST1 = 0x5A49,
PLV_E = 0x5A4A,
PLV_U = 0x5A4B,
PLV_FR = 0x5A4C,
PLV_RR = 0x5A4D,
PLV_PR = 0x5A4E,
PLV_BR = 0x5A4F,
PLV_LR = 0x5A50,
PLV_GR = 0x5A51,
PLV_TR = 0x5A52,
PLV_SR = 0x5A53,
PLV_DR = 0x5A54,
PLV_ZR = 0x5A55,
PLV_N1 = 0x5A56,
PLV_S2 = 0x5A57,
PLV_ST2 = 0x5A58,
PLV_ST3 = 0x5A59,
PLV_ST4 = 0x5A5A,
PLV_N2 = 0x5A5B,
PLV_N3 = 0x5A5C,
PLV_N4 = 0x5A5D,
PLV_N5 = 0x5A5E,
PLV_N6 = 0x5A5F,
PLV_N7 = 0x5A60,
PLV_N8 = 0x5A61,
PLV_N9 = 0x5A62,
PLV_NA = 0x5A63,
PLV_NB = 0x5A64,
PLV_NC = 0x5A65,
PLV_X1 = 0x5A66,
PLV_X2 = 0x5A67,
PLV_X3 = 0x5A68,
PLV_X4 = 0x5A69,
PLV_X5 = 0x5A6A,
PLV_X6 = 0x5A6B,
PLV_X7 = 0x5A6C,
PLV_X8 = 0x5A6D,
PLV_X9 = 0x5A6E,
PLV_X10 = 0x5A6F,
PLV_X11 = 0x5A70,
PLV_X12 = 0x5A71,
PLV_X13 = 0x5A72,
PLV_X14 = 0x5A73,
PLV_X15 = 0x5A74,
PLV_X16 = 0x5A75,
PLV_X17 = 0x5A76,
PLV_X18 = 0x5A77,
PLV_X19 = 0x5A78,
PLV_X20 = 0x5A79,
PLV_X21 = 0x5A7A,
PLV_X22 = 0x5A7B,
PLV_X23 = 0x5A7C,
PLV_X24 = 0x5A7D,
PLV_X25 = 0x5A7E,
PLV_X26 = 0x5A7F,
QK_MAGIC_SWAP_CONTROL_CAPS_LOCK = 0x7000,
QK_MAGIC_UNSWAP_CONTROL_CAPS_LOCK = 0x7001,
QK_MAGIC_TOGGLE_CONTROL_CAPS_LOCK = 0x7002,
@@ -1483,6 +1549,7 @@ enum qk_keycode_defines {
#define IS_QK_PERSISTENT_DEF_LAYER(code) ((code) >= QK_PERSISTENT_DEF_LAYER && (code) <= QK_PERSISTENT_DEF_LAYER_MAX)
#define IS_QK_SWAP_HANDS(code) ((code) >= QK_SWAP_HANDS && (code) <= QK_SWAP_HANDS_MAX)
#define IS_QK_TAP_DANCE(code) ((code) >= QK_TAP_DANCE && (code) <= QK_TAP_DANCE_MAX)
#define IS_QK_PLOVER_HID(code) ((code) >= QK_PLOVER_HID && (code) <= QK_PLOVER_HID_MAX)
#define IS_QK_MAGIC(code) ((code) >= QK_MAGIC && (code) <= QK_MAGIC_MAX)
#define IS_QK_MIDI(code) ((code) >= QK_MIDI && (code) <= QK_MIDI_MAX)
#define IS_QK_SEQUENCER(code) ((code) >= QK_SEQUENCER && (code) <= QK_SEQUENCER_MAX)
@@ -1509,6 +1576,7 @@ enum qk_keycode_defines {
#define IS_MOUSE_KEYCODE(code) ((code) >= QK_MOUSE_CURSOR_UP && (code) <= QK_MOUSE_ACCELERATION_2)
#define IS_MODIFIER_KEYCODE(code) ((code) >= KC_LEFT_CTRL && (code) <= KC_RIGHT_GUI)
#define IS_SWAP_HANDS_KEYCODE(code) ((code) >= QK_SWAP_HANDS_TOGGLE && (code) <= QK_SWAP_HANDS_ONE_SHOT)
#define IS_PLOVER_HID_KEYCODE(code) ((code) >= PLV_S1 && (code) <= PLV_X26)
#define IS_MAGIC_KEYCODE(code) ((code) >= QK_MAGIC_SWAP_CONTROL_CAPS_LOCK && (code) <= QK_MAGIC_TOGGLE_ESCAPE_CAPS_LOCK)
#define IS_MIDI_KEYCODE(code) ((code) >= QK_MIDI_ON && (code) <= QK_MIDI_PITCH_BEND_UP)
#define IS_SEQUENCER_KEYCODE(code) ((code) >= QK_SEQUENCER_ON && (code) <= QK_SEQUENCER_STEPS_CLEAR)
@@ -1535,6 +1603,7 @@ enum qk_keycode_defines {
#define MOUSE_KEYCODE_RANGE QK_MOUSE_CURSOR_UP ... QK_MOUSE_ACCELERATION_2
#define MODIFIER_KEYCODE_RANGE KC_LEFT_CTRL ... KC_RIGHT_GUI
#define SWAP_HANDS_KEYCODE_RANGE QK_SWAP_HANDS_TOGGLE ... QK_SWAP_HANDS_ONE_SHOT
#define PLOVER_HID_KEYCODE_RANGE PLV_S1 ... PLV_X26
#define MAGIC_KEYCODE_RANGE QK_MAGIC_SWAP_CONTROL_CAPS_LOCK ... QK_MAGIC_TOGGLE_ESCAPE_CAPS_LOCK
#define MIDI_KEYCODE_RANGE QK_MIDI_ON ... QK_MIDI_PITCH_BEND_UP
#define SEQUENCER_KEYCODE_RANGE QK_SEQUENCER_ON ... QK_SEQUENCER_STEPS_CLEAR
+5
View File
@@ -55,6 +55,11 @@ int main(void) {
raw_hid_task();
#endif
#ifdef PLOVER_HID_ENABLE
void plover_hid_task(void);
plover_hid_task();
#endif
#ifdef CONSOLE_ENABLE
void console_task(void);
console_task();
@@ -56,8 +56,14 @@ typedef struct PACKED {
#define EECONFIG_KB_DATABLOCK ((uint8_t *)(EECONFIG_BASE_SIZE))
#define EECONFIG_USER_DATABLOCK ((uint8_t *)((EECONFIG_BASE_SIZE) + (EECONFIG_KB_DATA_SIZE)))
#define EECONFIG_MODULES_DATABLOCK ((uint8_t *)((EECONFIG_BASE_SIZE) + (EECONFIG_KB_DATA_SIZE) + (EECONFIG_USER_DATA_SIZE)))
// Actual value is injected via the generated community_post_config.h
#ifndef EECONFIG_MODULE_DATA_SIZE
# define EECONFIG_MODULE_DATA_SIZE 0
#endif
// Size of EEPROM being used, other code can refer to this for available EEPROM
#define EECONFIG_SIZE ((EECONFIG_BASE_SIZE) + (EECONFIG_KB_DATA_SIZE) + (EECONFIG_USER_DATA_SIZE))
#define EECONFIG_SIZE ((EECONFIG_BASE_SIZE) + (EECONFIG_KB_DATA_SIZE) + (EECONFIG_USER_DATA_SIZE) + (EECONFIG_MODULE_DATA_SIZE))
STATIC_ASSERT((intptr_t)EECONFIG_HANDEDNESS == 14, "EEPROM handedness offset is incorrect");
+46
View File
@@ -0,0 +1,46 @@
/* Copyright 2021 dnaq
*
* 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 <limits.h>
#include "plover_hid.h"
#include "report.h"
#include "host.h"
#include "compiler_support.h"
// The button index handed to plover_hid_update() is `keycode - QK_PLOVER_HID`, so the report's
// data field must hold a bit for every keycode in the range or the bit-packing below overflows.
STATIC_ASSERT(sizeof(((report_plover_hid_t *)0)->data) * CHAR_BIT >= (QK_PLOVER_HID_MAX - QK_PLOVER_HID + 1), "Plover HID report data too small for the QK_PLOVER_HID keycode range");
static report_plover_hid_t plover_hid_report = {.report_id = REPORT_ID_PLOVER_HID};
static bool plover_hid_report_updated = false;
void plover_hid_update(uint8_t button, bool pressed) {
if (pressed) {
plover_hid_report.data[button / 8] |= (1 << (7 - (button % 8)));
} else {
plover_hid_report.data[button / 8] &= ~(1 << (7 - (button % 8)));
}
plover_hid_report_updated = true;
}
void plover_hid_task(void) {
if (!plover_hid_report_updated) {
return;
}
host_plover_hid_send(&plover_hid_report);
plover_hid_report_updated = false;
}
+23
View File
@@ -0,0 +1,23 @@
/* Copyright 2021 dnaq
*
* 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
#include <stdint.h>
#include <stdbool.h>
void plover_hid_update(uint8_t button, bool pressed);
void plover_hid_task(void);
+5 -1
View File
@@ -57,7 +57,11 @@ static inline uint16_t translate_keycode(uint16_t keycode) {
void cancel_key_lock(void) {
watching = false;
UNSET_KEY_STATE(0x0);
// Clear the full 256-bit state, otherwise every actually-locked key will still be latched.
key_state[0] = 0;
key_state[1] = 0;
key_state[2] = 0;
key_state[3] = 0;
}
bool process_key_lock(uint16_t *keycode, keyrecord_t *record) {
@@ -366,13 +366,13 @@ static bool try_activating_override(const uint16_t keycode, const uint8_t layer,
schedule_deferred_register(mod_free_replacement);
send_keyboard_report();
} else {
send_keyboard_report();
// On macOS there seems to be a race condition when it comes to the keyboard report and consumer keycodes. It seems the OS may recognize a consumer keycode before an updated keyboard report, even if the keyboard report is actually sent before the consumer key. I assume it is some sort of race condition because it happens infrequently and very irregularly. Waiting for about at least 10ms between sending the keyboard report and sending the consumer code has shown to fix this.
wait_ms(10);
if (IS_BASIC_KEYCODE(mod_free_replacement)) {
add_key(mod_free_replacement);
} else {
key_override_printf("NOT KEY 2\n");
send_keyboard_report();
// On macOS there seems to be a race condition when it comes to the keyboard report and consumer keycodes. It seems the OS may recognize a consumer keycode before an updated keyboard report, even if the keyboard report is actually sent before the consumer key. I assume it is some sort of race condition because it happens infrequently and very irregularly. Waiting for about at least 10ms between sending the keyboard report and sending the consumer code has shown to fix this.
wait_ms(10);
register_code(mod_free_replacement);
}
}
@@ -0,0 +1,26 @@
/* Copyright 2021 dnaq
*
* 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 "process_plover_hid.h"
#include "plover_hid.h"
bool process_plover_hid(uint16_t keycode, keyrecord_t *record) {
if (!IS_QK_PLOVER_HID(keycode)) {
return true;
}
plover_hid_update(keycode - QK_PLOVER_HID, record->event.pressed);
return false;
}
@@ -0,0 +1,21 @@
/* Copyright 2021 dnaq
*
* 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
#include "quantum.h"
bool process_plover_hid(uint16_t keycode, keyrecord_t *record);
+3
View File
@@ -374,6 +374,9 @@ bool process_record_quantum(keyrecord_t *record) {
#if defined(LED_MATRIX_ENABLE)
process_led_matrix(keycode, record) &&
#endif
#ifdef PLOVER_HID_ENABLE
process_plover_hid(keycode, record) &&
#endif
#ifdef STENO_ENABLE
process_steno(keycode, record) &&
#endif
+4
View File
@@ -95,6 +95,10 @@ extern layer_state_t layer_state;
# endif
#endif
#ifdef PLOVER_HID_ENABLE
# include "process_plover_hid.h"
#endif
#ifdef STENO_ENABLE
# include "process_steno.h"
#endif
+4
View File
@@ -45,6 +45,10 @@ uint16_t get_last_keycode(void) {
return last_record.keycode;
}
const keyrecord_t* get_last_record(void) {
return &last_record;
}
uint8_t get_last_mods(void) {
return last_mods;
}
+1 -1
View File
@@ -26,7 +26,7 @@ void set_last_keycode(uint16_t keycode); /**< Sets the last key. */
void set_last_mods(uint8_t mods); /**< Sets the last mods. */
/** @brief Gets the record for the last key. */
keyrecord_t* get_last_record(void);
const keyrecord_t* get_last_record(void);
/** @brief Sets keycode and record info for the last key. */
void set_last_record(uint16_t keycode, keyrecord_t* record);
+4
View File
@@ -1,3 +1,7 @@
# THIS IS THE DEVELOP BRANCH
Warning- This is the `develop` branch of QMK Firmware. You may encounter broken code here. Please see [Breaking Changes](https://docs.qmk.fm/#/breaking_changes) for more information.
# Quantum Mechanical Keyboard Firmware
[![Current Version](https://img.shields.io/github/tag/qmk/qmk_firmware.svg)](https://github.com/qmk/qmk_firmware/tags)
@@ -0,0 +1,45 @@
// Copyright 2026 QMK
// SPDX-License-Identifier: GPL-2.0-or-later
#include <string.h>
#include "azoteq_iqs5xx.h"
static azoteq_iqs5xx_base_data_t mock_base_data;
static i2c_status_t mock_read_status = I2C_STATUS_SUCCESS;
void azoteq_iqs5xx_mock_reset(void) {
memset(&mock_base_data, 0, sizeof(mock_base_data));
mock_read_status = I2C_STATUS_SUCCESS;
}
void azoteq_iqs5xx_mock_set_base_data(azoteq_iqs5xx_base_data_t base_data) {
mock_base_data = base_data;
mock_read_status = I2C_STATUS_SUCCESS;
}
void i2c_init(void) {}
i2c_status_t i2c_ping_address(uint8_t address, uint16_t timeout) {
return I2C_STATUS_SUCCESS;
}
i2c_status_t i2c_read_register16(uint8_t devaddr, uint16_t regaddr, uint8_t *data, uint16_t length, uint16_t timeout) {
if (mock_read_status == I2C_STATUS_SUCCESS && data != NULL) {
memcpy(data, &mock_base_data, MIN(length, sizeof(mock_base_data)));
}
return mock_read_status;
}
i2c_status_t i2c_write_register16(uint8_t devaddr, uint16_t regaddr, const uint8_t *data, uint16_t length, uint16_t timeout) {
return I2C_STATUS_SUCCESS;
}
uint8_t pointing_device_handle_buttons(uint8_t buttons, bool pressed, pointing_device_buttons_t button) {
if (pressed) {
buttons |= 1 << button;
} else {
buttons &= ~(1 << button);
}
return buttons;
}
+8
View File
@@ -0,0 +1,8 @@
// Copyright 2026 QMK
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "test_common.h"
#define AZOTEQ_IQS5XX_TPS43
+8
View File
@@ -0,0 +1,8 @@
# Copyright 2026 QMK
# SPDX-License-Identifier: GPL-2.0-or-later
SRC += drivers/sensors/azoteq_iqs5xx.c
SRC += tests/pointing/azoteq_iqs5xx/azoteq_iqs5xx_mock.c
VPATH += $(QUANTUM_DIR)/pointing_device
VPATH += drivers/sensors
@@ -0,0 +1,54 @@
// Copyright 2026 QMK
// SPDX-License-Identifier: GPL-2.0-or-later
#include "gtest/gtest.h"
extern "C" {
#include "azoteq_iqs5xx.h"
void azoteq_iqs5xx_mock_reset(void);
void azoteq_iqs5xx_mock_set_base_data(azoteq_iqs5xx_base_data_t base_data);
}
class AzoteqIqs5xx : public testing::Test {
protected:
void SetUp() override {
azoteq_iqs5xx_mock_reset();
}
};
TEST_F(AzoteqIqs5xx, PreservesIncomingButtonsWhenReportingMovement) {
azoteq_iqs5xx_base_data_t base_data = {0};
base_data.number_of_fingers = 1;
base_data.x.l = 12;
base_data.y.l = 34;
azoteq_iqs5xx_mock_set_base_data(base_data);
report_mouse_t input_report = {0};
input_report.buttons = (1 << POINTING_DEVICE_BUTTON1) | (1 << POINTING_DEVICE_BUTTON2);
report_mouse_t report = azoteq_iqs5xx_get_report(input_report);
EXPECT_EQ(report.x, 12);
EXPECT_EQ(report.y, 34);
EXPECT_EQ(report.h, 0);
EXPECT_EQ(report.v, 0);
EXPECT_EQ(report.buttons, input_report.buttons);
}
TEST_F(AzoteqIqs5xx, CombinesGestureButtonWithIncomingButtons) {
azoteq_iqs5xx_base_data_t base_data = {0};
base_data.gesture_events_1.two_finger_tap = true;
azoteq_iqs5xx_mock_set_base_data(base_data);
report_mouse_t input_report = {0};
input_report.buttons = 1 << POINTING_DEVICE_BUTTON1;
report_mouse_t report = azoteq_iqs5xx_get_report(input_report);
EXPECT_EQ(report.x, 0);
EXPECT_EQ(report.y, 0);
EXPECT_EQ(report.h, 0);
EXPECT_EQ(report.v, 0);
EXPECT_EQ(report.buttons, input_report.buttons | (1 << POINTING_DEVICE_BUTTON2));
}
@@ -80,6 +80,10 @@ usb_endpoint_in_t usb_endpoints_in[USB_ENDPOINT_IN_COUNT] = {
# endif
#endif
#if defined(PLOVER_HID_ENABLE)
[USB_ENDPOINT_IN_PLOVER_HID] = QMK_USB_ENDPOINT_IN(USB_EP_MODE_TYPE_INTR, PLOVER_HID_EPSIZE, PLOVER_HID_IN_EPNUM, PLOVER_HID_IN_CAPACITY, NULL, QMK_USB_REPORT_STORAGE_DEFAULT(PLOVER_HID_EPSIZE)),
#endif
#if defined(MIDI_ENABLE)
# if defined(USB_ENDPOINTS_ARE_REORDERABLE)
[USB_ENDPOINT_IN_MIDI] = QMK_USB_ENDPOINT_IN_SHARED(USB_EP_MODE_TYPE_BULK, MIDI_STREAM_EPSIZE, MIDI_STREAM_IN_EPNUM, MIDI_STREAM_IN_CAPACITY, NULL, NULL),
@@ -107,6 +111,10 @@ usb_endpoint_in_lut_t usb_endpoint_interface_lut[TOTAL_INTERFACES] = {
[RAW_INTERFACE] = USB_ENDPOINT_IN_RAW,
#endif
#if defined(PLOVER_HID_ENABLE)
[PLOVER_HID_INTERFACE] = USB_ENDPOINT_IN_PLOVER_HID,
#endif
#if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP)
[MOUSE_INTERFACE] = USB_ENDPOINT_IN_MOUSE,
#endif
@@ -43,6 +43,10 @@
# define RAW_OUT_CAPACITY USB_DEFAULT_BUFFER_CAPACITY
#endif
#if !defined(PLOVER_HID_IN_CAPACITY)
# define PLOVER_HID_IN_CAPACITY USB_DEFAULT_BUFFER_CAPACITY
#endif
#if !defined(MIDI_STREAM_IN_CAPACITY)
# define MIDI_STREAM_IN_CAPACITY USB_DEFAULT_BUFFER_CAPACITY
#endif
@@ -90,6 +94,10 @@ typedef enum {
USB_ENDPOINT_IN_RAW,
#endif
#if defined(PLOVER_HID_ENABLE)
USB_ENDPOINT_IN_PLOVER_HID,
#endif
#if defined(MIDI_ENABLE)
USB_ENDPOINT_IN_MIDI,
#endif
@@ -127,6 +135,7 @@ typedef enum {
#if defined(RAW_ENABLE)
USB_ENDPOINT_OUT_RAW,
#endif
#if defined(MIDI_ENABLE)
USB_ENDPOINT_OUT_MIDI,
#endif
+6
View File
@@ -489,6 +489,12 @@ void send_digitizer(report_digitizer_t *report) {
#endif
}
void send_plover_hid(report_plover_hid_t *report) {
#ifdef PLOVER_HID_ENABLE
send_report(USB_ENDPOINT_IN_PLOVER_HID, report, sizeof(report_plover_hid_t));
#endif
}
/* ---------------------------------------------------------
* Console functions
* ---------------------------------------------------------
+8
View File
@@ -342,6 +342,14 @@ void host_programmable_button_send(uint32_t data) {
__attribute__((weak)) void send_programmable_button(report_programmable_button_t *report) {}
#ifdef PLOVER_HID_ENABLE
void host_plover_hid_send(report_plover_hid_t *report) {
send_plover_hid(report);
}
#endif
__attribute__((weak)) void send_plover_hid(report_plover_hid_t *report) {}
#ifdef RAW_ENABLE
void host_raw_hid_send(uint8_t *data, uint8_t length) {
host_driver_t *driver = host_get_active_driver();
+1
View File
@@ -44,6 +44,7 @@ void host_mouse_send(report_mouse_t *report);
void host_system_send(uint16_t usage);
void host_consumer_send(uint16_t usage);
void host_programmable_button_send(uint32_t data);
void host_plover_hid_send(report_plover_hid_t *report);
void host_raw_hid_send(uint8_t *data, uint8_t length);
uint16_t host_last_system_usage(void);
+1
View File
@@ -37,3 +37,4 @@ typedef struct {
void send_joystick(report_joystick_t *report);
void send_digitizer(report_digitizer_t *report);
void send_programmable_button(report_programmable_button_t *report);
void send_plover_hid(report_plover_hid_t *report);
+11
View File
@@ -347,6 +347,11 @@ void EVENT_USB_Device_ConfigurationChanged(void) {
ConfigSuccess &= Endpoint_ConfigureEndpoint((RAW_OUT_EPNUM | ENDPOINT_DIR_OUT), EP_TYPE_INTERRUPT, RAW_EPSIZE, 1);
#endif
#ifdef PLOVER_HID_ENABLE
/* Setup plover HID endpoints */
ConfigSuccess &= Endpoint_ConfigureEndpoint((PLOVER_HID_IN_EPNUM | ENDPOINT_DIR_IN), EP_TYPE_INTERRUPT, PLOVER_HID_EPSIZE, 1);
#endif
#ifdef CONSOLE_ENABLE
/* Setup console endpoint */
ConfigSuccess &= Endpoint_ConfigureEndpoint((CONSOLE_IN_EPNUM | ENDPOINT_DIR_IN), EP_TYPE_INTERRUPT, CONSOLE_EPSIZE, 1);
@@ -571,6 +576,12 @@ void send_digitizer(report_digitizer_t *report) {
#endif
}
void send_plover_hid(report_plover_hid_t *report) {
#ifdef PLOVER_HID_ENABLE
send_report(PLOVER_HID_IN_EPNUM, report, sizeof(report_plover_hid_t));
#endif
}
/*******************************************************************************
* sendchar
******************************************************************************/
+10
View File
@@ -44,6 +44,11 @@ enum hid_report_ids {
#define IS_VALID_REPORT_ID(id) ((id) >= REPORT_ID_ALL && (id) <= REPORT_ID_COUNT)
// Plover HID has its own dedicated interface rather than the shared endpoint, so its report ID
// is fixed by the protocol at 0x50 ('P') and is intentionally NOT a member of enum
// hid_report_ids above (which only enumerates shared-endpoint reports up to REPORT_ID_COUNT).
#define REPORT_ID_PLOVER_HID 0x50
/* Mouse buttons */
#define MOUSE_BTN_MASK(n) (1 << (n))
enum mouse_buttons {
@@ -193,6 +198,11 @@ typedef struct {
uint32_t usage;
} PACKED report_programmable_button_t;
typedef struct {
uint8_t report_id; // REPORT_ID_PLOVER_HID
uint8_t data[8];
} PACKED report_plover_hid_t;
#ifdef MOUSE_EXTENDED_REPORT
# define MOUSE_REPORT_XY_MIN (INT16_MIN + 1)
# define MOUSE_REPORT_XY_MAX INT16_MAX
+79
View File
@@ -40,6 +40,7 @@
#include "report.h"
#include "usb_descriptor.h"
#include "usb_descriptor_common.h"
#include "compiler_support.h"
#ifdef JOYSTICK_ENABLE
# include "joystick.h"
@@ -478,6 +479,28 @@ const USB_Descriptor_HIDReport_Datatype_t PROGMEM RawReport[] = {
};
#endif
#ifdef PLOVER_HID_ENABLE
const USB_Descriptor_HIDReport_Datatype_t PROGMEM PloverReport[] = {
HID_RI_USAGE_PAGE(16, 0xFF50), //
HID_RI_USAGE(16, 0x4C56), // Vendor Defined (0xff P L V)
HID_RI_COLLECTION(8, 0x01), // Application
HID_RI_REPORT_ID(8, REPORT_ID_PLOVER_HID),
HID_RI_LOGICAL_MINIMUM(8, 0),
HID_RI_LOGICAL_MAXIMUM(8, 1),
HID_RI_REPORT_SIZE(8, 1),
HID_RI_REPORT_COUNT(8, 0x40),
HID_RI_USAGE_PAGE(8, 0x0A), // Usage Page: Ordinal
HID_RI_USAGE_MINIMUM(8, 0),
HID_RI_USAGE_MAXIMUM(8, 0x3F),
HID_RI_INPUT(8, HID_IOF_DATA | HID_IOF_VARIABLE | HID_IOF_ABSOLUTE),
HID_RI_END_COLLECTION(0),
};
// The Plover HID report is sent with sizeof(report_plover_hid_t), but the endpoint and descriptor
// are sized with PLOVER_HID_EPSIZE; they must match or reports get truncated/padded.
STATIC_ASSERT(sizeof(report_plover_hid_t) == PLOVER_HID_EPSIZE, "report_plover_hid_t size must match PLOVER_HID_EPSIZE");
#endif
#ifdef CONSOLE_ENABLE
const USB_Descriptor_HIDReport_Datatype_t PROGMEM ConsoleReport[] = {
HID_RI_USAGE_PAGE(16, 0xFF31), // Vendor Defined (PJRC Teensy compatible)
@@ -643,6 +666,46 @@ const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptor = {
},
#endif
#ifdef PLOVER_HID_ENABLE
/*
* Plover HID
*/
.Plover_Interface = {
.Header = {
.Size = sizeof(USB_Descriptor_Interface_t),
.Type = DTYPE_Interface
},
.InterfaceNumber = PLOVER_HID_INTERFACE,
.AlternateSetting = 0x00,
.TotalEndpoints = 1,
.Class = HID_CSCP_HIDClass,
.SubClass = HID_CSCP_NonBootSubclass,
.Protocol = HID_CSCP_NonBootProtocol,
.InterfaceStrIndex = NO_DESCRIPTOR
},
.Plover_HID = {
.Header = {
.Size = sizeof(USB_HID_Descriptor_HID_t),
.Type = HID_DTYPE_HID
},
.HIDSpec = VERSION_BCD(1, 1, 1),
.CountryCode = 0x00,
.TotalReportDescriptors = 1,
.HIDReportType = HID_DTYPE_Report,
.HIDReportLength = sizeof(PloverReport)
},
.Plover_INEndpoint = {
.Header = {
.Size = sizeof(USB_Descriptor_Endpoint_t),
.Type = DTYPE_Endpoint
},
.EndpointAddress = (ENDPOINT_DIR_IN | PLOVER_HID_IN_EPNUM),
.Attributes = (EP_TYPE_INTERRUPT | ENDPOINT_ATTR_NO_SYNC | ENDPOINT_USAGE_DATA),
.EndpointSize = PLOVER_HID_EPSIZE,
.PollingIntervalMS = 0x01
},
#endif
#if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP)
/*
* Mouse
@@ -1285,6 +1348,14 @@ uint16_t get_usb_descriptor(const uint16_t wValue, const uint16_t wIndex, const
break;
#endif
#ifdef PLOVER_HID_ENABLE
case PLOVER_HID_INTERFACE:
Address = &ConfigurationDescriptor.Plover_HID;
Size = sizeof(USB_HID_Descriptor_HID_t);
break;
#endif
#ifdef CONSOLE_ENABLE
case CONSOLE_INTERFACE:
Address = &ConfigurationDescriptor.Console_HID;
@@ -1342,6 +1413,14 @@ uint16_t get_usb_descriptor(const uint16_t wValue, const uint16_t wIndex, const
break;
#endif
#ifdef PLOVER_HID_ENABLE
case PLOVER_HID_INTERFACE:
Address = &PloverReport;
Size = sizeof(PloverReport);
break;
#endif
#ifdef CONSOLE_ENABLE
case CONSOLE_INTERFACE:
Address = &ConsoleReport;
+16
View File
@@ -78,6 +78,13 @@ typedef struct {
USB_Descriptor_Endpoint_t Raw_OUTEndpoint;
#endif
#ifdef PLOVER_HID_ENABLE
// Plover HID Interface
USB_Descriptor_Interface_t Plover_Interface;
USB_HID_Descriptor_HID_t Plover_HID;
USB_Descriptor_Endpoint_t Plover_INEndpoint;
#endif
#if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP)
// Mouse HID Interface
USB_Descriptor_Interface_t Mouse_Interface;
@@ -164,6 +171,10 @@ enum usb_interfaces {
RAW_INTERFACE,
#endif
#ifdef PLOVER_HID_ENABLE
PLOVER_HID_INTERFACE,
#endif
#if defined(MOUSE_ENABLE) && !defined(MOUSE_SHARED_EP)
MOUSE_INTERFACE,
#endif
@@ -227,6 +238,10 @@ enum usb_endpoints {
# endif
#endif
#ifdef PLOVER_HID_ENABLE
PLOVER_HID_IN_EPNUM = NEXT_EPNUM,
#endif
#ifdef SHARED_EP_ENABLE
SHARED_IN_EPNUM = NEXT_EPNUM,
#endif
@@ -287,6 +302,7 @@ enum usb_endpoints {
#define SHARED_EPSIZE 32
#define MOUSE_EPSIZE 16
#define RAW_EPSIZE 32
#define PLOVER_HID_EPSIZE 9
#define CONSOLE_EPSIZE 32
#define MIDI_STREAM_EPSIZE 64
#define CDC_NOTIFICATION_EPSIZE 8
+83
View File
@@ -68,6 +68,10 @@ enum usb_interfaces {
RAW_INTERFACE,
#endif
#ifdef PLOVER_HID_ENABLE
PLOVER_HID_INTERFACE,
#endif
#if defined(SHARED_EP_ENABLE) && !defined(KEYBOARD_SHARED_EP)
SHARED_INTERFACE,
#endif
@@ -87,6 +91,10 @@ STATIC_ASSERT(TOTAL_INTERFACES <= MAX_INTERFACES, "There are not enough availabl
# error Mouse/Extra Keys share an endpoint with Console. Please disable one of the two.
#endif
#if defined(PLOVER_HID_ENABLE) && defined(RAW_ENABLE)
# error Plover HID shares an endpoint with Raw HID. Please disable one of the two.
#endif
static report_keyboard_t keyboard_report_sent;
static void send_report_fragment(uint8_t endpoint, void *data, size_t size) {
@@ -281,6 +289,14 @@ void send_programmable_button(report_programmable_button_t *report) {
#endif
}
#define PLOVER_HID_EPSIZE 9
void send_plover_hid(report_plover_hid_t *report) {
#ifdef PLOVER_HID_ENABLE
send_report(4, report, sizeof(report_plover_hid_t));
#endif
}
/*------------------------------------------------------------------*
* Request from host *
*------------------------------------------------------------------*/
@@ -771,6 +787,26 @@ const PROGMEM uchar raw_hid_report[] = {
};
#endif
#ifdef PLOVER_HID_ENABLE
// clang-format off
const PROGMEM uchar plover_hid_report[] = {
0x06, 0x50, 0xFF, // Usage Page (Vendor Defined)
0x0A, 0x56, 0x4C, // Usage (Vendor Defined) (0xff P L V)
0xA1, 0x01, // Collection (Application)
0x85, REPORT_ID_PLOVER_HID, // Report ID
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x40, // Report Count (43)
0x05, 0x0A, // Usage Page: Ordinal
0x19, 0x00, // Usage Minimum
0x29, 0x3F, // Usage Maximum (63)
0x81, 0x02, // Output (Data, Variable, Absolute)
0xC0 // End Collection
};
// clang-format on
#endif
#if defined(CONSOLE_ENABLE)
const PROGMEM uchar console_hid_report[] = {
0x06, 0x31, 0xFF, // Usage Page (Vendor Defined - PJRC Teensy compatible)
@@ -963,6 +999,46 @@ const PROGMEM usbConfigurationDescriptor_t usbConfigurationDescriptor = {
},
# endif
# if defined(PLOVER_HID_ENABLE)
/*
* Plover HID
*/
.ploverInterface = {
.header = {
.bLength = sizeof(usbInterfaceDescriptor_t),
.bDescriptorType = USBDESCR_INTERFACE
},
.bInterfaceNumber = PLOVER_HID_INTERFACE,
.bAlternateSetting = 0x00,
.bNumEndpoints = 1,
.bInterfaceClass = 0x03,
.bInterfaceSubClass = 0x00,
.bInterfaceProtocol = 0x00,
.iInterface = 0x00
},
.ploverHID = {
.header = {
.bLength = sizeof(usbHIDDescriptor_t),
.bDescriptorType = USBDESCR_HID
},
.bcdHID = 0x0101,
.bCountryCode = 0x00,
.bNumDescriptors = 1,
.bDescriptorType = USBDESCR_HID_REPORT,
.wDescriptorLength = sizeof(plover_hid_report)
},
.ploverINEndpoint = {
.header = {
.bLength = sizeof(usbEndpointDescriptor_t),
.bDescriptorType = USBDESCR_ENDPOINT
},
.bEndpointAddress = (USBRQ_DIR_DEVICE_TO_HOST | USB_CFG_EP4_NUMBER),
.bmAttributes = 0x03,
.wMaxPacketSize = PLOVER_HID_EPSIZE,
.bInterval = 0x01
},
# endif
# ifdef SHARED_EP_ENABLE
/*
* Shared
@@ -1140,6 +1216,13 @@ USB_PUBLIC usbMsgLen_t usbFunctionDescriptor(struct usbRequest *rq) {
break;
#endif
#if defined(PLOVER_HID_ENABLE)
case PLOVER_HID_INTERFACE:
usbMsgPtr = (usbMsgPtr_t)plover_hid_report;
len = sizeof(plover_hid_report);
break;
#endif
#ifdef SHARED_EP_ENABLE
case SHARED_INTERFACE:
usbMsgPtr = (usbMsgPtr_t)shared_hid_report;
+6
View File
@@ -104,6 +104,12 @@ typedef struct usbConfigurationDescriptor {
usbEndpointDescriptor_t rawOUTEndpoint;
#endif
#if defined(PLOVER_HID_ENABLE)
usbInterfaceDescriptor_t ploverInterface;
usbHIDDescriptor_t ploverHID;
usbEndpointDescriptor_t ploverINEndpoint;
#endif
#if defined(SHARED_EP_ENABLE) && !defined(KEYBOARD_SHARED_EP)
usbInterfaceDescriptor_t sharedInterface;
usbHIDDescriptor_t sharedHID;