Merge remote-tracking branch 'upstream/master' into fl16-july-merge

This commit is contained in:
Daniel Schaefer 2023-07-14 15:52:17 +08:00
commit cc3f63e8e3
15243 changed files with 590081 additions and 480796 deletions

4
.clangd Normal file
View File

@ -0,0 +1,4 @@
CompileFlags:
Add: [-Wno-unknown-attributes, -Wno-maybe-uninitialized, -Wno-unknown-warning-option]
Remove: [-W*, -mcall-prologues]
Compiler: clang

View File

@ -19,7 +19,7 @@ name: Update API Data
jobs:
api_data:
runs-on: ubuntu-latest
container: qmkfm/qmk_cli
container: ghcr.io/qmk/qmk_cli
# protect against those who work in their fork on 'important' branches
if: github.repository == 'qmk/qmk_firmware'

View File

@ -4,6 +4,7 @@ name: Essential files modified
# contents: write
#
#on:
# workflow_dispatch:
# push:
# branches:
# - master
@ -31,7 +32,7 @@ jobs:
fetch-depth: 0
- name: Bump version and push tag
uses: anothrNick/github-tag-action@1.61.0
uses: anothrNick/github-tag-action@1.66.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
DEFAULT_BUMP: 'patch'

View File

@ -5,23 +5,29 @@ permissions:
on:
push:
branches:
- master
- develop
branches: [master, develop]
workflow_dispatch:
inputs:
branch:
type: choice
description: 'Branch to build'
options: [master, develop]
concurrency: ci_build-${{ github.event.inputs.branch || github.ref_name }}
jobs:
ci_builds:
if: github.repository == 'qmk/qmk_firmware'
name: "CI Build"
runs-on: self-hosted
timeout-minutes: 1380
if: github.repository == 'qmk/qmk_firmware'
strategy:
fail-fast: false
matrix:
keymap: [default, via]
container: qmkfm/qmk_cli
container: ghcr.io/qmk/qmk_cli
steps:
- name: Disable safe.directory check
@ -30,19 +36,39 @@ jobs:
- uses: actions/checkout@v3
with:
submodules: recursive
ref: ${{ github.event.inputs.branch || github.ref }}
- name: Install dependencies
run: pip3 install -r requirements.txt
- name: Run `qmk mass-compile` (keymap ${{ matrix.keymap }})
run: qmk mass-compile -j $(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || getconf _NPROCESSORS_ONLN 2>/dev/null) -km ${{ matrix.keymap }}
run: |
export NCPUS=$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || getconf _NPROCESSORS_ONLN 2>/dev/null)
qmk mass-compile -t -j $NCPUS -km ${{ matrix.keymap }} -e DUMP_CI_METADATA=yes || touch .failed
# Generate the step summary markdown
./util/ci/generate_failure_markdown.sh > $GITHUB_STEP_SUMMARY || true
# Truncate to a maximum of 1MB to deal with GitHub workflow limit
truncate --size='<960K' $GITHUB_STEP_SUMMARY || true
# Exit with failure if the compilation stage failed
[ ! -f .failed ] || exit 1
- name: 'Upload binaries'
- name: 'Upload artifacts'
uses: actions/upload-artifact@v3
if: always()
with:
name: binaries-${{ matrix.keymap }}
name: artifacts-${{ github.event.inputs.branch || github.ref_name }}-${{ matrix.keymap }}
if-no-files-found: ignore
path: |
*.bin
*.hex
*.uf2
.build/failed.*
- name: 'CI Discord Notification'
if: always()
working-directory: util/ci/
env:
DISCORD_WEBHOOK: ${{ secrets.CI_DISCORD_WEBHOOK }}
run: |
python3 -m pip install -r requirements.txt
python3 ./discord-results.py --branch ${{ github.event.inputs.branch || github.ref_name }} --keymap ${{ matrix.keymap }} --url ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}

View File

@ -18,7 +18,7 @@ jobs:
test:
runs-on: ubuntu-latest
container: qmkfm/qmk_cli
container: ghcr.io/qmk/qmk_cli
steps:
- name: Disable safe.directory check

View File

@ -17,7 +17,7 @@ name: Generate Docs
jobs:
generate:
runs-on: ubuntu-latest
container: qmkfm/qmk_cli
container: ghcr.io/qmk/qmk_cli
# protect against those who develop with their fork on master
if: github.repository == 'qmk/qmk_firmware'
@ -37,7 +37,7 @@ jobs:
qmk --verbose generate-docs
- name: Deploy
uses: JamesIves/github-pages-deploy-action@v4.4.1
uses: JamesIves/github-pages-deploy-action@v4.4.3
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BASE_BRANCH: master

View File

@ -18,6 +18,7 @@ jobs:
matrix:
branch:
- xap
- riot
steps:
- uses: actions/checkout@v3

View File

@ -19,7 +19,7 @@ jobs:
lint:
runs-on: ubuntu-latest
container: qmkfm/qmk_cli
container: ghcr.io/qmk/qmk_cli
steps:
- name: Disable safe.directory check
@ -35,7 +35,7 @@ jobs:
- name: Get changed files
id: file_changes
uses: tj-actions/changed-files@v35
uses: tj-actions/changed-files@v37
- name: Run qmk formatters
shell: 'bash {0}'

View File

@ -13,7 +13,7 @@ jobs:
lint:
runs-on: ubuntu-latest
container: qmkfm/qmk_cli
container: ghcr.io/qmk/qmk_cli
steps:
- name: Disable safe.directory check
@ -47,7 +47,7 @@ jobs:
git config user.email 'hello@qmk.fm'
- name: Create Pull Request
uses: peter-evans/create-pull-request@v4
uses: peter-evans/create-pull-request@v5
if: ${{ github.repository == 'qmk/qmk_firmware'}}
with:
token: ${{ secrets.QMK_BOT_TOKEN }}

View File

@ -12,7 +12,7 @@ jobs:
lint:
runs-on: ubuntu-latest
container: qmkfm/qmk_cli
container: ghcr.io/qmk/qmk_cli
steps:
- name: Disable safe.directory check
@ -27,7 +27,7 @@ jobs:
- name: Get changed files
id: file_changes
uses: tj-actions/changed-files@v35
uses: tj-actions/changed-files@v37
- name: Print info
run: |
@ -36,6 +36,7 @@ jobs:
echo '${{ steps.file_changes.outputs.all_changed_files}}'
- name: Run qmk lint
if: always()
shell: 'bash {0}'
run: |
QMK_CHANGES=$(echo -e '${{ steps.file_changes.outputs.all_changed_files}}' | sed 's/ /\n/g')
@ -72,3 +73,32 @@ jobs:
exit 255
fi
exit $exit_code
- name: Verify at most one added keyboard
if: always()
shell: 'bash {0}'
run: |
git reset --hard
git clean -xfd
# Get the keyboard list and count for the target branch
git checkout -f ${{ github.base_ref }}
git pull --ff-only
QMK_KEYBOARDS_BASE=$(qmk list-keyboards)
QMK_KEYBOARDS_BASE_COUNT=$(qmk list-keyboards | wc -l)
# Get the keyboard list and count for the PR
git checkout -f ${{ github.head_ref }}
git merge --no-commit --squash ${{ github.base_ref }}
QMK_KEYBOARDS_PR=$(qmk list-keyboards)
QMK_KEYBOARDS_PR_COUNT=$(qmk list-keyboards | wc -l)
echo "::group::Keyboards changes in this PR"
diff -d -U 0 <(echo "$QMK_KEYBOARDS_BASE") <(echo "$QMK_KEYBOARDS_PR") | grep -vE '^(---|\+\+\+|@@)' | sed -e 's@^-@Removed: @g' -e 's@^+@ Added: @g'
echo "::endgroup::"
if [[ $QMK_KEYBOARDS_PR_COUNT -gt $(($QMK_KEYBOARDS_BASE_COUNT + 1)) ]]; then
echo "More than one keyboard added in this PR -- see the PR Checklist."
echo "::error::More than one keyboard added in this PR -- see the PR Checklist."
exit 1
fi

View File

@ -13,7 +13,7 @@ jobs:
regen:
runs-on: ubuntu-latest
container: qmkfm/qmk_cli
container: ghcr.io/qmk/qmk_cli
steps:
- name: Disable safe.directory check

View File

@ -13,7 +13,7 @@ jobs:
regen:
runs-on: ubuntu-latest
container: qmkfm/qmk_cli
container: ghcr.io/qmk/qmk_cli
steps:
- name: Disable safe.directory check
@ -34,7 +34,7 @@ jobs:
git config user.email 'hello@qmk.fm'
- name: Create Pull Request
uses: peter-evans/create-pull-request@v4
uses: peter-evans/create-pull-request@v5
if: ${{ github.repository == 'qmk/qmk_firmware'}}
with:
token: ${{ secrets.QMK_BOT_TOKEN }}

View File

@ -13,7 +13,7 @@ jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v7
- uses: actions/stale@v8
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}

View File

@ -23,7 +23,7 @@ jobs:
test:
runs-on: ubuntu-latest
container: qmkfm/qmk_cli
container: ghcr.io/qmk/qmk_cli
steps:
- uses: actions/checkout@v3

4
.gitignore vendored
View File

@ -30,6 +30,9 @@ quantum/version.h
*.qmk
*.uf2
# DD config at wrong location
/keyboards/**/keymaps/*/info.json
# Old-style QMK Makefiles
/keyboards/**/Makefile
@ -45,7 +48,6 @@ quantum/version.h
.idea/
.project
.settings/
.vagrant/
# ?
.dep

View File

@ -3,7 +3,7 @@
"recommendations": [
"EditorConfig.EditorConfig",
"xaver.clang-format",
"ms-vscode.cpptools",
"llvm-vs-code-extensions.vscode-clangd",
"bierner.github-markdown-preview",
"donjayamanne.git-extension-pack"
]

View File

@ -26,6 +26,9 @@
},
"python.formatting.provider": "yapf",
"[json]": {
"editor.formatOnSave": false
}
"editor.formatOnSave": false
},
"clangd.arguments": [
"--header-insertion=never"
]
}

View File

@ -1,6 +0,0 @@
FROM qmkfm/qmk_cli
VOLUME /qmk_firmware
WORKDIR /qmk_firmware
CMD qmk compile -kb all -km default

95
Vagrantfile vendored
View File

@ -1,95 +0,0 @@
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure(2) do |config|
# define a name instead of just 'default'
config.vm.define "qmk_firmware"
# VMware/Virtualbox ( and also Hyperv/Parallels) 64 bit
config.vm.box = "generic/debian10"
config.vm.synced_folder '.', '/vagrant'
# This section allows you to customize the Virtualbox VM
# settings, ie showing the GUI or upping the memory
# or cores if desired
config.vm.provider "virtualbox" do |vb|
# Hide the VirtualBox GUI when booting the machine
vb.gui = false
# Uncomment the below lines if you want to program
# your Teensy via the VM rather than your host OS
#vb.customize ['modifyvm', :id, '--usb', 'on']
#vb.customize ['usbfilter', 'add', '0',
# '--target', :id,
# '--name', 'teensy',
# '--vendorid', '0x16c0',
# '--productid','0x0478'
# ]
# Customize the amount of memory on the VM:
vb.memory = "512"
# Uncomment the below lines if you have time sync
# issues with make and incremental builds
#vb.customize [ "guestproperty", "set", :id, "/VirtualBox/GuestAdd/VBoxService/--timesync-set-threshold", 1000 ]
end
# This section allows you to customize the VMware VM
# settings, ie showing the GUI or upping the memory
# or cores if desired
config.vm.provider "vmware_workstation" do |vmw|
# Hide the VMware GUI when booting the machine
vmw.gui = false
# Customize the amount of memory on the VM:
vmw.memory = "512"
end
config.vm.provider "vmware_fusion" do |vmf|
# Hide the vmfare GUI when booting the machine
vmf.gui = false
# Customize the amount of memory on the VM:
vmf.memory = "512"
end
# Docker provider pulls from hub.docker.com respecting docker.image if
# config.vm.box is nil. In this case, we adhoc build util/vagrant/Dockerfile.
# Note that this bind-mounts from the current dir to
# /vagrant in the guest, so unless your UID is 1000 to match vagrant in the
# image, you'll need to: chmod -R a+rw .
config.vm.provider "docker" do |docker, override|
override.vm.box = nil
docker.build_dir = "util/vagrant"
docker.has_ssh = true
end
# Unless we are running the docker container directly
# 1. run container detached on vm
# 2. attach on 'vagrant ssh'
["virtualbox", "vmware_workstation", "vmware_fusion"].each do |type|
config.vm.provider type do |virt, override|
override.vm.provision "docker" do |d|
d.run "qmkfm/qmk_cli",
cmd: "tail -f /dev/null",
args: "--privileged -v /dev:/dev -v '/vagrant:/vagrant'"
end
override.vm.provision "shell", inline: <<-SHELL
echo 'docker restart qmkfm-qmk_cli && exec docker exec -it qmkfm-qmk_cli /bin/bash -l' >> ~vagrant/.bashrc
SHELL
end
end
config.vm.post_up_message = <<-EOT
Log into the environment using 'vagrant ssh'. QMK directory synchronized with
host is located at /vagrant
To compile the .hex files use make command inside this directory, e.g.
cd /vagrant
make <keyboard>:default
Examples:
make planck/rev4:default:dfu
make planck/rev4:default
EOT
end

View File

@ -29,6 +29,11 @@ KEYBOARD_FILESAFE := $(subst /,_,$(KEYBOARD))
TARGET ?= $(KEYBOARD_FILESAFE)_$(KEYMAP)
KEYBOARD_OUTPUT := $(BUILD_DIR)/obj_$(KEYBOARD_FILESAFE)
ifeq ($(strip $(DUMP_CI_METADATA)),yes)
$(info CI Metadata: KEYBOARD=$(KEYBOARD))
$(info CI Metadata: KEYMAP=$(KEYMAP))
endif
# Force expansion
TARGET := $(TARGET)
@ -338,6 +343,15 @@ $(KEYBOARD_OUTPUT)/src/default_keyboard.h: $(INFO_JSON_FILES)
generated-files: $(KEYBOARD_OUTPUT)/src/info_config.h $(KEYBOARD_OUTPUT)/src/default_keyboard.c $(KEYBOARD_OUTPUT)/src/default_keyboard.h
generated-files: $(KEYMAP_OUTPUT)/src/info_deps.d
$(KEYMAP_OUTPUT)/src/info_deps.d:
@$(SILENT) || printf "$(MSG_GENERATING) $@" | $(AWK_CMD)
$(eval CMD=$(QMK_BIN) generate-make-dependencies -kb $(KEYBOARD) -km $(KEYMAP) -o $(KEYMAP_OUTPUT)/src/info_deps.d)
@$(BUILD_CMD)
-include $(KEYMAP_OUTPUT)/src/info_deps.d
.INTERMEDIATE : generated-files
# Userspace setup and definitions
@ -441,6 +455,14 @@ $(eval $(call add_qmk_prefix_defs,MCU_FAMILY,MCU_FAMILY))
$(eval $(call add_qmk_prefix_defs,MCU_SERIES,MCU_SERIES))
$(eval $(call add_qmk_prefix_defs,BOARD,BOARD))
# Control whether intermediate file listings are generated
# e.g.:
# make handwired/onekey/blackpill_f411:default KEEP_INTERMEDIATES=yes
# cat .build/obj_handwired_onekey_blackpill_f411_default/quantum/quantum.i | sed -e 's@^#.*@@g' -e 's@^\s*//.*@@g' -e '/^\s*$/d' | clang-format
ifeq ($(strip $(KEEP_INTERMEDIATES)), yes)
OPT_DEFS += -save-temps=obj
endif
# TODO: remove this bodge?
PROJECT_DEFS := $(OPT_DEFS)
PROJECT_INC := $(VPATH) $(EXTRAINCDIRS) $(KEYBOARD_PATHS)

View File

@ -75,6 +75,10 @@ $(TEST)_SRC += \
tests/test_common/main.cpp \
$(QUANTUM_PATH)/logging/print.c
ifneq ($(strip $(INTROSPECTION_KEYMAP_C)),)
$(TEST)_DEFS += -DINTROSPECTION_KEYMAP_C=\"$(strip $(INTROSPECTION_KEYMAP_C))\"
endif
$(TEST_OBJ)/$(TEST)_SRC := $($(TEST)_SRC)
$(TEST_OBJ)/$(TEST)_INC := $($(TEST)_INC) $(VPATH) $(GTEST_INC)
$(TEST_OBJ)/$(TEST)_DEFS := $($(TEST)_DEFS)

View File

@ -134,7 +134,7 @@ ifeq ($(strip $(MOUSEKEY_ENABLE)), yes)
SRC += $(QUANTUM_DIR)/mousekey.c
endif
VALID_POINTING_DEVICE_DRIVER_TYPES := adns5050 adns9800 analog_joystick cirque_pinnacle_i2c cirque_pinnacle_spi paw3204 pmw3360 pmw3389 pimoroni_trackball custom
VALID_POINTING_DEVICE_DRIVER_TYPES := adns5050 adns9800 analog_joystick cirque_pinnacle_i2c cirque_pinnacle_spi paw3204 pmw3320 pmw3360 pmw3389 pimoroni_trackball custom
ifeq ($(strip $(POINTING_DEVICE_ENABLE)), yes)
ifeq ($(filter $(POINTING_DEVICE_DRIVER),$(VALID_POINTING_DEVICE_DRIVER_TYPES)),)
$(call CATASTROPHIC_ERROR,Invalid POINTING_DEVICE_DRIVER,POINTING_DEVICE_DRIVER="$(POINTING_DEVICE_DRIVER)" is not a valid pointing device type)
@ -213,10 +213,10 @@ else
SRC += eeprom_driver.c eeprom_spi.c
else ifeq ($(strip $(EEPROM_DRIVER)), legacy_stm32_flash)
# STM32 Emulated EEPROM, backed by MCU flash (soon to be deprecated)
OPT_DEFS += -DEEPROM_DRIVER -DEEPROM_STM32_FLASH_EMULATED
OPT_DEFS += -DEEPROM_DRIVER -DEEPROM_LEGACY_EMULATED_FLASH
COMMON_VPATH += $(PLATFORM_PATH)/$(PLATFORM_KEY)/$(DRIVER_DIR)/flash
COMMON_VPATH += $(DRIVER_PATH)/flash
SRC += eeprom_driver.c eeprom_stm32.c flash_stm32.c
SRC += eeprom_driver.c eeprom_legacy_emulated_flash.c legacy_flash_ops.c
else ifeq ($(strip $(EEPROM_DRIVER)), transient)
# Transient EEPROM implementation -- no data storage but provides runtime area for it
OPT_DEFS += -DEEPROM_DRIVER -DEEPROM_TRANSIENT
@ -419,7 +419,7 @@ endif
RGB_MATRIX_ENABLE ?= no
VALID_RGB_MATRIX_TYPES := AW20216 IS31FL3731 IS31FL3733 IS31FL3737 IS31FL3741 IS31FL3742A IS31FL3743A IS31FL3745 IS31FL3746A CKLED2001 WS2812 custom
VALID_RGB_MATRIX_TYPES := AW20216 IS31FL3731 IS31FL3733 IS31FL3736 IS31FL3737 IS31FL3741 IS31FL3742A IS31FL3743A IS31FL3745 IS31FL3746A CKLED2001 WS2812 custom
ifeq ($(strip $(RGB_MATRIX_ENABLE)), yes)
ifeq ($(filter $(RGB_MATRIX_DRIVER),$(VALID_RGB_MATRIX_TYPES)),)
$(call CATASTROPHIC_ERROR,Invalid RGB_MATRIX_DRIVER,RGB_MATRIX_DRIVER="$(RGB_MATRIX_DRIVER)" is not a valid matrix type)
@ -460,6 +460,13 @@ endif
QUANTUM_LIB_SRC += i2c_master.c
endif
ifeq ($(strip $(RGB_MATRIX_DRIVER)), IS31FL3736)
OPT_DEFS += -DIS31FL3736 -DSTM32_I2C -DHAL_USE_I2C=TRUE
COMMON_VPATH += $(DRIVER_PATH)/led/issi
SRC += is31fl3736.c
QUANTUM_LIB_SRC += i2c_master.c
endif
ifeq ($(strip $(RGB_MATRIX_DRIVER)), IS31FL3737)
OPT_DEFS += -DIS31FL3737 -DSTM32_I2C -DHAL_USE_I2C=TRUE
COMMON_VPATH += $(DRIVER_PATH)/led/issi
@ -574,7 +581,7 @@ ifeq ($(strip $(BACKLIGHT_ENABLE)), yes)
endif
endif
VALID_WS2812_DRIVER_TYPES := bitbang pwm spi i2c vendor
VALID_WS2812_DRIVER_TYPES := bitbang custom i2c pwm spi vendor
WS2812_DRIVER ?= bitbang
ifeq ($(strip $(WS2812_DRIVER_REQUIRED)), yes)
@ -584,15 +591,11 @@ ifeq ($(strip $(WS2812_DRIVER_REQUIRED)), yes)
OPT_DEFS += -DWS2812_DRIVER_$(strip $(shell echo $(WS2812_DRIVER) | tr '[:lower:]' '[:upper:]'))
ifeq ($(strip $(WS2812_DRIVER)), bitbang)
SRC += ws2812.c
else
SRC += ws2812_$(strip $(WS2812_DRIVER)).c
SRC += ws2812_$(strip $(WS2812_DRIVER)).c
ifeq ($(strip $(PLATFORM)), CHIBIOS)
ifeq ($(strip $(WS2812_DRIVER)), pwm)
OPT_DEFS += -DSTM32_DMA_REQUIRED=TRUE
endif
ifeq ($(strip $(PLATFORM)), CHIBIOS)
ifeq ($(strip $(WS2812_DRIVER)), pwm)
OPT_DEFS += -DSTM32_DMA_REQUIRED=TRUE
endif
endif
@ -741,17 +744,28 @@ endif
VALID_OLED_DRIVER_TYPES := SSD1306 custom
OLED_DRIVER ?= SSD1306
VALID_OLED_TRANSPORT_TYPES := i2c spi custom
OLED_TRANSPORT ?= i2c
ifeq ($(strip $(OLED_ENABLE)), yes)
ifeq ($(filter $(OLED_DRIVER),$(VALID_OLED_DRIVER_TYPES)),)
$(call CATASTROPHIC_ERROR,Invalid OLED_DRIVER,OLED_DRIVER="$(OLED_DRIVER)" is not a valid OLED driver)
else
OPT_DEFS += -DOLED_ENABLE
COMMON_VPATH += $(DRIVER_PATH)/oled
ifeq ($(filter $(OLED_TRANSPORT),$(VALID_OLED_TRANSPORT_TYPES)),)
$(call CATASTROPHIC_ERROR,Invalid OLED_TRANSPORT,OLED_TRANSPORT="$(OLED_TRANSPORT)" is not a valid OLED transport)
else
OPT_DEFS += -DOLED_ENABLE
COMMON_VPATH += $(DRIVER_PATH)/oled
ifneq ($(strip $(OLED_DRIVER)), custom)
SRC += oled_driver.c
endif
OPT_DEFS += -DOLED_DRIVER_$(strip $(shell echo $(OLED_DRIVER) | tr '[:lower:]' '[:upper:]'))
ifeq ($(strip $(OLED_DRIVER)), SSD1306)
SRC += ssd1306_sh1106.c
QUANTUM_LIB_SRC += i2c_master.c
OPT_DEFS += -DOLED_TRANSPORT_$(strip $(shell echo $(OLED_TRANSPORT) | tr '[:lower:]' '[:upper:]'))
ifeq ($(strip $(OLED_TRANSPORT)), i2c)
QUANTUM_LIB_SRC += i2c_master.c
endif
ifeq ($(strip $(OLED_TRANSPORT)), spi)
QUANTUM_LIB_SRC += spi_master.c
endif
endif
endif
endif
@ -813,9 +827,9 @@ endif
ifeq ($(strip $(PS2_MOUSE_ENABLE)), yes)
PS2_ENABLE := yes
MOUSE_ENABLE := yes
SRC += ps2_mouse.c
OPT_DEFS += -DPS2_MOUSE_ENABLE
OPT_DEFS += -DMOUSE_ENABLE
endif
VALID_PS2_DRIVER_TYPES := busywait interrupt usart vendor
@ -892,10 +906,11 @@ ifeq ($(strip $(BLUETOOTH_ENABLE)), yes)
OPT_DEFS += -DBLUETOOTH_ENABLE
NO_USB_STARTUP_CHECK := yes
COMMON_VPATH += $(DRIVER_PATH)/bluetooth
SRC += outputselect.c bluetooth.c
SRC += outputselect.c
ifeq ($(strip $(BLUETOOTH_DRIVER)), BluefruitLE)
OPT_DEFS += -DBLUETOOTH_BLUEFRUIT_LE -DHAL_USE_SPI=TRUE
SRC += $(DRIVER_PATH)/bluetooth/bluetooth.c
SRC += $(DRIVER_PATH)/bluetooth/bluefruit_le.cpp
QUANTUM_LIB_SRC += analog.c
QUANTUM_LIB_SRC += spi_master.c
@ -903,6 +918,7 @@ ifeq ($(strip $(BLUETOOTH_ENABLE)), yes)
ifeq ($(strip $(BLUETOOTH_DRIVER)), RN42)
OPT_DEFS += -DBLUETOOTH_RN42 -DHAL_USE_SERIAL=TRUE
SRC += $(DRIVER_PATH)/bluetooth/bluetooth.c
SRC += $(DRIVER_PATH)/bluetooth/rn42.c
QUANTUM_LIB_SRC += uart.c
endif

View File

@ -152,6 +152,7 @@ endif
# To produce a UF2 file in your build, add to your keyboard's rules.mk:
# FIRMWARE_FORMAT = uf2
UF2CONV = $(TOP_DIR)/util/uf2conv.py
UF2CONV_ARGS ?=
UF2_FAMILY ?= 0x0
# Compiler flags to generate dependency files.
@ -219,7 +220,7 @@ gccversion :
@$(BUILD_CMD)
%.uf2: %.elf
$(eval CMD=$(HEX) $< $(BUILD_DIR)/$(TARGET).tmp && $(UF2CONV) $(BUILD_DIR)/$(TARGET).tmp --output $@ --convert --family $(UF2_FAMILY) >/dev/null 2>&1)
$(eval CMD=$(HEX) $< $(BUILD_DIR)/$(TARGET).tmp && $(UF2CONV) $(UF2CONV_ARGS) $(BUILD_DIR)/$(TARGET).tmp --output $@ --convert --family $(UF2_FAMILY) >/dev/null 2>&1)
#@$(SILENT) || printf "$(MSG_EXECUTING) '$(CMD)':\n"
@$(SILENT) || printf "$(MSG_UF2) $@" | $(AWK_CMD)
@$(BUILD_CMD)

View File

@ -7,7 +7,12 @@ endif
# TODO: opt in rather than assume everything uses a pro micro
PIN_COMPATIBLE ?= promicro
# Remove whitespace from any rule.mk provided vars
# - env cannot be overwritten but cannot have whitespace anyway
CONVERT_TO:=$(strip $(CONVERT_TO))
ifneq ($(CONVERT_TO),)
# stash so we can overwrite env provided vars if needed
ACTIVE_CONVERTER=$(CONVERT_TO)
@ -23,13 +28,13 @@ ifneq ($(CONVERT_TO),)
TARGET := $(TARGET)_$(CONVERT_TO)
# Configure any defaults
OPT_DEFS += -DCONVERT_TO_$(strip $(shell echo $(CONVERT_TO) | tr '[:lower:]' '[:upper:]'))
OPT_DEFS += -DCONVERTER_TARGET=\"$(strip $(CONVERT_TO))\"
OPT_DEFS += -DCONVERT_TO_$(shell echo $(CONVERT_TO) | tr '[:lower:]' '[:upper:]')
OPT_DEFS += -DCONVERTER_TARGET=\"$(CONVERT_TO)\"
OPT_DEFS += -DCONVERTER_ENABLED
VPATH += $(CONVERTER)
# Configure for "alias" - worst case it produces an idential define
OPT_DEFS += -DCONVERT_TO_$(strip $(shell echo $(ACTIVE_CONVERTER) | tr '[:lower:]' '[:upper:]'))
OPT_DEFS += -DCONVERT_TO_$(shell echo $(ACTIVE_CONVERTER) | tr '[:lower:]' '[:upper:]')
# Finally run any converter specific logic
include $(CONVERTER)/converter.mk

View File

@ -32,6 +32,7 @@ GENERIC_FEATURES = \
KEY_OVERRIDE \
LEADER \
PROGRAMMABLE_BUTTON \
REPEAT_KEY \
SECURE \
SPACE_CADET \
SWAP_HANDS \

View File

@ -85,7 +85,8 @@ OTHER_OPTION_NAMES = \
SECURE_ENABLE \
CAPS_WORD_ENABLE \
AUTOCORRECT_ENABLE \
TRI_LAYER_ENABLE
TRI_LAYER_ENABLE \
REPEAT_KEY_ENABLE
define NAME_ECHO
@printf " %-30s = %-16s # %s\\n" "$1" "$($1)" "$(origin $1)"

View File

@ -0,0 +1,18 @@
{
"keycodes": {
"0x7C79": {
"group": "quantum",
"key": "QK_REPEAT_KEY",
"aliases": [
"QK_REP"
]
},
"0x7C7A": {
"group": "quantum",
"key": "QK_ALT_REPEAT_KEY",
"aliases": [
"QK_AREP"
]
}
}
}

View File

@ -33,7 +33,7 @@
"blok": {
"processor": "RP2040",
"bootloader": "rp2040",
"board": "QMK_PM2040"
"board": "QMK_BLOK"
},
"michi": {
"processor": "RP2040",
@ -74,6 +74,11 @@
"processor": "RP2040",
"bootloader": "rp2040",
"board": "QMK_PM2040"
},
"liatris": {
"processor": "RP2040",
"bootloader": "rp2040",
"board": "QMK_PM2040"
}
}
}

View File

@ -10,95 +10,129 @@
// deprecated: Default `false`. Set to `true` to turn on warning when a value exists
// invalid: Default `false`. Set to `true` to generate errors when a value exists
// replace_with: use with a key marked deprecated or invalid to designate a replacement
// APA102
"APA102_CI_PIN": {"info_key": "apa102.clock_pin"},
"APA102_DEFAULT_BRIGHTNESS": {"info_key": "apa102.default_brightness", "value_type": "int"},
"APA102_DI_PIN": {"info_key": "apa102.data_pin"},
// Audio
"AUDIO_VOICES": {"info_key": "audio.voices", "value_type": "bool"},
"SENDSTRING_BELL": {"info_key": "audio.macro_beep", "value_type": "bool"},
// Backlight
"BACKLIGHT_BREATHING": {"info_key": "backlight.breathing", "value_type": "bool"},
"BREATHING_PERIOD": {"info_key": "backlight.breathing_period", "value_type": "int"},
"BACKLIGHT_CAPS_LOCK": {"info_key": "backlight.as_caps_lock", "value_type": "bool"},
"BACKLIGHT_LEVELS": {"info_key": "backlight.levels", "value_type": "int"},
"BACKLIGHT_LIMIT_VAL": {"info_key": "backlight.max_brightness", "value_type": "int"},
"BACKLIGHT_ON_STATE": {"info_key": "backlight.on_state", "value_type": "int"},
"BACKLIGHT_PIN": {"info_key": "backlight.pin"},
"BACKLIGHT_PINS": {"info_key": "backlight.pins", "value_type": "array"},
"BOOTMAGIC_LITE_ROW": {"info_key": "bootmagic.matrix.0", "value_type": "int"},
"BREATHING_PERIOD": {"info_key": "backlight.breathing_period", "value_type": "int"},
// Bootmagic
"BOOTMAGIC_LITE_COLUMN": {"info_key": "bootmagic.matrix.1", "value_type": "int"},
"BOOTMAGIC_LITE_ROW_RIGHT": {"info_key": "split.bootmagic.matrix.0", "value_type": "int"},
"BOOTMAGIC_LITE_COLUMN_RIGHT": {"info_key": "split.bootmagic.matrix.1", "value_type": "int"},
"BOOTMAGIC_LITE_ROW": {"info_key": "bootmagic.matrix.0", "value_type": "int"},
"BOOTMAGIC_LITE_ROW_RIGHT": {"info_key": "split.bootmagic.matrix.0", "value_type": "int"},
// Caps Word
"BOTH_SHIFTS_TURNS_ON_CAPS_WORD": {"info_key": "caps_word.both_shifts_turns_on", "value_type": "bool"},
"CAPS_WORD_IDLE_TIMEOUT": {"info_key": "caps_word.idle_timeout", "value_type": "int"},
"COMBO_COUNT": {"info_key": "combo.count", "value_type": "int"},
"COMBO_TERM": {"info_key": "combo.term", "value_type": "int"},
"DEBOUNCE": {"info_key": "debounce", "value_type": "int"},
"DIODE_DIRECTION": {"info_key": "diode_direction"},
"CAPS_WORD_INVERT_ON_SHIFT": {"info_key": "caps_word.invert_on_shift", "value_type": "bool"},
"DOUBLE_TAP_SHIFT_TURNS_ON_CAPS_WORD": {"info_key": "caps_word.double_tap_shift_turns_on", "value_type": "bool"},
"FORCE_NKRO": {"info_key": "usb.force_nkro", "value_type": "bool"},
// Combos
"COMBO_TERM": {"info_key": "combo.term", "value_type": "int"},
// Dynamic Keymap
"DYNAMIC_KEYMAP_EEPROM_MAX_ADDR": {"info_key": "dynamic_keymap.eeprom_max_addr", "value_type": "int"},
"DYNAMIC_KEYMAP_LAYER_COUNT": {"info_key": "dynamic_keymap.layer_count", "value_type": "int"},
"HOLD_ON_OTHER_KEY_PRESS": {"info_key": "tapping.hold_on_other_key_press", "value_type": "bool"},
"HOLD_ON_OTHER_KEY_PRESS_PER_KEY": {"info_key": "tapping.hold_on_other_key_press_per_key", "value_type": "bool"},
"LAYOUTS": {"info_key": "layout_aliases", "value_type": "mapping"},
"LEADER_PER_KEY_TIMING": {"info_key": "leader_key.timing", "value_type": "bool"},
"LEADER_KEY_STRICT_KEY_PROCESSING": {"info_key": "leader_key.strict_processing", "value_type": "bool"},
"LEADER_TIMEOUT": {"info_key": "leader_key.timeout", "value_type": "int"},
// Indicators
"LED_CAPS_LOCK_PIN": {"info_key": "indicators.caps_lock"},
"LED_NUM_LOCK_PIN": {"info_key": "indicators.num_lock"},
"LED_SCROLL_LOCK_PIN": {"info_key": "indicators.scroll_lock"},
"LED_COMPOSE_PIN": {"info_key": "indicators.compose"},
"LED_KANA_PIN": {"info_key": "indicators.kana"},
"LED_PIN_ON_STATE": {"info_key": "indicators.on_state", "value_type": "int"},
// Leader Key
"LEADER_PER_KEY_TIMING": {"info_key": "leader_key.timing", "value_type": "bool"},
"LEADER_KEY_STRICT_KEY_PROCESSING": {"info_key": "leader_key.strict_processing", "value_type": "bool"},
"LEADER_TIMEOUT": {"info_key": "leader_key.timeout", "value_type": "int"},
// LED Matrix
"LED_MATRIX_CENTER": {"info_key": "led_matrix.center_point", "value_type": "array.int"},
"LED_MATRIX_HUE_STEP": {"info_key": "led_matrix.hue_steps", "value_type": "int"},
"LED_MATRIX_MAXIMUM_BRIGHTNESS": {"info_key": "led_matrix.max_brightness", "value_type": "int"},
"LED_MATRIX_SAT_STEP": {"info_key": "led_matrix.sat_steps", "value_type": "int"},
"LED_MATRIX_SPD_STEP": {"info_key": "led_matrix.speed_steps", "value_type": "int"},
"LED_MATRIX_SPLIT": {"info_key": "led_matrix.split_count", "value_type": "array.int"},
"LED_MATRIX_TIMEOUT": {"info_key": "led_matrix.timeout", "value_type": "int"},
"LED_MATRIX_HUE_STEP": {"info_key": "led_matrix.hue_steps", "value_type": "int"},
"LED_MATRIX_SAT_STEP": {"info_key": "led_matrix.sat_steps", "value_type": "int"},
"LED_MATRIX_VAL_STEP": {"info_key": "led_matrix.val_steps", "value_type": "int"},
"LED_MATRIX_SPD_STEP": {"info_key": "led_matrix.speed_steps", "value_type": "int"},
// LUFA Bootloader
"QMK_ESC_INPUT": {"info_key": "qmk_lufa_bootloader.esc_input"},
"QMK_ESC_OUTPUT": {"info_key": "qmk_lufa_bootloader.esc_output"},
"QMK_LED": {"info_key": "qmk_lufa_bootloader.led"},
"QMK_SPEAKER": {"info_key": "qmk_lufa_bootloader.speaker"},
// Matrix
"DEBOUNCE": {"info_key": "debounce", "value_type": "int"},
"DIODE_DIRECTION": {"info_key": "diode_direction"},
"MATRIX_HAS_GHOST": {"info_key": "matrix_pins.ghost", "value_type": "bool"},
"MATRIX_INPUT_PRESSED_STATE": {"info_key": "matrix_pins.input_pressed_state", "value_type": "int"},
"MATRIX_IO_DELAY": {"info_key": "matrix_pins.io_delay", "value_type": "int"},
// Mouse Keys
"MOUSEKEY_DELAY": {"info_key": "mousekey.delay", "value_type": "int"},
"MOUSEKEY_INTERVAL": {"info_key": "mousekey.interval", "value_type": "int"},
"MOUSEKEY_MAX_SPEED": {"info_key": "mousekey.max_speed", "value_type": "int"},
"MOUSEKEY_TIME_TO_MAX": {"info_key": "mousekey.time_to_max", "value_type": "int"},
"MOUSEKEY_WHEEL_DELAY": {"info_key": "mousekey.wheel_delay", "value_type": "int"},
// One Shot
"ONESHOT_TIMEOUT": {"info_key": "oneshot.timeout", "value_type": "int"},
"ONESHOT_TAP_TOGGLE": {"info_key": "oneshot.tap_toggle", "value_type": "int"},
"PERMISSIVE_HOLD": {"info_key": "tapping.permissive_hold", "value_type": "bool"},
"PERMISSIVE_HOLD_PER_KEY": {"info_key": "tapping.permissive_hold_per_key", "value_type": "bool"},
// PS/2
"PS2_CLOCK_PIN": {"info_key": "ps2.clock_pin"},
"PS2_DATA_PIN": {"info_key": "ps2.data_pin"},
"RETRO_TAPPING": {"info_key": "tapping.retro", "value_type": "bool"},
"RETRO_TAPPING_PER_KEY": {"info_key": "tapping.retro_per_key", "value_type": "bool"},
"RGB_DI_PIN": {"info_key": "rgblight.pin"},
// RGB Matrix
"RGB_MATRIX_CENTER": {"info_key": "rgb_matrix.center_point", "value_type": "array.int"},
"RGB_MATRIX_HUE_STEP": {"info_key": "rgb_matrix.hue_steps", "value_type": "int"},
"RGB_MATRIX_MAXIMUM_BRIGHTNESS": {"info_key": "rgb_matrix.max_brightness", "value_type": "int"},
"RGB_MATRIX_SAT_STEP": {"info_key": "rgb_matrix.sat_steps", "value_type": "int"},
"RGB_MATRIX_SPD_STEP": {"info_key": "rgb_matrix.speed_steps", "value_type": "int"},
"RGB_MATRIX_SPLIT": {"info_key": "rgb_matrix.split_count", "value_type": "array.int"},
"RGB_MATRIX_TIMEOUT": {"info_key": "rgb_matrix.timeout", "value_type": "int"},
"RGB_MATRIX_VAL_STEP": {"info_key": "rgb_matrix.val_steps", "value_type": "int"},
// RGBLight
"RGBLED_NUM": {"info_key": "rgblight.led_count", "value_type": "int"},
"RGBLED_SPLIT": {"info_key": "rgblight.split_count", "value_type": "array.int"},
"RGBLIGHT_HUE_STEP": {"info_key": "rgblight.hue_steps", "value_type": "int"},
"RGBLIGHT_LAYER_BLINK": {"info_key": "rgblight.layers.blink", "value_type": "bool"},
"RGBLIGHT_LAYERS": {"info_key": "rgblight.layers.enabled", "value_type": "bool"},
"RGBLIGHT_LAYERS_OVERRIDE_RGB_OFF": {"info_key": "rgblight.layers.override_rgb", "value_type": "bool"},
"RGBLIGHT_LIMIT_VAL": {"info_key": "rgblight.max_brightness", "value_type": "int"},
"RGBLIGHT_MAX_LAYERS": {"info_key": "rgblight.layers.max", "value_type": "int"},
"RGBLIGHT_HUE_STEP": {"info_key": "rgblight.hue_steps", "value_type": "int"},
"RGBLIGHT_SAT_STEP": {"info_key": "rgblight.saturation_steps", "value_type": "int"},
"RGBLIGHT_VAL_STEP": {"info_key": "rgblight.brightness_steps", "value_type": "int"},
"RGBLIGHT_SLEEP": {"info_key": "rgblight.sleep", "value_type": "bool"},
"RGBLIGHT_SPLIT": {"info_key": "rgblight.split", "value_type": "bool"},
"RGB_MATRIX_CENTER": {"info_key": "rgb_matrix.center_point", "value_type": "array.int"},
"RGB_MATRIX_MAXIMUM_BRIGHTNESS": {"info_key": "rgb_matrix.max_brightness", "value_type": "int"},
"RGB_MATRIX_SPLIT": {"info_key": "rgb_matrix.split_count", "value_type": "array.int"},
"RGB_MATRIX_TIMEOUT": {"info_key": "rgb_matrix.timeout", "value_type": "int"},
"RGB_MATRIX_HUE_STEP": {"info_key": "rgb_matrix.hue_steps", "value_type": "int"},
"RGB_MATRIX_SAT_STEP": {"info_key": "rgb_matrix.sat_steps", "value_type": "int"},
"RGB_MATRIX_VAL_STEP": {"info_key": "rgb_matrix.val_steps", "value_type": "int"},
"RGB_MATRIX_SPD_STEP": {"info_key": "rgb_matrix.speed_steps", "value_type": "int"},
"RGBLIGHT_VAL_STEP": {"info_key": "rgblight.brightness_steps", "value_type": "int"},
"RGBW": {"info_key": "rgblight.rgbw", "value_type": "bool"},
"QMK_ESC_OUTPUT": {"info_key": "qmk_lufa_bootloader.esc_output"},
"QMK_ESC_INPUT": {"info_key": "qmk_lufa_bootloader.esc_input"},
"QMK_LED": {"info_key": "qmk_lufa_bootloader.led"},
"QMK_SPEAKER": {"info_key": "qmk_lufa_bootloader.speaker"},
// Secure
"SECURE_IDLE_TIMEOUT": {"info_key": "secure.idle_timeout", "value_type": "int"},
"SECURE_UNLOCK_SEQUENCE": {"info_key": "secure.unlock_sequence", "value_type": "array.array.int", "to_json": false},
"SECURE_UNLOCK_TIMEOUT": {"info_key": "secure.unlock_timeout", "value_type": "int"},
"SECURE_IDLE_TIMEOUT": {"info_key": "secure.idle_timeout", "value_type": "int"},
"SENDSTRING_BELL": {"info_key": "audio.macro_beep", "value_type": "bool"},
// Split Keyboard
"SOFT_SERIAL_PIN": {"info_key": "split.soft_serial_pin"},
"SOFT_SERIAL_SPEED": {"info_key": "split.soft_serial_speed"},
"SPLIT_MODS_ENABLE": {"info_key": "split.transport.sync_modifiers", "value_type": "bool"},
"SPLIT_TRANSPORT_MIRROR": {"info_key": "split.transport.sync_matrix_state", "value_type": "bool"},
"SPLIT_USB_DETECT": {"info_key": "split.usb_detect.enabled", "value_type": "bool"},
@ -106,35 +140,53 @@
"SPLIT_USB_TIMEOUT_POLL": {"info_key": "split.usb_detect.polling_interval", "value_type": "int"},
"SPLIT_WATCHDOG_ENABLE": {"info_key": "split.transport.watchdog", "value_type": "bool"},
"SPLIT_WATCHDOG_TIMEOUT": {"info_key": "split.transport.watchdog_timeout", "value_type": "int"},
"SOFT_SERIAL_PIN": {"info_key": "split.soft_serial_pin"},
"SOFT_SERIAL_SPEED": {"info_key": "split.soft_serial_speed"},
// Tapping
"HOLD_ON_OTHER_KEY_PRESS": {"info_key": "tapping.hold_on_other_key_press", "value_type": "bool"},
"HOLD_ON_OTHER_KEY_PRESS_PER_KEY": {"info_key": "tapping.hold_on_other_key_press_per_key", "value_type": "bool"},
"PERMISSIVE_HOLD": {"info_key": "tapping.permissive_hold", "value_type": "bool"},
"PERMISSIVE_HOLD_PER_KEY": {"info_key": "tapping.permissive_hold_per_key", "value_type": "bool"},
"RETRO_TAPPING": {"info_key": "tapping.retro", "value_type": "bool"},
"RETRO_TAPPING_PER_KEY": {"info_key": "tapping.retro_per_key", "value_type": "bool"},
"TAP_CODE_DELAY": {"info_key": "qmk.tap_keycode_delay", "value_type": "int"},
"TAP_HOLD_CAPS_DELAY": {"info_key": "qmk.tap_capslock_delay", "value_type": "int"},
"TAPPING_TERM": {"info_key": "tapping.term", "value_type": "int"},
"TAPPING_TERM_PER_KEY": {"info_key": "tapping.term_per_key", "value_type": "bool"},
"TAPPING_TOGGLE": {"info_key": "tapping.toggle", "value_type": "int"},
// USB
"FORCE_NKRO": {"info_key": "usb.force_nkro", "value_type": "bool"},
"USB_MAX_POWER_CONSUMPTION": {"info_key": "usb.max_power", "value_type": "int"},
"USB_POLLING_INTERVAL_MS": {"info_key": "usb.polling_interval", "value_type": "int"},
"USB_SUSPEND_WAKEUP_DELAY": {"info_key": "usb.suspend_wakeup_delay", "value_type": "int"},
// WS2812
"WS2812_DI_PIN": {"info_key": "ws2812.pin"},
"WS2812_I2C_ADDRESS": {"info_key": "ws2812.i2c_address", "value_type": "hex"},
"WS2812_I2C_TIMEOUT": {"info_key": "ws2812.i2c_timeout", "value_type": "int"},
"LAYOUTS": {"info_key": "layout_aliases", "value_type": "mapping"},
// Items we want flagged in lint
"NO_ACTION_MACRO": {"info_key": "_invalid.no_action_macro", "invalid": true},
"NO_ACTION_FUNCTION": {"info_key": "_invalid.no_action_function", "invalid": true},
"DESCRIPTION": {"info_key": "_invalid.usb_description", "invalid": true},
"DEBOUNCING_DELAY": {"info_key": "_invalid.debouncing_delay", "invalid": true, "replace_with": "DEBOUNCE"},
"DESCRIPTION": {"info_key": "_invalid.usb_description", "invalid": true},
"IGNORE_MOD_TAP_INTERRUPT": {"info_key": "_invalid.ignore_mod_tap_interrupt", "value_type": "bool", "invalid": true},
"IGNORE_MOD_TAP_INTERRUPT_PER_KEY": {"info_key": "_invalid.ignore_mod_tap_interrupt_per_key", "invalid": true}
"NO_ACTION_FUNCTION": {"info_key": "_invalid.no_action_function", "invalid": true},
"NO_ACTION_MACRO": {"info_key": "_invalid.no_action_macro", "invalid": true},
"PREVENT_STUCK_MODIFIERS": {"info_key": "_invalid.prevent_stuck_mods", "invalid": true},
"UNUSED_PINS": {"info_key": "_invalid.unused_pins", "deprecated": true},
"RGBLIGHT_ANIMATIONS": {"info_key": "_invalid.rgblight.animations.all", "value_type": "bool", "invalid": true},
"QMK_KEYS_PER_SCAN": {"info_key": "qmk.keys_per_scan", "value_type": "int", "deprecated": true},
"RGB_DI_PIN": {"info_key": "rgblight.pin", "invalid": true, "replace_with": "WS2812_DI_PIN or APA102_DI_PIN"},
"RGBLIGHT_ANIMATIONS": {"info_key": "_invalid.rgblight.animations.all", "value_type": "bool", "invalid": true},
"TAPPING_FORCE_HOLD": {"info_key": "tapping.force_hold", "value_type": "bool", "deprecated": true},
"TAPPING_FORCE_HOLD_PER_KEY": {"info_key": "tapping.force_hold_per_key", "value_type": "bool", "deprecated": true},
"IGNORE_MOD_TAP_INTERRUPT": {"info_key": "_deprecated.ignore_mod_tap_interrupt", "value_type": "bool", "deprecated": true},
"IGNORE_MOD_TAP_INTERRUPT_PER_KEY": {"info_key": "_invalid.ignore_mod_tap_interrupt_per_key", "invalid": true}
"UNUSED_PINS": {"info_key": "_invalid.unused_pins", "deprecated": true},
"COMBO_COUNT": {"info_key": "_invalid.combo.count", "invalid": true},
// USB params, need to mark as failure when specified in config.h, rather than deprecated
"DEVICE_VER": {"info_key": "usb.device_version", "value_type": "bcd_version", "deprecated": true, "replace_with": "`usb.device_version` in info.json"},
"MANUFACTURER": {"info_key": "manufacturer", "value_type": "str", "deprecated": true, "replace_with": "`manufacturer` in info.json"},
"PRODUCT": {"info_key": "keyboard_name", "warn_duplicate": false, "value_type": "str", "deprecated": true, "replace_with": "`keyboard_name` in info.json"},
"PRODUCT_ID": {"info_key": "usb.pid", "value_type": "hex", "deprecated": true, "replace_with": "`usb.pid` in info.json"},
"VENDOR_ID": {"info_key": "usb.vid", "value_type": "hex", "deprecated": true, "replace_with": "`usb.vid` in info.json"},
"PRODUCT": {"info_key": "keyboard_name", "warn_duplicate": false, "value_type": "str", "deprecated": true, "replace_with": "`keyboard_name` in info.json"},
"MANUFACTURER": {"info_key": "manufacturer", "value_type": "str", "deprecated": true, "replace_with": "`manufacturer` in info.json"},
"DEVICE_VER": {"info_key": "usb.device_version", "value_type": "bcd_version", "deprecated": true, "replace_with": "`usb.device_version` in info.json"}
}

View File

@ -10,36 +10,38 @@
// deprecated: Default `false`. Set to `true` to turn on warning when a value exists
// invalid: Default `false`. Set to `true` to generate errors when a value exists
// replace_with: use with a key marked deprecated or invalid to designate a replacement
"BACKLIGHT_DRIVER": {"info_key": "backlight.driver"},
"BLUETOOTH_DRIVER": {"info_key": "bluetooth.driver"},
"BOARD": {"info_key": "board"},
"BOOTLOADER": {"info_key": "bootloader", "warn_duplicate": false},
"BOOTMAGIC_ENABLE": {"info_key": "bootmagic.enabled", "value_type": "bool"},
"BLUETOOTH_DRIVER": {"info_key": "bluetooth.driver"},
"BACKLIGHT_DRIVER": {"info_key": "backlight.driver"},
"CAPS_WORD_ENABLE": {"info_key": "caps_word.enabled", "value_type": "bool"},
"DEBOUNCE_TYPE": {"info_key": "build.debounce_type"},
"EEPROM_DRIVER": {"info_key": "eeprom.driver"},
"ENCODER_ENABLE": {"info_key": "encoder.enabled", "value_type": "bool"},
"FIRMWARE_FORMAT": {"info_key": "build.firmware_format"},
"KEYBOARD_SHARED_EP": {"info_key": "usb.shared_endpoint.keyboard", "value_type": "bool"},
"MOUSE_SHARED_EP": {"info_key": "usb.shared_endpoint.mouse", "value_type": "bool"},
"LAYOUTS": {"info_key": "community_layouts", "value_type": "list"},
"LED_MATRIX_DRIVER": {"info_key": "led_matrix.driver"},
"RGB_MATRIX_DRIVER": {"info_key": "rgb_matrix.driver"},
"LTO_ENABLE": {"info_key": "build.lto", "value_type": "bool"},
"MCU": {"info_key": "processor", "warn_duplicate": false},
"MOUSE_SHARED_EP": {"info_key": "usb.shared_endpoint.mouse", "value_type": "bool"},
"MOUSEKEY_ENABLE": {"info_key": "mouse_key.enabled", "value_type": "bool"},
"NO_USB_STARTUP_CHECK": {"info_key": "usb.no_startup_check", "value_type": "bool"},
"PIN_COMPATIBLE": {"info_key": "pin_compatible"},
"PLATFORM_KEY": {"info_key": "platform_key", "to_json": false},
"PS2_DRIVER": {"info_key": "ps2.driver"},
"PS2_ENABLE": {"info_key": "ps2.enabled", "value_type": "bool"},
"PS2_MOUSE_ENABLE": {"info_key": "ps2.mouse_enabled", "value_type": "bool"},
"RGB_MATRIX_DRIVER": {"info_key": "rgb_matrix.driver"},
"SECURE_ENABLE": {"info_key": "secure.enabled", "value_type": "bool"},
"SPLIT_KEYBOARD": {"info_key": "split.enabled", "value_type": "bool"},
"SPLIT_TRANSPORT": {"info_key": "split.transport.protocol", "to_c": false},
"WAIT_FOR_USB": {"info_key": "usb.wait_for", "value_type": "bool"},
"STENO_ENABLE": {"info_key": "stenography.enabled", "value_type": "bool"},
"STENO_PROTOCOL": {"info_key": "stenography.protocol"},
"PS2_ENABLE": {"info_key": "ps2.enabled", "value_type": "bool"},
"PS2_MOUSE_ENABLE": {"info_key": "ps2.mouse_enabled", "value_type": "bool"},
"PS2_DRIVER": {"info_key": "ps2.driver"},
"PLATFORM_KEY": {"info_key": "platform_key", "to_json": false},
"WAIT_FOR_USB": {"info_key": "usb.wait_for", "value_type": "bool"},
"WS2812_DRIVER": {"info_key": "ws2812.driver"},
// Items we want flagged in lint
"CTPC": {"info_key": "_deprecated.ctpc", "deprecated": true, "replace_with": "CONVERT_TO=proton_c"},

View File

@ -41,6 +41,9 @@
"angel64": {
"target": "angel64/alpha"
},
"ashpil/modelm_usbc": {
"target": "ibm/model_m/ashpil_usbc"
},
"at101_blackheart": {
"target": "viktus/at101_bh"
},
@ -113,6 +116,15 @@
"cmm_studio/saka68": {
"target": "cmm_studio/saka68/solder"
},
"converter/modelm101": {
"target": "ibm/model_m/teensypp"
},
"converter/modelm101_teensy2": {
"target": "ibm/model_m/teensy2"
},
"converter/modelm_ssk": {
"target": "ibm/model_m_ssk/teensypp_ssk"
},
"cospad": {
"target": "kprepublic/cospad"
},
@ -149,6 +161,15 @@
"durgod/k320": {
"target": "durgod/k3x0/k320"
},
"durgod/hades": {
"target": "durgod/dgk6x/hades_ansi"
},
"durgod/hades_ansi": {
"target": "durgod/dgk6x/hades_ansi"
},
"durgod/hades_iso": {
"target": "durgod/dgk6x/hades_iso"
},
"dztech/dz60rgb": {
"target": "dztech/dz60rgb/v1"
},
@ -194,6 +215,9 @@
"handwired/ferris": {
"target": "ferris/0_1"
},
"handwired/ibm122m": {
"target": "ibm/model_m_122/ibm122m"
},
"handwired/p1800fl": {
"target": "team0110/p1800fl"
},
@ -248,6 +272,9 @@
"idobo": {
"target": "idobao/id75"
},
"jacky_studio/piggy60": {
"target": "jacky_studio/piggy60/rev1"
},
"jj40": {
"target": "kprepublic/jj40"
},
@ -260,6 +287,12 @@
"jones": {
"target": "jones/v03_1"
},
"kamigakushi": {
"target": "jaykeeb/kamigakushi",
"layouts": {
"LAYOUT": "LAYOUT_65_ansi_blocker_tsangan"
}
},
"katana60": {
"target": "rominronin/katana60/rev1"
},
@ -407,6 +440,9 @@
"montsinger/rebound": {
"target": "montsinger/rebound/rev1"
},
"mschwingen/modelm": {
"target": "ibm/model_m/mschwingen"
},
"noxary/268_2": {
"layouts": {
"LAYOUT": "LAYOUT_65_ansi_blocker"
@ -925,6 +961,12 @@
"m3n3van": {
"target": "matthewdias/m3n3van"
},
"massdrop/thekey": {
"target": "drop/thekey/v1"
},
"massdrop/thekey_v2": {
"target": "drop/thekey/v2"
},
"mechmini/v1": {
"target": "mechkeys/mechmini/v1"
},
@ -1222,6 +1264,9 @@
"treadstone48/rev2": {
"target": "marksard/treadstone48/rev2"
},
"tronguylabs/m122_3270": {
"target": "ibm/model_m_122/m122_3270"
},
"ua62": {
"target": "nacly/ua62"
},
@ -1282,6 +1327,9 @@
"ymdk_np21": {
"target": "ymdk/np21"
},
"yugo_m/model_m_101": {
"target": "ibm/model_m/yugo_m"
},
"yurei": {
"target": "kkatano/yurei"
},

View File

@ -71,6 +71,38 @@
"type": "string",
"pattern": "^[0-9a-z][0-9a-z_/]*$"
},
"keycode": {
"type": "string",
"minLength": 2,
"maxLength": 50,
"pattern": "^[A-Z][A-Zs_0-9]*$"
},
"keycode_short": {
"type": "string",
"minLength": 2,
"maxLength": 7,
"pattern": "^[A-Z][A-Zs_0-9]*$"
},
"keycode_decl": {
"type": "object",
"required": [
"key"
],
"properties": {
"key": {"$ref": "#/keycode"},
"label": {"$ref": "#/text_identifier"},
"aliases": {
"type": "array",
"minItems": 1,
"items": {"$ref": "#/keycode_short"}
}
}
},
"keycode_decl_array": {
"type": "array",
"minItems": 1
"items": {"$ref": "#/keycode_decl"}
},
"mcu_pin_array": {
"type": "array",
"items": {"$ref": "#/mcu_pin"}

View File

@ -35,7 +35,7 @@
},
"development_board": {
"type": "string",
"enum": ["promicro", "elite_c", "elite_pi", "proton_c", "kb2040", "promicro_rp2040", "blok", "michi", "bit_c_pro", "stemcell", "bluepill", "blackpill_f401", "blackpill_f411", "bonsai_c4", "helios"]
"enum": ["promicro", "elite_c", "elite_pi", "proton_c", "kb2040", "promicro_rp2040", "blok", "michi", "bit_c_pro", "stemcell", "bluepill", "blackpill_f401", "blackpill_f411", "bonsai_c4", "helios", "liatris"]
},
"pin_compatible": {
"type": "string",
@ -96,6 +96,19 @@
"unknown"
]
},
"apa102": {
"type": "object",
"additionalProperties": false,
"properties": {
"data_pin": {"$ref": "qmk.definitions.v1#/mcu_pin"},
"clock_pin": {"$ref": "qmk.definitions.v1#/mcu_pin"},
"default_brightness": {
"type": "integer",
"minimum": 0,
"maximum": 31
}
}
},
"audio": {
"type": "object",
"additionalProperties": false,
@ -133,7 +146,7 @@
"properties": {
"driver": {
"type": "string",
"enum": ["BluefruitLE", "RN42"]
"enum": ["BluefruitLE", "RN42", "custom"]
}
}
},
@ -214,7 +227,8 @@
"enabled": {"type": "boolean"},
"both_shifts_turns_on": {"type": "boolean"},
"double_tap_shift_turns_on": {"type": "boolean"},
"idle_timeout": {"$ref": "qmk.definitions.v1#/unsigned_int"}
"idle_timeout": {"$ref": "qmk.definitions.v1#/unsigned_int"},
"invert_on_shift": {"type": "boolean"}
}
},
"combo": {
@ -228,6 +242,11 @@
"type": "array",
"items": {"$ref": "qmk.definitions.v1#/filename"}
},
"eeprom": {
"properties": {
"driver": {"type": "string"}
}
},
"encoder": {
"$ref": "#/definitions/encoder_config",
"properties": {
@ -246,6 +265,7 @@
"on_state": {"$ref": "qmk.definitions.v1#/bit"}
}
},
"keycodes": {"$ref": "qmk.definitions.v1#/keycode_decl_array"},
"layout_aliases": {
"type": "object",
"additionalProperties": {"$ref": "qmk.definitions.v1#/layout_macro"}
@ -472,7 +492,10 @@
},
"led_count": {"$ref": "qmk.definitions.v1#/unsigned_int"},
"max_brightness": {"$ref": "qmk.definitions.v1#/unsigned_int_8"},
"pin": {"$ref": "qmk.definitions.v1#/mcu_pin"},
"pin": {
"$ref": "qmk.definitions.v1#/mcu_pin",
"$comment": "Deprecated: use ws2812.pin instead"
},
"rgbw": {"type": "boolean"},
"saturation_steps": {"$ref": "qmk.definitions.v1#/unsigned_int"},
"sleep": {"type": "boolean"},
@ -686,6 +709,19 @@
"led": {"$ref": "qmk.definitions.v1#/mcu_pin"},
"speaker": {"$ref": "qmk.definitions.v1#/mcu_pin"}
}
},
"ws2812": {
"type": "object",
"additionalProperties": false,
"properties": {
"driver": {
"type": "string",
"enum": ["bitbang", "custom", "i2c", "pwm", "spi", "vendor"]
},
"pin": {"$ref": "qmk.definitions.v1#/mcu_pin"},
"i2c_address": {"$ref": "qmk.definitions.v1#/hex_number_2d"},
"i2c_timeout": {"$ref": "qmk.definitions.v1#/unsigned_int"}
}
}
}
}

View File

@ -8,11 +8,7 @@
"type": "string",
"minLength": 2,
"maxLength": 50,
"pattern": "^[A-Zs_0-9]*$"
},
"hex_number_4d": {
"type": "string",
"pattern": "^0x[0-9A-F]{4}$"
"pattern": "^[A-Z][A-Zs_0-9]*$"
}
},
"properties": {
@ -34,10 +30,10 @@
"keycodes": {
"type": "object",
"propertyNames": {
"$ref": "#/definitions/hex_number_4d"
"$ref": "qmk.definitions.v1#/hex_number_4d"
},
"additionalProperties": {
"type": "object",
"type": "object", // use 'qmk.definitions.v1#/keycode_decl' when problem keycodes are removed
"required": [
"key"
],

View File

@ -67,6 +67,7 @@
}
}
},
"keycodes": {"$ref": "qmk.definitions.v1#/keycode_decl_array"},
"config": {"$ref": "qmk.keyboard.v1"},
"notes": {
"type": "string"

551
docs/ChangeLog/20230528.md Normal file
View File

@ -0,0 +1,551 @@
# QMK Breaking Changes - 2023 May 28 Changelog
## Notable Changes :id=notable-changes
As per last breaking changes cycle, there has been _a lot_ of emphasis on behind-the-scenes changes, mainly around migration of configurables into `info.json` files, cleanup of `info.json` files, additional layout definitions for keyboards, adding support for general community layouts to keyboards, as well as addressing technical debt.
Of note for keyboard designers:
* Layout and matrix definitions in `info.json` are now _mandatory_ for merge into QMK.
* Layout macros in `<yourkeyboard>.h` are no longer accepted into QMK Firmware.
* Existing keyboards have been meticulously converted by the QMK collaborators
* Layouts missing from keyboard definitions have been added in the process
* Keys within layouts should not specify `"w":1` or `"h":1` if the key size is 1 -- `w`/`h` should only be present for sizes other than 1
* `config_common.h` has been removed and should not be present anywhere in your keyboard code.
* `RGB_DI_PIN` will now cause an error during build:
* For WS2812-like LEDs, this should be moved to `info.json`: `"ws2812": { "pin": "xxx" }`
* For APA102 LEDs, this should be moved to `info.json`: `"apa102": { "data_pin": "xxx" }`
* Other mandatory data-driven changes should be automatically flagged during build
* Keymaps with `encoder_map` should now have the following change made:
* `encoder_map[][NUM_ENCODERS][2]` => `encoder_map[][NUM_ENCODERS][NUM_DIRECTIONS]`
* Users assumed the `2` referred to the number of encoders, rather than the number of directions (which is always 2)
### Repeat last key ([#19700](https://github.com/qmk/qmk_firmware/pull/19700)) :id=repeat-last-key
A new pair of keys has been added to QMK -- namely `QK_REPEAT_KEY` and `QK_ALT_REPEAT_KEY` (shortened: `QK_REP`/`QK_AREP`). These allow you to repeat the last key pressed, or in the case of the alternate key, press the "opposite" of the last key. For example, if you press `KC_LEFT`, pressing `QK_REPEAT_KEY` afterwards repeats `KC_LEFT`, but pressing `QK_ALT_REPEAT_KEY` instead sends `KC_RIGHT`.
The full list of default alternate keys is available on the [Repeat Key](feature_repeat_key.md) documentation.
To enable these keys, in your keymap's `rules.mk`, add:
```make
REPEAT_KEY_ENABLE = yes
```
...and add them to your keymap.
### User callback for pre process record ([#20584](https://github.com/qmk/qmk_firmware/pull/20584)) :id=user-callback-for-pre-process-record
Two new boolean callback functions, `pre_process_record_kb` and `pre_process_record_user`, have been added. They are called at the beginning of `process_record`, right before `process_combo`.
Similar to existing `*_kb` and `*_user` callback functions, returning `false` will halt further processing of key events. The `pre_process_record_user` function will allow user space opportunity to handle or capture an input before it undergoes quantum processing. For example, while action tapping is still resolving the tap or hold output of a mod-tap key, `pre_process_record_user` can capture the next key record of an input event that follows. That key record can be used to influence the [decision of the mod-tap](https://docs.qmk.fm/#/tap_hold) key that is currently undergoing quantum processing.
### Consolidate modelm ([#14996](https://github.com/qmk/qmk_firmware/pull/14996) :id=consolidate-modelm
Several build targets for the IBM Model M were cluttered in different folders. The maintainers of several Model M replacement controller projects agreed to consolidate them under one common folder.
The list of all moved keyboard locations is listed [below](20230528.md#updated-keyboard-codebases).
## Changes Requiring User Action :id=changes-requiring-user-action
### `IGNORE_MOD_TAP_INTERRUPT` behaviour changes ([#20211](https://github.com/qmk/qmk_firmware/pull/20211)) :id=i-m-t-i
Following up from the last breaking changes cycle, `IGNORE_MOD_TAP_INTERRUPT` has been removed and if present in keymap code, will now fail to build. The previous functionality for `IGNORE_MOD_TAP_INTERRUPT` is now default, and should you wish to revert to the old behaviour, you can use `HOLD_ON_OTHER_KEY_PRESS` instead.
For more information, you are invited to read the section on [HOLD_ON_OTHER_KEY_PRESS](tap_hold.md#hold-on-other-key-press) in the page on [Tap-Hold configuration options](tap_hold.md).
### Updated Keyboard Codebases :id=updated-keyboard-codebases
| Old Keyboard Name | New Keyboard Name |
|---------------------------------|-------------------------------------|
| ashpil/modelm_usbc | ibm/model_m/ashpil_usbc |
| binepad/bn009r2 | binepad/bn009/r2 |
| converter/modelm101 | ibm/model_m/teensypp |
| converter/modelm101_teensy2 | ibm/model_m/teensy2 |
| converter/modelm_ssk | ibm/model_m_ssk/teensypp_ssk |
| durgod/dgk6x/hades | durgod/dgk6x/hades_ansi |
| handwired/ibm122m | ibm/model_m_122/ibm122m |
| jacky_studio/piggy60/hotswap | jacky_studio/piggy60/rev1/hotswap |
| jacky_studio/piggy60/solder | jacky_studio/piggy60/rev1/solder |
| kamigakushi | jaykeeb/kamigakushi |
| massdrop/thekey | drop/thekey/v1 |
| massdrop/thekey_v2 | drop/thekey/v2 |
| mschwingen/modelm | ibm/model_m/mschwingen |
| tronguylabs/m122_3270 | ibm/model_m_122/m122_3270 |
| tronguylabs/m122_3270/blackpill | ibm/model_m_122/m122_3270/blackpill |
| tronguylabs/m122_3270/bluepill | ibm/model_m_122/m122_3270/bluepill |
| tronguylabs/m122_3270/teensy | ibm/model_m_122/m122_3270/teensy |
| yugo_m/model_m_101 | ibm/model_m/yugo_m |
## Notable core changes :id=notable-core
### Encoder functionality fallback ([#20320](https://github.com/qmk/qmk_firmware/pull/20320)) :id=encoder-functionality-fallback
For keyboards who have not yet been migrated to encoder map, a default set of encoder functionality is now enabled, gracefully degrading functionality depending on which flags are enabled by the keyboard:
* If `EXTRAKEY_ENABLE` is enabled by the keyboard, the encoder will be mapped to `KC_VOLU`/`KC_VOLD`
* If `MOUSEKEY_ENABLE` is enabled by the keyboard, the encoder will be mapped to `KC_MS_WH_UP`/`KC_MS_WH_DOWN`
* Otherwise, `KC_PGDN`/`KC_PGUP` will be used
Additionally, this ensures that builds on QMK Configurator produce some sort of usable encoder mapping.
### OLED Driver Improvements ([#20331](https://github.com/qmk/qmk_firmware/pull/20331)) :id=oled-driver-improvements
The "classic" OLED driver picked up support for additional sizes of OLED displays, support for the SH1107 controller, and SPI-based OLED support.
Other configurable items are available and can be found on the [OLED Driver page](https://docs.qmk.fm/#/feature_oled_driver).
## Full changelist :id=full-changelist
Core:
* Refactor `keyevent_t` for 1ms timing resolution ([#15847](https://github.com/qmk/qmk_firmware/pull/15847))
* PS/2 PIO Driver for RP2040 ([#17893](https://github.com/qmk/qmk_firmware/pull/17893))
* Relocate various modifier defines ([#18638](https://github.com/qmk/qmk_firmware/pull/18638))
* Added PMW3320 driver ([#19543](https://github.com/qmk/qmk_firmware/pull/19543))
* Keymap introspection for combos. ([#19670](https://github.com/qmk/qmk_firmware/pull/19670))
* Add direction to dynamic_macro_record_start_user ([#19689](https://github.com/qmk/qmk_firmware/pull/19689))
* Add Repeat Key ("repeat last key") as a core feature. ([#19700](https://github.com/qmk/qmk_firmware/pull/19700))
* [Cleanup] Quantum Painter ([#19825](https://github.com/qmk/qmk_firmware/pull/19825))
* Improve robustness of AW20216 driver ([#19849](https://github.com/qmk/qmk_firmware/pull/19849))
* Make "detected_host_os()" available on the SLAVE side of the split keyboard ([#19854](https://github.com/qmk/qmk_firmware/pull/19854))
* Add RP2040 Community Edition alias for splitkb.com's Liatris controller ([#19966](https://github.com/qmk/qmk_firmware/pull/19966))
* Remove some use of keymap.h ([#19980](https://github.com/qmk/qmk_firmware/pull/19980))
* Merge upstream changes to uf2conv ([#19993](https://github.com/qmk/qmk_firmware/pull/19993))
* Remove keymap.h ([#20004](https://github.com/qmk/qmk_firmware/pull/20004))
* Remove some use of keymap.h ([#20006](https://github.com/qmk/qmk_firmware/pull/20006))
* Quantum Painter QoL enhancements -- auto-poweroff, auto-flush, buffer sizing ([#20013](https://github.com/qmk/qmk_firmware/pull/20013))
* Make Pointing Device Auto Layer more configurable ([#20061](https://github.com/qmk/qmk_firmware/pull/20061))
* Add last activity functions for pointing device ([#20079](https://github.com/qmk/qmk_firmware/pull/20079))
* Caps Word "Invert on shift" option: pressing Shift inverts the shift state. ([#20092](https://github.com/qmk/qmk_firmware/pull/20092))
* Remove bootloader logic from `mcu_selection.mk` ([#20150](https://github.com/qmk/qmk_firmware/pull/20150))
* Update qmk_cli container references ([#20154](https://github.com/qmk/qmk_firmware/pull/20154))
* Clean up APA102 config and add DD mapping ([#20159](https://github.com/qmk/qmk_firmware/pull/20159))
* Sync activity timestamps between sides. ([#20192](https://github.com/qmk/qmk_firmware/pull/20192))
* Update Doxygen comments for some headers ([#20194](https://github.com/qmk/qmk_firmware/pull/20194))
* Make IGNORE_MOD_TAP_INTERRUPT the default behaviour for mod-taps ([#20211](https://github.com/qmk/qmk_firmware/pull/20211))
* Add some helpers to tidy up XAP ([#20235](https://github.com/qmk/qmk_firmware/pull/20235))
* Tidy up duplication of MIN/MAX fallback implementations ([#20236](https://github.com/qmk/qmk_firmware/pull/20236))
* Optionally keep intermediate file listings in order to do comparisons between builds. ([#20237](https://github.com/qmk/qmk_firmware/pull/20237))
* Add basic profiler. ([#20238](https://github.com/qmk/qmk_firmware/pull/20238))
* WS2812 driver improvements ([#20262](https://github.com/qmk/qmk_firmware/pull/20262))
* typing_heatmap: Add macro to configure increase steps ([#20300](https://github.com/qmk/qmk_firmware/pull/20300))
* Migrate `rgblight.pin` and `RGB_DI_PIN` to `ws2812.pin` ([#20303](https://github.com/qmk/qmk_firmware/pull/20303))
* Delete config_common.h ([#20312](https://github.com/qmk/qmk_firmware/pull/20312))
* Allow EEPROM_DRIVER from info.json ([#20313](https://github.com/qmk/qmk_firmware/pull/20313))
* rp2040: *_PAL_MODE overridable for this platform too ([#20314](https://github.com/qmk/qmk_firmware/pull/20314))
* Add core/fallback encoder behaviour ([#20320](https://github.com/qmk/qmk_firmware/pull/20320))
* OLED Driver improvements ([#20331](https://github.com/qmk/qmk_firmware/pull/20331))
* [Chore] Remove stray mod tap interrupt defines and per key functions ([#20347](https://github.com/qmk/qmk_firmware/pull/20347))
* Add swap hands toggle functions ([#20381](https://github.com/qmk/qmk_firmware/pull/20381))
* Prevent Tri-Layer keys from stopping caps word ([#20398](https://github.com/qmk/qmk_firmware/pull/20398))
* quantum/action_util.c: Use uint8_t for oneshot_layer_data ([#20423](https://github.com/qmk/qmk_firmware/pull/20423))
* Encoder map direction define. ([#20454](https://github.com/qmk/qmk_firmware/pull/20454))
* Realign and size check EECONFIG structures ([#20541](https://github.com/qmk/qmk_firmware/pull/20541))
* Clean up ISSI drivers, Add IS31FL3736 support ([#20572](https://github.com/qmk/qmk_firmware/pull/20572))
* Add a user callback for pre process record ([#20584](https://github.com/qmk/qmk_firmware/pull/20584))
* Disable debug on QP's internal task ([#20623](https://github.com/qmk/qmk_firmware/pull/20623))
* Add required string header file ([#20638](https://github.com/qmk/qmk_firmware/pull/20638))
* Add Develop is31fl3736 multi drivers ([#20642](https://github.com/qmk/qmk_firmware/pull/20642))
* Support PS/2 mouse 9-bit output with MOUSE_EXTENDED_REPORT ([#20734](https://github.com/qmk/qmk_firmware/pull/20734))
* BIOI G60/Morgan65: use custom Bluetooth driver ([#20897](https://github.com/qmk/qmk_firmware/pull/20897))
* Move `pre_process_record_kb()` before `process_combo()` ([#20969](https://github.com/qmk/qmk_firmware/pull/20969))
* Implement UF2 device type id extension tag ([#21029](https://github.com/qmk/qmk_firmware/pull/21029))
CLI:
* Add force support to 'qmk git-submodule' ([#19705](https://github.com/qmk/qmk_firmware/pull/19705))
* JSON encoder: improve sorting of layout dict keys ([#19974](https://github.com/qmk/qmk_firmware/pull/19974))
* Increase verbosity of make command ([#20172](https://github.com/qmk/qmk_firmware/pull/20172))
* Append user variables to the end of make command ([#20177](https://github.com/qmk/qmk_firmware/pull/20177))
* Strip API specific output from `qmk info` ([#20234](https://github.com/qmk/qmk_firmware/pull/20234))
* `qmk find`: usability improvements ([#20440](https://github.com/qmk/qmk_firmware/pull/20440))
* `qmk format-json`: Expose full key path and respect `sort_keys` ([#20836](https://github.com/qmk/qmk_firmware/pull/20836))
* Update json2c to use dump_lines ([#21013](https://github.com/qmk/qmk_firmware/pull/21013))
Submodule updates:
* Update ChibiOS to latest stable 21.11.x ([#20470](https://github.com/qmk/qmk_firmware/pull/20470))
Keyboards:
* Allow a larger int for the idle timeout for urbanvanilla keymap ([#19738](https://github.com/qmk/qmk_firmware/pull/19738))
* Change aidansmithdotdev/fine40 to use Encoder Map ([#19912](https://github.com/qmk/qmk_firmware/pull/19912))
* Custom keycodes in JSON ([#19925](https://github.com/qmk/qmk_firmware/pull/19925))
* Remove `"w":1` and `"h":1` from info.json ([#19961](https://github.com/qmk/qmk_firmware/pull/19961))
* Move matrix config to info.json, part 1 ([#19985](https://github.com/qmk/qmk_firmware/pull/19985))
* Move matrix config to info.json, part 2 ([#19987](https://github.com/qmk/qmk_firmware/pull/19987))
* Move matrix config to info.json, part 3 ([#19991](https://github.com/qmk/qmk_firmware/pull/19991))
* Move matrix config to info.json, part 4 ([#20001](https://github.com/qmk/qmk_firmware/pull/20001))
* Move matrix config to info.json, part 5 ([#20003](https://github.com/qmk/qmk_firmware/pull/20003))
* Move matrix config to info.json, part 6 ([#20019](https://github.com/qmk/qmk_firmware/pull/20019))
* Move matrix config to info.json, part 7 ([#20020](https://github.com/qmk/qmk_firmware/pull/20020))
* Move matrix config to info.json, part 8 ([#20030](https://github.com/qmk/qmk_firmware/pull/20030))
* Remove empty rules.mk from keymaps ([#20056](https://github.com/qmk/qmk_firmware/pull/20056))
* Adjust offset for some layouts ([#20075](https://github.com/qmk/qmk_firmware/pull/20075))
* Remove useless "ifdef KEYBOARD_*" ([#20078](https://github.com/qmk/qmk_firmware/pull/20078))
* Remove pointless `USE_I2C` blocks in keyboard headers ([#20084](https://github.com/qmk/qmk_firmware/pull/20084))
* Add support for ISO version of Durgod Hades ([#20110](https://github.com/qmk/qmk_firmware/pull/20110))
* Consolidate Binepad BN009 R1 and R2 into common folder ([#20113](https://github.com/qmk/qmk_firmware/pull/20113))
* Remove more empty headers ([#20155](https://github.com/qmk/qmk_firmware/pull/20155))
* Remove trailing zeroes in info.json layouts ([#20156](https://github.com/qmk/qmk_firmware/pull/20156))
* Clean up usage of `QMK_KEYBOARD_H` ([#20167](https://github.com/qmk/qmk_firmware/pull/20167))
* Move Keychron Q0 and Q0 Plus data-driven configuration; `keychron` keymap `rules.mk` cleanup ([#20168](https://github.com/qmk/qmk_firmware/pull/20168))
* Move ortho & numpad layouts to data driven ([#20183](https://github.com/qmk/qmk_firmware/pull/20183))
* Remove `RGB_DI_PIN` ifdefs ([#20218](https://github.com/qmk/qmk_firmware/pull/20218))
* Add the KJ-Modify RS40 PCB keyboard ([#20243](https://github.com/qmk/qmk_firmware/pull/20243))
* Move `WS2812_DRIVER` to data driven ([#20248](https://github.com/qmk/qmk_firmware/pull/20248))
* [jacky_studio/piggy60] move AVR PCB under rev1 ([#20253](https://github.com/qmk/qmk_firmware/pull/20253))
* Move 75% and 96% layouts to data driven ([#20289](https://github.com/qmk/qmk_firmware/pull/20289))
* Move split layouts to data driven ([#20290](https://github.com/qmk/qmk_firmware/pull/20290))
* Move 66% and 68% layouts to data driven ([#20293](https://github.com/qmk/qmk_firmware/pull/20293))
* add jacky_studio/piggy60/rev2 ([#20297](https://github.com/qmk/qmk_firmware/pull/20297))
* Move 65% layouts to data driven ([#20308](https://github.com/qmk/qmk_firmware/pull/20308))
* Move TKL F13 and FRL layouts to data driven ([#20310](https://github.com/qmk/qmk_firmware/pull/20310))
* Remove some use of keymap.h ([#20316](https://github.com/qmk/qmk_firmware/pull/20316))
* Move fullsize layouts to data driven ([#20317](https://github.com/qmk/qmk_firmware/pull/20317))
* Add 36-key layout for Beekeeb Piantor ([#20328](https://github.com/qmk/qmk_firmware/pull/20328))
* Add sriwedari70 and move kamigakushi to new folder ([#20334](https://github.com/qmk/qmk_firmware/pull/20334))
* Move TKL layouts to data driven ([#20337](https://github.com/qmk/qmk_firmware/pull/20337))
* Move Alice and Ergodox layouts to data driven ([#20340](https://github.com/qmk/qmk_firmware/pull/20340))
* Move small macropad-ish layouts to data driven ([#20341](https://github.com/qmk/qmk_firmware/pull/20341))
* Move `default` layouts to data driven ([#20349](https://github.com/qmk/qmk_firmware/pull/20349))
* Move `RGB_MATRIX_DRIVER` to data driven ([#20350](https://github.com/qmk/qmk_firmware/pull/20350))
* Move split space/backspace layouts to data driven ([#20356](https://github.com/qmk/qmk_firmware/pull/20356))
* Move single `LAYOUT`s to data driven ([#20365](https://github.com/qmk/qmk_firmware/pull/20365))
* Add encoder map for Iris Rev. 5 VIA ([#20412](https://github.com/qmk/qmk_firmware/pull/20412))
* Move remaining `LAYOUT`s to data driven ([#20422](https://github.com/qmk/qmk_firmware/pull/20422))
* Move single `LAYOUT_all`s to data driven ([#20430](https://github.com/qmk/qmk_firmware/pull/20430))
* 4pplet/yakiimo Layout Macro Conversion and Additions ([#20436](https://github.com/qmk/qmk_firmware/pull/20436))
* Move single `60_ansi`, `60_hhkb` and `60_iso` layouts to data driven ([#20438](https://github.com/qmk/qmk_firmware/pull/20438))
* Update brauner preonic layout ([#20439](https://github.com/qmk/qmk_firmware/pull/20439))
* AEBoards Satellite Rev1 Layout Macro Conversion ([#20442](https://github.com/qmk/qmk_firmware/pull/20442))
* Acheron Austin Layout Macro Conversion and Additions ([#20443](https://github.com/qmk/qmk_firmware/pull/20443))
* Move remaining `LAYOUT_all`s to data driven ([#20463](https://github.com/qmk/qmk_firmware/pull/20463))
* Update lotus58 RGB config ([#20468](https://github.com/qmk/qmk_firmware/pull/20468))
* Cleanup `ekow/akira` ([#20474](https://github.com/qmk/qmk_firmware/pull/20474))
* Move 60% layouts to data driven ([#20477](https://github.com/qmk/qmk_firmware/pull/20477))
* Move DZ60 and MJ6XY layouts to data driven ([#20478](https://github.com/qmk/qmk_firmware/pull/20478))
* AEBoards Constellation Layout Macro Updates ([#20487](https://github.com/qmk/qmk_firmware/pull/20487))
* AI03 Equinox Layout Macro Additions ([#20488](https://github.com/qmk/qmk_firmware/pull/20488))
* AI03 Vega Layout Macro Additions ([#20489](https://github.com/qmk/qmk_firmware/pull/20489))
* AKB OGR Layout Macro Additions ([#20490](https://github.com/qmk/qmk_firmware/pull/20490))
* AKB Vero Layout Macro Additions ([#20491](https://github.com/qmk/qmk_firmware/pull/20491))
* Alf DC60 Layout Macro Additions ([#20494](https://github.com/qmk/qmk_firmware/pull/20494))
* Alf X2 Layout Macro Additions ([#20495](https://github.com/qmk/qmk_firmware/pull/20495))
* Koolertron AMAG23 Touch-Up ([#20496](https://github.com/qmk/qmk_firmware/pull/20496))
* BIOI G60 Layout Macro Additions ([#20498](https://github.com/qmk/qmk_firmware/pull/20498))
* BIOI Morgan65 Layout Macro Additions ([#20499](https://github.com/qmk/qmk_firmware/pull/20499))
* BIOI S65 Layout Macro Additions ([#20500](https://github.com/qmk/qmk_firmware/pull/20500))
* Boston Layout Macro Additions ([#20504](https://github.com/qmk/qmk_firmware/pull/20504))
* Potato65S Layout Macro Additions ([#20508](https://github.com/qmk/qmk_firmware/pull/20508))
* Move miscellaneous layouts to data driven ([#20516](https://github.com/qmk/qmk_firmware/pull/20516))
* Cable Car Designs Cypher rev6 Layout Additions and Touch-Up ([#20518](https://github.com/qmk/qmk_firmware/pull/20518))
* Caffeinated Studios Serpent65 Layout Macro Additions ([#20519](https://github.com/qmk/qmk_firmware/pull/20519))
* CannonKeys Adelie Layout Macro Additions ([#20546](https://github.com/qmk/qmk_firmware/pull/20546))
* CannonKeys Aella Layout Macro Additions ([#20547](https://github.com/qmk/qmk_firmware/pull/20547))
* CannonKeys Balance Layout Macro Additions and Touch-Up ([#20548](https://github.com/qmk/qmk_firmware/pull/20548))
* CannonKeys Brutal v2 1800 Layout Macro Additions ([#20549](https://github.com/qmk/qmk_firmware/pull/20549))
* CannonKeys Brutal v2 65 Layout Macro Additions ([#20552](https://github.com/qmk/qmk_firmware/pull/20552))
* CannonKeys Cloudline Layout Macro Additions ([#20553](https://github.com/qmk/qmk_firmware/pull/20553))
* CannonKeys Crin Layout Macro Additions ([#20554](https://github.com/qmk/qmk_firmware/pull/20554))
* CannonKeys DevastatingTKL Layout Macro Additions ([#20555](https://github.com/qmk/qmk_firmware/pull/20555))
* CannonKeys Ellipse Layout Macro Additions ([#20558](https://github.com/qmk/qmk_firmware/pull/20558))
* CannonKeys Ellipse Hotswap Layout Macro Addition & Touch-Up ([#20560](https://github.com/qmk/qmk_firmware/pull/20560))
* CannonKeys Gentoo Layout Macro Additions ([#20561](https://github.com/qmk/qmk_firmware/pull/20561))
* CannonKeys Gentoo Hotswap Touch-Up ([#20562](https://github.com/qmk/qmk_firmware/pull/20562))
* CannonKeys HoodrowG Layout Macro Additions ([#20563](https://github.com/qmk/qmk_firmware/pull/20563))
* CannonKeys Moment Layout Macro Additions ([#20564](https://github.com/qmk/qmk_firmware/pull/20564))
* CannonKeys Moment Hotswap Touch-Up ([#20565](https://github.com/qmk/qmk_firmware/pull/20565))
* CannonKeys Nearfield Layout Macro Addition ([#20566](https://github.com/qmk/qmk_firmware/pull/20566))
* CannonKeys Obliterated75 Layout Macro Additions ([#20567](https://github.com/qmk/qmk_firmware/pull/20567))
* CannonKeys Onyx Layout Macro Additions ([#20568](https://github.com/qmk/qmk_firmware/pull/20568))
* CannonKeys Rekt1800 Layout Macro Additions ([#20569](https://github.com/qmk/qmk_firmware/pull/20569))
* CannonKeys Serenity Layout Macro Additions ([#20570](https://github.com/qmk/qmk_firmware/pull/20570))
* CannonKeys Vector Layout Macro Additions ([#20571](https://github.com/qmk/qmk_firmware/pull/20571))
* Carbo65 Community Layout support ([#20580](https://github.com/qmk/qmk_firmware/pull/20580))
* cest73 TKM Layout Macro Additions ([#20583](https://github.com/qmk/qmk_firmware/pull/20583))
* Charue Charon Layout Macro Additions ([#20585](https://github.com/qmk/qmk_firmware/pull/20585))
* Charue Sunsetter R2 Layout Macro Additions ([#20586](https://github.com/qmk/qmk_firmware/pull/20586))
* Remove `FLIP_HALF` layouts and move to data driven ([#20588](https://github.com/qmk/qmk_firmware/pull/20588))
* update ymdk/id75/rules.mk for develop ([#20592](https://github.com/qmk/qmk_firmware/pull/20592))
* CherryB Studio CB1800 Layout Macro Additions ([#20593](https://github.com/qmk/qmk_firmware/pull/20593))
* CherryB Studio CB65 Layout Macro Additions ([#20594](https://github.com/qmk/qmk_firmware/pull/20594))
* CherryB Studio CB87RGB Layout Macro Additions ([#20595](https://github.com/qmk/qmk_firmware/pull/20595))
* CheckerBoards G_IDB60 Layout Macro Edits ([#20596](https://github.com/qmk/qmk_firmware/pull/20596))
* CherryB Studio CB87v2 Layout Macro Additions ([#20597](https://github.com/qmk/qmk_firmware/pull/20597))
* CX60 Community Layout Support ([#20598](https://github.com/qmk/qmk_firmware/pull/20598))
* Demiurge Layout Macro Touch-Up ([#20599](https://github.com/qmk/qmk_firmware/pull/20599))
* Ducky One 2 SF 1967ST Layout Macro Additions ([#20600](https://github.com/qmk/qmk_firmware/pull/20600))
* Move `FORCE_NKRO` to data driven ([#20604](https://github.com/qmk/qmk_firmware/pull/20604))
* dyz Synthesis60 Layout Macro Addition ([#20610](https://github.com/qmk/qmk_firmware/pull/20610))
* DZTech Bocc Layout Macro Additions ([#20611](https://github.com/qmk/qmk_firmware/pull/20611))
* E88 Layout Macro Additions ([#20612](https://github.com/qmk/qmk_firmware/pull/20612))
* Emery65 Layout Macro Additions ([#20613](https://github.com/qmk/qmk_firmware/pull/20613))
* EvyD13 MX5160 Layout Macro Additions ([#20614](https://github.com/qmk/qmk_firmware/pull/20614))
* FJLabs AD65 Layout Macro Additions ([#20619](https://github.com/qmk/qmk_firmware/pull/20619))
* FJLabs Avalon Layout Additions and Touch-Up ([#20620](https://github.com/qmk/qmk_firmware/pull/20620))
* FJLabs Midway60 Layout Macro Additions ([#20621](https://github.com/qmk/qmk_firmware/pull/20621))
* FJLabs Polaris Layout Additions and Touch-Up ([#20622](https://github.com/qmk/qmk_firmware/pull/20622))
* FJLabs Sinanju WK Layout Additions and Touch-Up ([#20628](https://github.com/qmk/qmk_firmware/pull/20628))
* LFK87 refactor ([#20635](https://github.com/qmk/qmk_firmware/pull/20635))
* Fox Lab Time80 Layout Macro Additions ([#20636](https://github.com/qmk/qmk_firmware/pull/20636))
* FJLabs Solanis Layout Macro Additions ([#20639](https://github.com/qmk/qmk_firmware/pull/20639))
* GrayStudio Aero 75 Refactor and Touch-Up ([#20640](https://github.com/qmk/qmk_firmware/pull/20640))
* Move `USB_MAX_POWER_CONSUMPTION` to data driven ([#20648](https://github.com/qmk/qmk_firmware/pull/20648))
* `info.json` whitespace cleanups ([#20651](https://github.com/qmk/qmk_firmware/pull/20651))
* Hand88 Layout Macro Additions ([#20657](https://github.com/qmk/qmk_firmware/pull/20657))
* Cyberstar Handwired Layout Macro Additions ([#20658](https://github.com/qmk/qmk_firmware/pull/20658))
* split_65 Handwired Layout Macro Addition and Touch-Up ([#20659](https://github.com/qmk/qmk_firmware/pull/20659))
* Bebol Handwired Layout Macro Additions ([#20660](https://github.com/qmk/qmk_firmware/pull/20660))
* Glacier Handwired Layout Macro Addition and Touch-Up ([#20661](https://github.com/qmk/qmk_firmware/pull/20661))
* Koalafications Handwired Layout Macro Additions ([#20662](https://github.com/qmk/qmk_firmware/pull/20662))
* The Galleon Handwired Layout Macro Additions ([#20663](https://github.com/qmk/qmk_firmware/pull/20663))
* More `info.json` whitespace cleanups ([#20665](https://github.com/qmk/qmk_firmware/pull/20665))
* Remove use of layout macros for LFKeyboards LED config ([#20666](https://github.com/qmk/qmk_firmware/pull/20666))
* Helix rev2: remove 4 rows option ([#20667](https://github.com/qmk/qmk_firmware/pull/20667))
* Wakizashi40 Handwired Touch-Up ([#20671](https://github.com/qmk/qmk_firmware/pull/20671))
* yttyx: convert readme to utf-8 encoding ([#20672](https://github.com/qmk/qmk_firmware/pull/20672))
* Alicia Cook Layout Macro Additions ([#20675](https://github.com/qmk/qmk_firmware/pull/20675))
* Primus75 Layout Macro Additions ([#20676](https://github.com/qmk/qmk_firmware/pull/20676))
* Volcano660 Layout Macro Additions ([#20677](https://github.com/qmk/qmk_firmware/pull/20677))
* Iris Keyboards Iris60 Layout Macro Additions ([#20678](https://github.com/qmk/qmk_firmware/pull/20678))
* Irene Layout Macro Additions ([#20679](https://github.com/qmk/qmk_firmware/pull/20679))
* Iron180 Layout Macro Additions ([#20680](https://github.com/qmk/qmk_firmware/pull/20680))
* kinesis/alvicstep: remove kicad project files ([#20681](https://github.com/qmk/qmk_firmware/pull/20681))
* Remove more junk files and scripts ([#20682](https://github.com/qmk/qmk_firmware/pull/20682))
* JKeys Design Gentleman65 Layout Macro Addition and Touch-Up ([#20684](https://github.com/qmk/qmk_firmware/pull/20684))
* JKeys Design Gentleman65 Suited Edition Layout Macro Addition ([#20685](https://github.com/qmk/qmk_firmware/pull/20685))
* add additional layouts to `dactyl_manuform` variants ([#20688](https://github.com/qmk/qmk_firmware/pull/20688))
* TheDogKeyboard Layout Macro Addition ([#20689](https://github.com/qmk/qmk_firmware/pull/20689))
* KBDfans Bella Soldered Layout Macro Additions ([#20691](https://github.com/qmk/qmk_firmware/pull/20691))
* KBDfans Bounce75 Hotswap Touch-Up ([#20692](https://github.com/qmk/qmk_firmware/pull/20692))
* KBDfans KBD66 Layout Additions and Refactor ([#20693](https://github.com/qmk/qmk_firmware/pull/20693))
* KBDfans Odin RGB Touch-Up ([#20694](https://github.com/qmk/qmk_firmware/pull/20694))
* KBDfans Odin Soldered Layout Additions and Touch-Up ([#20695](https://github.com/qmk/qmk_firmware/pull/20695))
* keebzdotnet FMe Layout Additions ([#20696](https://github.com/qmk/qmk_firmware/pull/20696))
* Kegen G-Boy Layout Additions ([#20697](https://github.com/qmk/qmk_firmware/pull/20697))
* Escape Unicode characters in info.json ([#20698](https://github.com/qmk/qmk_firmware/pull/20698))
* Kiko's Lab Ellora65 Layout Additions ([#20699](https://github.com/qmk/qmk_firmware/pull/20699))
* Even more `info.json` whitespace cleanups ([#20703](https://github.com/qmk/qmk_firmware/pull/20703))
* kkatano Bakeneko 65 V3 Layout Additions ([#20706](https://github.com/qmk/qmk_firmware/pull/20706))
* kopibeng MNK65 Layout Additions ([#20708](https://github.com/qmk/qmk_firmware/pull/20708))
* kopibeng Typ65+ Layout Additions ([#20710](https://github.com/qmk/qmk_firmware/pull/20710))
* kopibeng XT60 Layout Additions ([#20711](https://github.com/qmk/qmk_firmware/pull/20711))
* kopibeng XT60_SINGA Layout Additions ([#20712](https://github.com/qmk/qmk_firmware/pull/20712))
* kopibeng XT8x Layout Additions ([#20713](https://github.com/qmk/qmk_firmware/pull/20713))
* Lefty Touch-Up ([#20714](https://github.com/qmk/qmk_firmware/pull/20714))
* Loki65 Layout Additions ([#20715](https://github.com/qmk/qmk_firmware/pull/20715))
* Lucid Alexa Solder Layout Additions ([#20716](https://github.com/qmk/qmk_firmware/pull/20716))
* Lucid Phantom Soldered Layout Additions ([#20717](https://github.com/qmk/qmk_firmware/pull/20717))
* Leftover30 Layout Addition ([#20718](https://github.com/qmk/qmk_firmware/pull/20718))
* Matrix Cain RE Touch-Up ([#20719](https://github.com/qmk/qmk_firmware/pull/20719))
* Matrix Lab 8XV1.2 OG Layout Updates ([#20720](https://github.com/qmk/qmk_firmware/pull/20720))
* Mechlovin Studio Hex6C Layout Additions ([#20722](https://github.com/qmk/qmk_firmware/pull/20722))
* Mechlovin.Studio Rogue87 Rev.1 Layout Additions ([#20724](https://github.com/qmk/qmk_firmware/pull/20724))
* Mechlovin.Studio Rouge87 Rev.1 Layout Additions ([#20725](https://github.com/qmk/qmk_firmware/pull/20725))
* Mechlovin.Studio infinity87 Rev.1 Layout Additions ([#20726](https://github.com/qmk/qmk_firmware/pull/20726))
* Mechlovin.Studio Infinity87 RGB Rev1 Layout Additions ([#20727](https://github.com/qmk/qmk_firmware/pull/20727))
* Mechlovin9 Layout Addition ([#20728](https://github.com/qmk/qmk_firmware/pull/20728))
* 1upkeyboards/pi50 WS2812_DI_PIN patch for develop ([#20731](https://github.com/qmk/qmk_firmware/pull/20731))
* Mechlovin.Studio Infinity87 Rev.2 Layout Additions ([#20735](https://github.com/qmk/qmk_firmware/pull/20735))
* Mechlovin.Studio Olly JF Layout Additions ([#20736](https://github.com/qmk/qmk_firmware/pull/20736))
* Mechlovin Studio Serratus Layout Additions ([#20737](https://github.com/qmk/qmk_firmware/pull/20737))
* MechWild Mercutio Layout Addition ([#20738](https://github.com/qmk/qmk_firmware/pull/20738))
* MisterKnife Knife66 ISO Layout Addition ([#20739](https://github.com/qmk/qmk_firmware/pull/20739))
* MNK1800s Layout Addition ([#20740](https://github.com/qmk/qmk_firmware/pull/20740))
* MNK75 Layout Additions ([#20741](https://github.com/qmk/qmk_firmware/pull/20741))
* Mode SixtyFive S Layout Additions ([#20742](https://github.com/qmk/qmk_firmware/pull/20742))
* Mode SeventyFive H Layout Addition ([#20743](https://github.com/qmk/qmk_firmware/pull/20743))
* Monstargear XO87 Soldered Layout Additions ([#20744](https://github.com/qmk/qmk_firmware/pull/20744))
* MTBKeys MTB60 Solder Layout Additions ([#20745](https://github.com/qmk/qmk_firmware/pull/20745))
* Nix Keyboards Day Off 60 Touch-Up and Layout Additions ([#20746](https://github.com/qmk/qmk_firmware/pull/20746))
* Kastenwagen 1840 Layout Addition ([#20747](https://github.com/qmk/qmk_firmware/pull/20747))
* Kastenwagen 48 Layout Addition ([#20748](https://github.com/qmk/qmk_firmware/pull/20748))
* NovelKeys NK87 Touch-Up ([#20749](https://github.com/qmk/qmk_firmware/pull/20749))
* NovelKeys NK87B Touch-Up ([#20750](https://github.com/qmk/qmk_firmware/pull/20750))
* Noxary 378 Layout Addition ([#20751](https://github.com/qmk/qmk_firmware/pull/20751))
* Noxary Valhalla Layout Addition ([#20752](https://github.com/qmk/qmk_firmware/pull/20752))
* Nightly Boards/DeskDaily Daily60 Layout Additions ([#20753](https://github.com/qmk/qmk_firmware/pull/20753))
* Odelia Touch-Up ([#20754](https://github.com/qmk/qmk_firmware/pull/20754))
* One Key Co Dango40 Touch-Up and Layout Addition ([#20755](https://github.com/qmk/qmk_firmware/pull/20755))
* P3D Glitch Layout Addition ([#20763](https://github.com/qmk/qmk_firmware/pull/20763))
* Pearl Boards Pandora Layout Additions ([#20764](https://github.com/qmk/qmk_firmware/pull/20764))
* Pearl Boards Pearl Layout Addition ([#20765](https://github.com/qmk/qmk_firmware/pull/20765))
* support boards with APM32 instead of the STM32 ([#20770](https://github.com/qmk/qmk_firmware/pull/20770))
* Pearl Boards Zeus Layout Additions ([#20773](https://github.com/qmk/qmk_firmware/pull/20773))
* Peej Rosaline Staggered Layout Additions ([#20774](https://github.com/qmk/qmk_firmware/pull/20774))
* plywrks Lune Layout Touch-Up ([#20775](https://github.com/qmk/qmk_firmware/pull/20775))
* Project Keyboard Signature65 Layout Additions ([#20776](https://github.com/qmk/qmk_firmware/pull/20776))
* protoTypist Allison Layout Additions ([#20777](https://github.com/qmk/qmk_firmware/pull/20777))
* Prototypist J-01 Rev1 Layout Additions ([#20778](https://github.com/qmk/qmk_firmware/pull/20778))
* Protozoa Cassini Layout Additions ([#20779](https://github.com/qmk/qmk_firmware/pull/20779))
* Protozoa P.01 Layout Additions ([#20781](https://github.com/qmk/qmk_firmware/pull/20781))
* QwertleKeys Calice Layout Addition ([#20782](https://github.com/qmk/qmk_firmware/pull/20782))
* Ramlord WITF Layout Touch-Up and Addition ([#20783](https://github.com/qmk/qmk_firmware/pull/20783))
* Rart45: rename LAYOUT_all to LAYOUT ([#20784](https://github.com/qmk/qmk_firmware/pull/20784))
* Rart60 Layout Additions ([#20785](https://github.com/qmk/qmk_firmware/pull/20785))
* Rart67 Layout Additions ([#20786](https://github.com/qmk/qmk_firmware/pull/20786))
* Rart67M: rename LAYOUT_all to LAYOUT ([#20787](https://github.com/qmk/qmk_firmware/pull/20787))
* RART75 Layout Additions ([#20788](https://github.com/qmk/qmk_firmware/pull/20788))
* RART75 Hotswap Layout Additions ([#20789](https://github.com/qmk/qmk_firmware/pull/20789))
* RART75M: rename LAYOUT_all to LAYOUT ([#20790](https://github.com/qmk/qmk_firmware/pull/20790))
* RART80 Hotswap Layout Additions ([#20791](https://github.com/qmk/qmk_firmware/pull/20791))
* Rartand Layout Additions ([#20799](https://github.com/qmk/qmk_firmware/pull/20799))
* Rartlice: rename LAYOUT_all to LAYOUT ([#20800](https://github.com/qmk/qmk_firmware/pull/20800))
* Ratio65 Hotswap: rename LAYOUT_all to LAYOUT_65_ansi_blocker ([#20801](https://github.com/qmk/qmk_firmware/pull/20801))
* Ratio65 Solder Layout Additions ([#20802](https://github.com/qmk/qmk_firmware/pull/20802))
* Specifying the default board file is redundant ([#20807](https://github.com/qmk/qmk_firmware/pull/20807))
* RGBKB Pan Layout Additions ([#20809](https://github.com/qmk/qmk_firmware/pull/20809))
* saevus cor Layout Additions ([#20810](https://github.com/qmk/qmk_firmware/pull/20810))
* Clean up trailing commas from info.json ([#20812](https://github.com/qmk/qmk_firmware/pull/20812))
* Enable LTO on salicylic acid 7skb to reduce size ([#20813](https://github.com/qmk/qmk_firmware/pull/20813))
* Reduce compiled size for mt64rgb's via keymap ([#20814](https://github.com/qmk/qmk_firmware/pull/20814))
* Reduce compiled size for prototypist oceanographer's via keymap ([#20816](https://github.com/qmk/qmk_firmware/pull/20816))
* Sauce Mild Layout Additions ([#20818](https://github.com/qmk/qmk_firmware/pull/20818))
* VCL x SawnsProjects VCL65 Layout Additions ([#20819](https://github.com/qmk/qmk_firmware/pull/20819))
* senselessclay had60 Layout Additions ([#20820](https://github.com/qmk/qmk_firmware/pull/20820))
* Space Holdings Nebula12B ([#20821](https://github.com/qmk/qmk_firmware/pull/20821))
* SmithRune Iron180 Layout Additions ([#20822](https://github.com/qmk/qmk_firmware/pull/20822))
* Stello65 Beta Layout Additions and Clean-Up ([#20824](https://github.com/qmk/qmk_firmware/pull/20824))
* Studio Kestra Nue Layout Additions ([#20825](https://github.com/qmk/qmk_firmware/pull/20825))
* Switchplate Peripherals 910 Layout Additions ([#20827](https://github.com/qmk/qmk_firmware/pull/20827))
* TKC California Layout Addition and Touch-Up ([#20829](https://github.com/qmk/qmk_firmware/pull/20829))
* TKC M0lly Layout Additions ([#20830](https://github.com/qmk/qmk_firmware/pull/20830))
* TKC TKL A/B87 Layout Additions ([#20831](https://github.com/qmk/qmk_firmware/pull/20831))
* Viendi 8L Layout Additions ([#20832](https://github.com/qmk/qmk_firmware/pull/20832))
* Viktus Smolka Layout Additions ([#20833](https://github.com/qmk/qmk_firmware/pull/20833))
* Viktus SP111 Layout Additions ([#20834](https://github.com/qmk/qmk_firmware/pull/20834))
* Viktus SP_Mini Layout Additions ([#20835](https://github.com/qmk/qmk_firmware/pull/20835))
* W1-AT Layout Additions ([#20842](https://github.com/qmk/qmk_firmware/pull/20842))
* Weirdo Geminate60 Layout Additions ([#20843](https://github.com/qmk/qmk_firmware/pull/20843))
* Cypher rev5 Layout Additions ([#20844](https://github.com/qmk/qmk_firmware/pull/20844))
* Prophet Layout Additions ([#20845](https://github.com/qmk/qmk_firmware/pull/20845))
* Tidy up encoder_map directions ([#20847](https://github.com/qmk/qmk_firmware/pull/20847))
* Rama Works Koyu Community Layout Support ([#20848](https://github.com/qmk/qmk_firmware/pull/20848))
* Rama Works M65-B Community Layout Support ([#20850](https://github.com/qmk/qmk_firmware/pull/20850))
* Rama Works M65-BX Community Layout Support ([#20851](https://github.com/qmk/qmk_firmware/pull/20851))
* Rama Works U80-A Community Layout Support ([#20853](https://github.com/qmk/qmk_firmware/pull/20853))
* Wilba Tech WT60-B Community Layout Support ([#20854](https://github.com/qmk/qmk_firmware/pull/20854))
* Wilba Tech WT60-BX Layout Additions and Touch-Up ([#20855](https://github.com/qmk/qmk_firmware/pull/20855))
* Wilba Tech WT60-C Community Layout Support ([#20858](https://github.com/qmk/qmk_firmware/pull/20858))
* Wilba Tech WT60-D Layout Addition and Touch-Up ([#20859](https://github.com/qmk/qmk_firmware/pull/20859))
* Wilba Tech WT60-G Community Layout Support ([#20860](https://github.com/qmk/qmk_firmware/pull/20860))
* Wilba Tech WT60-G2 Community Layout Support ([#20861](https://github.com/qmk/qmk_firmware/pull/20861))
* Wilba Tech WT60-H2: rename LAYOUT_all to LAYOUT_60_ansi_tsangan_split_rshift ([#20864](https://github.com/qmk/qmk_firmware/pull/20864))
* Wilba Tech WT60-XT Layout Additions and Touch-Up ([#20865](https://github.com/qmk/qmk_firmware/pull/20865))
* Wilba Tech WT65-A Community Layout Support and Touch-Up ([#20866](https://github.com/qmk/qmk_firmware/pull/20866))
* Wilba Tech WT65-B Layout Addition and Touch-Up ([#20867](https://github.com/qmk/qmk_firmware/pull/20867))
* Wilba Tech WT65-F Community Layout Support and Touch-Up ([#20869](https://github.com/qmk/qmk_firmware/pull/20869))
* Wilba Tech WT65-FX Community Layout Support ([#20870](https://github.com/qmk/qmk_firmware/pull/20870))
* Wilba Tech WT65-G Layout Additions and Touch-Up ([#20871](https://github.com/qmk/qmk_firmware/pull/20871))
* Wilba Tech WT65-G2 Layout Additions and Touch-Up ([#20872](https://github.com/qmk/qmk_firmware/pull/20872))
* Wilba Tech WT65-XT: rename LAYOUT_all to LAYOUT_65_xt_ansi_blocker_tsangan ([#20873](https://github.com/qmk/qmk_firmware/pull/20873))
* Wilba Tech WT65-XTX Layout Additions and Touch-Up ([#20874](https://github.com/qmk/qmk_firmware/pull/20874))
* Wilba Tech WT69-A Layout Addition and Touch-Up ([#20875](https://github.com/qmk/qmk_firmware/pull/20875))
* Wilba Tech WT70-JB Layout Addition and Touch-Up ([#20876](https://github.com/qmk/qmk_firmware/pull/20876))
* Wilba Tech WT75-A Layout Additions and Touch-Up ([#20877](https://github.com/qmk/qmk_firmware/pull/20877))
* Wilba Tech WT75-B Layout Additions and Touch-Up ([#20878](https://github.com/qmk/qmk_firmware/pull/20878))
* Wilba Tech WT75-C Layout Additions and Touch-Up ([#20879](https://github.com/qmk/qmk_firmware/pull/20879))
* Wilba Tech WT80-G Layout Additions and Touch-Up ([#20880](https://github.com/qmk/qmk_firmware/pull/20880))
* WinKeys Mini Winni: rename LAYOUT_all to LAYOUT_ortho_2x4 ([#20881](https://github.com/qmk/qmk_firmware/pull/20881))
* Scarlet Bandana Layout Additions ([#20882](https://github.com/qmk/qmk_firmware/pull/20882))
* Winkeyless B87 Community Layout Support ([#20884](https://github.com/qmk/qmk_firmware/pull/20884))
* Xelus AkiS Layout Additions ([#20885](https://github.com/qmk/qmk_firmware/pull/20885))
* Xelus Dharma Layout Additions ([#20886](https://github.com/qmk/qmk_firmware/pull/20886))
* Xelus Kangaroo Layout Additions ([#20887](https://github.com/qmk/qmk_firmware/pull/20887))
* Xelus La+ Layout Addition ([#20888](https://github.com/qmk/qmk_firmware/pull/20888))
* Xelus Pachi Mini 32U4 Community Layout Support ([#20889](https://github.com/qmk/qmk_firmware/pull/20889))
* Xelus Pachi rev1 Community Layout Support ([#20891](https://github.com/qmk/qmk_firmware/pull/20891))
* Xelus Trinity XT TKL Layout Additions ([#20892](https://github.com/qmk/qmk_firmware/pull/20892))
* Xelus Valor FRL TKL Layout Additions ([#20893](https://github.com/qmk/qmk_firmware/pull/20893))
* YDKB Chili Community Layout Support ([#20895](https://github.com/qmk/qmk_firmware/pull/20895))
* YDKB Grape Layout Additions ([#20899](https://github.com/qmk/qmk_firmware/pull/20899))
* YMDK Wings Layout Addition ([#20900](https://github.com/qmk/qmk_firmware/pull/20900))
* YMDK Wings Hotswap: rename LAYOUT_all to LAYOUT ([#20901](https://github.com/qmk/qmk_firmware/pull/20901))
* YMDK YM68 Community Layout Support ([#20906](https://github.com/qmk/qmk_firmware/pull/20906))
* Yugo-M Controller Layout Additions ([#20907](https://github.com/qmk/qmk_firmware/pull/20907))
* Zicodia TKLFRLNRLMLAO Layout Addition ([#20908](https://github.com/qmk/qmk_firmware/pull/20908))
* ZTBoards After Layout Addition ([#20912](https://github.com/qmk/qmk_firmware/pull/20912))
* ZTBoards Noon Layout Addition ([#20913](https://github.com/qmk/qmk_firmware/pull/20913))
* SawnsProjects Amber80 Solder Community Layout Support ([#20917](https://github.com/qmk/qmk_firmware/pull/20917))
* Pearl Boards Atlas Layout Additions ([#20918](https://github.com/qmk/qmk_firmware/pull/20918))
* Xiudi XD004: rename LAYOUT_all to LAYOUT_ortho_1x4 ([#20919](https://github.com/qmk/qmk_firmware/pull/20919))
* Wilba Tech WT80-BC Community Layout Support ([#20920](https://github.com/qmk/qmk_firmware/pull/20920))
* 4pplet Eagle Viper REP Rev B Community Layout Support ([#20921](https://github.com/qmk/qmk_firmware/pull/20921))
* FR4Boards unix60 Layout Additions ([#20926](https://github.com/qmk/qmk_firmware/pull/20926))
* MC-76K: rename LAYOUT_all to LAYOUT ([#20927](https://github.com/qmk/qmk_firmware/pull/20927))
* Mechlovin Studio Jay60 Community Layout Support ([#20928](https://github.com/qmk/qmk_firmware/pull/20928))
* MisterKnife Knife66 Layout Additions ([#20929](https://github.com/qmk/qmk_firmware/pull/20929))
* MisterKnife Knife66 ISO Layout Additions II ([#20930](https://github.com/qmk/qmk_firmware/pull/20930))
* 4pplet Waffling80 Community Layout Support and Touch-Up ([#20932](https://github.com/qmk/qmk_firmware/pull/20932))
* Acheron Elongate Delta: rename LAYOUT_all to LAYOUT ([#20956](https://github.com/qmk/qmk_firmware/pull/20956))
* ADPenrose Akemipad Layout Addition ([#20957](https://github.com/qmk/qmk_firmware/pull/20957))
* ADPenrose Shisaku: rename LAYOUT_all to LAYOUT ([#20958](https://github.com/qmk/qmk_firmware/pull/20958))
* AEBoards Aegis Layout Additions ([#20960](https://github.com/qmk/qmk_firmware/pull/20960))
* rart/rart80:via: restore rules.mk after #20334 ([#21002](https://github.com/qmk/qmk_firmware/pull/21002))
* Remove HHKB RN42 code ([#21007](https://github.com/qmk/qmk_firmware/pull/21007))
* Move `thekey` to Drop vendor folder ([#21032](https://github.com/qmk/qmk_firmware/pull/21032))
Keyboard fixes:
* userspace/community layout fixes ([#19998](https://github.com/qmk/qmk_firmware/pull/19998))
* Fix layout macro keys with no matrix position ([#20033](https://github.com/qmk/qmk_firmware/pull/20033))
* Restore matrix pins for ep/40 ([#20083](https://github.com/qmk/qmk_firmware/pull/20083))
* kbdfans/tiger80: remove duplicate keys in info.json ([#20148](https://github.com/qmk/qmk_firmware/pull/20148))
* Fixup z70ultra — replace mis-removed file ([#20157](https://github.com/qmk/qmk_firmware/pull/20157))
* Fixup CI build for F103C6 onekey. ([#20188](https://github.com/qmk/qmk_firmware/pull/20188))
* Fix layouts containing keys with multiple matrix positions ([#20191](https://github.com/qmk/qmk_firmware/pull/20191))
* Fix some more missing `#pragma once`s ([#20241](https://github.com/qmk/qmk_firmware/pull/20241))
* Fixup CI build for `nack`. ([#20292](https://github.com/qmk/qmk_firmware/pull/20292))
* Fixup Pointing device functions ([#20311](https://github.com/qmk/qmk_firmware/pull/20311))
* Fix a handful of CLI errors ([#20321](https://github.com/qmk/qmk_firmware/pull/20321))
* Fix API errors ([#20326](https://github.com/qmk/qmk_firmware/pull/20326))
* Set up DEFAULT_FOLDER for primekb/meridian ([#20367](https://github.com/qmk/qmk_firmware/pull/20367))
* Fix up via keymap builds. ([#20383](https://github.com/qmk/qmk_firmware/pull/20383))
* Fix up via keymap builds. ([#20397](https://github.com/qmk/qmk_firmware/pull/20397))
* Fix some missing QMK_KEYBOARD_H includes in user keymaps ([#20417](https://github.com/qmk/qmk_firmware/pull/20417))
* Update ymdk/id75 config ([#20432](https://github.com/qmk/qmk_firmware/pull/20432))
* Fix info.json LTO and format encoder definitions ([#20456](https://github.com/qmk/qmk_firmware/pull/20456))
* Fixup dymium65 RGB Pin on develop ([#20473](https://github.com/qmk/qmk_firmware/pull/20473))
* Fixup missing include in mxss `via` keymap ([#20475](https://github.com/qmk/qmk_firmware/pull/20475))
* Fix nk plus ws2812 config ([#20524](https://github.com/qmk/qmk_firmware/pull/20524))
* cannonkeys/ellipse_hs: correct layout macro references ([#20577](https://github.com/qmk/qmk_firmware/pull/20577))
* Remove use of layout macros for `music_map` ([#20634](https://github.com/qmk/qmk_firmware/pull/20634))
* Vertex/angle65 WS2812 pin fix ([#20653](https://github.com/qmk/qmk_firmware/pull/20653))
* Fix ws2812 pin for phantagom boards ([#20670](https://github.com/qmk/qmk_firmware/pull/20670))
* Fixup 1upkeyboards/pi50 ([#20733](https://github.com/qmk/qmk_firmware/pull/20733))
* Fix `test_json2c_no_json()` ([#20756](https://github.com/qmk/qmk_firmware/pull/20756))
* Fix mxss rgblight.c compilation issues ([#20804](https://github.com/qmk/qmk_firmware/pull/20804))
* Fixup paladin64 ([#20805](https://github.com/qmk/qmk_firmware/pull/20805))
* Fixup dogtag ([#20808](https://github.com/qmk/qmk_firmware/pull/20808))
* Fixup zwag75 ([#20923](https://github.com/qmk/qmk_firmware/pull/20923))
* Fixup latinpadble ([#20924](https://github.com/qmk/qmk_firmware/pull/20924))
* Add missing layout data for a handful of boards ([#20931](https://github.com/qmk/qmk_firmware/pull/20931))
* Fixup evo70 ([#20949](https://github.com/qmk/qmk_firmware/pull/20949))
* Fixup Crkbd default keymap ([#20962](https://github.com/qmk/qmk_firmware/pull/20962))
* Fix key display on Corne OLED ([#21044](https://github.com/qmk/qmk_firmware/pull/21044))
Others:
* Add layer-cycle example ([#19069](https://github.com/qmk/qmk_firmware/pull/19069))
* Remove remnants of Vagrant. ([#20000](https://github.com/qmk/qmk_firmware/pull/20000))
* Develop cleanup IS31FL3736 docs ([#20633](https://github.com/qmk/qmk_firmware/pull/20633))
* Organise config/rules <-> info mappings ([#20723](https://github.com/qmk/qmk_firmware/pull/20723))
* Add a change log for PR20584 ([#20998](https://github.com/qmk/qmk_firmware/pull/20998))
Bugs:
* Strip whitespace from CONVERT_TO variables ([#19948](https://github.com/qmk/qmk_firmware/pull/19948))
* Check all rows have the correct number of columns when parsing `g_led_config` ([#19954](https://github.com/qmk/qmk_firmware/pull/19954))
* Fix OSMs getting stuck ([#20034](https://github.com/qmk/qmk_firmware/pull/20034))
* Fix rgblight layers when animations aren't enabled ([#20097](https://github.com/qmk/qmk_firmware/pull/20097))
* Fixed split keyboard issue where custom LED indicators could activate incorrect LEDs (#20203) ([#20204](https://github.com/qmk/qmk_firmware/pull/20204))
* Reduce _validate complexity ([#20274](https://github.com/qmk/qmk_firmware/pull/20274))
* `qmk info`: account for ISO enter when calculating layout X offset ([#20325](https://github.com/qmk/qmk_firmware/pull/20325))
* Disable specific warnings to mitigate compilation problems with `KEEP_INTERMEDIATES=yes`. ([#20339](https://github.com/qmk/qmk_firmware/pull/20339))
* Fix compilation issue with Swap Hands and Encoder Map ([#20348](https://github.com/qmk/qmk_firmware/pull/20348))
* Fix preprocessor condition for SPLIT_HAPTIC_ENABLE ([#20411](https://github.com/qmk/qmk_firmware/pull/20411))
* Fix compilation issues with PS/2 driver on F4x1 controllers ([#20433](https://github.com/qmk/qmk_firmware/pull/20433))
* Fix capital letters not getting sent with sendstring_swiss_fr.h ([#20515](https://github.com/qmk/qmk_firmware/pull/20515))
* Duplicate board files for blok converter ([#20629](https://github.com/qmk/qmk_firmware/pull/20629))
* Fix Mod-Tap combo regression ([#20669](https://github.com/qmk/qmk_firmware/pull/20669))
* Revert use of legacy wear leveling driver now ChibiOS is fixed ([#20806](https://github.com/qmk/qmk_firmware/pull/20806))
* Fix compilation error introduced by #20669 ([#20849](https://github.com/qmk/qmk_firmware/pull/20849))
* Fix English word list retrieval in qmk generate-autocorrect-data ([#20915](https://github.com/qmk/qmk_firmware/pull/20915))
* Improve keymap folder resolution ([#20981](https://github.com/qmk/qmk_firmware/pull/20981))
* Fix issue with Repeat Key-Combo test ([#21005](https://github.com/qmk/qmk_firmware/pull/21005))
* `qmk info` - Remove printing of "Keyboard Folder" ([#21033](https://github.com/qmk/qmk_firmware/pull/21033))

View File

@ -41,7 +41,6 @@
* [Keymap Overview](keymap.md)
* Development Environments
* [Docker Guide](getting_started_docker.md)
* [Vagrant Guide](getting_started_vagrant.md)
* Flashing
* [Flashing](flashing.md)
* [Flashing ATmega32A (ps2avrgb)](flashing_bootloadhid.md)
@ -71,6 +70,7 @@
* [Macros](feature_macros.md)
* [Mouse Keys](feature_mouse_keys.md)
* [Programmable Button](feature_programmable_button.md)
* [Repeat Key](feature_repeat_key.md)
* [Space Cadet Shift](feature_space_cadet.md)
* [US ANSI Shifted Keys](keycodes_us_ansi_shifted.md)
@ -139,7 +139,7 @@
* Breaking Changes
* [Overview](breaking_changes.md)
* [My Pull Request Was Flagged](breaking_changes_instructions.md)
* [Most Recent ChangeLog](ChangeLog/20230226.md "QMK v0.20.0 - 2023 Feb 26")
* [Most Recent ChangeLog](ChangeLog/20230528.md "QMK v0.21.0 - 2023 May 28")
* [Past Breaking Changes](breaking_changes_history.md)
* C Development

View File

@ -10,27 +10,25 @@ Practically, this means QMK merges the `develop` branch into the `master` branch
## What has been included in past Breaking Changes?
* [2023 May 28](ChangeLog/20230528.md)
* [2023 Feb 26](ChangeLog/20230226.md)
* [2022 Nov 26](ChangeLog/20221126.md)
* [2022 Aug 27](ChangeLog/20220827.md)
* [2022 May 28](ChangeLog/20220528.md)
* [2022 Feb 26](ChangeLog/20220226.md)
* [Older Breaking Changes](breaking_changes_history.md)
## When is the next Breaking Change?
The next Breaking Change is scheduled for May 28, 2023.
The next Breaking Change is scheduled for August 27, 2023.
### Important Dates
* 2023 Feb 26 - `develop` is tagged with a new release version. Each push to `master` is subsequently merged to `develop` by GitHub actions.
* 2023 Apr 30 - `develop` closed to new PRs.
* 2023 Apr 30 - Call for testers.
* 2023 May 14 - Last day for merges -- after this point `develop` is locked for testing and accepts only bugfixes
* 2023 May 21 - `develop` is locked, only critical bugfix PRs merged.
* 2023 May 26 - `master` is locked, no PRs merged.
* 2023 May 28 - Merge `develop` to `master`.
* 2023 May 28 - `master` is unlocked. PRs can be merged again.
* 2023 May 28 - `develop` is tagged with a new release version. Each push to `master` is subsequently merged to `develop` by GitHub actions.
* 2023 Jul 30 - `develop` closed to new PRs.
* 2023 Jul 30 - Call for testers.
* 2023 Aug 13 - Last day for merges -- after this point `develop` is locked for testing and accepts only bugfixes
* 2023 Aug 20 - `develop` is locked, only critical bugfix PRs merged.
* 2023 Aug 25 - `master` is locked, no PRs merged.
* 2023 Aug 27 - Merge `develop` to `master`.
* 2023 Aug 27 - `master` is unlocked. PRs can be merged again.
## What changes will be included?
@ -50,7 +48,7 @@ Criteria for acceptance:
Strongly suggested:
* The PR has a ChangeLog file describing the changes under `<qmk_firmware>/docs/Changelog/20221126`.
* The PR has a ChangeLog file describing the changes under `<qmk_firmware>/docs/Changelog/20230827`.
* This should be in Markdown format, with a name in the format `PR12345.md`, substituting the digits for your PRs ID.
* One strong recommendation that the ChangeLog document matches the PR description on GitHub, so as to ensure traceability.

View File

@ -2,6 +2,7 @@
This page links to all previous changelogs from the QMK Breaking Changes process.
* [2023 May 28](ChangeLog/20230528.md) - version 0.21.0
* [2023 Feb 26](ChangeLog/20230226.md) - version 0.20.0
* [2022 Nov 26](ChangeLog/20221126.md) - version 0.19.0
* [2022 Aug 27](ChangeLog/20220827.md) - version 0.18.0

View File

@ -23,14 +23,6 @@ If it is determined that your submission is a breaking change, there are a few t
If you are contributing core code, and the only reason it needs to go through breaking changes is that you are updating keymaps to match your change, consider whether you can submit your feature in a way that the old keymaps continue to work. Then submit a separate PR that goes through the breaking changes process to remove the old code.
### Contribute a ChangeLog Entry
We require submissions that go through the Breaking Change process to include a changelog entry. The entry should be a short summary of the changes your pull request makes &ndash; [each section here started as a changelog](ChangeLog/20190830.md "n.b. This should link to the 2019 Aug 30 Breaking Changes doc - @noroadsleft").
Your changelog should be located at `docs/ChangeLog/YYYYMMDD/PR####.md`, where `YYYYMMDD` is the date on which QMK's breaking change branch &ndash; usually named `develop` &ndash; will be merged into the `master` branch, and `####` is the number of your pull request.
If your submission requires action on the part of users, your changelog should instruct users what action(s) must be taken, or link to a location that does so.
### Document Your Changes
Understanding the purpose for your submission, and possible implications or actions it will require can make the review process more straightforward. A changelog may suffice for this purpose, but more extensive changes may require a level of detail that is ill-suited for a changelog.

View File

@ -165,16 +165,31 @@ qmk find -f 'processor=STM32F411'
qmk find -f 'processor=STM32F411' -f 'features.rgb_matrix=true'
```
The following filter expressions are also supported:
- `exists(key)`: Match targets where `key` is present.
- `absent(key)`: Match targets where `key` is not present.
- `contains(key, value)`: Match targets where `key` contains `value`. Can be used for strings, arrays and object keys.
- `length(key, value)`: Match targets where the length of `key` is `value`. Can be used for strings, arrays and objects.
You can also list arbitrary values for each matched target with `--print`:
```
qmk find -f 'processor=STM32F411' -p 'keyboard_name' -p 'features.rgb_matrix'
```
**Usage**:
```
qmk find [-h] [-km KEYMAP] [-f FILTER]
qmk find [-h] [-km KEYMAP] [-p PRINT] [-f FILTER]
options:
-km KEYMAP, --keymap KEYMAP
The keymap name to build. Default is 'default'.
-p PRINT, --print PRINT
For each matched target, print the value of the supplied info.json key. May be passed multiple times.
-f FILTER, --filter FILTER
Filter the list of keyboards based on the supplied value in rules.mk. Matches info.json structure, and accepts the formats 'features.rgblight=true' or 'exists(matrix_pins.direct)'. May be passed multiple times, all filters need to match. Value may include wildcards such as '*' and '?'.
Filter the list of keyboards based on their info.json data. Accepts the formats key=value, function(key), or function(key,value), eg. 'features.rgblight=true'. Valid functions are 'absent', 'contains', 'exists' and 'length'. May be passed multiple times; all filters need to match. Value may include wildcards such as '*' and '?'.
```
## `qmk console`

View File

@ -8,8 +8,8 @@ Most of our style is pretty easy to pick up on, but right now it's not entirely
* Closing Brace: Lined up with the first character of the statement that opens the block
* Else If: Place the closing brace at the beginning of the line and the next opening brace at the end of the same line.
* Optional Braces: Always include optional braces.
* Good: if (condition) { return false; }
* Bad: if (condition) return false;
* Good: `if (condition) { return false; }`
* Bad: `if (condition) return false;`
* We encourage use of C style comments: `/* */`
* Think of them as a story describing the feature
* Use them liberally to explain why particular decisions were made.

View File

@ -150,7 +150,7 @@ If you define these options you will enable the associated feature, which may in
* `#define TAPPING_TERM_PER_KEY`
* enables handling for per key `TAPPING_TERM` settings
* `#define RETRO_TAPPING`
* tap anyway, even after TAPPING_TERM, if there was no other key interruption between press and release
* tap anyway, even after `TAPPING_TERM`, if there was no other key interruption between press and release
* See [Retro Tapping](tap_hold.md#retro-tapping) for details
* `#define RETRO_TAPPING_PER_KEY`
* enables handling for per key `RETRO_TAPPING` settings
@ -161,9 +161,6 @@ If you define these options you will enable the associated feature, which may in
* See [Permissive Hold](tap_hold.md#permissive-hold) for details
* `#define PERMISSIVE_HOLD_PER_KEY`
* enabled handling for per key `PERMISSIVE_HOLD` settings
* `#define IGNORE_MOD_TAP_INTERRUPT`
* makes it possible to do rolling combos (zx) with keys that convert to other keys on hold, by enforcing the `TAPPING_TERM` for both keys.
* See [Ignore Mod Tap Interrupt](tap_hold.md#ignore-mod-tap-interrupt) for details
* `#define QUICK_TAP_TERM 100`
* tap-then-hold timing to use a dual role key to repeat keycode
* See [Quick Tap Term](tap_hold.md#quick-tap-term)
@ -189,8 +186,6 @@ If you define these options you will enable the associated feature, which may in
* how long before oneshot times out
* `#define ONESHOT_TAP_TOGGLE 2`
* how many taps before oneshot toggle is triggered
* `#define COMBO_COUNT 2`
* Set this to the number of combos that you're using in the [Combo](feature_combo.md) feature. Or leave it undefined and programmatically set the count.
* `#define COMBO_TERM 200`
* how long for the Combo keys to be detected. Defaults to `TAPPING_TERM` if not defined.
* `#define COMBO_MUST_HOLD_MODS`
@ -217,7 +212,7 @@ If you define these options you will enable the associated feature, which may in
## RGB Light Configuration
* `#define RGB_DI_PIN D7`
* `#define WS2812_DI_PIN D7`
* pin the DI on the WS2812 is hooked-up to
* `#define RGBLIGHT_LAYERS`
* Lets you define [lighting layers](feature_rgblight.md?id=lighting-layers) that can be toggled on or off. Great for showing the current keyboard layer or caps lock state.
@ -233,7 +228,7 @@ If you define these options you will enable the associated feature, which may in
* `#define RGBLIGHT_SPLIT`
* Needed if both halves of the board have RGB LEDs wired directly to the RGB output pin on the controllers instead of passing the output of the left half to the input of the right half
* `#define RGBLED_SPLIT { 6, 6 }`
* number of LEDs connected that are directly wired to `RGB_DI_PIN` on each half of a split keyboard
* number of LEDs connected that are directly wired to the RGB pin on each half of a split keyboard
* First value indicates number of LEDs for left half, second value is for the right half
* When RGBLED_SPLIT is defined, RGBLIGHT_SPLIT is implicitly defined.
* `#define RGBLIGHT_HUE_STEP 12`

View File

@ -37,9 +37,9 @@ For more information on bitwise operators in C, click [here](https://en.wikipedi
In practice, this means that you can check whether a given modifier is active with `get_mods() & MOD_BIT(KC_<modifier>)` (see the [list of modifier keycodes](keycodes_basic.md#modifiers)) or with `get_mods() & MOD_MASK_<modifier>` if the difference between left and right hand modifiers is not important and you want to match both. Same thing can be done for one-shot modifiers if you replace `get_mods()` with `get_oneshot_mods()`.
To check that *only* a specific set of mods is active at a time, AND the modifier state and your desired mod mask as explained above and compare the result to the mod mask itself: `get_mods() & <mod mask> == <mod mask>`.
To check that *only* a specific set of mods is active at a time, use a simple equality operator: `get_mods() == <mod mask>`.
For example, let's say you want to trigger a piece of custom code if one-shot left control and one-shot left shift are on but every other one-shot mods are off. To do so, you can compose the desired mod mask by combining the mod bits for left control and shift with `(MOD_BIT(KC_LCTL) | MOD_BIT(KC_LSFT))` and then plug it in: `get_oneshot_mods() & (MOD_BIT(KC_LCTL) | MOD_BIT(KC_LSFT)) == (MOD_BIT(KC_LCTL) | MOD_BIT(KC_LSFT))`. Using `MOD_MASK_CS` instead for the mod bitmask would have forced you to press four modifier keys (both versions of control and shift) to fulfill the condition.
For example, let's say you want to trigger a piece of custom code if one-shot left control and one-shot left shift are on but every other one-shot mods are off. To do so, you can compose the desired mod mask by combining the mod bits for left control and shift with `(MOD_BIT(KC_LCTL) | MOD_BIT(KC_LSFT))` and then plug it in: `get_oneshot_mods() == (MOD_BIT(KC_LCTL) | MOD_BIT(KC_LSFT))`. Using `MOD_MASK_CS` instead for the mod bitmask would have forced you to press four modifier keys (both versions of control and shift) to fulfill the condition.
The full list of mod masks is as follows:
@ -91,7 +91,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) {
case KC_ESC:
// Detect the activation of only Left Alt
if ((get_mods() & MOD_BIT(KC_LALT)) == MOD_BIT(KC_LALT)) {
if (get_mods() == MOD_BIT(KC_LALT)) {
if (record->event.pressed) {
// No need to register KC_LALT because it's already active.
// The Alt modifier will apply on this KC_TAB.
@ -184,4 +184,4 @@ This page used to encompass a large set of features. We have moved many sections
## Key Overrides :id=key-overrides
* [Key Overrides](feature_key_overrides.md)
* [Key Overrides](feature_key_overrides.md)

View File

@ -90,6 +90,26 @@ by defining `IS_COMMAND()` in config.h:
## Customizing Caps Word :id=customizing-caps-word
### Invert on shift :id=invert-on-shift
By default, Caps Word turns off when Shift keys are pressed, considering them as
word-breaking. Alternatively with the `CAPS_WORD_INVERT_ON_SHIFT` option,
pressing the Shift key continues Caps Word and inverts the shift state. This
is convenient for uncapitalizing one or a few letters within a word, for
example with Caps Word on, typing "D, B, Shift+A, Shift+A, S" produces "DBaaS",
or typing "P, D, F, Shift+S" produces "PDFs".
Enable it by adding in config.h
```c
#define CAPS_WORD_INVERT_ON_SHIFT
```
This option works with regular Shift keys `KC_LSFT` and `KC_RSFT`, mod-tap Shift
keys, and one-shot Shift keys. Note that while Caps Word is on, one-shot Shift
keys behave like regular Shift keys, and have effect only while they are held.
### Idle timeout :id=idle-timeout
Caps Word turns off automatically if no keys are pressed for

View File

@ -4,15 +4,12 @@ The Combo feature is a chording type solution for adding custom actions. It lets
To enable this feature, you need to add `COMBO_ENABLE = yes` to your `rules.mk`.
Additionally, in your `config.h`, you'll need to specify the number of combos that you'll be using, by adding `#define COMBO_COUNT 1` (replacing 1 with the number that you're using). It is also possible to not define this and instead set the variable `COMBO_LEN` yourself. There's a trick where we don't need to think about this variable at all. More on this later.
Then, in your `keymap.c` file, you'll need to define a sequence of keys, terminated with `COMBO_END`, and a structure to list the combination of keys, and its resulting action.
```c
const uint16_t PROGMEM test_combo1[] = {KC_A, KC_B, COMBO_END};
const uint16_t PROGMEM test_combo2[] = {KC_C, KC_D, COMBO_END};
combo_t key_combos[COMBO_COUNT] = {
combo_t key_combos[] = {
COMBO(test_combo1, KC_ESC),
COMBO(test_combo2, LCTL(KC_Z)), // keycodes with modifiers are possible too!
};
@ -33,7 +30,7 @@ It is possible to overlap combos. Before, with the example below both combos wou
```c
const uint16_t PROGMEM test_combo1[] = {LSFT_T(KC_A), LT(1, KC_B), COMBO_END};
const uint16_t PROGMEM test_combo2[] = {LSFT_T(KC_A), LT(1, KC_B), KC_C, COMBO_END};
combo_t key_combos[COMBO_COUNT] = {
combo_t key_combos[] = {
COMBO(test_combo1, KC_ESC)
COMBO(test_combo2, KC_TAB)
};
@ -41,24 +38,22 @@ combo_t key_combos[COMBO_COUNT] = {
## Examples
A long list of combos can be defined in an `enum` list that ends with `COMBO_LENGTH` and you can leave `COMBO_COUNT` undefined:
A long list of combos can be defined in an `enum` list:
```c
enum combos {
AB_ESC,
JK_TAB,
QW_SFT,
SD_LAYER,
COMBO_LENGTH
SD_LAYER
};
uint16_t COMBO_LEN = COMBO_LENGTH; // remove the COMBO_COUNT define and use this instead!
const uint16_t PROGMEM ab_combo[] = {KC_A, KC_B, COMBO_END};
const uint16_t PROGMEM jk_combo[] = {KC_J, KC_K, COMBO_END};
const uint16_t PROGMEM qw_combo[] = {KC_Q, KC_W, COMBO_END};
const uint16_t PROGMEM sd_combo[] = {KC_S, KC_D, COMBO_END};
combo_t key_combos[COMBO_COUNT] = {
combo_t key_combos[] = {
[AB_ESC] = COMBO(ab_combo, KC_ESC),
[JK_TAB] = COMBO(jk_combo, KC_TAB),
[QW_SFT] = COMBO(qw_combo, KC_LSFT),
@ -72,9 +67,7 @@ For a more complicated implementation, you can use the `process_combo_event` fun
enum combo_events {
EM_EMAIL,
BSPC_LSFT_CLEAR,
COMBO_LENGTH
};
uint16_t COMBO_LEN = COMBO_LENGTH; // remove the COMBO_COUNT define and use this instead!
const uint16_t PROGMEM email_combo[] = {KC_E, KC_M, COMBO_END};
const uint16_t PROGMEM clear_line_combo[] = {KC_BSPC, KC_LSFT, COMBO_END};
@ -259,18 +252,6 @@ bool combo_should_trigger(uint16_t combo_index, combo_t *combo, uint16_t keycode
}
```
### Variable Length Combos
If you leave `COMBO_COUNT` undefined in `config.h`, it allows you to programmatically declare the size of the Combo data structure and avoid updating `COMBO_COUNT`. Instead a variable called `COMBO_LEN` has to be set. It can be set with something similar to the following in `keymap.c`: `uint16_t COMBO_LEN = ARRAY_SIZE(key_combos);` or by adding `COMBO_LENGTH` as the *last* entry in the combo enum and then `uint16_t COMBO_LEN = COMBO_LENGTH;` as such:
```c
enum myCombos {
...,
COMBO_LENGTH
};
uint16_t COMBO_LEN = COMBO_LENGTH;
```
Regardless of the method used to declare `COMBO_LEN`, this also requires to convert the `combo_t key_combos[COMBO_COUNT] = {...};` line to `combo_t key_combos[] = {...};`.
### Combo timer
Normally, the timer is started on the first key press and then reset on every subsequent key press within the `COMBO_TERM`.
@ -300,10 +281,8 @@ Here's an example where a combo resolves to two modifiers, and on key releases t
```c
enum combos {
AB_MODS,
COMBO_LENGTH
AB_MODS
};
uint16_t COMBO_LEN = COMBO_LENGTH;
const uint16_t PROGMEM ab_combo[] = {KC_A, KC_B, COMBO_END};
@ -415,6 +394,4 @@ SUBS(TH_THE, "the", KC_T, KC_H) // SUBS uses SEND_STRING to output the give
...
```
Now, you can update only one place to add or alter combos. You don't even need to remember to update the `COMBO_COUNT` or the `COMBO_LEN` variables at all. Everything is taken care of. Magic!
For small to huge ready made dictionaries of combos, you can check out http://combos.gboards.ca/.

View File

@ -17,15 +17,16 @@ Currently the following converters are available:
| `promicro` | `bit_c_pro` |
| `promicro` | `stemcell` |
| `promicro` | `bonsai_c4` |
| `promicro` | `elite_pi` |
| `promicro` | `rp2040_ce` |
| `promicro` | `elite_pi` |
| `promicro` | `helios` |
| `promicro` | `liatris` |
| `promicro` | `michi` |
| `elite_c` | `stemcell` |
| `elite_c` | `rp2040_ce` |
| `elite_c` | `elite_pi` |
| `elite_c` | `helios` |
| `elite_c` | `liatris` |
See below for more in depth information on each converter.
@ -88,6 +89,7 @@ If a board currently supported in QMK uses a [Pro Micro](https://www.sparkfun.co
| [customMK Bonsai C4](https://shop.custommk.com/products/bonsai-c4-microcontroller-board) | `bonsai_c4` |
| [Elite-Pi](https://keeb.io/products/elite-pi-usb-c-pro-micro-replacement-rp2040) | `elite_pi` |
| [0xCB Helios](https://keeb.supply/products/0xcb-helios) | `helios` |
| [Liatris](https://splitkb.com/products/liatris) | `liatris` |
| [Michi](https://github.com/ci-bus/michi-promicro-rp2040) | `michi` |
Converter summary:
@ -104,6 +106,7 @@ Converter summary:
| `rp2040_ce` | `-e CONVERT_TO=rp2040_ce` | `CONVERT_TO=rp2040_ce` | `#ifdef CONVERT_TO_RP2040_CE` |
| `elite_pi` | `-e CONVERT_TO=elite_pi` | `CONVERT_TO=elite_pi` | `#ifdef CONVERT_TO_ELITE_PI` |
| `helios` | `-e CONVERT_TO=helios` | `CONVERT_TO=helios` | `#ifdef CONVERT_TO_HELIOS` |
| `liatris` | `-e CONVERT_TO=liatris` | `CONVERT_TO=liatris` | `#ifdef CONVERT_TO_LIATRIS` |
| `michi` | `-e CONVERT_TO=michi` | `CONVERT_TO=michi` | `#ifdef CONVERT_TO_MICHI` |
### Proton C :id=proton_c
@ -168,7 +171,7 @@ The Bonsai C4 only has one on-board LED (B2), and by default, both the Pro Micro
#define B0 PAL_LINE(GPIOA, 9)
```
### RP2040 Community Edition - Elite-Pi and Helios :id=rp2040_ce
### RP2040 Community Edition - Elite-Pi, Helios, and Liatris :id=rp2040_ce
Feature set currently identical to [Adafruit KB2040](#kb2040).
@ -185,6 +188,7 @@ If a board currently supported in QMK uses an [Elite-C](https://keeb.io/products
| [STeMCell](https://github.com/megamind4089/STeMCell) | `stemcell` |
| [Elite-Pi](https://keeb.io/products/elite-pi-usb-c-pro-micro-replacement-rp2040) | `elite_pi` |
| [0xCB Helios](https://keeb.supply/products/0xcb-helios) | `helios` |
| [Liatris](https://splitkb.com/products/liatris) | `liatris` |
Converter summary:
@ -194,6 +198,7 @@ Converter summary:
| `rp2040_ce` | `-e CONVERT_TO=rp2040_ce` | `CONVERT_TO=rp2040_ce` | `#ifdef CONVERT_TO_RP2040_CE` |
| `elite_pi` | `-e CONVERT_TO=elite_pi` | `CONVERT_TO=elite_pi` | `#ifdef CONVERT_TO_ELITE_PI` |
| `helios` | `-e CONVERT_TO=helios` | `CONVERT_TO=helios` | `#ifdef CONVERT_TO_HELIOS` |
| `liatris` | `-e CONVERT_TO=liatris` | `CONVERT_TO=liatris` | `#ifdef CONVERT_TO_LIATRIS` |
### STeMCell :id=stemcell_elite

View File

@ -57,78 +57,78 @@ susceptible to noise, you must choose a debounce method that will also mitigate
if the scanning is slow, and you are using a timestamp-based algorithm, you might end up making a debouncing decision based on only two
sampled values, which will limit the noise-resistance of the algorithm.
* Currently all built-in debounce algorithms support timestamp-based debouncing only. In the future we might
implement cycles-based debouncing, and it will be selectable via a ```config.h``` macro.
implement cycles-based debouncing, and it will be selectable via a `config.h` macro.
2) Symmetric vs Asymmetric
* Symmetric - apply the same debouncing algorithm, to both key-up and key-down events.
* Recommended naming convention: ```sym_*```
* Recommended naming convention: `sym_*`
* Asymmetric - apply different debouncing algorithms to key-down and key-up events. E.g. Eager key-down, Defer key-up.
* Recommended naming convention: ```asym_*``` followed by details of the type of algorithm in use, in order, for key-down and then key-up
* Recommended naming convention: `asym_*` followed by details of the type of algorithm in use, in order, for key-down and then key-up
3) Eager vs Defer
* Eager - any key change is reported immediately. All further inputs for DEBOUNCE ms are ignored.
* Eager algorithms are not noise-resistant.
* Recommended naming conventions:
* ```sym_eager_*```
* ```asym_eager_*_*```: key-down is using eager algorithm
* ```asym_*_eager_*```: key-up is using eager algorithm
* `sym_eager_*`
* `asym_eager_*_*`: key-down is using eager algorithm
* `asym_*_eager_*`: key-up is using eager algorithm
* Defer - wait for no changes for DEBOUNCE ms before reporting change.
* Defer algorithms are noise-resistant
* Recommended naming conventions:
* ```sym_defer_*```
* ```asym_defer_*_*```: key-down is using defer algorithm
* ```asym_*_defer_*```: key-up is using defer algorithm
* `sym_defer_*`
* `asym_defer_*_*`: key-down is using defer algorithm
* `asym_*_defer_*`: key-up is using defer algorithm
4) Global vs Per-Key vs Per-Row
* Global - one timer for all keys. Any key change state affects global timer
* Recommended naming convention: ```*_g```
* Recommended naming convention: `*_g`
* Per-key - one timer per key
* Recommended naming convention: ```*_pk```
* Recommended naming convention: `*_pk`
* Per-row - one timer per row
* Recommended naming convention: ```*_pr```
* Recommended naming convention: `*_pr`
* Per-key and per-row algorithms consume more resources (in terms of performance,
and ram usage), but fast typists might prefer them over global.
## Debounce algorithms supported by QMK
## Supported Debounce Algorithms
QMK supports multiple debounce algorithms through its debounce API.
QMK supports multiple algorithms through its debounce API.
### Debounce selection
### Debounce Time
| DEBOUNCE_TYPE | Description | What else is needed |
| ------------- | --------------------------------------------------- | ----------------------------- |
| Not defined | Use the default algorithm, currently sym_defer_g | Nothing |
| custom | Use your own debounce code | ```SRC += debounce.c``` add your own debounce.c and implement necessary functions |
| Anything Else | Use another algorithm from quantum/debounce/* | Nothing |
Default debounce time is 5 milliseconds and it can be changed with the following line in `config.h`:
```
#define DEBOUNCE 10
```
?> Setting `DEBOUNCE` to `0` will disable this feature.
**Regarding split keyboards**:
The debounce code is compatible with split keyboards.
### Debounce Method
### Selecting an included debouncing method
Keyboards may select one of the already implemented debounce methods, by adding to ```rules.mk``` the following line:
Keyboards may select one of the core debounce methods by adding the following line into `rules.mk`:
```
DEBOUNCE_TYPE = <name of algorithm>
```
Where name of algorithm is one of:
* ```sym_defer_g``` - debouncing per keyboard. On any state change, a global timer is set. When ```DEBOUNCE``` milliseconds of no changes has occurred, all input changes are pushed.
* This is the current default algorithm. This is the highest performance algorithm with lowest memory usage, and it's also noise-resistant.
* ```sym_eager_pr``` - debouncing per row. On any state change, response is immediate, followed by locking the row ```DEBOUNCE``` milliseconds of no further input for that row.
For use in keyboards where refreshing ```NUM_KEYS``` 8-bit counters is computationally expensive / low scan rate, and fingers usually only hit one row at a time. This could be
appropriate for the ErgoDox models; the matrix is rotated 90°, and hence its "rows" are really columns, and each finger only hits a single "row" at a time in normal use.
* ```sym_eager_pk``` - debouncing per key. On any state change, response is immediate, followed by ```DEBOUNCE``` milliseconds of no further input for that key
* ```sym_defer_pr``` - debouncing per row. On any state change, a per-row timer is set. When ```DEBOUNCE``` milliseconds of no changes have occurred on that row, the entire row is pushed. Can improve responsiveness over `sym_defer_g` while being less susceptible than per-key debouncers to noise.
* ```sym_defer_pk``` - debouncing per key. On any state change, a per-key timer is set. When ```DEBOUNCE``` milliseconds of no changes have occurred on that key, the key status change is pushed.
* ```asym_eager_defer_pk``` - debouncing per key. On a key-down state change, response is immediate, followed by ```DEBOUNCE``` milliseconds of no further input for that key. On a key-up state change, a per-key timer is set. When ```DEBOUNCE``` milliseconds of no changes have occurred on that key, the key-up status change is pushed.
Name of algorithm is one of:
### A couple algorithms that could be implemented in the future:
* ```sym_defer_pr```
* ```sym_eager_g```
| Algorithm | Description |
| --------------------- | ----------- |
| `sym_defer_g` | Debouncing per keyboard. On any state change, a global timer is set. When `DEBOUNCE` milliseconds of no changes has occurred, all input changes are pushed. This is the highest performance algorithm with lowest memory usage and is noise-resistant. |
| `sym_defer_pr` | Debouncing per row. On any state change, a per-row timer is set. When `DEBOUNCE` milliseconds of no changes have occurred on that row, the entire row is pushed. This can improve responsiveness over `sym_defer_g` while being less susceptible to noise than per-key algorithm. |
| `sym_defer_pk` | Debouncing per key. On any state change, a per-key timer is set. When `DEBOUNCE` milliseconds of no changes have occurred on that key, the key status change is pushed. |
| `sym_eager_pr` | Debouncing per row. On any state change, response is immediate, followed by `DEBOUNCE` milliseconds of no further input for that row. |
| `sym_eager_pk` | Debouncing per key. On any state change, response is immediate, followed by `DEBOUNCE` milliseconds of no further input for that key. |
| `asym_eager_defer_pk` | Debouncing per key. On a key-down state change, response is immediate, followed by `DEBOUNCE` milliseconds of no further input for that key. On a key-up state change, a per-key timer is set. When `DEBOUNCE` milliseconds of no changes have occurred on that key, the key-up status change is pushed. |
### Use your own debouncing code
You have the option to implement you own debouncing algorithm. To do this:
* Set ```DEBOUNCE_TYPE = custom``` in ```rules.mk```.
* Add ```SRC += debounce.c``` in ```rules.mk```
* Add your own ```debounce.c```. Look at current implementations in ```quantum/debounce``` for examples.
?> `sym_defer_g` is the default if `DEBOUNCE_TYPE` is undefined.
?> `sym_eager_pr` is suitable for use in keyboards where refreshing `NUM_KEYS` 8-bit counters is computationally expensive or has low scan rate while fingers usually hit one row at a time. This could be appropriate for the ErgoDox models where the matrix is rotated 90°. Hence its "rows" are really columns and each finger only hits a single "row" at a time with normal usage.
### Implementing your own debouncing code
You have the option to implement you own debouncing algorithm with the following steps:
* Set `DEBOUNCE_TYPE = custom` in `rules.mk`.
* Add `SRC += debounce.c` in `rules.mk`
* Implement your own `debounce.c`. See `quantum/debounce` for examples.
* Debouncing occurs after every raw matrix scan.
* Use num_rows rather than MATRIX_ROWS, so that split keyboards are supported correctly.
* If the algorithm might be applicable to other keyboards, please consider adding it to ```quantum/debounce```
* Use num_rows instead of MATRIX_ROWS to support split keyboards correctly.
* If your custom algorithm is applicable to other keyboards, please consider making a pull request.

View File

@ -59,7 +59,7 @@ There are a number of hooks that you can use to add custom functionality and fee
Note, that direction indicates which macro it is, with `1` being Macro 1, `-1` being Macro 2, and 0 being no macro.
* `dynamic_macro_record_start_user(void)` - Triggered when you start recording a macro.
* `dynamic_macro_record_start_user(int8_t direction)` - Triggered when you start recording a macro.
* `dynamic_macro_play_user(int8_t direction)` - Triggered when you play back a macro.
* `dynamic_macro_record_key_user(int8_t direction, keyrecord_t *record)` - Triggered on each keypress while recording a macro.
* `dynamic_macro_record_end_user(int8_t direction)` - Triggered when the macro recording is stopped.

View File

@ -81,7 +81,7 @@ Your `keymap.c` will then need an encoder mapping defined (for four layers and t
```c
#if defined(ENCODER_MAP_ENABLE)
const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][2] = {
const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][NUM_DIRECTIONS] = {
[_BASE] = { ENCODER_CCW_CW(KC_MS_WH_UP, KC_MS_WH_DOWN), ENCODER_CCW_CW(KC_VOLD, KC_VOLU) },
[_LOWER] = { ENCODER_CCW_CW(RGB_HUD, RGB_HUI), ENCODER_CCW_CW(RGB_SAD, RGB_SAI) },
[_RAISE] = { ENCODER_CCW_CW(RGB_VAD, RGB_VAI), ENCODER_CCW_CW(RGB_SPD, RGB_SPI) },
@ -102,9 +102,9 @@ Using encoder mapping pumps events through the normal QMK keycode processing pip
## Callbacks
When not using `ENCODER_MAP_ENABLE = yes`, the callback functions can be inserted into your `<keyboard>.c`:
?> [**Default Behaviour**](https://github.com/qmk/qmk_firmware/blob/master/quantum/encoder.c#L79-#L98): all encoders installed will function as volume up (`KC_VOLU`) on clockwise rotation and volume down (`KC_VOLD`) on counter-clockwise rotation. If you do not wish to override this, no further configuration is necessary.
?> Those who are adding new keyboard support where encoders are enabled at the keyboard level should include basic encoder functionality at the keyboard level (`<keyboard>.c`) using the `encoder_update_kb()` function, that way it works for QMK Configuator users and exists in general.
If you would like the alter the default behaviour, and are not using `ENCODER_MAP_ENABLE = yes`, the callback functions can be inserted into your `<keyboard>.c`:
```c
bool encoder_update_kb(uint8_t index, bool clockwise) {
@ -113,9 +113,9 @@ bool encoder_update_kb(uint8_t index, bool clockwise) {
}
if (index == 0) { /* First encoder */
if (clockwise) {
tap_code_delay(KC_VOLU, 10);
tap_code(KC_PGDN);
} else {
tap_code_delay(KC_VOLD, 10);
tap_code(KC_PGUP);
}
} else if (index == 1) { /* Second encoder */
if (clockwise) {
@ -134,9 +134,9 @@ or `keymap.c`:
bool encoder_update_user(uint8_t index, bool clockwise) {
if (index == 0) { /* First encoder */
if (clockwise) {
tap_code_delay(KC_VOLU, 10);
tap_code(KC_PGDN);
} else {
tap_code_delay(KC_VOLD, 10);
tap_code(KC_PGUP);
}
} else if (index == 1) { /* Second encoder */
if (clockwise) {
@ -149,7 +149,7 @@ bool encoder_update_user(uint8_t index, bool clockwise) {
}
```
!> If you return `true` in the keymap level `_user` function, it will allow the keyboard level encoder code to run on top of your own. Returning `false` will override the keyboard level function, if setup correctly. This is generally the safest option to avoid confusion.
!> If you return `true` in the keymap level `_user` function, it will allow the keyboard/core level encoder code to run on top of your own. Returning `false` will override the keyboard level function, if setup correctly. This is generally the safest option to avoid confusion.
## Hardware

View File

@ -64,7 +64,7 @@ There are a number of functions (and variables) related to how you can use or ma
| `layer_move(layer)` | Turns specified layer on, and all other layers off. |
| `layer_on(layer)` | Turns specified layer on, leaves all other layers in existing state. |
| `layer_off(layer)` | Turns specified layer off, leaves all other layers in existing state. |
| `layer_invert(layer)` | Interverts/toggles the state of the specified layer |
| `layer_invert(layer)` | Inverts/toggles the state of the specified layer |
| `layer_or(layer_mask)` | Turns on layers based on matching bits between specifed layer and existing layer state. |
| `layer_and(layer_mask)` | Turns on layers based on matching enabled bits between specifed layer and existing layer state. |
| `layer_xor(layer_mask)` | Turns on layers based on non-matching bits between specifed layer and existing layer state. |
@ -127,6 +127,54 @@ layer_state_t layer_state_set_user(layer_state_t state) {
}
```
### Example: Keycode to cycle through layers
This example shows how to implement a custom keycode to cycle through a range of layers.
```c
// Define the keycode, `QK_USER` avoids collisions with existing keycodes
enum keycodes {
KC_CYCLE_LAYERS = QK_USER,
};
// 1st layer on the cycle
#define LAYER_CYCLE_START 0
// Last layer on the cycle
#define LAYER_CYCLE_END 4
// Add the behaviour of this new keycode
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
switch (keycode) {
case KC_CYCLE_LAYERS:
// Our logic will happen on presses, nothing is done on releases
if (!record->event.pressed) {
// We've already handled the keycode (doing nothing), let QMK know so no further code is run unnecessarily
return false;
}
uint8_t current_layer = get_highest_layer(layer_state);
// Check if we are within the range, if not quit
if (current_layer > LAYER_CYCLE_END || current_layer < LAYER_CYCLE_START) {
return false;
}
uint8_t next_layer = current_layer + 1;
if (next_layer > LAYER_CYCLE_END) {
next_layer = LAYER_CYCLE_START;
}
layer_move(next_layer);
return false;
// Process other keycodes normally
default:
return true;
}
}
// Place `KC_CYCLE_LAYERS` as a keycode in your keymap
```
Use the `IS_LAYER_ON_STATE(state, layer)` and `IS_LAYER_OFF_STATE(state, layer)` macros to check the status of a particular layer.
Outside of `layer_state_set_*` functions, you can use the `IS_LAYER_ON(layer)` and `IS_LAYER_OFF(layer)` macros to check global layer state.

View File

@ -378,13 +378,7 @@ For inspiration and examples, check out the built-in effects under `quantum/led_
## EEPROM storage :id=eeprom-storage
The EEPROM for it is currently shared with the RGB Matrix system (it's generally assumed only one feature would be used at a time), but could be configured to use its own 32bit address with:
```c
#define EECONFIG_LED_MATRIX (uint32_t *)28
```
Where `28` is an unused index from `eeconfig.h`.
The EEPROM for it is currently shared with the RGB Matrix system (it's generally assumed only one feature would be used at a time).
### Direct Operation :id=direct-operation
|Function |Description |

View File

@ -2,15 +2,18 @@
## Supported Hardware
OLED modules using SSD1306 or SH1106 driver ICs, communicating over I2C.
OLED modules using SSD1306, SH1106 or SH1107 driver ICs, communicating over I2C or SPI.
Tested combinations:
|IC |Size |Platform|Notes |
|---------|------|--------|------------------------|
|SSD1306 |128x32|AVR |Primary support |
|SSD1306 |128x64|AVR |Verified working |
|SSD1306 |128x32|Arm | |
|SH1106 |128x64|AVR |No rotation or scrolling|
|IC |Size |Platform|Notes |
|---------|-------|--------|------------------------|
|SSD1306 |128x32 |AVR |Primary support |
|SSD1306 |128x64 |AVR |Verified working |
|SSD1306 |128x32 |Arm | |
|SH1106 |128x64 |AVR |No scrolling |
|SH1107 |64x128 |AVR |No scrolling |
|SH1107 |64x128 |Arm |No scrolling |
|SH1107 |128x128|Arm |No scrolling |
Hardware configurations using Arm-based microcontrollers or different sizes of OLED modules may be compatible, but are untested.
@ -23,15 +26,26 @@ OLED_ENABLE = yes
```
## OLED type
|OLED Driver |Supported Device |
|-------------------|---------------------------|
|SSD1306 (default) |For both SSD1306 and SH1106|
|OLED Driver |Supported Device |
|-------------------|------------------------------------|
|SSD1306 (default) |For both SSD1306, SH1106, and SH1107|
e.g.
```make
OLED_DRIVER = SSD1306
```
|OLED Transport | |
|---------------|------------------------------------------------|
|i2c (default) | Uses I2C for communication with the OLED panel |
|spi | Uses SPI for communication with the OLED panel |
e.g.
```make
OLED_TRANSPORT = i2c
```
Then in your `keymap.c` file, implement the OLED task call. This example assumes your keymap has three layers named `_QWERTY`, `_FN` and `_ADJ`:
```c
@ -159,32 +173,57 @@ These configuration options should be placed in `config.h`. Example:
#define OLED_BRIGHTNESS 128
```
|Define |Default |Description |
|---------------------------|-------------------------------|---------------------------------------------------------------------------------------------------------------------|
|`OLED_BRIGHTNESS` |`255` |The default brightness level of the OLED, from 0 to 255. |
|`OLED_COLUMN_OFFSET` |`0` |Shift output to the right this many pixels.<br />Useful for 128x64 displays centered on a 132x64 SH1106 IC. |
|`OLED_DISPLAY_CLOCK` |`0x80` |Set the display clock divide ratio/oscillator frequency. |
|`OLED_FONT_H` |`"glcdfont.c"` |The font code file to use for custom fonts |
|`OLED_FONT_START` |`0` |The starting character index for custom fonts |
|`OLED_FONT_END` |`223` |The ending character index for custom fonts |
|`OLED_FONT_WIDTH` |`6` |The font width |
|`OLED_FONT_HEIGHT` |`8` |The font height (untested) |
|`OLED_IC` |`OLED_IC_SSD1306` |Set to `OLED_IC_SH1106` or `OLED_IC_SH1107` if the corresponding controller chip is used. |
|`OLED_FADE_OUT` |*Not defined* |Enables fade out animation. Use together with `OLED_TIMEOUT`. |
|`OLED_FADE_OUT_INTERVAL` |`0` |The speed of fade out animation, from 0 to 15. Larger values are slower. |
|`OLED_SCROLL_TIMEOUT` |`0` |Scrolls the OLED screen after 0ms of OLED inactivity. Helps reduce OLED Burn-in. Set to 0 to disable. |
|`OLED_SCROLL_TIMEOUT_RIGHT`|*Not defined* |Scroll timeout direction is right when defined, left when undefined. |
|`OLED_TIMEOUT` |`60000` |Turns off the OLED screen after 60000ms of screen update inactivity. Helps reduce OLED Burn-in. Set to 0 to disable. |
|`OLED_UPDATE_INTERVAL` |`0` (`50` for split keyboards) |Set the time interval for updating the OLED display in ms. This will improve the matrix scan rate. |
|`OLED_UPDATE_PROCESS_LIMIT'|`1` |Set the number of dirty blocks to render per loop. Increasing may degrade performance. |
### I2C Configuration
|Define |Default |Description |
|---------------------------|-----------------|--------------------------------------------------------------------------------------------------------------------------|
|`OLED_DISPLAY_ADDRESS` |`0x3C` |The i2c address of the OLED Display |
|`OLED_FONT_H` |`"glcdfont.c"` |The font code file to use for custom fonts |
|`OLED_FONT_START` |`0` |The starting character index for custom fonts |
|`OLED_FONT_END` |`223` |The ending character index for custom fonts |
|`OLED_FONT_WIDTH` |`6` |The font width |
|`OLED_FONT_HEIGHT` |`8` |The font height (untested) |
|`OLED_TIMEOUT` |`60000` |Turns off the OLED screen after 60000ms of screen update inactivity. Helps reduce OLED Burn-in. Set to 0 to disable. |
|`OLED_FADE_OUT` |*Not defined* |Enables fade out animation. Use together with `OLED_TIMEOUT`. |
|`OLED_FADE_OUT_INTERVAL` |`0` |The speed of fade out animation, from 0 to 15. Larger values are slower. |
|`OLED_SCROLL_TIMEOUT` |`0` |Scrolls the OLED screen after 0ms of OLED inactivity. Helps reduce OLED Burn-in. Set to 0 to disable. |
|`OLED_SCROLL_TIMEOUT_RIGHT`|*Not defined* |Scroll timeout direction is right when defined, left when undefined. |
|`OLED_IC` |`OLED_IC_SSD1306`|Set to `OLED_IC_SH1106` if you're using the SH1106 OLED controller. |
|`OLED_COLUMN_OFFSET` |`0` |(SH1106 only.) Shift output to the right this many pixels.<br />Useful for 128x64 displays centered on a 132x64 SH1106 IC.|
|`OLED_BRIGHTNESS` |`255` |The default brightness level of the OLED, from 0 to 255. |
|`OLED_UPDATE_INTERVAL` |`0` |Set the time interval for updating the OLED display in ms. This will improve the matrix scan rate. |
## 128x64 & Custom sized OLED Displays
### SPI Configuration
The default display size for this feature is 128x32 and all necessary defines are precalculated with that in mind. We have added a define, `OLED_DISPLAY_128X64`, to switch all the values to be used in a 128x64 display, as well as added a custom define, `OLED_DISPLAY_CUSTOM`, that allows you to provide the necessary values to the driver.
|Define |Default |Description |
|---------------------------|-----------------|--------------------------------------------------------------------------------------------------------------------------|
|`OLED_DC_PIN` | Required |The pin used for the DC connection of the OLED Display. |
|`OLED_CS_PIN` | Required |The pin used for the CS connection of the OLED Display. |
|`OLED_RST_PIN` | *Not defined* |The pin used for the RST connection of the OLED Display (may be left undefined if the RST pin is not connected). |
|`OLED_SPI_MODE` |`3` (default) |The SPI Mode for the OLED Display (not typically changed). |
|`OLED_SPI_DIVISOR` |`2` (default) |The SPI Multiplier to use for the OLED Display. |
## 128x64 & Custom sized OLED Displays
The default display size for this feature is 128x32, and the defaults are set with that in mind. However, there are a number of additional presets for common sizes that we have added. You can define one of these values to use the presets. If your display doesn't match one of these presets, you can define `OLED_DISPLAY_CUSTOM` to manually specify all of the values.
|Define |Default |Description |
|----------------------|---------------|---------------------------------------------------------------------------------------------------------------------------------------|
|`OLED_DISPLAY_128X64` |*Not defined* |Changes the display defines for use with 128x64 displays. |
|`OLED_DISPLAY_64X32` |*Not defined* |Changes the display defines for use with 64x32 displays. |
|`OLED_DISPLAY_64X48` |*Not defined* |Changes the display defines for use with 64x48 displays. |
|`OLED_DISPLAY_64X128` |*Not defined* |Changes the display defines for use with 64x128 displays. |
|`OLED_DISPLAY_128X128`|*Not defined* |Changes the display defines for use with 128x128 displays. |
|`OLED_DISPLAY_CUSTOM` |*Not defined* |Changes the display defines for use with custom displays.<br>Requires user to implement the below defines. |
!> 64x128 and 128x128 displays default to the SH1107 IC type, as these heights are not supported by the other IC types.
|Define |Default |Description |
|---------------------|---------------|----------------------------------------------------------------------------------------------------------------------------------------|
|`OLED_DISPLAY_128X64`|*Not defined* |Changes the display defines for use with 128x64 displays. |
|`OLED_DISPLAY_CUSTOM`|*Not defined* |Changes the display defines for use with custom displays.<br>Requires user to implement the below defines. |
| --------------------|---------------|----------------------------------------------------------------------------------------------------------------------------------------|
|`OLED_DISPLAY_WIDTH` |`128` |The width of the OLED display. |
|`OLED_DISPLAY_HEIGHT`|`32` |The height of the OLED display. |
|`OLED_MATRIX_SIZE` |`512` |The local buffer size to allocate.<br>`(OLED_DISPLAY_HEIGHT / 8 * OLED_DISPLAY_WIDTH)`. |
@ -192,14 +231,13 @@ These configuration options should be placed in `config.h`. Example:
|`OLED_BLOCK_COUNT` |`16` |The number of blocks the display is divided into for dirty rendering.<br>`(sizeof(OLED_BLOCK_TYPE) * 8)`. |
|`OLED_BLOCK_SIZE` |`32` |The size of each block for dirty rendering<br>`(OLED_MATRIX_SIZE / OLED_BLOCK_COUNT)`. |
|`OLED_COM_PINS` |`COM_PINS_SEQ` |How the SSD1306 chip maps it's memory to display.<br>Options are `COM_PINS_SEQ`, `COM_PINS_ALT`, `COM_PINS_SEQ_LR`, & `COM_PINS_ALT_LR`.|
|`OLED_COM_PIN_COUNT` |*Not defined* |Number of COM pins supported by the controller.<br>If not defined, the value appropriate for the defined `OLED_IC` is used. |
|`OLED_COM_PIN_OFFSET`|`0` |Number of the first COM pin used by the OLED matrix. |
|`OLED_SOURCE_MAP` |`{ 0, ... N }` |Precalculated source array to use for mapping source buffer to target OLED memory in 90 degree rendering. |
|`OLED_TARGET_MAP` |`{ 24, ... N }`|Precalculated target array to use for mapping source buffer to target OLED memory in 90 degree rendering. |
### 90 Degree Rotation - Technical Mumbo Jumbo
!> Rotation is unsupported on the SH1106.
```c
// OLED Rotation enum values are flags
typedef enum {
@ -210,7 +248,7 @@ typedef enum {
} oled_rotation_t;
```
OLED displays driven by SSD1306 drivers only natively support in hardware 0 degree and 180 degree rendering. This feature is done in software and not free. Using this feature will increase the time to calculate what data to send over i2c to the OLED. If you are strapped for cycles, this can cause keycodes to not register. In testing however, the rendering time on an ATmega32U4 board only went from 2ms to 5ms and keycodes not registering was only noticed once we hit 15ms.
OLED displays driven by SSD1306, SH1106 or SH1107 drivers only natively support in hardware 0 degree and 180 degree rendering. This feature is done in software and not free. Using this feature will increase the time to calculate what data to send over i2c to the OLED. If you are strapped for cycles, this can cause keycodes to not register. In testing however, the rendering time on an ATmega32U4 board only went from 2ms to 5ms and keycodes not registering was only noticed once we hit 15ms.
90 degree rotation is achieved by using bitwise operations to rotate each 8 block of memory and uses two precalculated arrays to remap buffer memory to OLED memory. The memory map defines are precalculated for remap performance and are calculated based on the display height, width, and block size. For example, in the 128x32 implementation with a `uint8_t` block type, we have a 64 byte block size. This gives us eight 8 byte blocks that need to be rotated and rendered. The OLED renders horizontally two 8 byte blocks before moving down a page, e.g:
@ -232,6 +270,8 @@ However the local buffer is stored as if it was Height x Width display instead o
So those precalculated arrays just index the memory offsets in the order in which each one iterates its data.
Rotation on SH1106 and SH1107 is noticeably less efficient than on SSD1306, because these controllers do not support the “horizontal addressing mode”, which allows transferring the data for the whole rotated block at once; instead, separate address setup commands for every page in the block are required. The screen refresh time for SH1107 is therefore about 45% higher than for a same size screen with SSD1306 when using STM32 MCUs (on AVR the slowdown is about 20%, because the code which actually rotates the bitmap consumes more time).
## OLED API
```c
@ -253,6 +293,11 @@ bool oled_init(oled_rotation_t rotation);
oled_rotation_t oled_init_kb(oled_rotation_t rotation);
oled_rotation_t oled_init_user(oled_rotation_t rotation);
// Send commands/data to screen
bool oled_send_cmd(const uint8_t *data, uint16_t size);
bool oled_send_cmd_P(const uint8_t *data, uint16_t size);
bool oled_send_data(const uint8_t *data, uint16_t size);
// Clears the display buffer, resets cursor position to 0, and sets the buffer to dirty for rendering
void oled_clear(void);
@ -386,7 +431,9 @@ uint8_t oled_max_chars(void);
uint8_t oled_max_lines(void);
```
!> Scrolling and rotation are unsupported on the SH1106.
!> Scrolling is unsupported on the SH1106 and SH1107.
!> Scrolling does not work properly on the SSD1306 if the display width is smaller than 128.
## SSD1306.h Driver Conversion Guide

View File

@ -20,13 +20,13 @@ To use the ADNS 5050 sensor, add this to your `rules.mk`
POINTING_DEVICE_DRIVER = adns5050
```
The ADNS 5050 sensor uses a serial type protocol for communication, and requires an additional light source.
The ADNS 5050 sensor uses a serial type protocol for communication, and requires an additional light source.
| Setting | Description | Default |
| ------------------- | ------------------------------------------------------------------ | -------------------------- |
| `ADNS5050_SCLK_PIN` | (Required) The pin connected to the clock pin of the sensor. | `POINTING_DEVICE_SCLK_PIN` |
| `ADNS5050_SDIO_PIN` | (Required) The pin connected to the data pin of the sensor. | `POINTING_DEVICE_SDIO_PIN` |
| `ADNS5050_CS_PIN` | (Required) The pin connected to the Chip Select pin of the sensor. | `POINTING_DEVICE_CS_PIN` |
| Setting (`config.h`) | Description | Default |
| -------------------- | ------------------------------------------------------------------ | -------------------------- |
| `ADNS5050_SCLK_PIN` | (Required) The pin connected to the clock pin of the sensor. | `POINTING_DEVICE_SCLK_PIN` |
| `ADNS5050_SDIO_PIN` | (Required) The pin connected to the data pin of the sensor. | `POINTING_DEVICE_SDIO_PIN` |
| `ADNS5050_CS_PIN` | (Required) The pin connected to the Chip Select pin of the sensor. | `POINTING_DEVICE_CS_PIN` |
@ -40,9 +40,9 @@ To use the ADNS 9800 sensor, add this to your `rules.mk`
POINTING_DEVICE_DRIVER = adns9800
```
The ADNS 9800 is an SPI driven optical sensor, that uses laser output for surface tracking.
The ADNS 9800 is an SPI driven optical sensor, that uses laser output for surface tracking.
| Setting | Description | Default |
| Setting (`config.h`) | Description | Default |
| ----------------------- | ---------------------------------------------------------------------- | ------------------------ |
| `ADNS9800_CLOCK_SPEED` | (Optional) Sets the clock speed that the sensor runs at. | `2000000` |
| `ADNS9800_SPI_LSBFIRST` | (Optional) Sets the Least/Most Significant Byte First setting for SPI. | `false` |
@ -63,7 +63,7 @@ POINTING_DEVICE_DRIVER = analog_joystick
The Analog Joystick is an analog (ADC) driven sensor. There are a variety of joysticks that you can use for this.
| Setting | Description | Default |
| Setting (`config.h`) | Description | Default |
| --------------------------------- | -------------------------------------------------------------------------- | ------------- |
| `ANALOG_JOYSTICK_X_AXIS_PIN` | (Required) The pin used for the vertical/X axis. | _not defined_ |
| `ANALOG_JOYSTICK_Y_AXIS_PIN` | (Required) The pin used for the horizontal/Y axis. | _not defined_ |
@ -153,7 +153,7 @@ Additionally, `POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE` is supported in thi
#### Relative mode gestures
| Gesture Setting | Description | Default |
| Gesture Setting (`config.h`) | Description | Default |
| -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| `CIRQUE_PINNACLE_TAP_ENABLE` | (Optional) Enable tap to "left click". Works on both sides of a split keyboard. | _not defined_ |
| `CIRQUE_PINNACLE_SECONDARY_TAP_ENABLE` | (Optional) Tap in upper right corner (half of the finger needs to be outside of the trackpad) of the trackpad will result in "right click". `CIRQUE_PINNACLE_TAP_ENABLE` must be enabled. | _not defined_ |
@ -172,10 +172,10 @@ POINTING_DEVICE_DRIVER = paw3204
The paw 3204 sensor uses a serial type protocol for communication, and requires an additional light source.
| Setting | Description | Default |
| ------------------ |--------------------------------------------------------------- | -------------------------- |
| `PAW3204_SCLK_PIN` | (Required) The pin connected to the clock pin of the sensor. | `POINTING_DEVICE_SCLK_PIN` |
| `PAW3204_SDIO_PIN` | (Required) The pin connected to the data pin of the sensor. | `POINTING_DEVICE_SDIO_PIN` |
| Setting (`config.h`) | Description | Default |
| -------------------- |--------------------------------------------------------------- | -------------------------- |
| `PAW3204_SCLK_PIN` | (Required) The pin connected to the clock pin of the sensor. | `POINTING_DEVICE_SCLK_PIN` |
| `PAW3204_SDIO_PIN` | (Required) The pin connected to the data pin of the sensor. | `POINTING_DEVICE_SDIO_PIN` |
The CPI range is 400-1600, with supported values of (400, 500, 600, 800, 1000, 1200 and 1600). Defaults to 1000 CPI.
@ -189,7 +189,7 @@ POINTING_DEVICE_DRIVER = pimoroni_trackball
The Pimoroni Trackball module is a I2C based breakout board with an RGB enable trackball.
| Setting | Description | Default |
| Setting (`config.h`) | Description | Default |
| ------------------------------------ | ---------------------------------------------------------------------------------- | ------- |
| `PIMORONI_TRACKBALL_ADDRESS` | (Required) Sets the I2C Address for the Pimoroni Trackball. | `0x0A` |
| `PIMORONI_TRACKBALL_TIMEOUT` | (Optional) The timeout for i2c communication with the trackball in milliseconds. | `100` |
@ -197,6 +197,24 @@ The Pimoroni Trackball module is a I2C based breakout board with an RGB enable t
| `PIMORONI_TRACKBALL_DEBOUNCE_CYCLES` | (Optional) The number of scan cycles used for debouncing on the ball press. | `20` |
| `PIMORONI_TRACKBALL_ERROR_COUNT` | (Optional) Specifies the number of read/write errors until the sensor is disabled. | `10` |
### PMW3320 Sensor
To use the PMW3320 sensor, add this to your `rules.mk`
```make
POINTING_DEVICE_DRIVER = pmw3320
```
The PMW3320 sensor uses a serial type protocol for communication, and requires an additional light source (it could work without one, but expect it to be out of service early).
| Setting | Description | Default |
| ------------------- | ------------------------------------------------------------------- | -------------------------- |
| `PMW3320_SCLK_PIN` | (Required) The pin connected to the clock pin of the sensor. | `POINTING_DEVICE_SCLK_PIN` |
| `PMW3320_SDIO_PIN` | (Required) The pin connected to the data pin of the sensor. | `POINTING_DEVICE_SDIO_PIN` |
| `PMW3320_CS_PIN` | (Required) The pin connected to the cable select pin of the sensor. | `POINTING_DEVICE_CS_PIN` |
The CPI range is 500-3500, in increments of 250. Defaults to 1000 CPI.
### PMW 3360 and PMW 3389 Sensor
This drivers supports both the PMW 3360 and PMW 3389 sensor as well as multiple sensors of the same type _per_ controller, so 2 can be attached at the same side for split keyboards (or unsplit keyboards).
@ -220,7 +238,7 @@ The CPI range is 50-16000, in increments of 50. Defaults to 2000 CPI.
Both PMW 3360 and PMW 3389 are SPI driven optical sensors, that use a built in IR LED for surface tracking.
If you have different CS wiring on each half you can use `PMW33XX_CS_PIN_RIGHT` or `PMW33XX_CS_PINS_RIGHT` in combination with `PMW33XX_CS_PIN` or `PMW33XX_CS_PINS` to configure both sides independently. If `_RIGHT` values aren't provided, they default to be the same as the left ones.
| Setting | Description | Default |
| Setting (`config.h`) | Description | Default |
| ---------------------------- | ------------------------------------------------------------------------------------------- | ------------------------ |
| `PMW33XX_CS_PIN` | (Required) Sets the Chip Select pin connected to the sensor. | `POINTING_DEVICE_CS_PIN` |
| `PMW33XX_CS_PINS` | (Alternative) Sets the Chip Select pins connected to multiple sensors. | `{PMW33XX_CS_PIN}` |
@ -434,6 +452,75 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) {
This allows you to toggle between scrolling and cursor movement by pressing the DRAG_SCROLL key.
### Advanced Drag Scroll
Sometimes, like with the Cirque trackpad, you will run into issues where the scrolling may be too fast.
Here is a slightly more advanced example of drag scrolling. You will be able to change the scroll speed based on the values in set in `SCROLL_DIVISOR_H` and `SCROLL_DIVISOR_V`. This bit of code is also set up so that instead of toggling the scrolling state with set_scrolling = !set_scrolling, the set_scrolling variable is set directly to record->event.pressed. This way, the drag scrolling will only be active while the DRAG_SCROLL button is held down.
```c
enum custom_keycodes {
DRAG_SCROLL = SAFE_RANGE,
};
bool set_scrolling = false;
// Modify these values to adjust the scrolling speed
#define SCROLL_DIVISOR_H 8.0
#define SCROLL_DIVISOR_V 8.0
// Variables to store accumulated scroll values
float scroll_accumulated_h = 0;
float scroll_accumulated_v = 0;
// Function to handle mouse reports and perform drag scrolling
report_mouse_t pointing_device_task_user(report_mouse_t mouse_report) {
// Check if drag scrolling is active
if (set_scrolling) {
// Calculate and accumulate scroll values based on mouse movement and divisors
scroll_accumulated_h += (float)mouse_report.x / SCROLL_DIVISOR_H;
scroll_accumulated_v += (float)mouse_report.y / SCROLL_DIVISOR_V;
// Assign integer parts of accumulated scroll values to the mouse report
mouse_report.h = (int8_t)scroll_accumulated_h;
mouse_report.v = (int8_t)scroll_accumulated_v;
// Update accumulated scroll values by subtracting the integer parts
scroll_accumulated_h -= (int8_t)scroll_accumulated_h;
scroll_accumulated_v -= (int8_t)scroll_accumulated_v;
// Clear the X and Y values of the mouse report
mouse_report.x = 0;
mouse_report.y = 0;
}
return mouse_report;
}
// Function to handle key events and enable/disable drag scrolling
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
switch (keycode) {
case DRAG_SCROLL:
// Toggle set_scrolling when DRAG_SCROLL key is pressed or released
set_scrolling = record->event.pressed;
break;
default:
break;
}
return true;
}
// Function to handle layer changes and disable drag scrolling when not in AUTO_MOUSE_DEFAULT_LAYER
layer_state_t layer_state_set_user(layer_state_t state) {
// Disable set_scrolling if the current layer is not the AUTO_MOUSE_DEFAULT_LAYER
if (get_highest_layer(state) != AUTO_MOUSE_DEFAULT_LAYER) {
set_scrolling = false;
}
return state;
}
```
## Split Examples
The following examples make use the `SPLIT_POINTING_ENABLE` functionality and show how to manipulate the mouse report for a scrolling mode.
@ -602,6 +689,10 @@ There are several functions that allow for more advanced interaction with the au
| `auto_mouse_layer_off(void)` | Disable target layer if appropriate will call (makes call to `layer_state_set`) | | `void`(None) |
| `auto_mouse_toggle(void)` | Toggle on/off target toggle state (disables layer deactivation when true) | | `void`(None) |
| `get_auto_mouse_toggle(void)` | Return value of toggling state variable | | `bool` |
| `set_auto_mouse_timeout(uint16_t timeout)` | Change/set the timeout for turing off the layer | | `void`(None) |
| `get_auto_mouse_timeout(void)` | Return the current timeout for turing off the layer | | `uint16_t` |
| `set_auto_mouse_debounce(uint16_t timeout)` | Change/set the debounce for preventing layer activation | | `void`(None) |
| `get_auto_mouse_debounce(void)` | Return the current debounce for preventing layer activation | | `uint8_t` |
_NOTES:_
- _Due to the nature of how some functions work, the `auto_mouse_trigger_reset`, and `auto_mouse_layer_off` functions should never be called in the `layer_state_set_*` stack as this can cause indefinite loops._
@ -713,7 +804,7 @@ _Note: The Cirque pinnacle track pad already implements a custom activation func
When using a custom pointing device (overwriting `pointing_device_task`) the following code should be somewhere in the `pointing_device_task_*` stack:
```c
void pointing_device_task(void) {
bool pointing_device_task(void) {
//...Custom pointing device task code
// handle automatic mouse layer (needs report_mouse_t as input)
@ -721,7 +812,7 @@ void pointing_device_task(void) {
//...More custom pointing device task code
pointing_device_send();
return pointing_device_send();
}
```

457
docs/feature_repeat_key.md Normal file
View File

@ -0,0 +1,457 @@
# Repeat Key
The Repeat Key performs the action of the last pressed key. Tapping the Repeat
Key after tapping the <kbd>Z</kbd> key types another "`z`." This is useful for
typing doubled letters, like the `z` in "`dazzle`": a double tap on <kbd>Z</kbd>
can instead be a roll from <kbd>Z</kbd> to <kbd>Repeat</kbd>, which is
potentially faster and more comfortable. The Repeat Key is also useful for
hotkeys, like repeating Ctrl + Shift + Right Arrow to select by word.
Repeat Key remembers mods that were active with the last key press. These mods
are combined with any additional mods while pressing the Repeat Key. If the last
press key was <kbd>Ctrl</kbd> + <kbd>Z</kbd>, then <kbd>Shift</kbd> +
<kbd>Repeat</kbd> performs Ctrl + Shift + `Z`.
## How do I enable Repeat Key
In your `rules.mk`, add:
```make
REPEAT_KEY_ENABLE = yes
```
Then pick a key in your keymap and assign it the keycode `QK_REPEAT_KEY` (short
alias `QK_REP`). Optionally, use the keycode `QK_ALT_REPEAT_KEY` (short alias
`QK_AREP`) on another key.
## Keycodes
|Keycode |Aliases |Description |
|-----------------------|---------|-------------------------------------|
|`QK_REPEAT_KEY` |`QK_REP` |Repeat the last pressed key |
|`QK_ALT_REPEAT_KEY` |`QK_AREP`|Perform alternate of the last key |
## Alternate Repeating
The Alternate Repeat Key performs the "alternate" action of the last pressed key
if it is defined. By default, Alternate Repeat is defined for navigation keys to
act in the reverse direction. When the last key is the common "select by word"
hotkey Ctrl + Shift + Right Arrow, the Alternate Repeat Key performs Ctrl +
Shift + Left Arrow, which together with the Repeat Key enables convenient
selection by words in either direction.
Alternate Repeat is enabled with the Repeat Key by default. Optionally, to
reduce firmware size, Alternate Repeat may be disabled by adding in config.h:
```c
#define NO_ALT_REPEAT_KEY
```
The following alternate keys are defined by default. See
`get_alt_repeat_key_keycode_user()` below for how to change or add to these
definitions. Where it makes sense, these definitions also include combinations
with mods, like Ctrl + Left &harr; Ctrl + Right Arrow.
**Navigation**
|Keycodes |Description |
|-----------------------------------|-----------------------------------|
|`KC_LEFT` &harr; `KC_RGHT` | Left &harr; Right Arrow |
|`KC_UP` &harr; `KC_DOWN` | Up &harr; Down Arrow |
|`KC_HOME` &harr; `KC_END` | Home &harr; End |
|`KC_PGUP` &harr; `KC_PGDN` | Page Up &harr; Page Down |
|`KC_MS_L` &harr; `KC_MS_R` | Mouse Cursor Left &harr; Right |
|`KC_MS_U` &harr; `KC_MS_D` | Mouse Cursor Up &harr; Down |
|`KC_WH_L` &harr; `KC_WH_R` | Mouse Wheel Left &harr; Right |
|`KC_WH_U` &harr; `KC_WH_D` | Mouse Wheel Up &harr; Down |
**Misc**
|Keycodes |Description |
|-----------------------------------|-----------------------------------|
|`KC_BSPC` &harr; `KC_DEL` | Backspace &harr; Delete |
|`KC_LBRC` &harr; `KC_RBRC` | `[` &harr; `]` |
|`KC_LCBR` &harr; `KC_RCBR` | `{` &harr; `}` |
**Media**
|Keycodes |Description |
|-----------------------------------|-----------------------------------|
|`KC_WBAK` &harr; `KC_WFWD` | Browser Back &harr; Forward |
|`KC_MNXT` &harr; `KC_MPRV` | Next &harr; Previous Media Track |
|`KC_MFFD` &harr; `KC_MRWD` | Fast Forward &harr; Rewind Media |
|`KC_VOLU` &harr; `KC_VOLD` | Volume Up &harr; Down |
|`KC_BRIU` &harr; `KC_BRID` | Brightness Up &harr; Down |
**Hotkeys in Vim, Emacs, and other programs**
|Keycodes |Description |
|-----------------------------------|-----------------------------------|
|mod + `KC_F` &harr; mod + `KC_B` | Forward &harr; Backward |
|mod + `KC_D` &harr; mod + `KC_U` | Down &harr; Up |
|mod + `KC_N` &harr; mod + `KC_P` | Next &harr; Previous |
|mod + `KC_A` &harr; mod + `KC_E` | Home &harr; End |
|mod + `KC_O` &harr; mod + `KC_I` | Vim jump list Older &harr; Newer |
|`KC_J` &harr; `KC_K` | Down &harr; Up |
|`KC_H` &harr; `KC_L` | Left &harr; Right |
|`KC_W` &harr; `KC_B` | Forward &harr; Backward by Word |
(where above, "mod" is Ctrl, Alt, or GUI)
## Defining alternate keys
Use the `get_alt_repeat_key_keycode_user()` callback to define the "alternate"
for additional keys or override the default definitions. For example, to define
Ctrl + Y as the alternate of Ctrl + Z, and vice versa, add the following in
keymap.c:
```c
uint16_t get_alt_repeat_key_keycode_user(uint16_t keycode, uint8_t mods) {
if ((mods & MOD_MASK_CTRL)) { // Was Ctrl held?
switch (keycode) {
case KC_Y: return C(KC_Z); // Ctrl + Y reverses to Ctrl + Z.
case KC_Z: return C(KC_Y); // Ctrl + Z reverses to Ctrl + Y.
}
}
return KC_TRNS; // Defer to default definitions.
}
```
The `keycode` and `mods` args are the keycode and mods that were active with the
last pressed key. The meaning of the return value from this function is:
* `KC_NO` &ndash; do nothing (any predefined alternate key is not used);
* `KC_TRNS` &ndash; use the default alternate key if it exists;
* anything else &ndash; use the specified keycode. Any keycode may be returned
as an alternate key, including custom keycodes.
Another example, defining Shift + Tab as the alternate of Tab, and vice versa:
```c
uint16_t get_alt_repeat_key_keycode_user(uint16_t keycode, uint8_t mods) {
bool shifted = (mods & MOD_MASK_SHIFT); // Was Shift held?
switch (keycode) {
case KC_TAB:
if (shifted) { // If the last key was Shift + Tab,
return KC_TAB; // ... the reverse is Tab.
} else { // Otherwise, the last key was Tab,
return S(KC_TAB); // ... and the reverse is Shift + Tab.
}
}
return KC_TRNS;
}
```
#### Eliminating SFBs
Alternate Repeat can be configured more generally to perform an action that
"complements" the last key. Alternate Repeat is not limited to reverse
repeating, and it need not be symmetric. You can use it to eliminate cases of
same-finger bigrams in your layout, that is, pairs of letters typed by the same
finger. The following addresses the top 5 same-finger bigrams in English on
QWERTY, so that for instance "`ed`" may be typed as <kbd>E</kbd>, <kbd>Alt
Repeat</kbd>.
```c
uint16_t get_alt_repeat_key_keycode_user(uint16_t keycode, uint8_t mods) {
switch (keycode) {
case KC_E: return KC_D; // For "ED" bigram.
case KC_D: return KC_E; // For "DE" bigram.
case KC_C: return KC_E; // For "CE" bigram.
case KC_L: return KC_O; // For "LO" bigram.
case KC_U: return KC_N; // For "UN" bigram.
}
return KC_TRNS;
}
```
#### Typing shortcuts
A useful possibility is having Alternate Repeat press [a
macro](feature_macros.md). This way macros can be used without having to
dedicate keys to them. The following defines a couple shortcuts.
* Typing <kbd>K</kbd>, <kbd>Alt Repeat</kbd> produces "`keyboard`," with the
initial "`k`" typed as usual and the "`eybord`" produced by the macro.
* Typing <kbd>.</kbd>, <kbd>Alt Repeat</kbd> produces "`../`," handy for "up
directory" on the shell. Similary, <kbd>.</kbd> types the initial "`.`" and
"`./`" is produced by the macro.
```c
enum custom_keycodes {
M_KEYBOARD = SAFE_RANGE,
M_UPDIR,
// Other custom keys...
};
uint16_t get_alt_repeat_key_keycode_user(uint16_t keycode, uint8_t mods) {
switch (keycode) {
case KC_K: return M_KEYBOARD;
case KC_DOT: return M_UPDIR;
}
return KC_TRNS;
}
bool process_record_user(uint16_t keycode, keyrecord_t* record) {
switch (keycode) {
case M_KEYBOARD: SEND_STRING(/*k*/"eyboard"); break;
case M_UPDIR: SEND_STRING(/*.*/"./"); break;
}
return true;
}
```
## Ignoring certain keys and mods
In tracking what is "the last key" to be repeated or alternate repeated,
modifier and layer switch keys are always ignored. This makes it possible to set
some mods and change layers between pressing a key and repeating it. By default,
all other (non-modifier, non-layer switch) keys are remembered so that they are
eligible for repeating. To configure additional keys to be ignored, define
`remember_last_key_user()` in your keymap.c.
#### Ignoring a key
The following ignores the Backspace key:
```c
bool remember_last_key_user(uint16_t keycode, keyrecord_t* record,
uint8_t* remembered_mods) {
switch (keycode) {
case KC_BSPC:
return false; // Ignore backspace.
}
return true; // Other keys can be repeated.
}
```
Then for instance, the Repeat key in <kbd>Left Arrow</kbd>,
<kbd>Backspace</kbd>, <kbd>Repeat</kbd> sends Left Arrow again instead of
repeating Backspace.
The `remember_last_key_user()` callback is called on every key press excluding
modifiers and layer switches. Returning true indicates the key is remembered,
while false means it is ignored.
#### Filtering remembered mods
The `remembered_mods` arg represents the mods that will be remembered with
this key. It can be modified to forget certain mods. This may be
useful to forget capitalization when repeating shifted letters, so that "Aaron"
does not becom "AAron":
```c
bool remember_last_key_user(uint16_t keycode, keyrecord_t* record,
uint8_t* remembered_mods) {
// Forget Shift on letter keys when Shift or AltGr are the only mods.
switch (keycode) {
case KC_A ... KC_Z:
if ((*remembered_mods & ~(MOD_MASK_SHIFT | MOD_BIT(KC_RALT))) == 0) {
*remembered_mods &= ~MOD_MASK_SHIFT;
}
break;
}
return true;
}
```
#### Further conditions
Besides checking the keycode, this callback could also make conditions based on
the current layer state (with `IS_LAYER_ON(layer)`) or mods (`get_mods()`). For
example, the following ignores keys on layer 2 as well as key combinations
involving GUI:
```c
bool remember_last_key_user(uint16_t keycode, keyrecord_t* record,
uint8_t* remembered_mods) {
if (IS_LAYER_ON(2) || (get_mods() & MOD_MASK_GUI)) {
return false; // Ignore layer 2 keys and GUI chords.
}
return true; // Other keys can be repeated.
}
```
?> See [Layer Functions](feature_layers.md#functions) and [Checking Modifier
State](feature_advanced_keycodes.md#checking-modifier-state) for further
details.
## Handle how a key is repeated
By default, pressing the Repeat Key will simply behave as if the last key
were pressed again. This also works with macro keys with custom handlers,
invoking the macro again. In case fine-tuning is needed for sensible repetition,
you can handle how a key is repeated with `get_repeat_key_count()` within
`process_record_user()`.
The `get_repeat_key_count()` function returns a signed count of times the key
has been repeated or alternate repeated. When a key is pressed as usual,
`get_repeat_key_count()` is 0. On the first repeat, it is 1, then the second
repeat, 2, and so on. Negative counts are used similarly for alternate
repeating. For instance supposing `MY_MACRO` is a custom keycode used in the
layout:
```c
bool process_record_user(uint16_t keycode, keyrecord_t* record) {
switch (keycode) {
case MY_MACRO:
if (get_repeat_key_count() > 0) {
// MY_MACRO is being repeated!
if (record->event.pressed) {
SEND_STRING("repeat!");
}
} else {
// MY_MACRO is being used normally.
if (record->event.pressed) {
SEND_STRING("macro");
}
}
return false;
// Other macros...
}
return true;
}
```
## Handle how a key is alternate repeated
Pressing the Alternate Repeat Key behaves as if the "alternate" of the last
pressed key were pressed, if an alternate is defined. To define how a particular
key is alternate repeated, use the `get_alt_repeat_key_keycode_user()` callback
as described above to define which keycode to use as its alternate. Beyond this,
`get_repeat_key_count()` may be used in custom handlers to fine-tune behavior
when alternate repeating.
The following example defines `MY_MACRO` as its own alternate, and specially
handles repeating and alternate repeating:
```c
uint16_t get_alt_repeat_key_keycode_user(uint16_t keycode, uint8_t mods) {
switch (keycode) {
case MY_MACRO: return MY_MACRO; // MY_MACRO is its own alternate.
}
return KC_TRNS;
}
bool process_record_user(uint16_t keycode, keyrecord_t* record) {
switch (keycode) {
case MY_MACRO:
if (get_repeat_key_count() > 0) { // Repeating.
if (record->event.pressed) {
SEND_STRING("repeat!");
}
} else if (get_repeat_key_count() < 0) { // Alternate repeating.
if (record->event.pressed) {
SEND_STRING("alt repeat!");
}
} else { // Used normally.
if (record->event.pressed) {
SEND_STRING("macro");
}
}
return false;
// Other macros...
}
return true;
}
```
## Functions
| Function | Description |
|--------------------------------|------------------------------------------------------------------------|
| `get_last_keycode()` | The last key's keycode, the key to be repeated. |
| `get_last_mods()` | Mods to apply when repeating. |
| `set_last_keycode(kc)` | Set the keycode to be repeated. |
| `set_last_mods(mods)` | Set the mods to apply when repeating. |
| `get_repeat_key_count()` | Signed count of times the key has been repeated or alternate repeated. |
| `get_alt_repeat_key_keycode()` | Keycode to be used for alternate repeating. |
## Additional "Alternate" keys
By leveraging `get_last_keycode()` in macros, it is possible to define
additional, distinct "Alternate Repeat"-like keys. The following defines two
keys `ALTREP2` and `ALTREP3` and implements ten shortcuts with them for common
English 5-gram letter patterns, taking inspiration from
[Stenotype](feature_stenography.md):
| Typing | Produces | Typing | Produces |
|----------------------------------|----------|----------------------------------|----------|
| <kbd>A</kbd>, <kbd>ALTREP2</kbd> | `ation` | <kbd>A</kbd>, <kbd>ALTREP3</kbd> | `about` |
| <kbd>I</kbd>, <kbd>ALTREP2</kbd> | `ition` | <kbd>I</kbd>, <kbd>ALTREP3</kbd> | `inter` |
| <kbd>S</kbd>, <kbd>ALTREP2</kbd> | `ssion` | <kbd>S</kbd>, <kbd>ALTREP3</kbd> | `state` |
| <kbd>T</kbd>, <kbd>ALTREP2</kbd> | `their` | <kbd>T</kbd>, <kbd>ALTREP3</kbd> | `there` |
| <kbd>W</kbd>, <kbd>ALTREP2</kbd> | `which` | <kbd>W</kbd>, <kbd>ALTREP3</kbd> | `would` |
```c
enum custom_keycodes {
ALTREP2 = SAFE_RANGE,
ALTREP3,
};
// Use ALTREP2 and ALTREP3 in your layout...
bool remember_last_key_user(uint16_t keycode, keyrecord_t* record,
uint8_t* remembered_mods) {
switch (keycode) {
case ALTREP2:
case ALTREP3:
return false; // Ignore ALTREP keys.
}
return true; // Other keys can be repeated.
}
static void process_altrep2(uint16_t keycode, uint8_t mods) {
switch (keycode) {
case KC_A: SEND_STRING(/*a*/"tion"); break;
case KC_I: SEND_STRING(/*i*/"tion"); break;
case KC_S: SEND_STRING(/*s*/"sion"); break;
case KC_T: SEND_STRING(/*t*/"heir"); break;
case KC_W: SEND_STRING(/*w*/"hich"); break;
}
}
static void process_altrep3(uint16_t keycode, uint8_t mods) {
switch (keycode) {
case KC_A: SEND_STRING(/*a*/"bout"); break;
case KC_I: SEND_STRING(/*i*/"nter"); break;
case KC_S: SEND_STRING(/*s*/"tate"); break;
case KC_T: SEND_STRING(/*t*/"here"); break;
case KC_W: SEND_STRING(/*w*/"ould"); break;
}
}
bool process_record_user(uint16_t keycode, keyrecord_t* record) {
switch (keycode) {
case ALTREP2:
if (record->event.pressed) {
process_altrep2(get_last_keycode(), get_last_mods());
}
return false;
case ALTREP3:
if (record->event.pressed) {
process_altrep3(get_last_keycode(), get_last_mods());
}
return false;
}
return true;
}
```

View File

@ -156,6 +156,82 @@ const is31_led PROGMEM g_is31_leds[RGB_MATRIX_LED_COUNT] = {
Where `X_Y` is the location of the LED in the matrix defined by [the datasheet](https://www.issi.com/WW/pdf/31FL3733.pdf) and the header file `drivers/led/issi/is31fl3733.h`. The `driver` is the index of the driver you defined in your `config.h` (`0`, `1`, `2`, or `3` for now).
---
### IS31FL3736 :id=is31fl3736
There is basic support for addressable RGB matrix lighting with the I2C IS31FL3736 RGB controller. To enable it, add this to your `rules.mk`:
```make
RGB_MATRIX_ENABLE = yes
RGB_MATRIX_DRIVER = IS31FL3736
```
You can use between 1 and 4 IS31FL3736 IC's. Do not specify `DRIVER_ADDR_<N>` defines for IC's that are not present on your keyboard.
Configure the hardware via your `config.h`:
| Variable | Description | Default |
|----------|-------------|---------|
| `ISSI_TIMEOUT` | (Optional) How long to wait for i2c messages, in milliseconds | 100 |
| `ISSI_PERSISTENCE` | (Optional) Retry failed messages this many times | 0 |
| `ISSI_PWM_FREQUENCY` | (Optional) PWM Frequency Setting - IS31FL3736B only | 0 |
| `ISSI_GLOBALCURRENT` | (Optional) Configuration for the Global Current Register | 0xFF |
| `ISSI_SWPULLUP` | (Optional) Set the value of the SWx lines on-chip de-ghosting resistors | PUR_0R (Disabled) |
| `ISSI_CSPULLUP` | (Optional) Set the value of the CSx lines on-chip de-ghosting resistors | PUR_0R (Disabled) |
| `DRIVER_COUNT` | (Required) How many RGB driver IC's are present | |
| `RGB_MATRIX_LED_COUNT` | (Required) How many RGB lights are present across all drivers | |
| `DRIVER_ADDR_1` | (Required) Address for the first RGB driver | |
| `DRIVER_ADDR_2` | (Optional) Address for the second RGB driver | |
| `DRIVER_ADDR_3` | (Optional) Address for the third RGB driver | |
| `DRIVER_ADDR_4` | (Optional) Address for the fourth RGB driver | |
The IS31FL3736 IC's have on-chip resistors that can be enabled to allow for de-ghosting of the RGB matrix. By default these resistors are not enabled (`ISSI_SWPULLUP`/`ISSI_CSPULLUP` are given the value of`PUR_0R`), the values that can be set to enable de-ghosting are as follows:
| `ISSI_SWPULLUP/ISSI_CSPULLUP` | Description |
|----------------------|-------------|
| `PUR_0R` | (default) Do not use the on-chip resistors/enable de-ghosting |
| `PUR_05KR` | The 0.5k Ohm resistor used during blanking period (t_NOL) |
| `PUR_1KR` | The 1k Ohm resistor used during blanking period (t_NOL) |
| `PUR_2KR` | The 2k Ohm resistor used during blanking period (t_NOL) |
| `PUR_4KR` | The 4k Ohm resistor used during blanking period (t_NOL) |
| `PUR_8KR` | The 8k Ohm resistor during blanking period (t_NOL) |
| `PUR_16KR` | The 16k Ohm resistor during blanking period (t_NOL) |
| `PUR_32KR` | The 32k Ohm resistor used during blanking period (t_NOL) |
Here is an example using 2 drivers.
```c
// This is a 7-bit address, that gets left-shifted and bit 0
// set to 0 for write, 1 for read (as per I2C protocol)
// The address will vary depending on your wiring:
// 0000 <-> GND
// 0101 <-> SCL
// 1010 <-> SDA
// 1111 <-> VCC
// ADDR represents A3:A0 of the 7-bit address.
// The result is: 0b101(ADDR)
#define DRIVER_ADDR_1 0b1010000
#define DRIVER_ADDR_2 0b1010001
#define DRIVER_COUNT 2
#define DRIVER_1_LED_TOTAL 30
#define DRIVER_2_LED_TOTAL 32
#define RGB_MATRIX_LED_COUNT (DRIVER_1_LED_TOTAL + DRIVER_2_LED_TOTAL)
```
!> Note the parentheses, this is so when `RGB_MATRIX_LED_COUNT` is used in code and expanded, the values are added together before any additional math is applied to them. As an example, `rand() % (DRIVER_1_LED_TOTAL + DRIVER_2_LED_TOTAL)` will give very different results than `rand() % DRIVER_1_LED_TOTAL + DRIVER_2_LED_TOTAL`.
Define these arrays listing all the LEDs in your `<keyboard>.c`:
```c
const is31_led PROGMEM g_is31_leds[RGB_MATRIX_LED_COUNT] = {
/* Refer to IS31 manual for these locations
* driver
* | R location
* | | G location
* | | | B location
* | | | | */
{0, B_1, A_1, C_1},
....
}
```
### IS31FL3737 :id=is31fl3737
There is basic support for addressable RGB matrix lighting with the I2C IS31FL3737 RGB controller. To enable it, add this to your `rules.mk`:
@ -218,8 +294,6 @@ Here is an example using 2 drivers.
```
!> Note the parentheses, this is so when `RGB_MATRIX_LED_COUNT` is used in code and expanded, the values are added together before any additional math is applied to them. As an example, `rand() % (DRIVER_1_LED_TOTAL + DRIVER_2_LED_TOTAL)` will give very different results than `rand() % DRIVER_1_LED_TOTAL + DRIVER_2_LED_TOTAL`.
Currently only 2 drivers are supported, but it would be trivial to support all 4 combinations.
Define these arrays listing all the LEDs in your `<keyboard>.c`:
```c
@ -361,7 +435,7 @@ Configure the hardware via your `config.h`:
```c
// The pin connected to the data pin of the LEDs
#define RGB_DI_PIN D7
#define WS2812_DI_PIN D7
// The number of LEDs connected
#define RGB_MATRIX_LED_COUNT 70
```
@ -383,9 +457,9 @@ Configure the hardware via your `config.h`:
```c
// The pin connected to the data pin of the LEDs
#define RGB_DI_PIN D7
#define APA102_DI_PIN D7
// The pin connected to the clock pin of the LEDs
#define RGB_CI_PIN D6
#define APA102_CI_PIN D6
// The number of LEDs connected
#define RGB_MATRIX_LED_COUNT 70
```
@ -690,6 +764,14 @@ Remove the spread effect entirely.
#define RGB_MATRIX_TYPING_HEATMAP_SLIM
```
It's also possible to adjust the tempo of *heating up*. It's defined as the number of shades that are
increased on the [HSV scale](https://en.wikipedia.org/wiki/HSL_and_HSV). Decreasing this value increases
the number of keystrokes needed to fully heat up the key.
```c
#define RGB_MATRIX_TYPING_HEATMAP_INCREASE_STEP 32
```
### RGB Matrix Effect Solid Reactive :id=rgb-matrix-effect-solid-reactive
Solid reactive effects will pulse RGB light on key presses with user configurable hues. To enable gradient mode that will automatically change reactive color, add the following define:
@ -811,13 +893,7 @@ These are defined in [`color.h`](https://github.com/qmk/qmk_firmware/blob/master
## EEPROM storage :id=eeprom-storage
The EEPROM for it is currently shared with the LED Matrix system (it's generally assumed only one feature would be used at a time), but could be configured to use its own 32bit address with:
```c
#define EECONFIG_RGB_MATRIX (uint32_t *)28
```
Where `28` is an unused index from `eeconfig.h`.
The EEPROM for it is currently shared with the LED Matrix system (it's generally assumed only one feature would be used at a time).
## Functions :id=functions

View File

@ -33,12 +33,13 @@ RGBLIGHT_DRIVER = APA102
At minimum you must define the data pin your LED strip is connected to, and the number of LEDs in the strip, in your `config.h`. For APA102 LEDs, you must also define the clock pin. If your keyboard has onboard RGB LEDs, and you are simply creating a keymap, you usually won't need to modify these.
|Define |Description |
|---------------|---------------------------------------------------------------------------------------------------------|
|`RGB_DI_PIN` |The pin connected to the data pin of the LEDs |
|`RGB_CI_PIN` |The pin connected to the clock pin of the LEDs (APA102 only) |
|`RGBLED_NUM` |The number of LEDs connected |
|`RGBLED_SPLIT` |(Optional) For split keyboards, the number of LEDs connected on each half directly wired to `RGB_DI_PIN` |
|Define |Description |
|---------------|-------------------------------------------------------------------------|
|`WS2812_DI_PIN`|The pin connected to the data pin of the LEDs (WS2812) |
|`APA102_DI_PIN`|The pin connected to the data pin of the LEDs (APA102) |
|`APA102_CI_PIN`|The pin connected to the clock pin of the LEDs (APA102) |
|`RGBLED_NUM` |The number of LEDs connected |
|`RGBLED_SPLIT` |(Optional) For split keyboards, the number of LEDs connected on each half|
Then you should be able to use the keycodes below to change the RGB lighting to your liking.

View File

@ -1,6 +1,6 @@
# Space Cadet: The Future, Built In
Steve Losh described the [Space Cadet Shift](https://stevelosh.com/blog/2012/10/a-modern-space-cadet/) quite well. Essentially, when you tap Left Shift on its own, you get an opening parenthesis; tap Right Shift on its own and you get the closing one. When held, the Shift keys function as normal. Yes, it's as cool as it sounds, and now even cooler supporting Control and Alt as well!
Steve Losh described the [Space Cadet Shift](https://web.archive.org/web/20230330090938/https://stevelosh.com/blog/2012/10/a-modern-space-cadet/) quite well. Essentially, when you tap Left Shift on its own, you get an opening parenthesis; tap Right Shift on its own and you get the closing one. When held, the Shift keys function as normal. Yes, it's as cool as it sounds, and now even cooler supporting Control and Alt as well!
## Usage

View File

@ -300,6 +300,12 @@ This enables transmitting the pointing device status to the master side of the s
This enables triggering of haptic feedback on the slave side of the split keyboard. For DRV2605L this will send the mode, but for solenoids it is expected that the desired mode is already set up on the slave.
```c
#define SPLIT_ACTIVITY_ENABLE
```
This synchronizes the activity timestamps between sides of the split keyboard, allowing for activity timeouts to occur.
### Custom data sync between sides :id=custom-data-sync
QMK's split transport allows for arbitrary data transactions at both the keyboard and user levels. This is modelled on a remote procedure call, with the master invoking a function on the slave side, with the ability to send data from master to slave, process it slave side, and send data back from slave to master.

View File

@ -138,7 +138,7 @@ bool post_process_steno_user(uint16_t keycode, keyrecord_t *record, steno_mode_t
This function is called after a key has been processed, but before any decision about whether or not to send a chord. This is where to put hooks for things like, say, live displays of steno chords or keys.
If `IS_PRESSED(record->event)` is false, and `n_pressed_keys` is 0 or 1, the chord will be sent shortly, but has not yet been sent. This relieves you of the need of keeping track of where a packet ends and another begins.
If `record->event.pressed` is false, and `n_pressed_keys` is 0 or 1, the chord will be sent shortly, but has not yet been sent. This relieves you of the need of keeping track of where a packet ends and another begins.
The `chord` argument contains the packet of the current chord as specified by the protocol in use. This is *NOT* simply a list of chorded steno keys of the form `[STN_E, STN_U, STN_BR, STN_GR]`. Refer to the appropriate protocol section of this document to learn more about the format of the packets in your steno protocol/mode of choice.

View File

@ -47,6 +47,11 @@ const uint8_t PROGMEM encoder_hand_swap_config[NUM_ENCODERS] = { 1, 0 };
### Functions :id=functions
| Function | Description |
|----------------------|---------------------------------------------|
| `is_swap_hands_on()` | Returns true if Swap-Hands is currently on. |
User callback functions to manipulate Swap-Hands:
| Function | Description |
|-----------------------|---------------------------------------------|
| `swap_hands_on()` | Turns Swap-Hands on. |
| `swap_hands_off()` | Turns Swap-Hands off. |
| `swap_hands_toggle()` | Toggles Swap-Hands. |
| `is_swap_hands_on()` | Returns true if Swap-Hands is currently on. |

View File

@ -1,4 +1,4 @@
# Word Per Minute (WPM) Calculcation
# Word Per Minute (WPM) Calculation
The WPM feature uses time between keystrokes to compute a rolling average words per minute rate and makes this available for various uses.

View File

@ -1,56 +0,0 @@
# Vagrant Quick Start
This project includes a `Vagrantfile` that will allow you to build a new firmware for your keyboard very easily without major changes to your primary operating system. This also ensures that when you clone the project and perform a build, you have the exact same environment as anyone else using the Vagrantfile to build. This makes it much easier for people to help you troubleshoot any issues you encounter.
## Requirements
Using the `Vagrantfile` in this repository requires you have [Vagrant](https://www.vagrantup.com/) as well as a supported provider installed:
* [VirtualBox](https://www.virtualbox.org/) (Version at least 5.0.12)
* Sold as 'the most accessible platform to use Vagrant'
* [VMware Workstation](https://www.vmware.com/products/workstation) and [Vagrant VMware plugin](https://www.vagrantup.com/vmware)
* The (paid) VMware plugin requires a licensed copy of VMware Workstation/Fusion
* [Docker](https://www.docker.com/)
Other than having Vagrant, a suitable provider installed and possibly a restart of your computer afterwards, you can simple run a 'vagrant up' anywhere inside the folder where you checked out this project and it will start an environment (either a virtual machine or container) that contains all the tools required to build this project. There is a post Vagrant startup hint that will get you off on the right foot, otherwise you can also reference the build documentation below.
## Flashing the Firmware
The "easy" way to flash the firmware is using a tool from your host OS:
* [QMK Toolbox](https://github.com/qmk/qmk_toolbox) (recommended)
* [Teensy Loader](https://www.pjrc.com/teensy/loader.html)
If you want to program via the command line you can uncomment the ['modifyvm'] lines in the Vagrantfile to enable the USB passthrough into Linux and then program using the command line tools like dfu-util/dfu-programmer or you can install the Teensy CLI version.
## Vagrantfile Overview
The development environment is configured to run the QMK Docker image, `qmkfm/qmk_cli`. This not only ensures predictability between systems, it also mirrors the CI environment.
## FAQ
### Why am I seeing issues under Virtualbox?
Certain versions of Virtualbox 5 appear to have an incompatibility with the Virtualbox extensions installed in the boxes in this Vagrantfile. If you encounter any issues with the /vagrant mount not succeeding, please upgrade your version of Virtualbox to at least 5.0.12. **Alternately, you can try running the following command:**
```
vagrant plugin install vagrant-vbguest
```
### How do I remove an existing environment?
Finished with your environment? From anywhere inside the folder where you checked out this project, Execute:
```
vagrant destroy
```
### What if I want to use Docker directly?
Want to benefit from the Vagrant workflow without a virtual machine? The Vagrantfile is configured to bypass running a virtual machine, and run the container directly. Execute the following when bringing up the environment to force the use of Docker:
```
vagrant up --provider=docker
```
### How do I access the virtual machine instead of the Docker container?
Execute the following to bypass the `vagrant` user booting directly to the official qmk builder image:
```
vagrant ssh -c 'sudo -i'
```

View File

@ -35,6 +35,40 @@ To use a 5V/16MHz Pro Micro as an ISP flashing tool, you will first need to load
!> Note that the `10` pin on the Pro Micro should be wired to the `RESET` pin on the keyboard's controller. ***DO NOT*** connect the `RESET` pin on the Pro Micro to the `RESET` on the keyboard.
### Arduino Uno / Micro as ISP
[Arduino Uno](https://store.arduino.cc/products/arduino-uno-rev3)
[Arduino Micro](https://store.arduino.cc/products/arduino-micro)
A standard Uno or Micro can be used as an ISP flashing tool using the [example "ArduinoISP" sketch](https://docs.arduino.cc/built-in-examples/arduino-isp/ArduinoISP#load-the-sketch) to emulate an STK500 ISP. Also works with Sparkfun Pro Micros and clones.
**AVRDUDE Programmer**: `stk500v1`
**AVRDUDE Port**: Serial
#### Wiring
|Uno |Keyboard|
|-----------|--------|
|`5V` |`VCC` |
|`GND` |`GND` |
|`10` (`B2`)|`RESET` |
|`13` (`B5`)|`SCLK` |
|`11` (`B3`)|`MOSI` |
|`12` (`B4`)|`MISO` |
|Micro |Keyboard|
|-----------|--------|
|`5V` |`VCC` |
|`GND` |`GND` |
|`10` (`B6`)|`RESET` |
|`15` (`B1`)|`SCLK` |
|`16` (`B2`)|`MOSI` |
|`14` (`B3`)|`MISO` |
!> Note that the `10` pin on the Uno/Micro should be wired to the `RESET` pin on the keyboard's controller. ***DO NOT*** connect the `RESET` pin on the Uno/Micro to the `RESET` on the keyboard.
### Teensy 2.0 as ISP
[PJRC Teensy 2.0](https://www.pjrc.com/store/teensy.html)
@ -57,6 +91,7 @@ To use a Teensy 2.0 as an ISP flashing tool, you will first need to load a [spec
!> Note that the `B0` pin on the Teensy should be wired to the `RESET` pin on the keyboard's controller. ***DO NOT*** connect the `RESET` pin on the Teensy to the `RESET` on the keyboard.
### SparkFun PocketAVR / USBtinyISP
[SparkFun PocketAVR](https://www.sparkfun.com/products/9825)

View File

@ -38,7 +38,6 @@
* [キーマップの概要](ja/keymap.md)
* 開発環境
* [Docker のガイド](ja/getting_started_docker.md)
* [Vagrant のガイド](ja/getting_started_vagrant.md)
* 書き込み
* [書き込み](ja/flashing.md)
* [ATmega32A の書き込み (ps2avrgb)](ja/flashing_bootloadhid.md)
@ -69,6 +68,7 @@
* [モッドタップ](ja/mod_tap.md)
* [マクロ](ja/feature_macros.md)
* [マウスキー](ja/feature_mouse_keys.md)
* [Repeat Key](ja/feature_repeat_key.md)
* [Space Cadet Shift](ja/feature_space_cadet.md)
* [US ANSI シフトキー](ja/keycodes_us_ansi_shifted.md)

View File

@ -159,9 +159,6 @@ QMK での全ての利用可能な設定にはデフォルトがあります。
* 詳細は [Permissive Hold](ja/tap_hold.md#permissive-hold) を見てください
* `#define PERMISSIVE_HOLD_PER_KEY`
* キーごとの `PERMISSIVE_HOLD` 設定の処理を有効にします
* `#define IGNORE_MOD_TAP_INTERRUPT`
* 両方のキーに `TAPPING_TERM` を適用することで、ホールド時に他のキーに変換するキーを使ってローリングコンボ (zx) をすることができるようにします
* 詳細は [Ignore Mod Tap Interrupt](ja/tap_hold.md#ignore-mod-tap-interrupt) を見てください
* `#define TAPPING_FORCE_HOLD`
* タップされた直後に、デュアルロールキーを修飾子として使用できるようにします
* [Tapping Force Hold](ja/tap_hold.md#tapping-force-hold)を見てください
@ -179,8 +176,6 @@ QMK での全ての利用可能な設定にはデフォルトがあります。
* ワンショットがタイムアウトするまでの時間
* `#define ONESHOT_TAP_TOGGLE 2`
* ワンショットトグルが引き起こされるまでのタップ数
* `#define COMBO_COUNT 2`
* [コンボ](ja/feature_combo.md)機能で使っているコンボの数にこれを設定します。
* `#define COMBO_TERM 200`
* コンボキーが検出されるまでの時間。定義されていない場合は、デフォルトは `TAPPING_TERM` です。
* `#define TAP_CODE_DELAY 100`

View File

@ -18,7 +18,7 @@
```c
const uint16_t PROGMEM test_combo[] = {KC_A, KC_B, COMBO_END};
combo_t key_combos[COMBO_COUNT] = {COMBO(test_combo, KC_ESC)};
combo_t key_combos[] = {COMBO(test_combo, KC_ESC)};
```
これは、A と B のキーを押した場合に、"Escape" を送信します。
@ -38,7 +38,7 @@ enum combos {
const uint16_t PROGMEM ab_combo[] = {KC_A, KC_B, COMBO_END};
const uint16_t PROGMEM jk_combo[] = {KC_J, KC_K, COMBO_END};
combo_t key_combos[COMBO_COUNT] = {
combo_t key_combos[] = {
[AB_ESC] = COMBO(ab_combo, KC_ESC),
[JK_TAB] = COMBO(jk_combo, KC_TAB)
};
@ -55,7 +55,7 @@ enum combo_events {
const uint16_t PROGMEM copy_combo[] = {KC_Z, KC_C, COMBO_END};
const uint16_t PROGMEM paste_combo[] = {KC_X, KC_V, COMBO_END};
combo_t key_combos[COMBO_COUNT] = {
combo_t key_combos[] = {
[ZC_COPY] = COMBO_ACTION(copy_combo),
[XV_PASTE] = COMBO_ACTION(paste_combo),
};

View File

@ -64,7 +64,7 @@ QMK はその場で作られた一時的なマクロをサポートします。
direction がどのマクロであるかを示すことに注意してください。`1` がマクロ 1、`-1` がマクロ 2、0 がマクロ無しです。
* `dynamic_macro_record_start_user(void)` - マクロの記録を開始する時に起動されます。
* `dynamic_macro_record_start_user(int8_t direction)` - マクロの記録を開始する時に起動されます。
* `dynamic_macro_play_user(int8_t direction)` - マクロを再生する時に起動されます。
* `dynamic_macro_record_key_user(int8_t direction, keyrecord_t *record)` - マクロの記録中に各キー押下で起動されます。
* `dynamic_macro_record_end_user(int8_t direction)` - マクロの記録を停止した時に起動されます。

View File

@ -80,7 +80,7 @@ bool process_steno_user(uint16_t keycode, keyrecord_t *record) { return true; }
bool post_process_steno_user(uint16_t keycode, keyrecord_t *record, steno_mode_t mode, uint8_t chord[6], int8_t pressed);
```
この関数はキーが処理された後、ただしコードを送信するかどうかを決める前に呼び出されます。`IS_PRESSED(record->event)` が false で、`pressed` が 0 または 1 の場合は、コードはまもなく送信されますが、まだ送信されてはいません。ここが速記コードあるいはキーのライブ表示などのフックを配置する場所です。
この関数はキーが処理された後、ただしコードを送信するかどうかを決める前に呼び出されます。`record->event.pressed` が false で、`pressed` が 0 または 1 の場合は、コードはまもなく送信されますが、まだ送信されてはいません。ここが速記コードあるいはキーのライブ表示などのフックを配置する場所です。
## キーコードリファレンス :id=keycode-reference

View File

@ -1,61 +0,0 @@
# Vagrant クイックスタート
<!---
original document: 0.12.43:docs/getting_started_vagrant.md
git diff 0.12.43 HEAD -- docs/getting_started_vagrant.md | cat
-->
このプロジェクトは、プライマリオペレーティングシステムに大きな変更を加えることなくキーボードの新しいファームウェアを非常に簡単に構築することができる `Vagrantfile` を含みます。これは、あなたがプロジェクトをクローンしビルドを実行した時に、ビルドのために Vagrantfile を使っている他のユーザと全く同じ環境を持つことも保証します。これにより、人々はあなたが遭遇した問題の解決をより簡単に行えるようになります。
## 必要事項
このリポジトリ内の `Vagrantfile` を使うには、[Vagrant](https://www.vagrantup.com/) およびサポートされるプロバイダがインストールされている必要があります:
* [VirtualBox](https://www.virtualbox.org/) (バージョン 5.0.12 以降)
* 「Vagrant を使うために最もアクセスしやすいプラットフォーム」とうたわれています。
* [VMware Workstation](https://www.vmware.com/products/workstation) および [Vagrant VMware プラグイン](https://www.vagrantup.com/vmware)
* (有料) VMware プラグインには、ライセンスされた VMware Workstation/Fusion のコピーが必要です。
* [Docker](https://www.docker.com/)
Vagrant 以外に、適切なプロバイダがインストールされ、その後におそらくコンピュータを再起動すると、このプロジェクトをチェックアウトしたフォルダ内の任意の場所で 'vagrant up' を単純に実行することができ、このプロジェクトをビルドするのに必要な全てのツールが含まれる環境(仮想マシンあるいはコンテナ)が開始されます。Vagrant 起動時にうまく始めるためのヒントが表示されますが、それ以外に、以下のビルドドキュメントを参照することもできます。
## ファームウェアの書き込み
ファームウェアを書き込む「簡単な」方法は、ホスト OS からツールを使うことです:
* [QMK Toolbox](https://github.com/qmk/qmk_toolbox) (推奨)
* [Teensy ローダー](https://www.pjrc.com/teensy/loader.html)
コマンドラインでプログラムしたい場合は、Vagranfile の ['modifyvm'] 行のコメントを解除して Linux への USB パススルーを有効にし、dfu-util/dfu-programmer のようなコマンドラインツールを使ってプログラムすることができます。あるいは Teensy CLI バージョンをインストールすることができます。
## Vagrantfile の概要
開発環境は QMK Docker イメージ、`qmkfm/qmk_cli` を実行するように設定されています。これはシステム間の予測可能性が保証されるだけでなく、CI 環境もミラーされます。
## FAQ
### Virtualbox で問題が発生するのはなぜですか?
Virtualbox 5 の特定のバージョンはこの Vagrantfile のボックスにインストールされている Virtualbox の拡張機能と互換性が無いようです。/vagrant のマウントで問題が発生した場合は、Virtualbox のバージョンを少なくとも 5.0.12 にアップグレードしてください。**または、以下のコマンドを実行してみることができます:**
```console
vagrant plugin install vagrant-vbguest
```
### 既存の環境を削除するにはどうすればいいですか?
あなたの環境での作業が完了しましたか?このプロジェクトをチェックアウトしたフォルダの中のどこからでも、以下を実行してください:
```console
vagrant destroy
```
### Docker を直接使いたい場合はどうしますか?
仮想マシン無しで Vagrant のワークフローを活用したいですかVagrantfile は仮想マシンの実行をバイパスし、コンテナを直接実行するように設定されています。Docker を強制的に使うように環境を立ち上げる場合は、以下を実行してください:
```console
vagrant up --provider=docker
```
### Docker コンテナではなく仮想マシンにアクセスするにはどうすればいいですか?
以下を実行して、公式の QMK ビルダーイメージから直接起動する `vagrant` ユーザをバイパスするようにします:
```console
vagrant ssh -c 'sudo -i'
```

View File

@ -63,8 +63,6 @@ uint16_t get_tapping_term(uint16_t keycode, keyrecord_t *record) {
通常、これら全てを `TAPPING_TERM` (デフォルト: 200ms) 内で行うと、ファームウェアとホストシステムによって `ax` として登録されます。許容ホールドを有効にすると、別のキーがタップされた場合にモッドタップキーを修飾キーと見なすように処理を変更し、 `X` (`SHIFT`+`x`) と登録されます。
?> `モッドタップ割り込みの無視`を有効にしている場合、これにより両方の動きが変更されます。通常のキーには、最初のキーが最初に放された場合、あるいは両方のキーが `TAPPING_TERM` より長くホールドされた場合に、修飾キーが追加されます。
この機能をより細かく制御するために、以下を `config.h` に追加することができます:
```c
@ -84,32 +82,6 @@ bool get_permissive_hold(uint16_t keycode, keyrecord_t *record) {
}
```
## モッドタップ割り込みの無視
この設定を有効にするには、これを `config.h` に追加してください:
```c
#define IGNORE_MOD_TAP_INTERRUPT
```
許容ホールドと同様に、これは高速なタイピストのためのファームウェアの処理方法を変更します。モッドタップキーを押し、他のキーを押し、モッドタップキーを放し、通常のキーを放すと、`TAPPING_TERM` 内で押された場合でも、通常はモッドと通常のキーが出力されます。これは、ローリングコンボキーや、頻繁に使用するキー(例えば、`RCTL_T(KC_QUOT)`)にモッドタップを使う高速なタイピストには望ましくない場合があります。
`モッドタップ割り込みの無視`を設定するには、両方のキーを `TAPPING_TERM` の間ホールドすると、(その修飾キーの)ホールド機能を実行する必要があります。
例えば:
- `SFT_T(KC_A)` を押す
- `KC_X` を押す
- `SFT_T(KC_A)` を放す
- `KC_X` を放す
通常、これは大文字の `X` (`SHIFT`+`x`)、またはモッド + キーを送信します。`モッドタップ割り込みの無視` を有効にすると、ホールドアクションを登録するには、両方のキーを `TAPPING_TERM` の間ホールドする必要があります。この場合、素早いタップは `ax` を送信しますが、両方をホールドすると、大文字の `X` (`SHIFT`+`x`) を出力します。
?> __注意__: これはモディファイアにのみ関係し、レイヤー切り替えキーには関係しません。
?> `許容ホールド`を有効にすると、これは両方がどのように動作するかを変更します。通常のキーには、最初のキーが最初に放された場合、あるいは両方のキーが `TAPPING_TERM` より長くホールドされた場合に、修飾キーが追加されます。
## タッピング強制ホールド
`タッピング強制ホールド` を有効にするには、以下を `config.h` に追加します:

View File

@ -804,6 +804,15 @@ See also: [Programmable Button](feature_programmable_button.md)
|`QK_PROGRAMMABLE_BUTTON_31`|`PB_31`|Programmable button 31|
|`QK_PROGRAMMABLE_BUTTON_32`|`PB_32`|Programmable button 32|
## Repeat Key :id=repeat-key
See also: [Repeat Key](feature_repeat_key.md)
|Keycode |Aliases |Description |
|-----------------------|---------|-------------------------------------|
|`QK_REPEAT_KEY` |`QK_REP` |Repeat the last pressed key |
|`QK_ALT_REPEAT_KEY` |`QK_AREP`|Perform alternate of the last key |
## Space Cadet :id=space-cadet
See also: [Space Cadet](feature_space_cadet.md)

View File

@ -111,8 +111,6 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) {
}
```
Enabling `IGNORE_MOD_TAP_INTERRUPT` is recommended when using Mod-Tap on alphanumeric keys to avoid hold function taking precendence when the next key is pressed quickly. See [Ignore Mod Tap Interrupt](tap_hold.md#ignore-mod-tap-interrupt) for more details.
### Changing both tap and hold
This last example implements custom tap and hold function with `LT(0,KC_NO)` to create a single copy-on-tap, paste-on-hold key:

View File

@ -4,6 +4,8 @@
The [QMK Configurator](https://config.qmk.fm) is an online graphical user interface that generates QMK Firmware `.hex` or `.bin` files.
It should be noted that Configurator cannot produce firmwares for keyboards using a different controller than they were designed for, i.e. an RP2040 controller on a board designed for pro micro. You will have to use the command line [converters](https://docs.qmk.fm/#/feature_converters?id=supported-converters) for this.
Watch the [Video Tutorial](https://www.youtube.com/watch?v=-imgglzDMdY). Many people find that is enough information to start programming their own keyboard.
The QMK Configurator works best with Chrome or Firefox.

View File

@ -85,6 +85,8 @@ Visit the [QMK Configurator](https://config.qmk.fm/#/) to create a keymap file:
3. Customise the key layout according to your preference.
4. Select download next to **KEYMAP.JSON** and save the JSON file into the `~/qmk_keymap/` folder.
!> **Important:** Make sure that the GitHub username you use in step 2 is correct. If it is not, the build process will fail to locate your files in the right folder.
### Add a GitHub Action workflow
Open the file `~/qmk_keymap/.github/workflows/build.yml` with your favorite [text editor](newbs_learn_more_resources.md#text-editor-resources), paste the following workflow content, and save it:
@ -95,7 +97,7 @@ on: [push, workflow_dispatch]
jobs:
build:
runs-on: ubuntu-latest
container: qmkfm/qmk_cli
container: ghcr.io/qmk/qmk_cli
strategy:
fail-fast: false
matrix:

View File

@ -15,7 +15,7 @@ Different keyboards have different ways to enter this special mode. If your PCB
* Press the physical `RESET` button, usually located on the underside of the PCB
* Locate header pins on the PCB labeled `RESET` and `GND`, and short them together while plugging your PCB in
If you've attempted all of the above to no avail, and the main chip on the board says `STM32` on it, this may be a bit more complicated. Generally your best bet is to ask on [Discord](https://discord.gg/Uq7gcHh) for assistance. It's likely some photos of the board will be asked for -- if you can get them ready beforehand it'll help move things along!
If you've attempted all of the above to no avail, and the main chip on the board says `STM32` or `RP2-B1` on it, this may be a bit more complicated. Generally your best bet is to ask on [Discord](https://discord.gg/Uq7gcHh) for assistance. It's likely some photos of the board will be asked for -- if you can get them ready beforehand it'll help move things along!
Otherwise, you should see a message in yellow, similar to this in QMK Toolbox:
@ -31,6 +31,8 @@ The simplest way to flash your keyboard will be with the [QMK Toolbox](https://g
However, the Toolbox is currently only available for Windows and macOS. If you're using Linux (or just wish to flash the firmware from the command line), skip to the [Flash your Keyboard from the Command Line](#flash-your-keyboard-from-the-command-line) section.
?> QMK Toolbox is not necessary for flashing [RP2040 devices](https://docs.qmk.fm/#/flashing?id=raspberry-pi-rp2040-uf2).
### Load the File into QMK Toolbox
Begin by opening the QMK Toolbox application. You'll want to locate the firmware file in Finder or Explorer. Your keyboard firmware may be in one of two formats- `.hex` or `.bin`. QMK tries to copy the appropriate one for your keyboard into the root `qmk_firmware` directory.

View File

@ -120,7 +120,7 @@ NOTE: remember to follow the instructions printed at the end of installation (us
### ** Windows **
After installing QMK you can set it up with this command:
Open QMK MSYS and run the following command:
qmk setup
@ -128,7 +128,7 @@ In most situations you will want to answer `y` to all of the prompts.
### ** macOS **
After installing QMK you can set it up with this command:
Open Terminal and run the following command:
qmk setup
@ -136,7 +136,7 @@ In most situations you will want to answer `y` to all of the prompts.
### ** Linux/WSL **
After installing QMK you can set it up with this command:
Open your preferred terminal app and run the following command:
qmk setup
@ -150,7 +150,7 @@ Luckily, the fix is easy. Run this as your user: `echo 'PATH="$HOME/.local/bin:$
### ** FreeBSD **
After installing QMK you can set it up with this command:
Open your preferred terminal app and run the following command:
qmk setup
@ -172,6 +172,8 @@ For example, to build a firmware for a Clueboard 66% you would use:
qmk compile -kb clueboard/66/rev3 -km default
?> The keyboard option is the path relative to the keyboard directory, the above example would be found in `qmk_firmware/keyboards/clueboard/66/rev3`. If you're unsure you can view a full list of supported keyboards with `qmk list-keyboards`.
When it is done you should have a lot of output that ends similar to this:
```

View File

@ -46,16 +46,7 @@ Before starting, you will want to make sure that you have all of the build tools
This part is super simple. However, there is some configuration that we need to do to ensure things are configured correctly.
### Configuring VS Code
First, we need to set up IntelliSense. This isn't strictly required, but it will make your life a LOT easier. To do this, we need to create the `.vscode/c_cpp_properties.json` file in the QMK Firmware folder, You can do this all manually, but I've done most of the work already.
Grab [this file](https://gist.github.com/drashna/48e2c49ce877be592a1650f91f8473e8) and save it. You may need to edit this file, if you didn't install MSYS2 to the default location, or are using WSL/LxSS.
Once you have saved this file, you will need to reload VS Code, if it was already running.
?> You should see an `extensions.json` and `settings.json` file in the `.vscode` folder, as well.
#### MSYS2 Setup
Now, we will set up the MSYS2 window to show up in VSCode as the integrated terminal. This has a number of advantages. Mostly, you can control+click on errors and jump to those files. This makes debugging much easier. It's also nice, in that you don't have to jump to another window.
@ -101,17 +92,28 @@ No, really, that's it. The paths needed are already included when installing th
There are a number of extensions that you may want to install:
* [Git Extension Pack](https://marketplace.visualstudio.com/items?itemName=donjayamanne.git-extension-pack) -
This installs a bunch of Git related tools that may make using Git with QMK Firmware easier.
* [Git Extension Pack](https://marketplace.visualstudio.com/items?itemName=donjayamanne.git-extension-pack) - This installs a bunch of Git related tools that may make using Git with QMK Firmware easier.
* [clangd](https://marketplace.visualstudio.com/items?itemName=llvm-vs-code-extensions.vscode-clangd) - _[Optional]_ - This is the language server for C/C++ that VS Code uses. It provides IntelliSense and other features.
* [EditorConfig for VS Code](https://marketplace.visualstudio.com/items?itemName=EditorConfig.EditorConfig) - _[Optional]_ - Helps to keep the code to the QMK Coding Conventions.
* [GitHub Markdown Preview](https://marketplace.visualstudio.com/items?itemName=bierner.github-markdown-preview) - _[Optional]_ - Makes the markdown preview in VS Code more like GitHub's.
* [VS Live Share Extension Pack](https://marketplace.visualstudio.com/items?itemName=MS-vsliveshare.vsliveshare-pack) - _[Optional]_ - This extension allows somebody else to access your workspace (or you to access somebody else's workspace) and help out. This is great if you're having issues and need some help from somebody.
Restart once you've installed any extensions
Restart once you've installed any extensions.
# Configure VS Code for QMK
1. Click <kbd><kbd>File</kbd> > <kbd>Open Folder</kbd></kbd>
2. Open the QMK Firmware folder that you cloned from GitHub.
2. Open the QMK Firmware folder that you cloned from GitHub.
3. Click <kbd><kbd>File</kbd> > <kbd>Save Workspace As...</kbd></kbd>
And now you're ready to code QMK Firmware in VS Code
## Configuring VS Code
Using the [standard `compile_commands.json` database](https://clang.llvm.org/docs/JSONCompilationDatabase.html), we can get the VS code _clangd_ extension to use the correct includes and defines used for your keyboard and keymap.
1. Run `qmk generate-compilation-database -kb <keyboard> -km <keymap>` to generate the `compile_commands.json`.
1. Inside VS code, press <kbd><kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>P</kbd></kbd> (macOS: <kbd><kbd>Command</kbd> + <kbd>Shift</kbd> + <kbd>P</kbd></kbd>) to open the command palette.
1. Start typing `clangd: Download Language Server` and select it when it appears. Note that this only needs to be done once on clangd extension installation, if it didn't already ask to do so.
1. Inside VS code, press <kbd><kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>P</kbd></kbd> (macOS: <kbd><kbd>Command</kbd> + <kbd>Shift</kbd> + <kbd>P</kbd></kbd>) to open the command palette.
1. Start typing `clangd: Restart Language Server` and select it when it appears.
Now you're ready to code QMK Firmware in VS Code!

View File

@ -53,6 +53,7 @@ https://github.com/qmk/qmk_firmware/pulls?q=is%3Apr+is%3Aclosed+label%3Akeyboard
- keyboard moves within the repository *must* go through the `develop` branch instead of `master`, so as to ensure compatibility for users
- `data/mappings/keyboard_aliases.hjson` must be updated to reflect the move, so users with pre-created configurator keymap.json files continue to detect the correct keyboard
- keyboard updates and refactors (eg. to data driven) *must* go through `develop` to reduce `master` -> `develop` merge conflicts
- PR submissions from a `kbfirmware` export (or equivalent) will not be accepted unless converted to new QMK standards -- try `qmk import-kbfirmware` first
- `info.json`
- With the move to [data driven](https://docs.qmk.fm/#/data_driven_config) keyboard configuration, we encourage contributors to utilise as many features as possible of the info.json [schema](https://github.com/qmk/qmk_firmware/blob/master/data/schemas/keyboard.jsonschema).
@ -61,7 +62,7 @@ https://github.com/qmk/qmk_firmware/pulls?q=is%3Apr+is%3Aclosed+label%3Akeyboard
- valid maintainer
- valid USB VID/PID and device version
- displays correctly in Configurator (press Ctrl+Shift+I to preview local file, turn on fast input to verify ordering)
- `layout` definitions should include matrix positions, so that `LAYOUT` macros can be generated at build time
- `layout` definitions must include matrix positions, so that `LAYOUT` macros can be generated at build time
- should use standard definitions if applicable
- use the Community Layout macro names where they apply (preferred above `LAYOUT`/`LAYOUT_all`)
- If the keyboard only has a single electrical/switch layout:
@ -123,7 +124,7 @@ https://github.com/qmk/qmk_firmware/pulls?q=is%3Apr+is%3Aclosed+label%3Akeyboard
- hardware that's enabled at the keyboard level and requires configuration such as OLED displays or encoders should have basic functionality implemented here
- `<keyboard>.h`
- `#include "quantum.h"` appears at the top
- `LAYOUT` macros should be moved to `info.json`
- `LAYOUT` macros are no longer accepted and should instead be moved to `info.json`
- keymap `config.h`
- no duplication of `rules.mk` or `config.h` from keyboard
- `keymaps/default/keymap.c`
@ -131,6 +132,7 @@ https://github.com/qmk/qmk_firmware/pulls?q=is%3Apr+is%3Aclosed+label%3Akeyboard
- if using `MO(1)` and `MO(2)` keycodes together to access a third layer, the [Tri Layer](https://docs.qmk.fm/#/feature_tri_layer) feature should be used, rather than manually implementing this using `layer_on/off()` and `update_tri_layer()` functions in the keymap's `process_record_user()`.
- default (and via) keymaps should be "pristine"
- bare minimum to be used as a "clean slate" for another user to develop their own user-specific keymap
- what does pristine mean? no custom keycodes. no advanced features like tap dance or macros. basic mod taps and home row mods would be acceptable where their use is necessary
- standard layouts preferred in these keymaps, if possible
- should use [encoder map feature](https://docs.qmk.fm/#/feature_encoders?id=encoder-map), rather than `encoder_update_user()`
- default keymap should not enable VIA -- the VIA integration documentation requires a keymap called `via`

View File

@ -15,3 +15,5 @@ On this page we have documented keycodes between `0x00FF` and `0xFFFF` which are
|`QK_CLEAR_EEPROM`|`EE_CLR` |Reinitializes the keyboard's EEPROM (persistent memory) |
|`QK_MAKE` | |Sends `qmk compile -kb (keyboard) -km (keymap)`, or `qmk flash` if shift is held. Puts keyboard into bootloader mode if shift & control are held |
|`QK_REBOOT` |`QK_RBT` |Resets the keyboard. Does not load the bootloader |
!> Note: `QK_MAKE` requires `#define ENABLE_COMPILE_KEYCODE` in your config.h to function.

View File

@ -32,16 +32,20 @@ Supported devices:
## Quantum Painter Configuration :id=quantum-painter-config
| Option | Default | Purpose |
|------------------------------------------|---------|---------------------------------------------------------------------------------------------------------------------------------------------|
| `QUANTUM_PAINTER_NUM_IMAGES` | `8` | The maximum number of images/animations that can be loaded at any one time. |
| `QUANTUM_PAINTER_NUM_FONTS` | `4` | The maximum number of fonts that can be loaded at any one time. |
| `QUANTUM_PAINTER_CONCURRENT_ANIMATIONS` | `4` | The maximum number of animations that can be executed at the same time. |
| `QUANTUM_PAINTER_LOAD_FONTS_TO_RAM` | `FALSE` | Whether or not fonts should be loaded to RAM. Relevant for fonts stored in off-chip persistent storage, such as external flash. |
| `QUANTUM_PAINTER_PIXDATA_BUFFER_SIZE` | `32` | The limit of the amount of pixel data that can be transmitted in one transaction to the display. Higher values require more RAM on the MCU. |
| `QUANTUM_PAINTER_SUPPORTS_256_PALETTE` | `FALSE` | If 256-color palettes are supported. Requires significantly more RAM on the MCU. |
| `QUANTUM_PAINTER_SUPPORTS_NATIVE_COLORS` | `FALSE` | If native color range is supported. Requires significantly more RAM on the MCU. |
| `QUANTUM_PAINTER_DEBUG` | _unset_ | Prints out significant amounts of debugging information to CONSOLE output. Significant performance degradation, use only for debugging. |
| Option | Default | Purpose |
|---------------------------------------------------|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `QUANTUM_PAINTER_DISPLAY_TIMEOUT` | `30000` | This controls the amount of time (in milliseconds) that all displays will remain on after the last user input. If set to `0`, the display will remain on indefinitely. |
| `QUANTUM_PAINTER_TASK_THROTTLE` | `1` | This controls the amount of time (in milliseconds) that the Quantum Painter internal task will wait between each execution. Affects animations, display timeout, and LVGL timing if enabled. |
| `QUANTUM_PAINTER_NUM_IMAGES` | `8` | The maximum number of images/animations that can be loaded at any one time. |
| `QUANTUM_PAINTER_NUM_FONTS` | `4` | The maximum number of fonts that can be loaded at any one time. |
| `QUANTUM_PAINTER_CONCURRENT_ANIMATIONS` | `4` | The maximum number of animations that can be executed at the same time. |
| `QUANTUM_PAINTER_LOAD_FONTS_TO_RAM` | `FALSE` | Whether or not fonts should be loaded to RAM. Relevant for fonts stored in off-chip persistent storage, such as external flash. |
| `QUANTUM_PAINTER_PIXDATA_BUFFER_SIZE` | `1024` | The limit of the amount of pixel data that can be transmitted in one transaction to the display. Higher values require more RAM on the MCU. |
| `QUANTUM_PAINTER_SUPPORTS_256_PALETTE` | `FALSE` | If 256-color palettes are supported. Requires significantly more RAM on the MCU. |
| `QUANTUM_PAINTER_SUPPORTS_NATIVE_COLORS` | `FALSE` | If native color range is supported. Requires significantly more RAM on the MCU. |
| `QUANTUM_PAINTER_DEBUG` | _unset_ | Prints out significant amounts of debugging information to CONSOLE output. Significant performance degradation, use only for debugging. |
| `QUANTUM_PAINTER_DEBUG_ENABLE_FLUSH_TASK_OUTPUT` | _unset_ | By default, debug output is disabled while the internal task is flushing the display(s). If you want to keep it enabled, add this to your `config.h`. Note: Console will get clogged. |
Drivers have their own set of configurable options, and are described in their respective sections.

View File

@ -88,6 +88,21 @@ Or if you're not using layers at all, you can outright remove the functionality
#define NO_ACTION_LAYER
```
## Magic keycodes
There are two `__attribute__ ((weak))` placeholder functions available to customize magic keycodes. If you are not using that feature to swap keycodes, such as backslash with backspace, add the following to your `keymap.c` or user space code:
```c
uint16_t keycode_config(uint16_t keycode) {
return keycode;
}
```
Likewise, if you are not using magic keycodes to swap modifiers, such as Control with GUI, add the following to your `keymap.c` or user space code:
```c
uint8_t mod_config(uint8_t mod) {
return mod;
}
```
Both of them will overwrite the placeholder functions with a simple return statement to reduce firmware size.
## OLED tweaks
@ -194,6 +209,7 @@ That said, there are a number of Pro Micro replacements with ARM controllers:
* [Blok](https://boardsource.xyz/store/628b95b494dfa308a6581622)
* [Elite-Pi](https://keeb.io/products/elite-pi-usb-c-pro-micro-replacement-rp2040)
* [0xCB Helios](https://keeb.supply/products/0xcb-helios) ([Open Source](https://github.com/0xCB-dev/0xCB-Helios), DIY/PCBA/Shop)
* [Liatris](https://splitkb.com/products/liatris)
* [Michi](https://github.com/ci-bus/michi-promicro-rp2040)
There are other, non-Pro Micro compatible boards out there. The most popular being:

View File

@ -130,20 +130,18 @@ Note that until the tap-or-hold decision completes (which happens when either th
To better illustrate the tap-or-hold decision modes, let us compare the expected output of each decision mode in a handful of tapping scenarios involving a mod-tap key (`LSFT_T(KC_A)`) and a regular key (`KC_B`) with the `TAPPING_TERM` set to 200ms.
By default, mod-taps behave like `HOLD_ON_OTHER_KEY_PRESS`, while layer-taps behave like "Ignore Interrupt" out of the box. If you want "Ignore Interrupt"-like behaviour for mod-taps, you must enable `IGNORE_MOD_TAP_INTERRUPT`, or return `false` in the `get_hold_on_other_key_press` function for all mod-taps.
Note: "`kc` held" in the "Physical key event" column means that the key wasn't physically released yet at this point in time.
#### Distinct taps (AABB) :id=distinct-taps
| Time | Physical key event |Ignore Interrupt| `PERMISSIVE_HOLD` | `HOLD_ON_OTHER_KEY_PRESS` |
| Time | Physical key event | Default | `PERMISSIVE_HOLD` | `HOLD_ON_OTHER_KEY_PRESS` |
|------|--------------------|----------------|-------------------|----------------------------|
| 0 | `LSFT_T(KC_A)` down| | | |
| 199 | `LSFT_T(KC_A)` up | a | a | a |
| 210 | `KC_B` down | ab | ab | ab |
| 220 | `KC_B` up | ab | ab | ab |
| Time | Physical key event |Ignore Interrupt| `PERMISSIVE_HOLD` | `HOLD_ON_OTHER_KEY_PRESS` |
| Time | Physical key event | Default | `PERMISSIVE_HOLD` | `HOLD_ON_OTHER_KEY_PRESS` |
|------|--------------------|----------------|-------------------|----------------------------|
| 0 | `LSFT_T(KC_A)` down| | | |
| 200 | `LSFT_T(KC_A)` held|<kbd>Shift</kbd>| <kbd>Shift</kbd> | <kbd>Shift</kbd> |
@ -153,14 +151,14 @@ Note: "`kc` held" in the "Physical key event" column means that the key wasn't p
#### Nested tap (ABBA) :id=nested-tap
| Time | Physical key event |Ignore Interrupt| `PERMISSIVE_HOLD` | `HOLD_ON_OTHER_KEY_PRESS` |
| Time | Physical key event | Default | `PERMISSIVE_HOLD` | `HOLD_ON_OTHER_KEY_PRESS` |
|------|--------------------|----------------|-------------------|----------------------------|
| 0 | `LSFT_T(KC_A)` down| | | |
| 110 | `KC_B` down | | | B |
| 120 | `KC_B` up | | B | B |
| 199 | `LSFT_T(KC_A)` up | ab | B | B |
| Time | Physical key event |Ignore Interrupt| `PERMISSIVE_HOLD` | `HOLD_ON_OTHER_KEY_PRESS` |
| Time | Physical key event | Default | `PERMISSIVE_HOLD` | `HOLD_ON_OTHER_KEY_PRESS` |
|------|--------------------|----------------|-------------------|----------------------------|
| 0 | `LSFT_T(KC_A)` down| | | |
| 110 | `KC_B` down | | | B |
@ -168,7 +166,7 @@ Note: "`kc` held" in the "Physical key event" column means that the key wasn't p
| 200 | `LSFT_T(KC_A)` held| B | B | B |
| 210 | `LSFT_T(KC_A)` up | B | B | B |
| Time | Physical key event |Ignore Interrupt| `PERMISSIVE_HOLD` | `HOLD_ON_OTHER_KEY_PRESS` |
| Time | Physical key event | Default | `PERMISSIVE_HOLD` | `HOLD_ON_OTHER_KEY_PRESS` |
|------|--------------------|----------------|-------------------|----------------------------|
| 0 | `LSFT_T(KC_A)` down| | | |
| 200 | `LSFT_T(KC_A)` held|<kbd>Shift</kbd>| <kbd>Shift</kbd> | <kbd>Shift</kbd> |
@ -178,14 +176,14 @@ Note: "`kc` held" in the "Physical key event" column means that the key wasn't p
#### Rolling keys (ABAB) :id=rolling-keys
| Time | Physical key event |Ignore Interrupt| `PERMISSIVE_HOLD` | `HOLD_ON_OTHER_KEY_PRESS` |
| Time | Physical key event | Default | `PERMISSIVE_HOLD` | `HOLD_ON_OTHER_KEY_PRESS` |
|------|--------------------|----------------|-------------------|----------------------------|
| 0 | `LSFT_T(KC_A)` down| | | |
| 110 | `KC_B` down | | | B |
| 130 | `LSFT_T(KC_A)` up | ab | ab | B |
| 140 | `KC_B` up | ab | ab | B |
| Time | Physical key event |Ignore Interrupt| `PERMISSIVE_HOLD` | `HOLD_ON_OTHER_KEY_PRESS` |
| Time | Physical key event | Default | `PERMISSIVE_HOLD` | `HOLD_ON_OTHER_KEY_PRESS` |
|------|--------------------|----------------|-------------------|----------------------------|
| 0 | `LSFT_T(KC_A)` down| | | |
| 110 | `KC_B` down | | | B |
@ -241,10 +239,8 @@ Example sequence 3 (Mod Tap):
| +--------------+ | |
+---------------------------|--------+
```
Based on previous examples, you might have expected the output of the above sequence to be `KC_A` `KC_X`
since `SFT_T(KC_A)` is NOT held longer than the `TAPPING_TERM`.
However, the actual output would be capital `X` (`SHIFT` + `x`) due to reasons
explained under [Ignore Mod Tap Interrupt](#ignore-mod-tap-interrupt).
In the above sequence, `SFT_T(KC_A)` has been released before the end of its `TAPPING_TERM` and as such will be interpreted as `KC_A`,
followed by any key event that happened after the initial press of `SFT_T(KC_A)`. In this instance, the output would be `KC_A` `KC_X`.
### Permissive Hold
@ -300,7 +296,7 @@ However, this slightly different sequence will not be affected by the “permiss
In the sequence above the dual-role key is released before the other key is released, and if that happens within the tapping term, the “permissive hold” mode will still choose the tap action for the dual-role key, and the sequence will be registered as `al` by the host. We could describe this as a “rolling press” (the two keys' key down and key up events behave as if you were rolling a ball across the two keys, first pressing each key down in sequence and then releasing them in the same order).
?> The `PERMISSIVE_HOLD` option is not noticeable if you also enable `HOLD_ON_OTHER_KEY_PRESS` because the latter option considers both the “nested tap” and “rolling press” sequences like shown above as a hold action, not the tap action. `HOLD_ON_OTHER_KEY_PRESS` makes the Tap-Or-Hold decision earlier in the chain of key events, thus taking a precedence over `PERMISSIVE_HOLD`. This remark also applies to default mod-taps.
?> The `PERMISSIVE_HOLD` option is not noticeable if you also enable `HOLD_ON_OTHER_KEY_PRESS` because the latter option considers both the “nested tap” and “rolling press” sequences like shown above as a hold action, not the tap action. `HOLD_ON_OTHER_KEY_PRESS` makes the Tap-Or-Hold decision earlier in the chain of key events, thus taking a precedence over `PERMISSIVE_HOLD`.
For more granular control of this feature, you can add the following to your `config.h`:
@ -356,8 +352,6 @@ An example of a sequence that is affected by the “hold on other key press” m
Normally, if you do all this within the `TAPPING_TERM` (default: 200ms), this will be registered as `al` by the firmware and host system. With the `HOLD_ON_OTHER_KEY_PRESS` option enabled, the Layer Tap key is considered as a layer switch if another key is pressed, and the above sequence would be registered as `KC_RGHT` (the mapping of `L` on layer 2).
?> The `HOLD_ON_OTHER_KEY_PRESS` option is essentially redundant with the default mod-tap behaviour. The only notable difference is that `HOLD_ON_OTHER_KEY_PRESS` reduces the delay before the key events are made visible to the host.
For more granular control of this feature, you can add the following to your `config.h`:
```c
@ -379,73 +373,6 @@ bool get_hold_on_other_key_press(uint16_t keycode, keyrecord_t *record) {
}
```
## Ignore Mod Tap Interrupt
To enable this setting, add this to your `config.h`:
```c
#define IGNORE_MOD_TAP_INTERRUPT
```
?> This option affects only the Mod Tap keys; it does not affect other dual-role keys such as Layer Tap.
By default, the tap-or-hold decision for Mod Tap keys strongly prefers the hold action. If you press a Mod Tap key, then press another key while still holding the Mod Tap key down, the Mod Tap press will be handled as a modifier hold even if the Mod Tap key is then released within the tapping term, and irrespective of the order in which those keys are released. Using options such as `PERMISSIVE_HOLD` or `HOLD_ON_OTHER_KEY_PRESS` will not affect the functionality of Mod Tap keys in a major way (these options would still affect the delay until the common code for dual-role keys finishes its tap-or-hold decision, but then the special code for Mod Tap keys will override the result of that decision and choose the hold action if another key was pressed). In fact, by default, the tap-or-hold decision for Mod Tap keys is done in the same way as if the `HOLD_ON_OTHER_KEY_PRESS` option was enabled, but without the decreased delay provided by `HOLD_ON_OTHER_KEY_PRESS`.
If the `IGNORE_MOD_TAP_INTERRUPT` option is enabled, Mod Tap keys are no longer treated as a special case, and their behavior will match the behavior of other dual-role keys such as Layer Tap. Then the behavior of Mod Tap keys can be further tuned using other options such as `PERMISSIVE_HOLD` or `HOLD_ON_OTHER_KEY_PRESS`.
An example of a sequence that will be affected by the `IGNORE_MOD_TAP_INTERRUPT` option (assuming that options like `PERMISSIVE_HOLD` or `HOLD_ON_OTHER_KEY_PRESS` are not enabled):
- `SFT_T(KC_A)` Down
- `KC_X` Down
- `SFT_T(KC_A)` Up
- `KC_X` Up
```
TAPPING_TERM
+---------------------------|--------+
| +-------------+ | |
| | SFT_T(KC_A) | | |
| +-------------+ | |
| +--------------+ | |
| | KC_X | | |
| +--------------+ | |
+---------------------------|--------+
```
Normally, this would send a capital `X` (`SHIFT`+`x`), even if the sequence is performed faster than the `TAPPING_TERM`. However, if the `IGNORE_MOD_TAP_INTERRUPT` option is enabled, the `SFT_T(KC_A)` key must be held longer than the `TAPPING_TERM` to register the hold action. A quick tap will output `ax` in this case, while a hold will still output a capital `X` (`SHIFT`+`x`).
However, if the `HOLD_ON_OTHER_KEY_PRESS` option is enabled in addition to `IGNORE_MOD_TAP_INTERRUPT`, the above sequence will again send a capital `X` (`SHIFT`+`x`) even if performed faster than the `TAPPING_TERM`. The difference from the default configuration is that by default the host will receive the key events only after the `SFT_T(KC_A)` key is released, but with the `HOLD_ON_OTHER_KEY_PRESS` option, the host will start receiving key events when the `KC_X` key is pressed.
For more granular control of this feature, you can add the following to your `config.h`:
```c
#define HOLD_ON_OTHER_KEY_PRESS_PER_KEY
```
?> This option affects *all* dual-role keys.
You can then add the following function to your keymap:
```c
bool get_hold_on_other_key_press(uint16_t keycode, keyrecord_t *record) {
switch (keycode) {
case SFT_T(KC_SPC):
// Do not force the mod-tap key press to be handled as a modifier
// if any other key was pressed while the mod-tap key is held down.
return false;
default:
// Force the dual-role key press to be handled as a modifier if any
// other key was pressed while the mod-tap key is held down.
return true;
}
}
```
Note that you must return `false` in `get_hold_on_other_key_press` in order to apply `IGNORE_MOD_TAP_INTERRUPT` for a certain mod-tap key.
?> `IGNORE_MOD_TAP_INTERRUPT[_PER_KEY]` is being progressively phased out to align the (default) behavior and configuration of mod-taps with the rest of dual-role keys.
## Quick Tap Term
When the user holds a key after tapping it, the tapping function is repeated by default, rather than activating the hold function. This allows keeping the ability to auto-repeat the tapping function of a dual-role key. `QUICK_TAP_TERM` enables fine tuning of that ability. If set to `0`, it will remove the auto-repeat ability and activate the hold function instead.

View File

@ -129,6 +129,8 @@ The `process_record()` function itself is deceptively simple, but hidden within
* [`void action_exec(keyevent_t event)`](https://github.com/qmk/qmk_firmware/blob/325da02e57fe7374e77b82cb00360ba45167e25c/quantum/action.c#L78-L140)
* [`void pre_process_record_quantum(keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/325da02e57fe7374e77b82cb00360ba45167e25c/quantum/quantum.c#L204)
* [`bool pre_process_record_kb(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/27119fa77e8a1b95fff80718d3db4f3e32849298/quantum/quantum.c#L117)
* [`bool pre_process_record_user(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/27119fa77e8a1b95fff80718d3db4f3e32849298/quantum/quantum.c#L121)
* [`bool process_combo(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/325da02e57fe7374e77b82cb00360ba45167e25c/quantum/process_keycode/process_combo.c#L521)
* [`void process_record(keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/325da02e57fe7374e77b82cb00360ba45167e25c/quantum/action.c#L254)
* [`bool process_record_quantum(keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/325da02e57fe7374e77b82cb00360ba45167e25c/quantum/quantum.c#L224)

View File

@ -72,12 +72,12 @@ WS2812_DRIVER = i2c
Configure the hardware via your config.h:
```c
#define WS2812_ADDRESS 0xb0 // default: 0xb0
#define WS2812_TIMEOUT 100 // default: 100
#define WS2812_I2C_ADDRESS 0xB0 // default: 0xB0
#define WS2812_I2C_TIMEOUT 100 // default: 100
```
### SPI
Targeting STM32 boards where WS2812 support is offloaded to an SPI hardware device. The advantage is that the use of DMA offloads processing of the WS2812 protocol from the MCU. `RGB_DI_PIN` for this driver is the configured SPI MOSI pin. Due to the nature of repurposing SPI to drive the LEDs, the other SPI pins, MISO and SCK, **must** remain unused. To configure it, add this to your rules.mk:
Targeting STM32 boards where WS2812 support is offloaded to an SPI hardware device. The advantage is that the use of DMA offloads processing of the WS2812 protocol from the MCU. `WS2812_DI_PIN` for this driver is the configured SPI MOSI pin. Due to the nature of repurposing SPI to drive the LEDs, the other SPI pins, MISO and SCK, **must** remain unused. To configure it, add this to your rules.mk:
```make
WS2812_DRIVER = spi
@ -183,7 +183,7 @@ This can be configured for bitbang, PWM and SPI.
Note: This only applies to STM32 boards.
To configure the `RGB_DI_PIN` to open drain configuration add this to your config.h file:
To configure the `WS2812_DI_PIN` to open drain configuration add this to your config.h file:
```c
#define WS2812_EXTERNAL_PULLUP
```

View File

@ -42,7 +42,6 @@
* [键映射总览](zh-cn/keymap.md)
* 开发环境
* [Docker指南](zh-cn/getting_started_docker.md)
* [Vagrant指南](zh-cn/getting_started_vagrant.md)
* 刷写(Flashing)
* [刷写](zh-cn/flashing.md)
* [刷写ATmega32A (ps2avrgb)](zh-cn/flashing_bootloadhid.md)
@ -74,6 +73,7 @@
* [Mod-Tap](zh-cn/mod_tap.md)
* [](zh-cn/feature_macros.md)
* [鼠标键](zh-cn/feature_mouse_keys.md)
* [Repeat Key](zh-cn/feature_repeat_key.md)
* [Space Cadet Shift](zh-cn/feature_space_cadet.md)
* [US ANSI上档键值](zh-cn/keycodes_us_ansi_shifted.md)
@ -188,5 +188,5 @@
* [Midi辅助功能](zh-cn/internals/midi_util.md)
* [发送函数](zh-cn/internals/send_functions.md)
* [Sysex工具](zh-cn/internals/sysex_tools.md)
<!--fromen:20211014-12:00(GMT+8) commit 04cf161aa01fd433b5dae69d9fd31569ed5dca59-->

View File

@ -1,61 +0,0 @@
# Vagrant快速上手指引
<!---
original document: 0.15.12:docs/getting_started_vagrant.md
git diff 0.15.12 HEAD -- docs/getting_started_vagrant.md | cat
-->
本工程包含一份 `Vagrantfile`可以方便地在不更改你系统环境情况下完成新固件文件的构建工作。这同时也保证了在你拉取该工程代码后的编译环境与也使用Vagrantfile的其它人的一致。当你需要其他人协助你排查遇到的问题时会方便很多。
## 需求
本工程中的 `Vagrantfile` 需要安装[Vagrant](https://www.vagrantup.com/)以及可用的虚拟机服务:
* [VirtualBox](https://www.virtualbox.org/) (5.0.12及以后版本)
* 卖点是'最适用于Vagrant的平台'
* [VMware Workstation](https://www.vmware.com/products/workstation) 及 [Vagrant VMware插件](https://www.vagrantup.com/vmware)
* 付费购买的VMware插件需要在经过正版授权的VMware Workstation/Fusion上运行
* [Docker](https://www.docker.com/)
安装了Vagrant之后在安装合适的虚拟机服务后可能需要重启机器。拉取本工程后在工程目录下执行 'vagrant up' 将启动一个包含了所有本工程所需工具的构建环境虚拟机或是容器。最后会有一个vagrant启动提示告知你一切正常就绪否则你也可以参考一下下面的构建文档。
## 刷写固件
比较“简单”的方案是在你的宿主系统上借助以下工具刷写固件:
* [QMK工具箱](https://github.com/qmk/qmk_toolbox) (推荐)
* [Teensy Loader](https://www.pjrc.com/teensy/loader.html)
如果你希望通过命令行进行编程工作可以在Vagrantfile中取消掉['modifyvm']的注释以允许USB直通到Linux环境既可以使用dfu-util/dfu-programmer之类的命令行工具进行编程工作或是安装Teensy的命令行版本。
## Vagrantfile概览
开发环境被配置为运行QMK Docker镜像 `qmkfm/qmk_cli`不仅让各系统下的功能预期一致也是我们CI环境的镜像。
## FAQ
### 为什么我的VirtualBox环境会有问题
VirtualBox 5的某些版本与工程中Vagrantfile中指定的VirtualBox扩展存在兼容问题。如果你遇到了/vagrant挂载不成功的问题请升级VirtualBox至5.0.12或更高版本。**或者,可以尝试执行如下命令:**
```console
vagrant plugin install vagrant-vbguest
```
### 如何移除一个现有环境?
不再需要这个环境了是吗?在本工程目录下的任何位置,执行:
```console
vagrant destroy
```
### 如果我是想直接用Docker呢
想在不使用虚拟机技术的情况下也能使用Vagrant工作流Vagrangfile已配置为允许绕过运行虚拟机直接运行容器。通过如下方式执行命令可以强制使用Docker来启动环境
```console
vagrant up --provider=docker
```
### 如何访问虚拟机环境而非Docker容器
通过如下方法跳过 `vagrant` 的用户初始化过程以在QMK构建镜像中直接执行
```console
vagrant ssh -c 'sudo -i'
```

View File

@ -117,8 +117,6 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) {
}
```
在数字及字母键上使用Mod-Tap时推荐启用 `IGNORE_MOD_TAP_INTERRUPT`,以避免在快速按下下一个键时保持功能优先级。参见[忽略Mod Tap中断](zh-cn/tap_hold.md#ignore-mod-tap-interrupt)。
### 同时改变点击和按住功能
最后一个例子通过 `LT(0,KC_NO)` 实现了点击复制,按住粘贴的功能:

View File

@ -21,9 +21,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <stdbool.h>
/**
* \defgroup hd44780
* \file
*
* HD44780 Character LCD Driver
* \defgroup hd44780 HD44780 Character LCD Driver
* \{
*/

View File

@ -27,7 +27,7 @@
# if defined(STM32F0XX) || defined(STM32F1XX) || defined(STM32F3XX) || defined(STM32F4XX) || defined(STM32L0XX) || defined(GD32VF103)
# define APA102_NOPS (100 / (1000000000L / (CPU_CLOCK / 4))) // This calculates how many loops of 4 nops to run to delay 100 ns
# else
# error("APA102_NOPS configuration required")
# error APA102_NOPS configuration required
# define APA102_NOPS 0 // this just pleases the compile so the above error is easier to spot
# endif
# endif
@ -43,14 +43,14 @@
} \
} while (0)
#define APA102_SEND_BIT(byte, bit) \
do { \
writePin(RGB_DI_PIN, (byte >> bit) & 1); \
io_wait; \
writePinHigh(RGB_CI_PIN); \
io_wait; \
writePinLow(RGB_CI_PIN); \
io_wait; \
#define APA102_SEND_BIT(byte, bit) \
do { \
writePin(APA102_DI_PIN, (byte >> bit) & 1); \
io_wait; \
writePinHigh(APA102_CI_PIN); \
io_wait; \
writePinLow(APA102_CI_PIN); \
io_wait; \
} while (0)
uint8_t apa102_led_brightness = APA102_DEFAULT_BRIGHTNESS;
@ -77,11 +77,11 @@ void rgblight_call_driver(LED_TYPE *start_led, uint8_t num_leds) {
}
void static apa102_init(void) {
setPinOutput(RGB_DI_PIN);
setPinOutput(RGB_CI_PIN);
setPinOutput(APA102_DI_PIN);
setPinOutput(APA102_CI_PIN);
writePinLow(RGB_DI_PIN);
writePinLow(RGB_CI_PIN);
writePinLow(APA102_DI_PIN);
writePinLow(APA102_CI_PIN);
}
void apa102_set_brightness(uint8_t brightness) {

View File

@ -1,4 +1,5 @@
/* Copyright 2021 Jasper Chan
* 2023 Huckies <https://github.com/Huckies>
*
* 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
@ -15,6 +16,7 @@
*/
#include "aw20216.h"
#include "wait.h"
#include "spi_master.h"
/* The AW20216 appears to be somewhat similar to the IS31FL743, although quite
@ -34,6 +36,8 @@
#define AW_REG_CONFIGURATION 0x00 // PG0
#define AW_REG_GLOBALCURRENT 0x01 // PG0
#define AW_REG_RESET 0x2F // PG0
#define AW_REG_MIXFUNCTION 0x46 // PG0
// Default value of AW_REG_CONFIGURATION
// D7:D4 = 1011, SWSEL (SW1~SW12 active)
@ -41,7 +45,10 @@
// D2:D1 = 00, OSDE (open/short detection enable)
// D0 = 0, CHIPEN (write 1 to enable LEDs when hardware enable pulled high)
#define AW_CONFIG_DEFAULT 0b10110000
#define AW_MIXCR_DEFAULT 0b00000000
#define AW_RESET_CMD 0xAE
#define AW_CHIPEN 1
#define AW_LPEN (0x01 << 1)
#define AW_PWM_REGISTER_COUNT 216
@ -94,6 +101,10 @@ static inline bool AW20216_write_register(pin_t cs_pin, uint8_t page, uint8_t re
return AW20216_write(cs_pin, page, reg, &value, 1);
}
void AW20216_soft_reset(pin_t cs_pin) {
AW20216_write_register(cs_pin, AW_PAGE_FUNCTION, AW_REG_RESET, AW_RESET_CMD);
}
static void AW20216_init_scaling(pin_t cs_pin) {
// Set constant current to the max, control brightness with PWM
for (uint8_t i = 0; i < AW_PWM_REGISTER_COUNT; i++) {
@ -111,15 +122,23 @@ static inline void AW20216_soft_enable(pin_t cs_pin) {
AW20216_write_register(cs_pin, AW_PAGE_FUNCTION, AW_REG_CONFIGURATION, AW_CONFIG_DEFAULT | AW_CHIPEN);
}
static inline void AW20216_auto_lowpower(pin_t cs_pin) {
AW20216_write_register(cs_pin, AW_PAGE_FUNCTION, AW_REG_MIXFUNCTION, AW_MIXCR_DEFAULT | AW_LPEN);
}
void AW20216_init(pin_t cs_pin, pin_t en_pin) {
setPinOutput(en_pin);
writePinHigh(en_pin);
AW20216_soft_reset(cs_pin);
wait_ms(2);
// Drivers should start with all scaling and PWM registers as off
AW20216_init_current_limit(cs_pin);
AW20216_init_scaling(cs_pin);
AW20216_soft_enable(cs_pin);
AW20216_auto_lowpower(cs_pin);
}
void AW20216_set_color(int index, uint8_t red, uint8_t green, uint8_t blue) {

View File

@ -45,9 +45,7 @@ void IS31FL3218_write_register(uint8_t reg, uint8_t data) {
void IS31FL3218_write_pwm_buffer(uint8_t *pwm_buffer) {
g_twi_transfer_buffer[0] = ISSI_REG_PWM;
for (int i = 0; i < 18; i++) {
g_twi_transfer_buffer[1 + i] = pwm_buffer[i];
}
memcpy(g_twi_transfer_buffer + 1, pwm_buffer, 18);
i2c_transmit(ISSI_ADDRESS, g_twi_transfer_buffer, 19, ISSI_TIMEOUT);
}

View File

@ -18,6 +18,7 @@
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
void IS31FL3218_init(void);
void IS31FL3218_set_color(int index, uint8_t red, uint8_t green, uint8_t blue);

View File

@ -123,9 +123,7 @@ void IS31FL3731_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) {
// copy the data from i to i+15
// device will auto-increment register for data after the first byte
// thus this sets registers 0x24-0x33, 0x34-0x43, etc. in one transfer
for (int j = 0; j < 16; j++) {
g_twi_transfer_buffer[1 + j] = pwm_buffer[i + j];
}
memcpy(g_twi_transfer_buffer + 1, pwm_buffer + i, 16);
#if ISSI_PERSISTENCE > 0
for (uint8_t i = 0; i < ISSI_PERSISTENCE; i++) {

View File

@ -20,6 +20,7 @@
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "progmem.h"
typedef struct is31_led {

View File

@ -111,9 +111,7 @@ void IS31FL3731_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) {
// copy the data from i to i+15
// device will auto-increment register for data after the first byte
// thus this sets registers 0x24-0x33, 0x34-0x43, etc. in one transfer
for (int j = 0; j < 16; j++) {
g_twi_transfer_buffer[1 + j] = pwm_buffer[i + j];
}
memcpy(g_twi_transfer_buffer + 1, pwm_buffer + i, 16);
#if ISSI_PERSISTENCE > 0
for (uint8_t i = 0; i < ISSI_PERSISTENCE; i++) {

View File

@ -19,6 +19,7 @@
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "progmem.h"
typedef struct is31_led {

View File

@ -129,9 +129,7 @@ bool IS31FL3733_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) {
// Copy the data from i to i+15.
// Device will auto-increment register for data after the first byte
// Thus this sets registers 0x00-0x0F, 0x10-0x1F, etc. in one transfer.
for (int j = 0; j < 16; j++) {
g_twi_transfer_buffer[1 + j] = pwm_buffer[i + j];
}
memcpy(g_twi_transfer_buffer + 1, pwm_buffer + i, 16);
#if ISSI_PERSISTENCE > 0
for (uint8_t i = 0; i < ISSI_PERSISTENCE; i++) {

View File

@ -22,6 +22,7 @@
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "progmem.h"
typedef struct is31_led {

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