forked from mirrors/qmk_firmware
Compare commits
39 Commits
0.14.1
...
qmk_compil
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
81b17125eb | ||
|
|
6f4742bde6 | ||
|
|
4fadb98a02 | ||
|
|
335dd3c5c3 | ||
|
|
dcbfdb5cfc | ||
|
|
823a74ebae | ||
|
|
08b0ecb175 | ||
|
|
b4e18c9019 | ||
|
|
07b8035ba9 | ||
|
|
4f20c94b97 | ||
|
|
ea862e24f6 | ||
|
|
7fe506006e | ||
|
|
d3ed6fa8a4 | ||
|
|
50fdb2a52c | ||
|
|
596c4a1f87 | ||
|
|
b46064a891 | ||
|
|
baa423004a | ||
|
|
92e606b927 | ||
|
|
b705020daf | ||
|
|
5fbfab1f3b | ||
|
|
13a2da973f | ||
|
|
532bff7b6c | ||
|
|
a1866a962c | ||
|
|
d227c8692a | ||
|
|
ef7fdee6c8 | ||
|
|
55d6956553 | ||
|
|
f87cd8e8a0 | ||
|
|
8800adc533 | ||
|
|
94d7635a4a | ||
|
|
7209d7cca9 | ||
|
|
5d5668c3f8 | ||
|
|
77a93fec79 | ||
|
|
9afc64cd61 | ||
|
|
c729df09ca | ||
|
|
566d598516 | ||
|
|
f155865804 | ||
|
|
1ac3b3e9b6 | ||
|
|
7b8cdfc19d | ||
|
|
9fe7b5307a |
1
.github/labeler.yml
vendored
1
.github/labeler.yml
vendored
@@ -22,7 +22,6 @@ keymap:
|
||||
via:
|
||||
- keyboards/**/keymaps/via/*
|
||||
cli:
|
||||
- bin/qmk
|
||||
- requirements.txt
|
||||
- lib/python/**/*
|
||||
python:
|
||||
|
||||
2
.github/workflows/api.yml
vendored
2
.github/workflows/api.yml
vendored
@@ -12,7 +12,7 @@ on:
|
||||
jobs:
|
||||
api_data:
|
||||
runs-on: ubuntu-latest
|
||||
container: qmkfm/base_container
|
||||
container: qmkfm/qmk_cli
|
||||
|
||||
# protect against those who develop with their fork on master
|
||||
if: github.repository == 'qmk/qmk_firmware'
|
||||
|
||||
5
.github/workflows/cli.yml
vendored
5
.github/workflows/cli.yml
vendored
@@ -8,7 +8,6 @@ on:
|
||||
pull_request:
|
||||
paths:
|
||||
- 'lib/python/**'
|
||||
- 'bin/qmk'
|
||||
- 'requirements.txt'
|
||||
- '.github/workflows/cli.yml'
|
||||
|
||||
@@ -16,7 +15,7 @@ jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
container: qmkfm/base_container
|
||||
container: qmkfm/qmk_cli
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
@@ -25,4 +24,4 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: pip3 install -r requirements-dev.txt
|
||||
- name: Run tests
|
||||
run: bin/qmk pytest
|
||||
run: qmk pytest
|
||||
|
||||
2
.github/workflows/develop_api.yml
vendored
2
.github/workflows/develop_api.yml
vendored
@@ -12,7 +12,7 @@ on:
|
||||
jobs:
|
||||
api_data:
|
||||
runs-on: ubuntu-latest
|
||||
container: qmkfm/base_container
|
||||
container: qmkfm/qmk_cli
|
||||
|
||||
# protect against those who work in their fork on develop
|
||||
if: github.repository == 'qmk/qmk_firmware'
|
||||
|
||||
2
.github/workflows/docs.yml
vendored
2
.github/workflows/docs.yml
vendored
@@ -14,7 +14,7 @@ on:
|
||||
jobs:
|
||||
generate:
|
||||
runs-on: ubuntu-latest
|
||||
container: qmkfm/base_container
|
||||
container: qmkfm/qmk_cli
|
||||
|
||||
# protect against those who develop with their fork on master
|
||||
if: github.repository == 'qmk/qmk_firmware'
|
||||
|
||||
2
.github/workflows/format.yaml
vendored
2
.github/workflows/format.yaml
vendored
@@ -16,7 +16,7 @@ jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
container: qmkfm/base_container
|
||||
container: qmkfm/qmk_cli
|
||||
|
||||
steps:
|
||||
- uses: rlespinasse/github-slug-action@v3.x
|
||||
|
||||
2
.github/workflows/lint.yml
vendored
2
.github/workflows/lint.yml
vendored
@@ -9,7 +9,7 @@ jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
container: qmkfm/base_container
|
||||
container: qmkfm/qmk_cli
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
FROM qmkfm/base_container
|
||||
FROM qmkfm/qmk_cli
|
||||
|
||||
VOLUME /qmk_firmware
|
||||
WORKDIR /qmk_firmware
|
||||
COPY . .
|
||||
|
||||
CMD make all:default
|
||||
CMD qmk compile -kb all -km default
|
||||
|
||||
6
Makefile
6
Makefile
@@ -30,11 +30,7 @@ endif
|
||||
endif
|
||||
|
||||
# Determine which qmk cli to use
|
||||
ifeq (,$(shell which qmk))
|
||||
QMK_BIN = bin/qmk
|
||||
else
|
||||
QMK_BIN = qmk
|
||||
endif
|
||||
QMK_BIN := qmk
|
||||
|
||||
# avoid 'Entering|Leaving directory' messages
|
||||
MAKEFLAGS += --no-print-directory
|
||||
|
||||
4
Vagrantfile
vendored
4
Vagrantfile
vendored
@@ -68,13 +68,13 @@ Vagrant.configure(2) do |config|
|
||||
["virtualbox", "vmware_workstation", "vmware_fusion"].each do |type|
|
||||
config.vm.provider type do |virt, override|
|
||||
override.vm.provision "docker" do |d|
|
||||
d.run "qmkfm/base_container",
|
||||
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-base_container && exec docker exec -it qmkfm-base_container /bin/bash -l' >> ~vagrant/.bashrc
|
||||
echo 'docker restart qmkfm-qmk_cli && exec docker exec -it qmkfm-qmk_cli /bin/bash -l' >> ~vagrant/.bashrc
|
||||
SHELL
|
||||
end
|
||||
end
|
||||
|
||||
58
bin/qmk
58
bin/qmk
@@ -1,58 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""CLI wrapper for running QMK commands.
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# Add the QMK python libs to our path
|
||||
script_dir = Path(os.path.realpath(__file__)).parent
|
||||
qmk_dir = script_dir.parent
|
||||
python_lib_dir = Path(qmk_dir / 'lib' / 'python').resolve()
|
||||
sys.path.append(str(python_lib_dir))
|
||||
|
||||
# Setup the CLI
|
||||
import milc # noqa
|
||||
|
||||
milc.EMOJI_LOGLEVELS['INFO'] = '{fg_blue}Ψ{style_reset_all}'
|
||||
|
||||
|
||||
@milc.cli.entrypoint('QMK Helper Script')
|
||||
def qmk_main(cli):
|
||||
"""The function that gets run when no subcommand is provided.
|
||||
"""
|
||||
cli.print_help()
|
||||
|
||||
|
||||
def main():
|
||||
"""Setup our environment and then call the CLI entrypoint.
|
||||
"""
|
||||
# Change to the root of our checkout
|
||||
os.environ['ORIG_CWD'] = os.getcwd()
|
||||
os.environ['DEPRECATED_BIN_QMK'] = '1'
|
||||
os.chdir(qmk_dir)
|
||||
|
||||
print('Warning: The bin/qmk script is being deprecated. Please install the QMK CLI: python3 -m pip install qmk', file=sys.stderr)
|
||||
|
||||
# Import the subcommands
|
||||
import milc.subcommand.config # noqa
|
||||
import qmk.cli # noqa
|
||||
|
||||
# Execute
|
||||
return_code = milc.cli()
|
||||
|
||||
if return_code is False:
|
||||
exit(1)
|
||||
|
||||
elif return_code is not True and isinstance(return_code, int):
|
||||
if return_code < 0 or return_code > 255:
|
||||
milc.cli.log.error('Invalid return_code: %d', return_code)
|
||||
exit(255)
|
||||
|
||||
exit(return_code)
|
||||
|
||||
exit(0)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -115,6 +115,7 @@ include $(INFO_RULES_MK)
|
||||
# Check for keymap.json first, so we can regenerate keymap.c
|
||||
include build_json.mk
|
||||
|
||||
# Pull in keymap level rules.mk
|
||||
ifeq ("$(wildcard $(KEYMAP_PATH))", "")
|
||||
# Look through the possible keymap folders until we find a matching keymap.c
|
||||
ifneq ("$(wildcard $(MAIN_KEYMAP_PATH_5)/keymap.c)","")
|
||||
@@ -345,6 +346,7 @@ ifeq ("$(USER_NAME)","")
|
||||
endif
|
||||
USER_PATH := users/$(USER_NAME)
|
||||
|
||||
# Pull in user level rules.mk
|
||||
-include $(USER_PATH)/rules.mk
|
||||
ifneq ("$(wildcard $(USER_PATH)/config.h)","")
|
||||
CONFIG_H += $(USER_PATH)/config.h
|
||||
@@ -356,6 +358,23 @@ endif
|
||||
# Disable features that a keyboard doesn't support
|
||||
-include disable_features.mk
|
||||
|
||||
# Pull in post_rules.mk files from all our subfolders
|
||||
ifneq ("$(wildcard $(KEYBOARD_PATH_1)/post_rules.mk)","")
|
||||
include $(KEYBOARD_PATH_1)/post_rules.mk
|
||||
endif
|
||||
ifneq ("$(wildcard $(KEYBOARD_PATH_2)/post_rules.mk)","")
|
||||
include $(KEYBOARD_PATH_2)/post_rules.mk
|
||||
endif
|
||||
ifneq ("$(wildcard $(KEYBOARD_PATH_3)/post_rules.mk)","")
|
||||
include $(KEYBOARD_PATH_3)/post_rules.mk
|
||||
endif
|
||||
ifneq ("$(wildcard $(KEYBOARD_PATH_4)/post_rules.mk)","")
|
||||
include $(KEYBOARD_PATH_4)/post_rules.mk
|
||||
endif
|
||||
ifneq ("$(wildcard $(KEYBOARD_PATH_5)/post_rules.mk)","")
|
||||
include $(KEYBOARD_PATH_5)/post_rules.mk
|
||||
endif
|
||||
|
||||
ifneq ("$(wildcard $(KEYMAP_PATH)/config.h)","")
|
||||
CONFIG_H += $(KEYMAP_PATH)/config.h
|
||||
endif
|
||||
|
||||
@@ -118,54 +118,6 @@ This command lets you configure the behavior of QMK. For the full `qmk config` d
|
||||
qmk config [-ro] [config_token1] [config_token2] [...] [config_tokenN]
|
||||
```
|
||||
|
||||
## `qmk console`
|
||||
|
||||
This command lets you connect to keyboard consoles to get debugging messages. It only works if your keyboard firmware has been compiled with `CONSOLE_ENABLE=yes`.
|
||||
|
||||
**Usage**:
|
||||
|
||||
```
|
||||
qmk console [-d <pid>:<vid>[:<index>]] [-l] [-n] [-t] [-w <seconds>]
|
||||
```
|
||||
|
||||
**Examples**:
|
||||
|
||||
Connect to all available keyboards and show their console messages:
|
||||
|
||||
```
|
||||
qmk console
|
||||
```
|
||||
|
||||
List all devices:
|
||||
|
||||
```
|
||||
qmk console -l
|
||||
```
|
||||
|
||||
Show only messages from clueboard/66/rev3 keyboards:
|
||||
|
||||
```
|
||||
qmk console -d C1ED:2370
|
||||
```
|
||||
|
||||
Show only messages from the second clueboard/66/rev3:
|
||||
|
||||
```
|
||||
qmk console -d C1ED:2370:2
|
||||
```
|
||||
|
||||
Show timestamps and VID:PID instead of names:
|
||||
|
||||
```
|
||||
qmk console -n -t
|
||||
```
|
||||
|
||||
Disable bootloader messages:
|
||||
|
||||
```
|
||||
qmk console --no-bootloaders
|
||||
```
|
||||
|
||||
## `qmk doctor`
|
||||
|
||||
This command examines your environment and alerts you to potential build or flash problems. It can fix many of them if you want it to.
|
||||
|
||||
@@ -105,7 +105,7 @@ enum my_keycodes {
|
||||
|
||||
Before opening a pull request, you can preview your changes if you have set up the development environment by running this command from the `qmk_firmware/` folder:
|
||||
|
||||
./bin/qmk docs
|
||||
qmk docs
|
||||
|
||||
or if you only have Python 3 installed:
|
||||
|
||||
|
||||
@@ -51,25 +51,6 @@ Wir suchen nach Freiwilligen, die ein `qmk`-Package für weitere Betriebssysteme
|
||||
* Installiere mit einem [virtualenv](https://virtualenv.pypa.io/en/latest/).
|
||||
* Weise den User an, die Umgebungs-Variable `QMK_HOME` zu setzen, um die Firmware-Quelle anders einzustellen als `~/qmk_firmware`.
|
||||
|
||||
# Lokale CLI
|
||||
|
||||
Wenn Du die globale CLI nicht verwenden möchtest, beinhaltet `qmk_firmware` auch eine lokale CLI. Du kannst sie hier finden: `qmk_firmware/bin/qmk`. Du kannst den `qmk`-Befehl aus irgendeinem Datei-Verzeichnis ausführen und es wird immer auf dieser Kopie von `qmk_firmware` arbeiten.
|
||||
|
||||
**Beispiel**:
|
||||
|
||||
```
|
||||
$ ~/qmk_firmware/bin/qmk hello
|
||||
Ψ Hello, World!
|
||||
```
|
||||
|
||||
## Einschränkungen der lokalen CLI
|
||||
|
||||
Hier ein Vergleich mit der globalen CLI:
|
||||
|
||||
* Die lokale CLI unterstützt kein `qmk setup` oder `qmk clone`.
|
||||
* Die lokale CLI arbeitet immer innerhalb der selben `qmk_firmware`-Verzeichnisstruktur, auch wenn Du mehrere Repositories geklont hast.
|
||||
* Die lokale CLI läuft nicht in einer virtualenv. Daher ist es möglich, dass Abhängigkeiten (dependencies) miteinander in Konflikt kommen/stehen.
|
||||
|
||||
# CLI-Befehle
|
||||
|
||||
## `qmk compile`
|
||||
|
||||
@@ -48,25 +48,6 @@ Nous recherchons des gens pour créer et maintenir un paquet `qmk` pour plus de
|
||||
* Installez en utilisant un virtualenv
|
||||
* Expliquez à l'utilisateur de définir la variable d'environnement `QMK_Home` pour "check out" les sources du firmware à un autre endroit que `~/qmk_firmware`.
|
||||
|
||||
# CLI locale
|
||||
|
||||
Si vous ne voulez pas utiliser la CLI globale, il y a une CLI locale empaquetée avec `qmk_firmware`. Vous pouvez le trouver dans `qmk_firmware/bin/qmk`. Vous pouvez lancer la commande `qmk` depuis n'importe quel répertoire et elle fonctionnera toujours sur cette copie de `qmk_firmware`.
|
||||
|
||||
**Exemple**:
|
||||
|
||||
```
|
||||
$ ~/qmk_firmware/bin/qmk hello
|
||||
Ψ Hello, World!
|
||||
```
|
||||
|
||||
## Limitations de la CLI locale
|
||||
|
||||
Il y a quelques limitations à la CLI locale comparé à la globale:
|
||||
|
||||
* La CLI locale ne supporte pas `qmk setup` ou `qmk clone`
|
||||
* La CLI locale n'opère pas sur le même arbre `qmk_firmware`, même si vous avez plusieurs dépôts clonés.
|
||||
* La CLI locale ne s'exécute pas dans un virtualenv, donc il y a des risques que des dépendances seront en conflit
|
||||
|
||||
# Les commandes CLI
|
||||
|
||||
## `qmk compile`
|
||||
|
||||
@@ -24,7 +24,7 @@ The "easy" way to flash the firmware is using a tool from your host OS:
|
||||
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/base_container`. This not only ensures predictability between systems, it also mirrors the CI environment.
|
||||
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
|
||||
|
||||
|
||||
@@ -144,10 +144,38 @@ The `rules.mk` file can also be placed in a sub-folder, and its reading order is
|
||||
* `keyboards/top_folder/sub_1/sub_2/sub_3/sub_4/rules.mk`
|
||||
* `keyboards/top_folder/keymaps/a_keymap/rules.mk`
|
||||
* `users/a_user_folder/rules.mk`
|
||||
* `keyboards/top_folder/sub_1/sub_2/sub_3/sub_4/post_rules.mk`
|
||||
* `keyboards/top_folder/sub_1/sub_2/sub_3/post_rules.mk`
|
||||
* `keyboards/top_folder/sub_1/sub_2/post_rules.mk`
|
||||
* `keyboards/top_folder/sub_1/post_rules.mk`
|
||||
* `keyboards/top_folder/post_rules.mk`
|
||||
* `common_features.mk`
|
||||
|
||||
Many of the settings written in the `rules.mk` file are interpreted by `common_features.mk`, which sets the necessary source files and compiler options.
|
||||
|
||||
The `post_rules.mk` file can interpret `features` of a keyboard-level before `common_features.mk`. For example, when your designed keyboard has the option to implement backlighting or underglow using rgblight.c, writing the following in the `post_rules.mk` makes it easier for the user to configure the `rules.mk`.
|
||||
|
||||
* `keyboards/top_folder/keymaps/a_keymap/rules.mk`
|
||||
```makefile
|
||||
# Please set the following according to the selection of the hardware implementation option.
|
||||
RGBLED_OPTION_TYPE = backlight ## none, backlight or underglow
|
||||
```
|
||||
* `keyboards/top_folder/post_rules.mk`
|
||||
```makefile
|
||||
ifeq ($(filter $(strip $(RGBLED_OPTION_TYPE))x, nonex backlightx underglowx x),)
|
||||
$(error unknown RGBLED_OPTION_TYPE value "$(RGBLED_OPTION_TYPE)")
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(RGBLED_OPTION_TYPE)),backlight)
|
||||
RGBLIGHT_ENABLE = yes
|
||||
OPT_DEFS += -DRGBLED_NUM=30
|
||||
endif
|
||||
ifeq ($(strip $(RGBLED_OPTION_TYPE)),underglow)
|
||||
RGBLIGHT_ENABLE = yes
|
||||
OPT_DEFS += -DRGBLED_NUM=6
|
||||
endif
|
||||
```
|
||||
|
||||
?> See `build_keyboard.mk` and `common_features.mk` for more details.
|
||||
|
||||
### `<keyboard_name.c>`
|
||||
|
||||
@@ -29,7 +29,7 @@ Vagrant 以外に、適切なプロバイダがインストールされ、その
|
||||
コマンドラインでプログラムしたい場合は、Vagranfile の ['modifyvm'] 行のコメントを解除して Linux への USB パススルーを有効にし、dfu-util/dfu-programmer のようなコマンドラインツールを使ってプログラムすることができます。あるいは Teensy CLI バージョンをインストールすることができます。
|
||||
|
||||
## Vagrantfile の概要
|
||||
開発環境は QMK Docker イメージ、`qmkfm/base_container` を実行するように設定されています。これはシステム間の予測可能性が保証されるだけでなく、CI 環境もミラーされます。
|
||||
開発環境は QMK Docker イメージ、`qmkfm/qmk_cli` を実行するように設定されています。これはシステム間の予測可能性が保証されるだけでなく、CI 環境もミラーされます。
|
||||
|
||||
## FAQ
|
||||
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
Run commands in the root directory of this repository.
|
||||
|
||||
```
|
||||
./bin/qmk compile && sudo dfu-programmer atmega32u4 erase && sudo dfu-programmer atmega32u4 flash ./dztech_dz65rgb_v2_jumper149.hex && sudo dfu-programmer atmega32u4 reset
|
||||
qmk compile && sudo dfu-programmer atmega32u4 erase && sudo dfu-programmer atmega32u4 flash ./dztech_dz65rgb_v2_jumper149.hex && sudo dfu-programmer atmega32u4 reset
|
||||
```
|
||||
|
||||
## build
|
||||
|
||||
```
|
||||
./bin/qmk compile
|
||||
qmk compile
|
||||
```
|
||||
|
||||
## flash
|
||||
|
||||
@@ -164,14 +164,25 @@ ifeq ($(strip $(OLED_ENABLE)), yes)
|
||||
OPT_DEFS += -DOLED_FONT_H=\"common/glcdfont.c\"
|
||||
endif
|
||||
else
|
||||
OLED_ENABLE = no # disable OLED in TOP/common_features.mk
|
||||
OLED_LOCAL_ENABLE = yes
|
||||
SRC += local_drivers/i2c.c
|
||||
SRC += local_drivers/ssd1306.c
|
||||
KEYBOARD_PATHS += $(HELIX_TOP_DIR)/local_drivers
|
||||
OPT_DEFS += -DOLED_LOCAL_ENABLE
|
||||
ifeq ($(strip $(LOCAL_GLCDFONT)), yes)
|
||||
OPT_DEFS += -DLOCAL_GLCDFONT
|
||||
ifeq ($(strip $(SPLIT_KEYBOARD)), yes)
|
||||
$(info Helix/rev2: The following combinations are not supported.)
|
||||
$(info - SPLIT_KEYBOARD = $(SPLIT_KEYBOARD)) # yes
|
||||
$(info - OLED_ENABLE = $(OLED_ENABLE)) # yes
|
||||
$(info - OLED_SELECT = $(OLED_SELECT)) # local
|
||||
$(info Force : OLED_ENABLE = no)
|
||||
$(info .)
|
||||
OLED_ENABLE = no
|
||||
endif
|
||||
ifeq ($(strip $(OLED_ENABLE)), yes)
|
||||
OLED_ENABLE = no # disable OLED in TOP/common_features.mk
|
||||
OLED_LOCAL_ENABLE = yes
|
||||
SRC += local_drivers/i2c.c
|
||||
SRC += local_drivers/ssd1306.c
|
||||
KEYBOARD_PATHS += $(HELIX_TOP_DIR)/local_drivers
|
||||
OPT_DEFS += -DOLED_LOCAL_ENABLE
|
||||
ifeq ($(strip $(LOCAL_GLCDFONT)), yes)
|
||||
OPT_DEFS += -DLOCAL_GLCDFONT
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
@@ -36,23 +36,23 @@ enum custom_layers {
|
||||
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
||||
|
||||
/* Base/Qwerty layer
|
||||
* .----------------------------------------. .-----------------------------------------.
|
||||
* | ~ | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | - |
|
||||
* |-----+------+------+------+------+------| |------+------+------+------+------+------|
|
||||
* | Tab | Q | W | E | R | T | | Y | U | I | O | P | [ |
|
||||
* |-----+------+------+------+------+------| |------+------+------+------+------+------|
|
||||
* | Esc | A | S | D | F | G | | H | J | K | L | ; | " |
|
||||
* |-----+------+------+------+------+------| |------+------+------+------+------+------|
|
||||
* |Lsft(| Z | X | C | V | B | | N | M | , | . | / |Rsft) |
|
||||
* |-----+------+------+------+------+------| |------+------+------+------+------+------|
|
||||
* |LCtrl| LGui | LAlt | Del | Spc/LftHnd | | Bckpc/Func | Left | Down | Up |Right |
|
||||
* '----------------------------------------' '-----------------------------------------'
|
||||
* .-----------------------------------------. .-----------------------------------------.
|
||||
* | ~ | 1 | 2 | 3 | 4 | 5 | | 6 | 7 | 8 | 9 | 0 | - |
|
||||
* |------+------+------+------+------+------| |------+------+------+------+------+------|
|
||||
* | Tab | Q | W | E | R | T | | Y | U | I | O | P | [ |
|
||||
* |------+------+------+------+------+------| |------+------+------+------+------+------|
|
||||
* | Esc | A | S | D | F | G | | H | J | K | L | ; | " |
|
||||
* |------+------+------+------+------+------| |------+------+------+------+------+------|
|
||||
* | Lsft(| Z | X | C | V | B | | N | M | , | . | / | Rsft)|
|
||||
* |------+------+------+------+------+------| |------+------+------+------+------+------|
|
||||
* | LCtrl| LGui | LAlt | Del | Spc/LftHnd | | Bckpc/Func | Left | Down | Up | Right|
|
||||
* '-----------------------------------------' '-----------------------------------------'
|
||||
*/
|
||||
|
||||
[_QWERTY] = LAYOUT(
|
||||
KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS,
|
||||
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC,
|
||||
KC_ESC, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT,
|
||||
LCTL_T(KC_ESC), KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT,
|
||||
KC_LSPO, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSPC,
|
||||
LCTL_T(KC_MPRV), LGUI_T(KC_MPLY), LALT_T(KC_MNXT), KC_DEL, SPC_LFT, SPC_LFT, BSP_FUNC, BSP_FUNC, KC_LEFT, KC_DOWN, KC_UP, KC_RGHT
|
||||
),
|
||||
@@ -61,22 +61,22 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
||||
* .-----------------------------------------. .-----------------------------------------.
|
||||
* | + | | | | | Rst | | NumLk| / | * | - | | \ |
|
||||
* |------+------+------+------+------+------| |------+------+------+------+------+------|
|
||||
* | | Home | [ | ] | Up | PgUp | | 7 | 8 | 9 | + | | ] |
|
||||
* | | Home | [ | Up | ] | PgUp | | 7 | 8 | 9 | + | | ] |
|
||||
* |------+------+------+------+------+------| |------+------+------+------+------+------|
|
||||
* | | End | Left | Down | Right| PgDn | | 4 | 5 | 6 | , | | Enter|
|
||||
* | | End | Left | Down | Right| PgDn | | 4 | 5 | 6 | , | | |
|
||||
* |------+------+------+------+------+------| |------+------+------+------+------+------|
|
||||
* | | Calc | MyPC |PrtScr| Enter|BckSpc| | 1 | 2 | 3 | = | PgUp | Home |
|
||||
* | | Calc | MyPC |PrtScr| Enter|BckSpc| | 1 | 2 | 3 | = | | Enter|
|
||||
* |------+------+------+------+------+------| |------+------+------+------+------+------|
|
||||
* | | Mute | | | | | | 0 | . | Enter| PgDn | End |
|
||||
* '-----------------------------------------' `-----------------------------------------'
|
||||
* | | Mute | | | | | | 0 | . | Enter| Home | End |
|
||||
* '-----------------------------------------' '-----------------------------------------'
|
||||
*/
|
||||
|
||||
[_LEFTHAND] = LAYOUT(
|
||||
KC_EQL, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, RESET, KC_NLCK, KC_PSLS, KC_PAST, KC_PMNS, KC_TRNS, KC_BSLS,
|
||||
KC_TRNS, KC_TRNS, KC_LBRC, KC_UP, KC_RBRC, KC_TRNS, KC_P7, KC_P8, KC_P9, KC_PPLS, KC_TRNS, KC_RBRC,
|
||||
KC_TRNS, KC_TRNS, KC_LEFT, KC_DOWN, KC_RGHT, KC_TRNS, KC_P4, KC_P5, KC_P6, KC_PCMM, KC_TRNS, KC_ENT,
|
||||
KC_TRNS, KC_CALC, KC_MYCM, KC_PSCR, KC_ENT, KC_BSPC, KC_P1, KC_P2, KC_P3, KC_PEQL, KC_PGUP, KC_HOME,
|
||||
KC_TRNS, KC_MUTE, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_P0, KC_P0, KC_PDOT, KC_PENT, KC_PGDN, KC_END
|
||||
KC_LCTL, KC_TRNS, KC_LEFT, KC_DOWN, KC_RGHT, KC_TRNS, KC_P4, KC_P5, KC_P6, KC_PCMM, KC_TRNS, KC_TRNS,
|
||||
KC_LSFT, KC_CALC, KC_MYCM, KC_PSCR, KC_ENT, KC_BSPC, KC_P1, KC_P2, KC_P3, KC_PEQL, KC_TRNS, KC_ENT,
|
||||
KC_LCTL, KC_MUTE, KC_LALT, KC_TRNS, KC_TRNS, KC_TRNS, KC_P0, KC_P0, KC_PDOT, KC_PENT, KC_HOME, KC_END
|
||||
),
|
||||
|
||||
/* Func/Numpad layer
|
||||
@@ -90,7 +90,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
||||
* | | | | | | | | | | | | | |
|
||||
* |------+------+------+------+------+------| |------+------+------+------+------+------|
|
||||
* | | | | | | | | | | | | | Rst |
|
||||
* '-----------------------------------------' `-----------------------------------------'
|
||||
* '-----------------------------------------' '-----------------------------------------'
|
||||
*/
|
||||
|
||||
|
||||
|
||||
51
keyboards/kelowna/rgb64/config.h
Normal file
51
keyboards/kelowna/rgb64/config.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/* Copyright 2021 Weirdo
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include "config_common.h"
|
||||
|
||||
/* USB Device descriptor parameter */
|
||||
#define VENDOR_ID 0x7764
|
||||
#define PRODUCT_ID 0x4C64
|
||||
#define DEVICE_VER 0x0001
|
||||
#define MANUFACTURER Weirdo
|
||||
#define PRODUCT kelownaRGB64
|
||||
|
||||
/* key matrix size */
|
||||
#define MATRIX_ROWS 5
|
||||
#define MATRIX_COLS 15
|
||||
|
||||
#define MATRIX_COL_PINS { A3, A4, A5, A7, B0, B1, B10, B15, A8, A9, A10, B7, B6, B5, B4}
|
||||
#define MATRIX_ROW_PINS { B12, B13, B14, C11, A1}
|
||||
#define DIODE_DIRECTION ROW2COL
|
||||
#define DEBOUNCE 5
|
||||
|
||||
|
||||
|
||||
#define RGB_DI_PIN A6
|
||||
#define RGBLED_NUM 64
|
||||
//#define RGBLIGHT_DISABLE_KEYCODES
|
||||
|
||||
|
||||
|
||||
|
||||
/* Mechanical locking support. Use KC_LCAP, KC_LNUM or KC_LSCR instead in keymap */
|
||||
#define LOCKING_SUPPORT_ENABLE
|
||||
|
||||
/* Locking resynchronize hack */
|
||||
#define LOCKING_RESYNC_ENABLE
|
||||
|
||||
|
||||
|
||||
77
keyboards/kelowna/rgb64/info.json
Normal file
77
keyboards/kelowna/rgb64/info.json
Normal file
@@ -0,0 +1,77 @@
|
||||
{
|
||||
"keyboard_name": "kelownaRGB64",
|
||||
"url": "",
|
||||
"maintainer": "qmk",
|
||||
"width": 15,
|
||||
"height": 5,
|
||||
"layouts": {
|
||||
"LAYOUT_64_ansi": {
|
||||
"layout": [
|
||||
{"label":"K00", "x":0, "y":0},
|
||||
{"label":"K01", "x":1, "y":0},
|
||||
{"label":"K02", "x":2, "y":0},
|
||||
{"label":"K03", "x":3, "y":0},
|
||||
{"label":"K04", "x":4, "y":0},
|
||||
{"label":"K05", "x":5, "y":0},
|
||||
{"label":"K06", "x":6, "y":0},
|
||||
{"label":"K07", "x":7, "y":0},
|
||||
{"label":"K08", "x":8, "y":0},
|
||||
{"label":"K09", "x":9, "y":0},
|
||||
{"label":"K0A", "x":10, "y":0},
|
||||
{"label":"K0B", "x":11, "y":0},
|
||||
{"label":"K0C", "x":12, "y":0},
|
||||
{"label":"K0E", "x":13, "y":0, "w":2},
|
||||
{"label":"K10", "x":0, "y":1, "w":1.5},
|
||||
{"label":"K12", "x":1.5, "y":1},
|
||||
{"label":"K13", "x":2.5, "y":1},
|
||||
{"label":"K14", "x":3.5, "y":1},
|
||||
{"label":"K15", "x":4.5, "y":1},
|
||||
{"label":"K16", "x":5.5, "y":1},
|
||||
{"label":"K17", "x":6.5, "y":1},
|
||||
{"label":"K18", "x":7.5, "y":1},
|
||||
{"label":"K19", "x":8.5, "y":1},
|
||||
{"label":"K1A", "x":9.5, "y":1},
|
||||
{"label":"K1B", "x":10.5, "y":1},
|
||||
{"label":"K1C", "x":11.5, "y":1},
|
||||
{"label":"K1D", "x":12.5, "y":1},
|
||||
{"label":"K1E", "x":13.5, "y":1, "w":1.5},
|
||||
{"label":"K20", "x":0, "y":2, "w":1.75},
|
||||
{"label":"K22", "x":1.75, "y":2},
|
||||
{"label":"K23", "x":2.75, "y":2},
|
||||
{"label":"K24", "x":3.75, "y":2},
|
||||
{"label":"K25", "x":4.75, "y":2},
|
||||
{"label":"K26", "x":5.75, "y":2},
|
||||
{"label":"K27", "x":6.75, "y":2},
|
||||
{"label":"K28", "x":7.75, "y":2},
|
||||
{"label":"K29", "x":8.75, "y":2},
|
||||
{"label":"K2A", "x":9.75, "y":2},
|
||||
{"label":"K2B", "x":10.75, "y":2},
|
||||
{"label":"K2C", "x":11.75, "y":2},
|
||||
{"label":"K2E", "x":12.75, "y":2, "w":2.25},
|
||||
{"label":"K30", "x":0, "y":3, "w":2},
|
||||
{"label":"K32", "x":2, "y":3},
|
||||
{"label":"K33", "x":3, "y":3},
|
||||
{"label":"K34", "x":4, "y":3},
|
||||
{"label":"K35", "x":5, "y":3},
|
||||
{"label":"K36", "x":6, "y":3},
|
||||
{"label":"K37", "x":7, "y":3},
|
||||
{"label":"K38", "x":8, "y":3},
|
||||
{"label":"K39", "x":9, "y":3},
|
||||
{"label":"K3A", "x":10, "y":3},
|
||||
{"label":"K3B", "x":11, "y":3},
|
||||
{"label":"K3C", "x":12, "y":3},
|
||||
{"label":"K3D", "x":13, "y":3},
|
||||
{"label":"K3E", "x":14, "y":3},
|
||||
{"label":"K40", "x":0, "y":4, "w":1.25},
|
||||
{"label":"K41", "x":1.25, "y":4, "w":1.25},
|
||||
{"label":"K42", "x":2.5, "y":4, "w":1.25},
|
||||
{"label":"K46", "x":3.75, "y":4, "w":6.25},
|
||||
{"label":"K4A", "x":10, "y":4},
|
||||
{"label":"K4B", "x":11, "y":4},
|
||||
{"label":"K4C", "x":12, "y":4},
|
||||
{"label":"K4D", "x":13, "y":4},
|
||||
{"label":"K4E", "x":14, "y":4}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
38
keyboards/kelowna/rgb64/keymaps/default/keymap.c
Normal file
38
keyboards/kelowna/rgb64/keymaps/default/keymap.c
Normal file
@@ -0,0 +1,38 @@
|
||||
/* Copyright 2021 Weirdo
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include QMK_KEYBOARD_H
|
||||
|
||||
|
||||
// [Keymaps] -----------------------------------------------------------------//
|
||||
enum layer_names {
|
||||
_BASE,
|
||||
_FN
|
||||
};
|
||||
|
||||
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
||||
[_BASE] = LAYOUT_64_ansi(KC_ESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC,
|
||||
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS,
|
||||
KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT,
|
||||
KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMMA, KC_DOT, KC_SLSH, KC_RSFT, KC_UP, KC_DEL,
|
||||
KC_LCTL, KC_LWIN, KC_LALT, KC_SPACE, KC_RALT, KC_RCTL, KC_LEFT, KC_DOWN, KC_RIGHT),
|
||||
|
||||
|
||||
[_FN] = LAYOUT_64_ansi(KC_GRV, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_DEL,
|
||||
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
|
||||
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
|
||||
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
|
||||
KC_TRNS, KC_TRNS, KC_TRNS, KC_SPACE, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS), //
|
||||
};
|
||||
47
keyboards/kelowna/rgb64/keymaps/via/keymap.c
Normal file
47
keyboards/kelowna/rgb64/keymaps/via/keymap.c
Normal file
@@ -0,0 +1,47 @@
|
||||
/* Copyright 2021 Weirdo
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include QMK_KEYBOARD_H
|
||||
|
||||
|
||||
// [Keymaps] -----------------------------------------------------------------//
|
||||
enum layer_names { _BASE, _FN ,_FN1 ,_FN2 };
|
||||
|
||||
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
||||
[_BASE] = LAYOUT_64_ansi(KC_ESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC,
|
||||
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS,
|
||||
KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT,
|
||||
KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMMA, KC_DOT, KC_SLSH, KC_RSFT, KC_UP, KC_DEL,
|
||||
KC_LCTL, KC_LWIN, KC_LALT, KC_SPACE, KC_RALT, KC_RCTL, KC_LEFT, KC_DOWN, KC_RIGHT),
|
||||
|
||||
|
||||
[_FN] = LAYOUT_64_ansi(KC_GRV, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_DEL,
|
||||
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
|
||||
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
|
||||
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
|
||||
KC_TRNS, KC_TRNS, KC_TRNS, KC_SPACE, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS), //
|
||||
|
||||
[_FN1] = LAYOUT_64_ansi(KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
|
||||
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
|
||||
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
|
||||
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
|
||||
KC_TRNS, KC_TRNS, KC_TRNS, KC_SPACE, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS),
|
||||
|
||||
[_FN2] = LAYOUT_64_ansi(KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
|
||||
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
|
||||
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
|
||||
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
|
||||
KC_TRNS, KC_TRNS, KC_TRNS, KC_SPACE, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS),
|
||||
};
|
||||
1
keyboards/kelowna/rgb64/keymaps/via/rules.mk
Normal file
1
keyboards/kelowna/rgb64/keymaps/via/rules.mk
Normal file
@@ -0,0 +1 @@
|
||||
VIA_ENABLE = yes
|
||||
17
keyboards/kelowna/rgb64/readme.md
Normal file
17
keyboards/kelowna/rgb64/readme.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# kelownaRGB64
|
||||
|
||||

|
||||
|
||||
A 60% keyboard based on STM32f303
|
||||
|
||||
* Keyboard Maintainer: [Weirdo](https://github.com/Weirdo-F)(https://github.com/Weirdo-F)
|
||||
* Hardware Supported: kelownaRGB64
|
||||
* Hardware Availability: Not yet
|
||||
|
||||
Make example for this keyboard (after setting up your build environment):
|
||||
|
||||
make kelowna/rgb64:default
|
||||
|
||||
Use the SWD interface on the board to connect to the STlink (JLink) to directly burn firmware without entering the bootloader.
|
||||
|
||||
See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_tools) and the [make instructions](https://docs.qmk.fm/#/getting_started_make_guide) for more information. Brand new to QMK? Start with our [Complete Newbs Guide](https://docs.qmk.fm/#/newbs).
|
||||
16
keyboards/kelowna/rgb64/rgb64.c
Normal file
16
keyboards/kelowna/rgb64/rgb64.c
Normal file
@@ -0,0 +1,16 @@
|
||||
/* Copyright 2021 Weirdo
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "rgb64.h"
|
||||
31
keyboards/kelowna/rgb64/rgb64.h
Normal file
31
keyboards/kelowna/rgb64/rgb64.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
Copyright 2021 Weirdo
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "quantum.h"
|
||||
|
||||
|
||||
#define LAYOUT_64_ansi( \
|
||||
K00, K01, K02, K03, K04, K05, K06, K07, K08, K09, K0A, K0B, K0C, K0E, \
|
||||
K10, K12, K13, K14, K15, K16, K17, K18, K19, K1A, K1B, K1C, K1D, K1E, \
|
||||
K20, K22, K23, K24, K25, K26, K27, K28, K29, K2A, K2B, K2C, K2E, \
|
||||
K30, K32, K33, K34, K35, K36, K37, K38, K39, K3A, K3B, K3C, K3D, K3E, \
|
||||
K40, K41, K42, K46, K4A, K4B, K4C, K4D, K4E \
|
||||
) { \
|
||||
{K00, K01, K02, K03, K04, K05, K06, K07, K08, K09, K0A, K0B, K0C, KC_NO, K0E}, \
|
||||
{K10, KC_NO, K12, K13, K14, K15, K16, K17, K18, K19, K1A, K1B, K1C, K1D, K1E}, \
|
||||
{K20, KC_NO, K22, K23, K24, K25, K26, K27, K28, K29, K2A, K2B, K2C, KC_NO, K2E}, \
|
||||
{K30, KC_NO, K32, K33, K34, K35, K36, K37, K38, K39, K3A, K3B, K3C, K3D, K3E}, \
|
||||
{K40, K41, K42, KC_NO, KC_NO, KC_NO, K46, KC_NO,KC_NO, KC_NO, K4A, K4B, K4C, K4D, K4E} \
|
||||
}
|
||||
24
keyboards/kelowna/rgb64/rules.mk
Normal file
24
keyboards/kelowna/rgb64/rules.mk
Normal file
@@ -0,0 +1,24 @@
|
||||
# MCU name
|
||||
MCU = STM32F303
|
||||
BOARD = QMK_PROTON_C
|
||||
|
||||
# Bootloader selection
|
||||
BOOTLOADER = stm32-dfu
|
||||
|
||||
# Build Options
|
||||
# change yes to no to disable
|
||||
#
|
||||
BOOTMAGIC_ENABLE = lite # Virtual DIP switch configuration
|
||||
MOUSEKEY_ENABLE = no # Mouse keys
|
||||
EXTRAKEY_ENABLE = yes # Audio control and System control
|
||||
CONSOLE_ENABLE = no # Console for debug
|
||||
COMMAND_ENABLE = no # Commands for debug and configuration
|
||||
# Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE
|
||||
SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend
|
||||
# if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work
|
||||
NKRO_ENABLE = yes # USB Nkey Rollover
|
||||
BACKLIGHT_ENABLE = no # Enable keyboard backlight functionality
|
||||
RGBLIGHT_ENABLE = yes # Enable keyboard RGB underglow
|
||||
BLUETOOTH_ENABLE = no # Enable Bluetooth
|
||||
AUDIO_ENABLE = no # Audio output
|
||||
LAYOUTS = 64_ansi
|
||||
97
keyboards/primekb/prime_e/keymaps/peott-fr/keymap.c
Normal file
97
keyboards/primekb/prime_e/keymaps/peott-fr/keymap.c
Normal file
@@ -0,0 +1,97 @@
|
||||
0414/* Copyright 2021 Pierre-Emmanuel Ott
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include QMK_KEYBOARD_H
|
||||
|
||||
enum custom_layers {
|
||||
_QWERTY,
|
||||
_LEFTHAND,
|
||||
_NUM,
|
||||
_FUNC
|
||||
};
|
||||
|
||||
#define SPC_LFT LT(_LEFTHAND, KC_SPC)
|
||||
#define FN_NUM LT(_NUM, KC_MNXT)
|
||||
#define BSP_FUNC LT(_FUNC, KC_BSPC)
|
||||
|
||||
/* This keymap is a regular 40s keymap for most. My concessions include no numpad, and a dedicated left-hand layer.
|
||||
Enter is on a layer, which seems somewhat safe!
|
||||
Changes/improvements include removing all the Quantum mod functions when on the arrow layer, so that Ctrl and Shift act without ambiguity based on short or long presses.
|
||||
The 3 LEDs on the board show Caps Lock/L1/L2 respectively. L3 has no LED.
|
||||
*/
|
||||
|
||||
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
||||
[_QWERTY] = LAYOUT(
|
||||
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC,
|
||||
LCTL_T(KC_ESC), KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT,
|
||||
KC_LSPO, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSPC,
|
||||
LCTL_T(KC_MPRV), LALT_T(KC_MPLY), FN_NUM, SPC_LFT, BSP_FUNC, LGUI_T(KC_DEL), RALT_T(KC_HOME), RCTL_T(KC_END)
|
||||
),
|
||||
[_LEFTHAND] = LAYOUT(
|
||||
KC_TRNS, KC_TRNS, KC_TRNS, KC_UP, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
|
||||
KC_LCTL, KC_TRNS, KC_LEFT, KC_DOWN, KC_RGHT, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_ENT,
|
||||
KC_LSFT, KC_CALC, KC_MYCM, KC_TRNS, KC_ENT, KC_BSPC, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_RSFT,
|
||||
KC_LCTL, KC_LALT, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_PGDN, KC_PGUP
|
||||
),
|
||||
[_NUM] = LAYOUT(
|
||||
KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL,
|
||||
KC_CAPS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_BSLS,
|
||||
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
|
||||
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS
|
||||
),
|
||||
[_FUNC] = LAYOUT(
|
||||
RESET, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12,
|
||||
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_PSCR, KC_SLCK, KC_PAUS, KC_INS, KC_TRNS, KC_TRNS,
|
||||
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, RGB_TOG, RGB_MOD, RGB_HUI, RGB_SAI, RGB_VAI, RGB_SPI, KC_TRNS,
|
||||
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS
|
||||
)
|
||||
};
|
||||
|
||||
void matrix_init_user(void) {
|
||||
// set CapsLock LED to output and low
|
||||
setPinOutput(B1);
|
||||
writePinLow(B1);
|
||||
// set Layer 1 to output and low
|
||||
setPinOutput(B2);
|
||||
writePinLow(B2);
|
||||
// set Layer 2 to output and low
|
||||
setPinOutput(B3);
|
||||
writePinLow(B3);
|
||||
}
|
||||
|
||||
//function to activate Caps Lock LED
|
||||
bool led_update_user(led_t led_state) {
|
||||
writePin(B1, led_state.caps_lock);
|
||||
return false;
|
||||
}
|
||||
|
||||
//function for layer indicator LED
|
||||
layer_state_t layer_state_set_user(layer_state_t state)
|
||||
{
|
||||
if (get_highest_layer(state) == 1) {
|
||||
writePinHigh(B2);
|
||||
}
|
||||
else {
|
||||
writePinLow(B2);
|
||||
}
|
||||
if (get_highest_layer(state) == 2) {
|
||||
writePinHigh(B3);
|
||||
}
|
||||
else {
|
||||
writePinLow(B3);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
99
keyboards/viktus/sp_mini/config.h
Normal file
99
keyboards/viktus/sp_mini/config.h
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
Copyright 2012 Jun Wako <wakojun@gmail.com>
|
||||
Copyright 2015 Jack Humbert
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "config_common.h"
|
||||
|
||||
/* USB Device descriptor parameter */
|
||||
#define VENDOR_ID 0x5644
|
||||
#define PRODUCT_ID 0x534D
|
||||
#define DEVICE_VER 0x0001
|
||||
#define MANUFACTURER Viktus_Design
|
||||
#define PRODUCT SP_Mini
|
||||
|
||||
/* key matrix size */
|
||||
// Rows are doubled-up
|
||||
#define MATRIX_ROWS 10
|
||||
#define MATRIX_COLS 8
|
||||
|
||||
|
||||
// wiring of each half
|
||||
#define MATRIX_ROW_PINS { F0, B5, B4, D7, D6 }
|
||||
#define MATRIX_COL_PINS { B6, C6, C7, D4, D2, D3, D5 } // no B7 on left hand
|
||||
#define MATRIX_ROW_PINS_RIGHT { F0, B5, B4, D7, D6 }
|
||||
#define MATRIX_COL_PINS_RIGHT { B6, C6, C7, D4, D2, D3, D5, B7 }
|
||||
|
||||
|
||||
#define DIODE_DIRECTION COL2ROW
|
||||
|
||||
/* Split Defines */
|
||||
#define SPLIT_USB_DETECT
|
||||
#define MASTER_LEFT
|
||||
#define USE_I2C
|
||||
|
||||
/* define if matrix has ghost */
|
||||
//#define MATRIX_HAS_GHOST
|
||||
|
||||
/* Set 0 if debouncing isn't needed */
|
||||
#define DEBOUNCE 5
|
||||
|
||||
|
||||
/* ws2812 RGB LED */
|
||||
#define RGB_DI_PIN E6
|
||||
#define RGBLIGHT_EFFECT_BREATHING
|
||||
#define RGBLIGHT_EFFECT_RAINBOW_MOOD
|
||||
#define RGBLIGHT_EFFECT_RAINBOW_SWIRL
|
||||
#define RGBLIGHT_EFFECT_SNAKE
|
||||
#define RGBLIGHT_EFFECT_KNIGHT
|
||||
#define RGBLIGHT_EFFECT_CHRISTMAS
|
||||
#define RGBLIGHT_EFFECT_STATIC_GRADIENT
|
||||
#define RGBLIGHT_EFFECT_RGB_TEST
|
||||
#define RGBLIGHT_EFFECT_ALTERNATING
|
||||
#define RGBLIGHT_EFFECT_TWINKLE
|
||||
|
||||
//#define RGBLIGHT_SPLIT
|
||||
#define RGBLED_NUM 24 // Number of LEDs
|
||||
#define RGBLED_SPLIT { 12, 12 }
|
||||
|
||||
|
||||
|
||||
#define ENCODERS_PAD_A {F4}
|
||||
#define ENCODERS_PAD_B {F1}
|
||||
//#define ENCODERS_PAD_A_RIGHT {F4}
|
||||
//#define ENCODERS_PAD_B_RIGHT {F1}
|
||||
|
||||
#define ENCODER_RESOLUTIONS { 8, 8 }
|
||||
|
||||
/*
|
||||
* Feature disable options
|
||||
* These options are also useful to firmware size reduction.
|
||||
*/
|
||||
|
||||
/* disable debug print */
|
||||
// #define NO_DEBUG
|
||||
|
||||
/* disable print */
|
||||
// #define NO_PRINT
|
||||
|
||||
/* disable action features */
|
||||
//#define NO_ACTION_LAYER
|
||||
//#define NO_ACTION_TAPPING
|
||||
//#define NO_ACTION_ONESHOT
|
||||
//#define NO_ACTION_MACRO
|
||||
//#define NO_ACTION_FUNCTION
|
||||
85
keyboards/viktus/sp_mini/info.json
Normal file
85
keyboards/viktus/sp_mini/info.json
Normal file
@@ -0,0 +1,85 @@
|
||||
{
|
||||
"keyboard_name": "sp_mini",
|
||||
"url": "",
|
||||
"maintainer": "jrfhoutx",
|
||||
"width": 16,
|
||||
"height": 5.5,
|
||||
"layouts": {
|
||||
"LAYOUT_all": {
|
||||
"layout": [
|
||||
{"x":0, "y":0},
|
||||
{"x":1.25, "y":0},
|
||||
{"x":2.25, "y":0},
|
||||
{"x":3.25, "y":0},
|
||||
{"x":4.25, "y":0},
|
||||
{"x":5.25, "y":0},
|
||||
{"x":6.25, "y":0},
|
||||
{"x":7.75, "y":0},
|
||||
{"x":8.75, "y":0},
|
||||
{"x":9.75, "y":0},
|
||||
{"x":10.75, "y":0},
|
||||
{"x":11.75, "y":0},
|
||||
{"x":12.75, "y":0},
|
||||
{"x":13.75, "y":0},
|
||||
{"x":15, "y":0},
|
||||
|
||||
{"x":0, "y":1.25},
|
||||
{"label":"Esc", "x":1.25, "y":1.25},
|
||||
{"label":"Q", "x":2.25, "y":1.25},
|
||||
{"label":"W", "x":3.25, "y":1.25},
|
||||
{"label":"E", "x":4.25, "y":1.25},
|
||||
{"label":"R", "x":5.25, "y":1.25},
|
||||
{"label":"T", "x":6.25, "y":1.25},
|
||||
{"label":"Y", "x":7.75, "y":1.25},
|
||||
{"label":"U", "x":8.75, "y":1.25},
|
||||
{"label":"I", "x":9.75, "y":1.25},
|
||||
{"label":"O", "x":10.75, "y":1.25},
|
||||
{"label":"P", "x":11.75, "y":1.25},
|
||||
{"label":"Delete", "x":12.75, "y":1.25},
|
||||
{"label":"Back", "x":13.75, "y":1.25},
|
||||
{"x":15, "y":1.25},
|
||||
|
||||
{"x":0, "y":2.25},
|
||||
{"label":"Tab", "x":1.25, "y":2.25, "w":1.25},
|
||||
{"label":"A", "x":2.5, "y":2.25},
|
||||
{"label":"S", "x":3.5, "y":2.25},
|
||||
{"label":"D", "x":4.5, "y":2.25},
|
||||
{"label":"F", "x":5.5, "y":2.25},
|
||||
{"label":"G", "x":6.5, "y":2.25},
|
||||
{"label":"H", "x":8, "y":2.25},
|
||||
{"label":"J", "x":9, "y":2.25},
|
||||
{"label":"K", "x":10, "y":2.25},
|
||||
{"label":"L", "x":11, "y":2.25},
|
||||
{"label":"\"", "x":12, "y":2.25},
|
||||
{"label":"Enter", "x":13, "y":2.25, "w":1.75},
|
||||
{"x":15, "y":2.25},
|
||||
|
||||
{"x":0, "y":3.25},
|
||||
{"label":"Shift", "x":1.25, "y":3.25, "w":1.75},
|
||||
{"label":"Z", "x":3, "y":3.25},
|
||||
{"label":"X", "x":4, "y":3.25},
|
||||
{"label":"C", "x":5, "y":3.25},
|
||||
{"label":"V", "x":6, "y":3.25},
|
||||
{"label":"B", "x":7, "y":3.25},
|
||||
{"label":"N", "x":8.5, "y":3.25},
|
||||
{"label":"M", "x":9.5, "y":3.25},
|
||||
{"label":"<", "x":10.5, "y":3.25},
|
||||
{"label":">", "x":11.5, "y":3.25},
|
||||
{"label":"Shift", "x":12.5, "y":3.25, "w":1.25},
|
||||
{"label":"\u2191", "x":14, "y":3.5},
|
||||
|
||||
{"x":0, "y":4.25},
|
||||
{"label":"Ctrl", "x":1.25, "y":4.25, "w":1.25},
|
||||
{"label":"LAlt", "x":2.5, "y":4.25},
|
||||
{"label":"LGUI", "x":3.5, "y":4.25},
|
||||
{"label":"Fn1", "x":4.5, "y":4.25, "w":1.25},
|
||||
{"label":"SPFn1", "x":5.75, "y":4.25, "w":2},
|
||||
{"label":"BSFn2", "x":8.25, "y":4.25, "w":2.25},
|
||||
{"label":"Alt", "x":10.5, "y":4.25, "w":1.25},
|
||||
{"label":"Fn2", "x":11.75, "y":4.25},
|
||||
{"label":"\u2190", "x":13, "y":4.5},
|
||||
{"label":"\u2193", "x":14, "y":4.5},
|
||||
{"label":"\u2192", "x":15, "y":4.5}]
|
||||
}
|
||||
}
|
||||
}
|
||||
128
keyboards/viktus/sp_mini/keymaps/default/keymap.c
Normal file
128
keyboards/viktus/sp_mini/keymaps/default/keymap.c
Normal file
@@ -0,0 +1,128 @@
|
||||
/* Copyright 2021 jrfhoutx
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include QMK_KEYBOARD_H
|
||||
|
||||
// Each layer gets a name for readability, which is then used in the keymap matrix below.
|
||||
// The underscores don't mean anything - you can have a layer called STUFF or any other name.
|
||||
// Layer names don't all need to be of the same length, obviously, and you can also skip them
|
||||
// entirely and just use numbers.
|
||||
|
||||
|
||||
enum custom_layers {
|
||||
_BASE,
|
||||
_FN1,
|
||||
_FN2,
|
||||
_FN3,
|
||||
};
|
||||
|
||||
enum custom_keycodes {
|
||||
QWERTY = SAFE_RANGE,
|
||||
};
|
||||
|
||||
#define KC_FN1 MO(_FN1)
|
||||
#define KC_FN2 MO(_FN2)
|
||||
#define SPFN1 LT(_FN1, KC_SPACE)
|
||||
#define BSFN2 LT(_FN2, KC_BSPC)
|
||||
|
||||
|
||||
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
||||
[_BASE] = LAYOUT_all(
|
||||
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, KC_F24, _______, _______,
|
||||
MO(1), KC_ESC, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_DEL, KC_BSPC, _______,
|
||||
MO(2), KC_TAB, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_QUOT, KC_ENT, _______,
|
||||
_______, KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_RSFT, KC_UP,
|
||||
_______, KC_LCTL, KC_LALT, KC_LGUI, KC_FN1, SPFN1, BSFN2, KC_RALT, KC_FN2, KC_LEFT, KC_DOWN, KC_RGHT
|
||||
),
|
||||
|
||||
[_FN1] = LAYOUT_all(
|
||||
_______, RESET, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
|
||||
_______, KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, _______,
|
||||
_______, RGB_TOG, RGB_HUI, RGB_SAI, RGB_VAI, KC_VOLU, KC_LBRC, KC_RBRC, KC_4, KC_5, KC_6, KC_SCLN, _______, _______,
|
||||
_______, RGB_MOD, RGB_HUD, RGB_SAD, RGB_VAD, KC_VOLD, KC_LCBR, KC_RCBR, KC_1, KC_2, KC_3, _______, KC_UP,
|
||||
_______, _______, _______, _______, _______, _______, KC_DEL, KC_0, _______, KC_LEFT, KC_DOWN, KC_RGHT
|
||||
),
|
||||
|
||||
[_FN2] = LAYOUT_all(
|
||||
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
|
||||
_______, KC_TILD, KC_EXLM, KC_AT, KC_HASH, KC_DLR, KC_PERC, KC_CIRC, KC_AMPR, KC_ASTR, KC_LPRN, KC_RPRN, KC_UNDS, KC_PLUS, _______,
|
||||
_______, _______, _______, _______, KC_INS, KC_PGUP, KC_HOME, _______, _______, _______, _______, KC_COLN, _______, _______,
|
||||
_______, _______, _______, _______, KC_DEL, KC_PGDN, KC_END, _______, _______, _______, _______, _______, KC_UP,
|
||||
_______, _______, _______, _______, _______, KC_DEL, _______, _______, _______, KC_LEFT, KC_DOWN, KC_RGHT
|
||||
),
|
||||
|
||||
[_FN3] = LAYOUT_all(
|
||||
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, KC_F24, _______, _______,
|
||||
MO(1), KC_ESC, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_DEL, KC_BSPC, _______,
|
||||
MO(2), KC_TAB, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_QUOT, KC_ENT, _______,
|
||||
_______, KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_RSFT, KC_UP,
|
||||
_______, KC_LCTL, KC_LALT, KC_LGUI, KC_FN1, SPFN1, BSFN2, KC_RALT, KC_FN2, KC_LEFT, KC_DOWN, KC_RGHT
|
||||
)
|
||||
|
||||
};
|
||||
|
||||
void keyboard_pre_init_user(void) {
|
||||
setPinOutput(F5); // initialize F5 for LED
|
||||
setPinOutput(F6); // initialize F6 for LED
|
||||
setPinOutput(F7); // initialize F7 for LED
|
||||
|
||||
}
|
||||
|
||||
layer_state_t layer_state_set_user(layer_state_t state) {
|
||||
writePinLow(F5);
|
||||
writePinLow(F6);
|
||||
writePinLow(F7);
|
||||
switch (get_highest_layer(state)) {
|
||||
case _FN1:
|
||||
writePinHigh(F5);
|
||||
break;
|
||||
case _FN2:
|
||||
writePinHigh(F6);
|
||||
break;
|
||||
case _FN3: // replace 'XXXX' with the layer or function name
|
||||
writePinHigh(F7);
|
||||
break;
|
||||
case KC_F24:
|
||||
writePinHigh(F7);
|
||||
writePinHigh(F5);
|
||||
writePinHigh(F6);
|
||||
break;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
|
||||
bool spongebob_mode = false;
|
||||
bool spongebob_case = false;
|
||||
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
|
||||
if (spongebob_mode) {
|
||||
switch(keycode) {
|
||||
case KC_A...KC_Z:
|
||||
if (record->event.pressed) {
|
||||
(spongebob_case ^= 1) == 0 ? tap_code16(S(keycode)) : tap_code(keycode);
|
||||
return false; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
switch(keycode) {
|
||||
case KC_F24:
|
||||
if (record->event.pressed) {
|
||||
spongebob_mode ^= 1;
|
||||
}
|
||||
return false; break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
136
keyboards/viktus/sp_mini/keymaps/via/keymap.c
Normal file
136
keyboards/viktus/sp_mini/keymaps/via/keymap.c
Normal file
@@ -0,0 +1,136 @@
|
||||
/* Copyright 2021 jrfhoutx
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include QMK_KEYBOARD_H
|
||||
|
||||
// Each layer gets a name for readability, which is then used in the keymap matrix below.
|
||||
// The underscores don't mean anything - you can have a layer called STUFF or any other name.
|
||||
// Layer names don't all need to be of the same length, obviously, and you can also skip them
|
||||
// entirely and just use numbers.
|
||||
|
||||
|
||||
enum custom_layers {
|
||||
_BASE,
|
||||
_FN1,
|
||||
_FN2,
|
||||
_FN3,
|
||||
};
|
||||
|
||||
enum custom_keycodes {
|
||||
QWERTY = SAFE_RANGE,
|
||||
};
|
||||
|
||||
#define KC_FN1 MO(_FN1)
|
||||
#define KC_FN2 MO(_FN2)
|
||||
#define SPFN1 LT(_FN1, KC_SPACE)
|
||||
#define BSFN2 LT(_FN2, KC_BSPC)
|
||||
|
||||
|
||||
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
||||
[_BASE] = LAYOUT_all(
|
||||
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
|
||||
MO(1), KC_ESC, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_DEL, KC_BSPC, _______,
|
||||
MO(2), KC_TAB, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_QUOT, KC_ENT, _______,
|
||||
_______, KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_RSFT, KC_UP,
|
||||
_______, KC_LCTL, KC_LALT, KC_LGUI, KC_FN1, SPFN1, BSFN2, KC_RALT, KC_FN2, KC_LEFT, KC_DOWN, KC_RGHT
|
||||
),
|
||||
|
||||
[_FN1] = LAYOUT_all(
|
||||
_______, RESET, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
|
||||
_______, KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, _______,
|
||||
_______, RGB_TOG, RGB_HUI, RGB_SAI, RGB_VAI, KC_VOLU, KC_LBRC, KC_RBRC, KC_4, KC_5, KC_6, KC_SCLN, _______, _______,
|
||||
_______, RGB_MOD, RGB_HUD, RGB_SAD, RGB_VAD, KC_VOLD, KC_LCBR, KC_RCBR, KC_1, KC_2, KC_3, _______, KC_UP,
|
||||
_______, _______, _______, _______, _______, _______, KC_DEL, KC_0, _______, KC_LEFT, KC_DOWN, KC_RGHT
|
||||
),
|
||||
|
||||
[_FN2] = LAYOUT_all(
|
||||
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
|
||||
_______, KC_TILD, KC_EXLM, KC_AT, KC_HASH, KC_DLR, KC_PERC, KC_CIRC, KC_AMPR, KC_ASTR, KC_LPRN, KC_RPRN, KC_UNDS, KC_PLUS, _______,
|
||||
_______, _______, _______, _______, KC_INS, KC_PGUP, KC_HOME, _______, _______, _______, _______, KC_COLN, _______, _______,
|
||||
_______, _______, _______, _______, KC_DEL, KC_PGDN, KC_END, _______, _______, _______, _______, _______, KC_UP,
|
||||
_______, _______, _______, _______, _______, KC_DEL, _______, _______, _______, KC_LEFT, KC_DOWN, KC_RGHT
|
||||
),
|
||||
|
||||
[_FN3] = LAYOUT_all(
|
||||
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, KC_F24, _______, _______,
|
||||
MO(1), KC_ESC, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_DEL, KC_BSPC, _______,
|
||||
MO(2), KC_TAB, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_QUOT, KC_ENT, _______,
|
||||
_______, KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_RSFT, KC_UP,
|
||||
_______, KC_LCTL, KC_LALT, KC_LGUI, KC_FN1, SPFN1, BSFN2, KC_RALT, KC_FN2, KC_LEFT, KC_DOWN, KC_RGHT
|
||||
)
|
||||
|
||||
};
|
||||
|
||||
void keyboard_pre_init_user(void) {
|
||||
setPinOutput(F5); // initialize F5 for LED
|
||||
setPinOutput(F6); // initialize F6 for LED
|
||||
setPinOutput(F7); // initialize F7 for LED
|
||||
|
||||
}
|
||||
|
||||
layer_state_t layer_state_set_user(layer_state_t state) {
|
||||
switch (get_highest_layer(state)) {
|
||||
case _FN1:
|
||||
writePinHigh(F5);
|
||||
writePinLow(F6);
|
||||
writePinLow(F7);
|
||||
break;
|
||||
case _FN2:
|
||||
writePinHigh(F6);
|
||||
writePinLow(F5);
|
||||
writePinLow(F7);
|
||||
break;
|
||||
case _FN3: // replace 'XXXX' with the layer or function name
|
||||
writePinHigh(F7);
|
||||
writePinLow(F5);
|
||||
writePinLow(F6);
|
||||
break;
|
||||
case KC_F24:
|
||||
writePinHigh(F7);
|
||||
writePinHigh(F5);
|
||||
writePinHigh(F6);
|
||||
break;
|
||||
default:
|
||||
writePinLow(F5);
|
||||
writePinLow(F6);
|
||||
writePinLow(F7);
|
||||
break;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
|
||||
bool spongebob_mode = false;
|
||||
bool spongebob_case = false;
|
||||
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
|
||||
if (spongebob_mode) {
|
||||
switch(keycode) {
|
||||
case KC_A...KC_Z:
|
||||
if (record->event.pressed) {
|
||||
(spongebob_case ^= 1) == 0 ? tap_code16(S(keycode)) : tap_code(keycode);
|
||||
return false; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
switch(keycode) {
|
||||
case USER00:
|
||||
if (record->event.pressed) {
|
||||
spongebob_mode ^= 1;
|
||||
}
|
||||
return false; break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
2
keyboards/viktus/sp_mini/keymaps/via/rules.mk
Normal file
2
keyboards/viktus/sp_mini/keymaps/via/rules.mk
Normal file
@@ -0,0 +1,2 @@
|
||||
VIA_ENABLE = yes
|
||||
|
||||
21
keyboards/viktus/sp_mini/readme.md
Normal file
21
keyboards/viktus/sp_mini/readme.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# sp_mini
|
||||
|
||||

|
||||
|
||||
The SP Mini is a 40% version of the SP-111 created in a collaboration of OneCreativeMind and BlindAssassin111 (Viktus owner). All design done by BlindAssassin111. The layout includes an F Row, left macro column, and arrows. Rotary encoders are supported in the top left and right positions. The board also features three through hole LED indicators and RGB underglow.
|
||||
|
||||
The SP Mini has dual ATMEGA32U4 controllers linked with USB Type C. Each PCB half has a single reset button and a standard AVR ISP header.
|
||||
|
||||
* Keyboard Maintainer: [jrfhoutx](https://github.com/jrfhoutx)
|
||||
* Hardware Supported: SP Mini FE (Founder's Edition), SP Mini LC (Low Cal)
|
||||
* Hardware Availability: Viktus Designs, LLC.
|
||||
|
||||
Make example for this keyboard (after setting up your build environment):
|
||||
|
||||
make viktus/sp_mini:default
|
||||
|
||||
Flashing example for this keyboard:
|
||||
|
||||
make viktus/sp_mini:default:flash
|
||||
|
||||
See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_tools) and the [make instructions](https://docs.qmk.fm/#/getting_started_make_guide) for more information. Brand new to QMK? Start with our [Complete Newbs Guide](https://docs.qmk.fm/#/newbs).
|
||||
24
keyboards/viktus/sp_mini/rules.mk
Normal file
24
keyboards/viktus/sp_mini/rules.mk
Normal file
@@ -0,0 +1,24 @@
|
||||
# MCU name
|
||||
MCU = atmega32u4
|
||||
|
||||
# Bootloader selection
|
||||
BOOTLOADER = atmel-dfu
|
||||
|
||||
# Build Options
|
||||
# change yes to no to disable
|
||||
#
|
||||
BOOTMAGIC_ENABLE = lite # Virtual DIP switch configuration
|
||||
MOUSEKEY_ENABLE = no # Mouse keys
|
||||
EXTRAKEY_ENABLE = yes # Audio control and System control
|
||||
CONSOLE_ENABLE = no # Console for debug
|
||||
COMMAND_ENABLE = no # Commands for debug and configuration
|
||||
# Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE
|
||||
SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend
|
||||
# if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work
|
||||
NKRO_ENABLE = yes # USB Nkey Rollover
|
||||
BACKLIGHT_ENABLE = no # Enable keyboard backlight functionality
|
||||
RGBLIGHT_ENABLE = yes # Enable keyboard RGB underglow
|
||||
BLUETOOTH_ENABLE = no # Enable Bluetooth
|
||||
AUDIO_ENABLE = no # Audio output
|
||||
SPLIT_KEYBOARD = yes
|
||||
ENCODER_ENABLE = yes
|
||||
45
keyboards/viktus/sp_mini/sp_mini.c
Normal file
45
keyboards/viktus/sp_mini/sp_mini.c
Normal file
@@ -0,0 +1,45 @@
|
||||
/* Copyright 2021 jrfhoutx
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "sp_mini.h"
|
||||
|
||||
void keyboard_pre_init_kb(void) {
|
||||
// enable built in pullups to avoid timeouts when right hand not connected
|
||||
setPinInputHigh(D0);
|
||||
setPinInputHigh(D1);
|
||||
|
||||
keyboard_pre_init_user();
|
||||
}
|
||||
|
||||
#ifdef ENCODER_ENABLE
|
||||
bool encoder_update_kb(uint8_t index, bool clockwise) {
|
||||
if (!encoder_update_user(index, clockwise)) { return false; }
|
||||
if (index == 0) { /* First encoder */
|
||||
if (clockwise) {
|
||||
tap_code(KC_PGDN);
|
||||
} else {
|
||||
tap_code(KC_PGUP);
|
||||
}
|
||||
} else if (index == 1) { /* Second encoder */
|
||||
if (clockwise) {
|
||||
tap_code(KC_VOLU);
|
||||
} else {
|
||||
tap_code(KC_VOLD);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
41
keyboards/viktus/sp_mini/sp_mini.h
Normal file
41
keyboards/viktus/sp_mini/sp_mini.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/* Copyright 2021 jrfhoutx
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "quantum.h"
|
||||
|
||||
#define ___ KC_NO
|
||||
|
||||
#define LAYOUT_all( \
|
||||
L00, L01, L02, L03, L04, L05, L06, R00, R01, R02, R03, R04, R05, R06, R07, \
|
||||
L10, L11, L12, L13, L14, L15, L16, R10, R11, R12, R13, R14, R15, R16, R17, \
|
||||
L20, L21, L22, L23, L24, L25, L26, R20, R21, R22, R23, R24, R26, R27, \
|
||||
L30, L31, L32, L33, L34, L35, L36, R31, R32, R33, R34, R35, R36, \
|
||||
L40, L41, L42, L43, L44, L45, R42, R43, R44, R45, R46, R47 \
|
||||
) \
|
||||
{ \
|
||||
{ L00, L01, L02, L03, L04, L05, L06 }, \
|
||||
{ L10, L11, L12, L13, L14, L15, L16 }, \
|
||||
{ L20, L21, L22, L23, L24, L25, L26 }, \
|
||||
{ L30, L31, L32, L33, L34, L35, L36 }, \
|
||||
{ L40, L41, L42, L43, L44, L45, ___ }, \
|
||||
{ R00, R01, R02, R03, R04, R05, R06, R07}, \
|
||||
{ R10, R11, R12, R13, R14, R15, R16, R17}, \
|
||||
{ R20, R21, R22, R23, R24, ___, R26, R27}, \
|
||||
{ ___, R31, R32, R33, R34, R35, R36, ___}, \
|
||||
{ ___, ___, R42, R43, R44, R45, R46, R47} \
|
||||
}
|
||||
@@ -37,37 +37,70 @@
|
||||
{"x": 3, "y": 5.25}
|
||||
]
|
||||
},
|
||||
"LAYOUT_ortho_4x6": {
|
||||
"LAYOUT_ortho_4x6_right": {
|
||||
"layout": [
|
||||
{"x": 0, "y": 0},
|
||||
{"x": 1, "y": 0},
|
||||
{"x": 2, "y": 0},
|
||||
{"x": 3, "y": 0},
|
||||
{"x": 4, "y": 0},
|
||||
{"x": 5.25, "y": 0},
|
||||
{"x": 5, "y": 0, "w": 1.5},
|
||||
|
||||
{"x": 0, "y": 1},
|
||||
{"x": 1, "y": 1},
|
||||
{"x": 2, "y": 1},
|
||||
{"x": 3, "y": 1},
|
||||
{"x": 4, "y": 1},
|
||||
{"x": 5.25, "y": 1},
|
||||
{"x": 5, "y": 1, "w": 1.5},
|
||||
|
||||
{"x": 0, "y": 2},
|
||||
{"x": 1, "y": 2},
|
||||
{"x": 2, "y": 2},
|
||||
{"x": 3, "y": 2},
|
||||
{"x": 4, "y": 2},
|
||||
{"x": 5.25, "y": 2},
|
||||
{"x": 5, "y": 2, "w": 1.5},
|
||||
|
||||
{"x": 0, "y": 3},
|
||||
{"x": 1, "y": 3},
|
||||
{"x": 2, "y": 3},
|
||||
{"x": 3, "y": 3},
|
||||
{"x": 4, "y": 3},
|
||||
{"x": 5.25, "y": 3}
|
||||
{"x": 5, "y": 3, "w": 1.5}
|
||||
]
|
||||
},
|
||||
|
||||
"LAYOUT_ortho_4x6_left": {
|
||||
"layout": [
|
||||
{"x": 0, "y": 0, "w": 1.5},
|
||||
{"x": 1.5, "y": 0},
|
||||
{"x": 2.5, "y": 0},
|
||||
{"x": 3.5, "y": 0},
|
||||
{"x": 4.5, "y": 0},
|
||||
{"x": 5.5, "y": 0},
|
||||
|
||||
{"x": 0, "y": 1, "w": 1.5},
|
||||
{"x": 1.5, "y": 1},
|
||||
{"x": 2.5, "y": 1},
|
||||
{"x": 3.5, "y": 1},
|
||||
{"x": 4.5, "y": 1},
|
||||
{"x": 5.5, "y": 1,},
|
||||
|
||||
{"x": 0, "y": 2, "w": 1.5},
|
||||
{"x": 1.5, "y": 2},
|
||||
{"x": 2.5, "y": 2},
|
||||
{"x": 3.5, "y": 2},
|
||||
{"x": 4.5, "y": 2},
|
||||
{"x": 5.5, "y": 2},
|
||||
|
||||
{"x": 0, "y": 3, "w": 1.5},
|
||||
{"x": 1.5, "y": 3},
|
||||
{"x": 2.5, "y": 3},
|
||||
{"x": 3.5, "y": 3},
|
||||
{"x": 4.5, "y": 3},
|
||||
{"x": 5.5, "y": 3}
|
||||
]
|
||||
},
|
||||
|
||||
"LAYOUT_numpad_6x4": {
|
||||
"layout": [
|
||||
{"x": 0, "y": 0},
|
||||
|
||||
@@ -36,18 +36,32 @@
|
||||
{ k05, k15, k25, k35 } \
|
||||
}
|
||||
|
||||
#define LAYOUT_ortho_4x6( \
|
||||
#define LAYOUT_ortho_4x6_right( \
|
||||
k00, k01, k02, k03, k04, k05, \
|
||||
k10, k11, k12, k13, k14, k15, \
|
||||
k20, k21, k22, k23, k24, k25, \
|
||||
k30, k31, k32, k33, k34, k35 \
|
||||
) { \
|
||||
{ k00, k10, k20, k30 }, \
|
||||
{ k01, k11, k21, k31 }, \
|
||||
{ k02, k12, k22, k32 }, \
|
||||
{ k03, k13, k23, k33 }, \
|
||||
{ k05, k15, k25, k35 }, \
|
||||
{ k04, k14, k24, k34 }, \
|
||||
{ k05, k15, k25, k35 } \
|
||||
{ k03, k13, k23, k33 }, \
|
||||
{ k02, k12, k22, k32 }, \
|
||||
{ k01, k11, k21, k31 }, \
|
||||
{ k00, k10, k20, k30 } \
|
||||
}
|
||||
|
||||
#define LAYOUT_ortho_4x6_left( \
|
||||
k00, k01, k02, k03, k04, k05, \
|
||||
k10, k11, k12, k13, k14, k15, \
|
||||
k20, k21, k22, k23, k24, k25, \
|
||||
k30, k31, k32, k33, k34, k35 \
|
||||
) { \
|
||||
{ k30, k20, k10, k00 }, \
|
||||
{ k31, k21, k11, k01 }, \
|
||||
{ k32, k22, k12, k02 }, \
|
||||
{ k33, k23, k13, k03 }, \
|
||||
{ k34, k24, k14, k04 }, \
|
||||
{ k35, k25, k15, k05 } \
|
||||
}
|
||||
|
||||
#define LAYOUT_numpad_6x4( \
|
||||
|
||||
21
layouts/default/ortho_4x6/default_ortho_4x6/keymap.c
Normal file
21
layouts/default/ortho_4x6/default_ortho_4x6/keymap.c
Normal file
@@ -0,0 +1,21 @@
|
||||
#include QMK_KEYBOARD_H
|
||||
|
||||
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
||||
/*
|
||||
* ┌───┬───┬───┬───┬───┬───┐
|
||||
* │Tab│ Q │ W │ E │ R │ T │
|
||||
* ├───┼───┼───┼───┼───┼───┤
|
||||
* │Bsp│ A │ S │ D │ F │ G │
|
||||
* ├───┼───┼───┼───┼───┼───┤
|
||||
* │Sft│ Z │ X │ C │ V │ B │
|
||||
* ├───┼───┼───┼───┼───┼───┤
|
||||
* │Ctl│App│GUI│Alt│Spc│Spc│
|
||||
* └───┴───┴───┴───┴───┴───┘
|
||||
*/
|
||||
[0] = LAYOUT_ortho_4x6(
|
||||
KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T,
|
||||
KC_BKSP, KC_A, KC_S, KC_D, KC_F, KC_G,
|
||||
KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B,
|
||||
KC_LCTL, KC_MENU, KC_LGUI, KC_LALT, KC_SPC, KC_SPC
|
||||
)
|
||||
};
|
||||
40
layouts/default/ortho_4x6/info.json
Normal file
40
layouts/default/ortho_4x6/info.json
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"keyboard_name": "4x6 ortholinear layout",
|
||||
"url": "",
|
||||
"maintainer": "qmk",
|
||||
"width": 4,
|
||||
"height": 4,
|
||||
"layouts": {
|
||||
"LAYOUT_ortho_4x6": {
|
||||
"layout": [
|
||||
{"x":0, "y":0},
|
||||
{"x":1, "y":0},
|
||||
{"x":2, "y":0},
|
||||
{"x":3, "y":0},
|
||||
{"x":4, "y":0},
|
||||
{"x":5, "y":0},
|
||||
|
||||
{"x":0, "y":1},
|
||||
{"x":1, "y":1},
|
||||
{"x":2, "y":1},
|
||||
{"x":3, "y":1},
|
||||
{"x":4, "y":1},
|
||||
{"x":5, "y":1},
|
||||
|
||||
{"x":0, "y":2},
|
||||
{"x":1, "y":2},
|
||||
{"x":2, "y":2},
|
||||
{"x":3, "y":2},
|
||||
{"x":4, "y":2},
|
||||
{"x":5, "y":2},
|
||||
|
||||
{"x":0, "y":3},
|
||||
{"x":1, "y":3},
|
||||
{"x":2, "y":3},
|
||||
{"x":3, "y":3},
|
||||
{"x":4, "y":3},
|
||||
{"x":5, "y":3}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
4
layouts/default/ortho_4x6/layout.json
Normal file
4
layouts/default/ortho_4x6/layout.json
Normal file
@@ -0,0 +1,4 @@
|
||||
[{a:7},"","","","","",""],
|
||||
["","","","","",""],
|
||||
["","","","","",""],
|
||||
["","","","","",""]
|
||||
3
layouts/default/ortho_4x6/readme.md
Normal file
3
layouts/default/ortho_4x6/readme.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# ortho_4x6
|
||||
|
||||
LAYOUT_ortho_4x6
|
||||
@@ -1,7 +1,8 @@
|
||||
"""Functions for working with config.h files.
|
||||
"""
|
||||
from pathlib import Path
|
||||
import re
|
||||
from functools import lru_cache
|
||||
from pathlib import Path
|
||||
|
||||
from milc import cli
|
||||
|
||||
@@ -12,18 +13,21 @@ single_comment_regex = re.compile(r'\s+/[/*].*$')
|
||||
multi_comment_regex = re.compile(r'/\*(.|\n)*?\*/', re.MULTILINE)
|
||||
|
||||
|
||||
@lru_cache(maxsize=0)
|
||||
def strip_line_comment(string):
|
||||
"""Removes comments from a single line string.
|
||||
"""
|
||||
return single_comment_regex.sub('', string)
|
||||
|
||||
|
||||
@lru_cache(maxsize=0)
|
||||
def strip_multiline_comment(string):
|
||||
"""Removes comments from a single line string.
|
||||
"""
|
||||
return multi_comment_regex.sub('', string)
|
||||
|
||||
|
||||
@lru_cache(maxsize=0)
|
||||
def c_source_files(dir_names):
|
||||
"""Returns a list of all *.c, *.h, and *.cpp files for a given list of directories
|
||||
|
||||
@@ -38,6 +42,7 @@ def c_source_files(dir_names):
|
||||
return files
|
||||
|
||||
|
||||
@lru_cache(maxsize=0)
|
||||
def find_layouts(file):
|
||||
"""Returns list of parsed LAYOUT preprocessor macros found in the supplied include file.
|
||||
"""
|
||||
@@ -144,6 +149,7 @@ def _default_key(label=None):
|
||||
return new_key
|
||||
|
||||
|
||||
@lru_cache(maxsize=0)
|
||||
def _parse_layout_macro(layout_macro):
|
||||
"""Split the LAYOUT macro into its constituent parts
|
||||
"""
|
||||
@@ -154,6 +160,7 @@ def _parse_layout_macro(layout_macro):
|
||||
return macro_name, layout, matrix
|
||||
|
||||
|
||||
@lru_cache(maxsize=0)
|
||||
def _parse_matrix_locations(matrix, file, macro_name):
|
||||
"""Parse raw matrix data into a dictionary keyed by the LAYOUT identifier.
|
||||
"""
|
||||
|
||||
@@ -35,7 +35,6 @@ subcommands = [
|
||||
'qmk.cli.chibios.confmigrate',
|
||||
'qmk.cli.clean',
|
||||
'qmk.cli.compile',
|
||||
'qmk.cli.console',
|
||||
'qmk.cli.docs',
|
||||
'qmk.cli.doctor',
|
||||
'qmk.cli.fileformat',
|
||||
@@ -181,8 +180,14 @@ if int(milc_version[0]) < 2 and int(milc_version[1]) < 4:
|
||||
print(f'Your MILC library is too old! Please upgrade: python3 -m pip install -U -r {str(requirements)}')
|
||||
exit(127)
|
||||
|
||||
# Make sure we can run binaries in the same directory as our Python interpreter
|
||||
python_dir = os.path.dirname(sys.executable)
|
||||
|
||||
if python_dir not in os.environ['PATH'].split(':'):
|
||||
os.environ['PATH'] = ":".join((python_dir, os.environ['PATH']))
|
||||
|
||||
# Check to make sure we have all our dependencies
|
||||
msg_install = 'Please run `python3 -m pip install -r %s` to install required python dependencies.'
|
||||
msg_install = f'Please run `{sys.executable} -m pip install -r %s` to install required python dependencies.'
|
||||
args = sys.argv[1:]
|
||||
while args and args[0][0] == '-':
|
||||
del args[0]
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"""
|
||||
from subprocess import DEVNULL
|
||||
|
||||
from qmk.commands import create_make_target
|
||||
from qmk.commands import _find_make
|
||||
from milc import cli
|
||||
|
||||
|
||||
@@ -11,4 +11,6 @@ from milc import cli
|
||||
def clean(cli):
|
||||
"""Runs `make clean` (or `make distclean` if --all is passed)
|
||||
"""
|
||||
cli.run(create_make_target('distclean' if cli.args.all else 'clean'), capture_output=False, stdin=DEVNULL)
|
||||
make_cmd = [_find_make(), 'distclean' if cli.args.all else 'clean']
|
||||
|
||||
cli.run(make_cmd, capture_output=False, stdin=DEVNULL)
|
||||
|
||||
@@ -2,23 +2,24 @@
|
||||
|
||||
You can compile a keymap already in the repo or using a QMK Configurator export.
|
||||
"""
|
||||
from subprocess import DEVNULL
|
||||
|
||||
from argcomplete.completers import FilesCompleter
|
||||
from milc import cli
|
||||
|
||||
import qmk.path
|
||||
from qmk.decorators import automagic_keyboard, automagic_keymap
|
||||
from qmk.commands import compile_configurator_json, create_make_command, parse_configurator_json
|
||||
from qmk.keyboard import keyboard_completer, keyboard_folder
|
||||
from qmk.commands import do_compile
|
||||
from qmk.keyboard import keyboard_completer, is_keyboard_target
|
||||
from qmk.keymap import keymap_completer
|
||||
from qmk.metadata import true_values, false_values
|
||||
|
||||
|
||||
@cli.argument('filename', nargs='?', arg_only=True, type=qmk.path.FileType('r'), completer=FilesCompleter('.json'), help='The configurator export to compile')
|
||||
@cli.argument('-kb', '--keyboard', type=keyboard_folder, completer=keyboard_completer, help='The keyboard to build a firmware for. Ignored when a configurator export is supplied.')
|
||||
@cli.argument('-t', '--target', help="The make target to run. By default it compiles the keyboard only.")
|
||||
@cli.argument('-kb', '--keyboard', type=is_keyboard_target, completer=keyboard_completer, help='The keyboard to build a firmware for. Ignored when a configurator export is supplied.')
|
||||
@cli.argument('-km', '--keymap', completer=keymap_completer, help='The keymap to build a firmware for. Ignored when a configurator export is supplied.')
|
||||
@cli.argument('-n', '--dry-run', arg_only=True, action='store_true', help="Don't actually build, just show the make command to be run.")
|
||||
@cli.argument('-j', '--parallel', type=int, default=1, help="Set the number of parallel make jobs; 0 means unlimited.")
|
||||
@cli.argument('-j', '--parallel', type=int, default=1, help="Set the number of parallel make jobs to run.")
|
||||
@cli.argument('-f', '--filter', arg_only=True, action='append', default=[], help="Filter your list against info.json.")
|
||||
@cli.argument('-e', '--env', arg_only=True, action='append', default=[], help="Set a variable to be passed to make. May be passed multiple times.")
|
||||
@cli.argument('-c', '--clean', arg_only=True, action='store_true', help="Remove object files before compiling.")
|
||||
@cli.subcommand('Compile a QMK Firmware.')
|
||||
@@ -31,47 +32,31 @@ def compile(cli):
|
||||
|
||||
If a keyboard and keymap are provided this command will build a firmware based on that.
|
||||
"""
|
||||
if cli.args.clean and not cli.args.filename and not cli.args.dry_run:
|
||||
command = create_make_command(cli.config.compile.keyboard, cli.config.compile.keymap, 'clean')
|
||||
cli.run(command, capture_output=False, stdin=DEVNULL)
|
||||
# If -f has been specified without a keyboard target, assume -kb all
|
||||
keyboard = cli.config.compile.keyboard or ''
|
||||
|
||||
# Build the environment vars
|
||||
envs = {}
|
||||
for env in cli.args.env:
|
||||
if '=' in env:
|
||||
key, value = env.split('=', 1)
|
||||
envs[key] = value
|
||||
else:
|
||||
cli.log.warning('Invalid environment variable: %s', env)
|
||||
if cli.args.filter and not cli.args.keyboard:
|
||||
cli.log.debug('--filter supplied without --keyboard, assuming --keyboard all.')
|
||||
keyboard = 'all'
|
||||
|
||||
# Determine the compile command
|
||||
command = None
|
||||
if cli.args.filename and cli.args.filter:
|
||||
cli.log.warning('Ignoring --filter because a keymap.json was provided.')
|
||||
|
||||
if cli.args.filename:
|
||||
# If a configurator JSON was provided generate a keymap and compile it
|
||||
user_keymap = parse_configurator_json(cli.args.filename)
|
||||
command = compile_configurator_json(user_keymap, parallel=cli.config.compile.parallel, **envs)
|
||||
filters = {}
|
||||
|
||||
else:
|
||||
if cli.config.compile.keyboard and cli.config.compile.keymap:
|
||||
# Generate the make command for a specific keyboard/keymap.
|
||||
command = create_make_command(cli.config.compile.keyboard, cli.config.compile.keymap, parallel=cli.config.compile.parallel, **envs)
|
||||
for filter in cli.args.filter:
|
||||
if '=' in filter:
|
||||
key, value = filter.split('=', 1)
|
||||
|
||||
elif not cli.config.compile.keyboard:
|
||||
cli.log.error('Could not determine keyboard!')
|
||||
elif not cli.config.compile.keymap:
|
||||
cli.log.error('Could not determine keymap!')
|
||||
if value in true_values:
|
||||
value = True
|
||||
elif value in false_values:
|
||||
value = False
|
||||
elif value.isdigit():
|
||||
value = int(value)
|
||||
elif '.' in value and value.replace('.').isdigit():
|
||||
value = float(value)
|
||||
|
||||
# Compile the firmware, if we're able to
|
||||
if command:
|
||||
cli.log.info('Compiling keymap with {fg_cyan}%s', ' '.join(command))
|
||||
if not cli.args.dry_run:
|
||||
cli.echo('\n')
|
||||
# FIXME(skullydazed/anyone): Remove text=False once milc 1.0.11 has had enough time to be installed everywhere.
|
||||
compile = cli.run(command, capture_output=False, text=False)
|
||||
return compile.returncode
|
||||
filters[key] = value
|
||||
|
||||
else:
|
||||
cli.log.error('You must supply a configurator export, both `--keyboard` and `--keymap`, or be in a directory for a keyboard or keymap.')
|
||||
cli.echo('usage: qmk compile [-h] [-b] [-kb KEYBOARD] [-km KEYMAP] [filename]')
|
||||
return False
|
||||
return do_compile(keyboard, cli.config.compile.keymap, cli.config.compile.parallel, cli.config.compile.target, filters)
|
||||
|
||||
@@ -1,303 +0,0 @@
|
||||
"""Acquire debugging information from usb hid devices
|
||||
|
||||
cli implementation of https://www.pjrc.com/teensy/hid_listen.html
|
||||
"""
|
||||
from pathlib import Path
|
||||
from threading import Thread
|
||||
from time import sleep, strftime
|
||||
|
||||
import hid
|
||||
import usb.core
|
||||
|
||||
from milc import cli
|
||||
|
||||
LOG_COLOR = {
|
||||
'next': 0,
|
||||
'colors': [
|
||||
'{fg_blue}',
|
||||
'{fg_cyan}',
|
||||
'{fg_green}',
|
||||
'{fg_magenta}',
|
||||
'{fg_red}',
|
||||
'{fg_yellow}',
|
||||
],
|
||||
}
|
||||
|
||||
KNOWN_BOOTLOADERS = {
|
||||
# VID , PID
|
||||
('03EB', '2FEF'): 'atmel-dfu: ATmega16U2',
|
||||
('03EB', '2FF0'): 'atmel-dfu: ATmega32U2',
|
||||
('03EB', '2FF3'): 'atmel-dfu: ATmega16U4',
|
||||
('03EB', '2FF4'): 'atmel-dfu: ATmega32U4',
|
||||
('03EB', '2FF9'): 'atmel-dfu: AT90USB64',
|
||||
('03EB', '2FFA'): 'atmel-dfu: AT90USB162',
|
||||
('03EB', '2FFB'): 'atmel-dfu: AT90USB128',
|
||||
('03EB', '6124'): 'Microchip SAM-BA',
|
||||
('0483', 'DF11'): 'stm32-dfu: STM32 BOOTLOADER',
|
||||
('16C0', '05DC'): 'USBasp: USBaspLoader',
|
||||
('16C0', '05DF'): 'bootloadHID: HIDBoot',
|
||||
('16C0', '0478'): 'halfkay: Teensy Halfkay',
|
||||
('1B4F', '9203'): 'caterina: Pro Micro 3.3V',
|
||||
('1B4F', '9205'): 'caterina: Pro Micro 5V',
|
||||
('1B4F', '9207'): 'caterina: LilyPadUSB',
|
||||
('1C11', 'B007'): 'kiibohd: Kiibohd DFU Bootloader',
|
||||
('1EAF', '0003'): 'stm32duino: Maple 003',
|
||||
('1FFB', '0101'): 'caterina: Polou A-Star 32U4 Bootloader',
|
||||
('2341', '0036'): 'caterina: Arduino Leonardo',
|
||||
('2341', '0037'): 'caterina: Arduino Micro',
|
||||
('239A', '000C'): 'caterina: Adafruit Feather 32U4',
|
||||
('239A', '000D'): 'caterina: Adafruit ItsyBitsy 32U4 3v',
|
||||
('239A', '000E'): 'caterina: Adafruit ItsyBitsy 32U4 5v',
|
||||
('2A03', '0036'): 'caterina: Arduino Leonardo',
|
||||
('2A03', '0037'): 'caterina: Arduino Micro',
|
||||
('314B', '0106'): 'apm32-dfu: APM32 DFU ISP Mode',
|
||||
('03EB', '2067'): 'qmk-hid: HID Bootloader',
|
||||
('03EB', '2045'): 'lufa-ms: LUFA Mass Storage Bootloader'
|
||||
}
|
||||
|
||||
|
||||
class MonitorDevice(object):
|
||||
def __init__(self, hid_device, numeric):
|
||||
self.hid_device = hid_device
|
||||
self.numeric = numeric
|
||||
self.device = hid.Device(path=hid_device['path'])
|
||||
self.current_line = ''
|
||||
|
||||
cli.log.info('Console Connected: %(color)s%(manufacturer_string)s %(product_string)s{style_reset_all} (%(color)s%(vendor_id)04X:%(product_id)04X:%(index)d{style_reset_all})', hid_device)
|
||||
|
||||
def read(self, size, encoding='ascii', timeout=1):
|
||||
"""Read size bytes from the device.
|
||||
"""
|
||||
return self.device.read(size, timeout).decode(encoding)
|
||||
|
||||
def read_line(self):
|
||||
"""Read from the device's console until we get a \n.
|
||||
"""
|
||||
while '\n' not in self.current_line:
|
||||
self.current_line += self.read(32).replace('\x00', '')
|
||||
|
||||
lines = self.current_line.split('\n', 1)
|
||||
self.current_line = lines[1]
|
||||
|
||||
return lines[0]
|
||||
|
||||
def run_forever(self):
|
||||
while True:
|
||||
try:
|
||||
message = {**self.hid_device, 'text': self.read_line()}
|
||||
identifier = (int2hex(message['vendor_id']), int2hex(message['product_id'])) if self.numeric else (message['manufacturer_string'], message['product_string'])
|
||||
message['identifier'] = ':'.join(identifier)
|
||||
message['ts'] = '{style_dim}{fg_green}%s{style_reset_all} ' % (strftime(cli.config.general.datetime_fmt),) if cli.args.timestamp else ''
|
||||
|
||||
cli.echo('%(ts)s%(color)s%(identifier)s:%(index)d{style_reset_all}: %(text)s' % message)
|
||||
|
||||
except hid.HIDException:
|
||||
break
|
||||
|
||||
|
||||
class FindDevices(object):
|
||||
def __init__(self, vid, pid, index, numeric):
|
||||
self.vid = vid
|
||||
self.pid = pid
|
||||
self.index = index
|
||||
self.numeric = numeric
|
||||
|
||||
def run_forever(self):
|
||||
"""Process messages from our queue in a loop.
|
||||
"""
|
||||
live_devices = {}
|
||||
live_bootloaders = {}
|
||||
|
||||
while True:
|
||||
try:
|
||||
for device in list(live_devices):
|
||||
if not live_devices[device]['thread'].is_alive():
|
||||
cli.log.info('Console Disconnected: %(color)s%(manufacturer_string)s %(product_string)s{style_reset_all} (%(color)s%(vendor_id)04X:%(product_id)04X:%(index)d{style_reset_all})', live_devices[device])
|
||||
del live_devices[device]
|
||||
|
||||
for device in self.find_devices():
|
||||
if device['path'] not in live_devices:
|
||||
device['color'] = LOG_COLOR['colors'][LOG_COLOR['next']]
|
||||
LOG_COLOR['next'] = (LOG_COLOR['next'] + 1) % len(LOG_COLOR['colors'])
|
||||
live_devices[device['path']] = device
|
||||
|
||||
try:
|
||||
monitor = MonitorDevice(device, self.numeric)
|
||||
device['thread'] = Thread(target=monitor.run_forever, daemon=True)
|
||||
|
||||
device['thread'].start()
|
||||
except Exception as e:
|
||||
device['e'] = e
|
||||
device['e_name'] = e.__class__.__name__
|
||||
cli.log.error("Could not connect to %(color)s%(manufacturer_string)s %(product_string)s{style_reset_all} (%(color)s:%(vendor_id)04X:%(product_id)04X:%(index)d): %(e_name)s: %(e)s", device)
|
||||
if cli.config.general.verbose:
|
||||
cli.log.exception(e)
|
||||
del live_devices[device['path']]
|
||||
|
||||
if cli.args.bootloaders:
|
||||
for device in self.find_bootloaders():
|
||||
if device.address in live_bootloaders:
|
||||
live_bootloaders[device.address]._qmk_found = True
|
||||
else:
|
||||
name = KNOWN_BOOTLOADERS[(int2hex(device.idVendor), int2hex(device.idProduct))]
|
||||
cli.log.info('Bootloader Connected: {style_bright}{fg_magenta}%s', name)
|
||||
device._qmk_found = True
|
||||
live_bootloaders[device.address] = device
|
||||
|
||||
for device in list(live_bootloaders):
|
||||
if live_bootloaders[device]._qmk_found:
|
||||
live_bootloaders[device]._qmk_found = False
|
||||
else:
|
||||
name = KNOWN_BOOTLOADERS[(int2hex(live_bootloaders[device].idVendor), int2hex(live_bootloaders[device].idProduct))]
|
||||
cli.log.info('Bootloader Disconnected: {style_bright}{fg_magenta}%s', name)
|
||||
del live_bootloaders[device]
|
||||
|
||||
sleep(.1)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
break
|
||||
|
||||
def is_bootloader(self, hid_device):
|
||||
"""Returns true if the device in question matches a known bootloader vid/pid.
|
||||
"""
|
||||
return (int2hex(hid_device.idVendor), int2hex(hid_device.idProduct)) in KNOWN_BOOTLOADERS
|
||||
|
||||
def is_console_hid(self, hid_device):
|
||||
"""Returns true when the usage page indicates it's a teensy-style console.
|
||||
"""
|
||||
return hid_device['usage_page'] == 0xFF31 and hid_device['usage'] == 0x0074
|
||||
|
||||
def is_filtered_device(self, hid_device):
|
||||
"""Returns True if the device should be included in the list of available consoles.
|
||||
"""
|
||||
return int2hex(hid_device['vendor_id']) == self.vid and int2hex(hid_device['product_id']) == self.pid
|
||||
|
||||
def find_devices_by_report(self, hid_devices):
|
||||
"""Returns a list of available teensy-style consoles by doing a brute-force search.
|
||||
|
||||
Some versions of linux don't report usage and usage_page. In that case we fallback to reading the report (possibly inaccurately) ourselves.
|
||||
"""
|
||||
devices = []
|
||||
|
||||
for device in hid_devices:
|
||||
path = device['path'].decode('utf-8')
|
||||
|
||||
if path.startswith('/dev/hidraw'):
|
||||
number = path[11:]
|
||||
report = Path(f'/sys/class/hidraw/hidraw{number}/device/report_descriptor')
|
||||
|
||||
if report.exists():
|
||||
rp = report.read_bytes()
|
||||
|
||||
if rp[1] == 0x31 and rp[3] == 0x09:
|
||||
devices.append(device)
|
||||
|
||||
return devices
|
||||
|
||||
def find_bootloaders(self):
|
||||
"""Returns a list of available bootloader devices.
|
||||
"""
|
||||
return list(filter(self.is_bootloader, usb.core.find(find_all=True)))
|
||||
|
||||
def find_devices(self):
|
||||
"""Returns a list of available teensy-style consoles.
|
||||
"""
|
||||
hid_devices = hid.enumerate()
|
||||
devices = list(filter(self.is_console_hid, hid_devices))
|
||||
|
||||
if not devices:
|
||||
devices = self.find_devices_by_report(hid_devices)
|
||||
|
||||
if self.vid and self.pid:
|
||||
devices = list(filter(self.is_filtered_device, devices))
|
||||
|
||||
# Add index numbers
|
||||
device_index = {}
|
||||
for device in devices:
|
||||
id = ':'.join((int2hex(device['vendor_id']), int2hex(device['product_id'])))
|
||||
|
||||
if id not in device_index:
|
||||
device_index[id] = 0
|
||||
|
||||
device_index[id] += 1
|
||||
device['index'] = device_index[id]
|
||||
|
||||
return devices
|
||||
|
||||
|
||||
def int2hex(number):
|
||||
"""Returns a string representation of the number as hex.
|
||||
"""
|
||||
return "%04X" % number
|
||||
|
||||
|
||||
def list_devices(device_finder):
|
||||
"""Show the user a nicely formatted list of devices.
|
||||
"""
|
||||
devices = device_finder.find_devices()
|
||||
|
||||
if devices:
|
||||
cli.log.info('Available devices:')
|
||||
for dev in devices:
|
||||
color = LOG_COLOR['colors'][LOG_COLOR['next']]
|
||||
LOG_COLOR['next'] = (LOG_COLOR['next'] + 1) % len(LOG_COLOR['colors'])
|
||||
cli.log.info("\t%s%s:%s:%d{style_reset_all}\t%s %s", color, int2hex(dev['vendor_id']), int2hex(dev['product_id']), dev['index'], dev['manufacturer_string'], dev['product_string'])
|
||||
|
||||
if cli.args.bootloaders:
|
||||
bootloaders = device_finder.find_bootloaders()
|
||||
|
||||
if bootloaders:
|
||||
cli.log.info('Available Bootloaders:')
|
||||
|
||||
for dev in bootloaders:
|
||||
cli.log.info("\t%s:%s\t%s", int2hex(dev.idVendor), int2hex(dev.idProduct), KNOWN_BOOTLOADERS[(int2hex(dev.idVendor), int2hex(dev.idProduct))])
|
||||
|
||||
|
||||
@cli.argument('--bootloaders', arg_only=True, default=True, action='store_boolean', help='displaying bootloaders.')
|
||||
@cli.argument('-d', '--device', help='Device to select - uses format <pid>:<vid>[:<index>].')
|
||||
@cli.argument('-l', '--list', arg_only=True, action='store_true', help='List available hid_listen devices.')
|
||||
@cli.argument('-n', '--numeric', arg_only=True, action='store_true', help='Show VID/PID instead of names.')
|
||||
@cli.argument('-t', '--timestamp', arg_only=True, action='store_true', help='Print the timestamp for received messages as well.')
|
||||
@cli.argument('-w', '--wait', type=int, default=1, help="How many seconds to wait between checks (Default: 1)")
|
||||
@cli.subcommand('Acquire debugging information from usb hid devices.', hidden=False if cli.config.user.developer else True)
|
||||
def console(cli):
|
||||
"""Acquire debugging information from usb hid devices
|
||||
"""
|
||||
vid = None
|
||||
pid = None
|
||||
index = 1
|
||||
|
||||
if cli.config.console.device:
|
||||
device = cli.config.console.device.split(':')
|
||||
|
||||
if len(device) == 2:
|
||||
vid, pid = device
|
||||
|
||||
elif len(device) == 3:
|
||||
vid, pid, index = device
|
||||
|
||||
if not index.isdigit():
|
||||
cli.log.error('Device index must be a number! Got "%s" instead.', index)
|
||||
exit(1)
|
||||
|
||||
index = int(index)
|
||||
|
||||
if index < 1:
|
||||
cli.log.error('Device index must be greater than 0! Got %s', index)
|
||||
exit(1)
|
||||
|
||||
else:
|
||||
cli.log.error('Invalid format for device, expected "<pid>:<vid>[:<index>]" but got "%s".', cli.config.console.device)
|
||||
cli.print_help()
|
||||
exit(1)
|
||||
|
||||
vid = vid.upper()
|
||||
pid = pid.upper()
|
||||
|
||||
device_finder = FindDevices(vid, pid, index, cli.args.numeric)
|
||||
|
||||
if cli.args.list:
|
||||
return list_devices(device_finder)
|
||||
|
||||
print('Looking for devices...', flush=True)
|
||||
device_finder.run_forever()
|
||||
@@ -26,7 +26,6 @@ ESSENTIAL_BINARIES = {
|
||||
'arm-none-eabi-gcc': {
|
||||
'version_arg': '-dumpversion'
|
||||
},
|
||||
'bin/qmk': {},
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -3,15 +3,13 @@
|
||||
You can compile a keymap already in the repo or using a QMK Configurator export.
|
||||
A bootloader must be specified.
|
||||
"""
|
||||
from subprocess import DEVNULL
|
||||
|
||||
from argcomplete.completers import FilesCompleter
|
||||
from milc import cli
|
||||
|
||||
import qmk.path
|
||||
from qmk.decorators import automagic_keyboard, automagic_keymap
|
||||
from qmk.commands import compile_configurator_json, create_make_command, parse_configurator_json
|
||||
from qmk.keyboard import keyboard_completer, keyboard_folder
|
||||
from qmk.commands import do_compile
|
||||
from qmk.keyboard import keyboard_completer, is_keyboard_target
|
||||
|
||||
|
||||
def print_bootloader_help():
|
||||
@@ -36,7 +34,7 @@ def print_bootloader_help():
|
||||
@cli.argument('-b', '--bootloaders', action='store_true', help='List the available bootloaders.')
|
||||
@cli.argument('-bl', '--bootloader', default='flash', help='The flash command, corresponding to qmk\'s make options of bootloaders.')
|
||||
@cli.argument('-km', '--keymap', help='The keymap to build a firmware for. Use this if you dont have a configurator file. Ignored when a configurator file is supplied.')
|
||||
@cli.argument('-kb', '--keyboard', type=keyboard_folder, completer=keyboard_completer, help='The keyboard to build a firmware for. Use this if you dont have a configurator file. Ignored when a configurator file is supplied.')
|
||||
@cli.argument('-kb', '--keyboard', type=is_keyboard_target, completer=keyboard_completer, help='The keyboard to build a firmware for. Use this if you dont have a configurator file. Ignored when a configurator file is supplied.')
|
||||
@cli.argument('-n', '--dry-run', arg_only=True, action='store_true', help="Don't actually build, just show the make command to be run.")
|
||||
@cli.argument('-j', '--parallel', type=int, default=1, help="Set the number of parallel make jobs; 0 means unlimited.")
|
||||
@cli.argument('-e', '--env', arg_only=True, action='append', default=[], help="Set a variable to be passed to make. May be passed multiple times.")
|
||||
@@ -54,55 +52,10 @@ def flash(cli):
|
||||
|
||||
If bootloader is omitted the make system will use the configured bootloader for that keyboard.
|
||||
"""
|
||||
if cli.args.clean and not cli.args.filename and not cli.args.dry_run:
|
||||
command = create_make_command(cli.config.flash.keyboard, cli.config.flash.keymap, 'clean')
|
||||
cli.run(command, capture_output=False, stdin=DEVNULL)
|
||||
|
||||
# Build the environment vars
|
||||
envs = {}
|
||||
for env in cli.args.env:
|
||||
if '=' in env:
|
||||
key, value = env.split('=', 1)
|
||||
envs[key] = value
|
||||
else:
|
||||
cli.log.warning('Invalid environment variable: %s', env)
|
||||
|
||||
# Determine the compile command
|
||||
command = ''
|
||||
|
||||
if cli.args.bootloaders:
|
||||
# Provide usage and list bootloaders
|
||||
cli.echo('usage: qmk flash [-h] [-b] [-n] [-kb KEYBOARD] [-km KEYMAP] [-bl BOOTLOADER] [filename]')
|
||||
cli.print_usage()
|
||||
print_bootloader_help()
|
||||
return False
|
||||
|
||||
if cli.args.filename:
|
||||
# Handle compiling a configurator JSON
|
||||
user_keymap = parse_configurator_json(cli.args.filename)
|
||||
keymap_path = qmk.path.keymap(user_keymap['keyboard'])
|
||||
command = compile_configurator_json(user_keymap, cli.args.bootloader, parallel=cli.config.flash.parallel, **envs)
|
||||
|
||||
cli.log.info('Wrote keymap to {fg_cyan}%s/%s/keymap.c', keymap_path, user_keymap['keymap'])
|
||||
|
||||
else:
|
||||
if cli.config.flash.keyboard and cli.config.flash.keymap:
|
||||
# Generate the make command for a specific keyboard/keymap.
|
||||
command = create_make_command(cli.config.flash.keyboard, cli.config.flash.keymap, cli.args.bootloader, parallel=cli.config.flash.parallel, **envs)
|
||||
|
||||
elif not cli.config.flash.keyboard:
|
||||
cli.log.error('Could not determine keyboard!')
|
||||
elif not cli.config.flash.keymap:
|
||||
cli.log.error('Could not determine keymap!')
|
||||
|
||||
# Compile the firmware, if we're able to
|
||||
if command:
|
||||
cli.log.info('Compiling keymap with {fg_cyan}%s', ' '.join(command))
|
||||
if not cli.args.dry_run:
|
||||
cli.echo('\n')
|
||||
compile = cli.run(command, capture_output=False, stdin=DEVNULL)
|
||||
return compile.returncode
|
||||
|
||||
else:
|
||||
cli.log.error('You must supply a configurator export, both `--keyboard` and `--keymap`, or be in a directory for a keyboard or keymap.')
|
||||
cli.echo('usage: qmk flash [-h] [-b] [-n] [-kb KEYBOARD] [-km KEYMAP] [-bl BOOTLOADER] [filename]')
|
||||
return False
|
||||
return do_compile(cli.config.flash.keyboard, cli.config.flash.keymap, cli.config.flash.parallel, cli.config.flash.bootloader)
|
||||
|
||||
@@ -11,15 +11,15 @@ def format_python(cli):
|
||||
"""Format python code according to QMK's style.
|
||||
"""
|
||||
edit = '--diff' if cli.args.dry_run else '--in-place'
|
||||
yapf_cmd = ['yapf', '-vv', '--recursive', edit, 'bin/qmk', 'lib/python']
|
||||
yapf_cmd = ['yapf', '-vv', '--recursive', edit, 'lib/python']
|
||||
try:
|
||||
cli.run(yapf_cmd, check=True, capture_output=False, stdin=DEVNULL)
|
||||
cli.log.info('Python code in `bin/qmk` and `lib/python` is correctly formatted.')
|
||||
cli.log.info('Python code in `lib/python` is correctly formatted.')
|
||||
return True
|
||||
|
||||
except CalledProcessError:
|
||||
if cli.args.dry_run:
|
||||
cli.log.error('Python code in `bin/qmk` and `lib/python` incorrectly formatted!')
|
||||
cli.log.error('Python code in `lib/python` is incorrectly formatted!')
|
||||
else:
|
||||
cli.log.error('Error formatting python code!')
|
||||
|
||||
|
||||
@@ -1,72 +1,129 @@
|
||||
"""Command to look over a keyboard/keymap and check for common mistakes.
|
||||
"""
|
||||
from pathlib import Path
|
||||
|
||||
from milc import cli
|
||||
|
||||
from qmk.decorators import automagic_keyboard, automagic_keymap
|
||||
from qmk.info import info_json
|
||||
from qmk.keyboard import find_readme, keyboard_completer
|
||||
from qmk.keyboard import keyboard_completer, list_keyboards
|
||||
from qmk.keymap import locate_keymap
|
||||
from qmk.path import is_keyboard, keyboard
|
||||
|
||||
|
||||
@cli.argument('--strict', action='store_true', help='Treat warnings as errors.')
|
||||
@cli.argument('-kb', '--keyboard', completer=keyboard_completer, help='The keyboard to check.')
|
||||
@cli.argument('-km', '--keymap', help='The keymap to check.')
|
||||
def keymap_check(kb, km):
|
||||
"""Perform the keymap level checks.
|
||||
"""
|
||||
ok = True
|
||||
keymap_path = locate_keymap(kb, km)
|
||||
|
||||
if not keymap_path:
|
||||
ok = False
|
||||
cli.log.error("%s: Can't find %s keymap.", kb, km)
|
||||
|
||||
return ok
|
||||
|
||||
|
||||
def rules_mk_assignment_only(keyboard_path):
|
||||
"""Check the keyboard-level rules.mk to ensure it only has assignments.
|
||||
"""
|
||||
current_path = Path()
|
||||
errors = []
|
||||
|
||||
for path_part in keyboard_path.parts:
|
||||
current_path = current_path / path_part
|
||||
rules_mk = current_path / 'rules.mk'
|
||||
|
||||
if rules_mk.exists():
|
||||
continuation = None
|
||||
|
||||
for i, line in enumerate(rules_mk.open()):
|
||||
line = line.strip()
|
||||
|
||||
if '#' in line:
|
||||
line = line[:line.index('#')]
|
||||
|
||||
if continuation:
|
||||
line = continuation + line
|
||||
continuation = None
|
||||
|
||||
if line:
|
||||
if line[-1] == '\\':
|
||||
continuation = line[:-1]
|
||||
continue
|
||||
|
||||
if line and '=' not in line:
|
||||
errors.append(f'Non-assignment code on line +{i} {rules_mk}: {line}')
|
||||
|
||||
return errors
|
||||
|
||||
|
||||
@cli.argument('--strict', action='store_true', help='Treat warnings as errors')
|
||||
@cli.argument('-kb', '--keyboard', completer=keyboard_completer, help='Comma separated list of keyboards to check')
|
||||
@cli.argument('-km', '--keymap', help='The keymap to check')
|
||||
@cli.argument('--all-kb', action='store_true', arg_only=True, help='Check all keyboards')
|
||||
@cli.subcommand('Check keyboard and keymap for common mistakes.')
|
||||
@automagic_keyboard
|
||||
@automagic_keymap
|
||||
def lint(cli):
|
||||
"""Check keyboard and keymap for common mistakes.
|
||||
"""
|
||||
if not cli.config.lint.keyboard:
|
||||
cli.log.error('Missing required argument: --keyboard')
|
||||
failed = []
|
||||
|
||||
# Determine our keyboard list
|
||||
if cli.args.all_kb:
|
||||
if cli.args.keyboard:
|
||||
cli.log.warning('Both --all-kb and --keyboard passed, --all-kb takes presidence.')
|
||||
|
||||
keyboard_list = list_keyboards()
|
||||
elif not cli.config.lint.keyboard:
|
||||
cli.log.error('Missing required arguments: --keyboard or --all-kb')
|
||||
cli.print_help()
|
||||
return False
|
||||
else:
|
||||
keyboard_list = cli.config.lint.keyboard.split(',')
|
||||
|
||||
if not is_keyboard(cli.config.lint.keyboard):
|
||||
cli.log.error('No such keyboard: %s', cli.config.lint.keyboard)
|
||||
return False
|
||||
# Lint each keyboard
|
||||
for kb in keyboard_list:
|
||||
if not is_keyboard(kb):
|
||||
cli.log.error('No such keyboard: %s', kb)
|
||||
continue
|
||||
|
||||
# Gather data about the keyboard.
|
||||
ok = True
|
||||
keyboard_path = keyboard(cli.config.lint.keyboard)
|
||||
keyboard_info = info_json(cli.config.lint.keyboard)
|
||||
readme_path = find_readme(cli.config.lint.keyboard)
|
||||
missing_readme_path = keyboard_path / 'readme.md'
|
||||
# Gather data about the keyboard.
|
||||
ok = True
|
||||
keyboard_path = keyboard(kb)
|
||||
keyboard_info = info_json(kb)
|
||||
|
||||
# Check for errors in the info.json
|
||||
if keyboard_info['parse_errors']:
|
||||
ok = False
|
||||
cli.log.error('Errors found when generating info.json.')
|
||||
|
||||
if cli.config.lint.strict and keyboard_info['parse_warnings']:
|
||||
ok = False
|
||||
cli.log.error('Warnings found when generating info.json (Strict mode enabled.)')
|
||||
|
||||
# Check for a readme.md and warn if it doesn't exist
|
||||
if not readme_path:
|
||||
ok = False
|
||||
cli.log.error('Missing %s', missing_readme_path)
|
||||
|
||||
# Keymap specific checks
|
||||
if cli.config.lint.keymap:
|
||||
keymap_path = locate_keymap(cli.config.lint.keyboard, cli.config.lint.keymap)
|
||||
|
||||
if not keymap_path:
|
||||
# Check for errors in the info.json
|
||||
if keyboard_info['parse_errors']:
|
||||
ok = False
|
||||
cli.log.error("Can't find %s keymap for %s keyboard.", cli.config.lint.keymap, cli.config.lint.keyboard)
|
||||
else:
|
||||
keymap_readme = keymap_path.parent / 'readme.md'
|
||||
if not keymap_readme.exists():
|
||||
cli.log.warning('Missing %s', keymap_readme)
|
||||
cli.log.error('%s: Errors found when generating info.json.', kb)
|
||||
|
||||
if cli.config.lint.strict:
|
||||
ok = False
|
||||
if cli.config.lint.strict and keyboard_info['parse_warnings']:
|
||||
ok = False
|
||||
cli.log.error('%s: Warnings found when generating info.json (Strict mode enabled.)', kb)
|
||||
|
||||
# Check the rules.mk file(s)
|
||||
rules_mk_assignment_errors = rules_mk_assignment_only(keyboard_path)
|
||||
if rules_mk_assignment_errors:
|
||||
ok = False
|
||||
cli.log.error('%s: Non-assignment code found in rules.mk. Move it to post_rules.mk instead.', kb)
|
||||
for assignment_error in rules_mk_assignment_errors:
|
||||
cli.log.error(assignment_error)
|
||||
|
||||
# Keymap specific checks
|
||||
if cli.config.lint.keymap:
|
||||
if not keymap_check(kb, cli.config.lint.keymap):
|
||||
ok = False
|
||||
|
||||
# Report status
|
||||
if not ok:
|
||||
failed.append(kb)
|
||||
|
||||
# Check and report the overall status
|
||||
if ok:
|
||||
cli.log.info('Lint check passed!')
|
||||
return True
|
||||
if failed:
|
||||
cli.log.error('Lint check failed for: %s', ', '.join(failed))
|
||||
return False
|
||||
|
||||
cli.log.error('Lint check failed!')
|
||||
return False
|
||||
cli.log.info('Lint check passed!')
|
||||
return True
|
||||
|
||||
@@ -12,6 +12,6 @@ def pytest(cli):
|
||||
"""Run several linting/testing commands.
|
||||
"""
|
||||
nose2 = cli.run(['nose2', '-v'], capture_output=False, stdin=DEVNULL)
|
||||
flake8 = cli.run(['flake8', 'lib/python', 'bin/qmk'], capture_output=False, stdin=DEVNULL)
|
||||
flake8 = cli.run(['flake8', 'lib/python'], capture_output=False, stdin=DEVNULL)
|
||||
|
||||
return flake8.returncode | nose2.returncode
|
||||
|
||||
@@ -1,22 +1,28 @@
|
||||
"""Helper functions for commands.
|
||||
"""
|
||||
from functools import lru_cache
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import shutil
|
||||
import threading
|
||||
from pathlib import Path
|
||||
from subprocess import DEVNULL
|
||||
from time import strftime
|
||||
from time import sleep, strftime
|
||||
|
||||
from dotty_dict import dotty
|
||||
from milc import cli
|
||||
|
||||
import qmk.keymap
|
||||
from qmk.constants import QMK_FIRMWARE, KEYBOARD_OUTPUT_PREFIX
|
||||
from qmk.info import info_json
|
||||
from qmk.json_schema import json_load
|
||||
from qmk.keyboard import list_keyboards
|
||||
|
||||
time_fmt = '%Y-%m-%d-%H:%M:%S'
|
||||
|
||||
|
||||
@lru_cache(maxsize=0)
|
||||
def _find_make():
|
||||
"""Returns the correct make command for this environment.
|
||||
"""
|
||||
@@ -55,7 +61,7 @@ def create_make_target(target, parallel=1, **env_vars):
|
||||
return [make_cmd, *get_make_parallel_args(parallel), *env, target]
|
||||
|
||||
|
||||
def create_make_command(keyboard, keymap, target=None, parallel=1, **env_vars):
|
||||
def create_make_command(keyboard, keymap, target=None, parallel=1, silent=False, **env_vars):
|
||||
"""Create a make compile command
|
||||
|
||||
Args:
|
||||
@@ -79,14 +85,29 @@ def create_make_command(keyboard, keymap, target=None, parallel=1, **env_vars):
|
||||
|
||||
A command that can be run to make the specified keyboard and keymap
|
||||
"""
|
||||
make_args = [keyboard, keymap]
|
||||
make_cmd = [_find_make(), '--no-print-directory', '-r', '-R', '-C', './', '-f', 'build_keyboard.mk']
|
||||
|
||||
env_vars['KEYBOARD'] = keyboard
|
||||
env_vars['KEYMAP'] = keymap
|
||||
env_vars['QMK_BIN'] = 'bin/qmk' if 'DEPRECATED_BIN_QMK' in os.environ else 'qmk'
|
||||
env_vars['VERBOSE'] = 'true' if cli.config.general.verbose else ''
|
||||
env_vars['SILENT'] = 'true' if silent else 'false'
|
||||
env_vars['COLOR'] = 'true' if cli.config.general.color else ''
|
||||
|
||||
if parallel > 1:
|
||||
make_cmd.append('-j')
|
||||
make_cmd.append(str(parallel))
|
||||
|
||||
if target:
|
||||
make_args.append(target)
|
||||
make_cmd.append(target)
|
||||
|
||||
return create_make_target(':'.join(make_args), parallel, **env_vars)
|
||||
for key, value in env_vars.items():
|
||||
make_cmd.append(f'{key}={value}')
|
||||
|
||||
return make_cmd
|
||||
|
||||
|
||||
@lru_cache(maxsize=0)
|
||||
def get_git_version(current_time, repo_dir='.', check_dir='.'):
|
||||
"""Returns the current git version for a repo, or the current time.
|
||||
"""
|
||||
@@ -233,12 +254,13 @@ def compile_configurator_json(user_keymap, bootloader=None, parallel=1, **env_va
|
||||
f'VERBOSE={verbose}',
|
||||
f'COLOR={color}',
|
||||
'SILENT=false',
|
||||
f'QMK_BIN={"bin/qmk" if "DEPRECATED_BIN_QMK" in os.environ else "qmk"}',
|
||||
'QMK_BIN="qmk"',
|
||||
])
|
||||
|
||||
return make_command
|
||||
return user_keymap['keyboard'], user_keymap['keymap'], make_command
|
||||
|
||||
|
||||
@lru_cache(maxsize=0)
|
||||
def parse_configurator_json(configurator_file):
|
||||
"""Open and parse a configurator json export
|
||||
"""
|
||||
@@ -332,3 +354,165 @@ def in_virtualenv():
|
||||
"""
|
||||
active_prefix = getattr(sys, "base_prefix", None) or getattr(sys, "real_prefix", None) or sys.prefix
|
||||
return active_prefix != sys.prefix
|
||||
|
||||
|
||||
def do_compile(keyboard, keymap, parallel, target=None, filters=None, environment=None):
|
||||
"""Shared code between `qmk compile` and `qmk flash`.
|
||||
"""
|
||||
if keyboard is None:
|
||||
keyboard = ''
|
||||
|
||||
if environment is None:
|
||||
environment = {}
|
||||
|
||||
all_keyboards = keyboard == 'all' or keyboard.startswith('all-')
|
||||
all_keymaps = keymap == 'all'
|
||||
multiple_compiles = all_keyboards or all_keymaps
|
||||
|
||||
# Setup the environment
|
||||
envs = {'REQUIRE_PLATFORM_KEY': ''}
|
||||
|
||||
for env in environment:
|
||||
if '=' in env:
|
||||
key, value = env.split('=', 1)
|
||||
if key in envs:
|
||||
cli.log.warning('Overwriting existing environment variable %s=%s with %s=%s!', key, envs[key], key, value)
|
||||
envs[key] = value
|
||||
else:
|
||||
cli.log.warning('Invalid environment variable: %s', env)
|
||||
|
||||
if keyboard.startswith('all-'):
|
||||
envs['REQUIRE_PLATFORM_KEY'] = keyboard[4:]
|
||||
|
||||
# Run clean if necessary
|
||||
if cli.args.clean and not cli.args.filename and not cli.args.dry_run:
|
||||
for kb, km in keyboard_keymap_iter(keyboard, keymap, {}):
|
||||
cli.log.info('Cleaning previous build files for keyboard {fg_cyan}%s{fg_reset} keymap {fg_cyan}%s', kb, km)
|
||||
make_cmd = create_make_command(kb, km, 'clean', 1, multiple_compiles, **envs)
|
||||
cli.run(make_cmd, capture_output=False, stdin=DEVNULL)
|
||||
|
||||
# Determine the compile command(s)
|
||||
command = None
|
||||
|
||||
if cli.args.filename:
|
||||
if cli.args.keyboard:
|
||||
cli.log.warning('Ignoring --keyboard because a keymap.json was provided.')
|
||||
|
||||
if cli.args.keymap:
|
||||
cli.log.warning('Ignoring --keymap because a keymap.json was provided.')
|
||||
|
||||
# If a configurator JSON was provided generate a keymap and compile it
|
||||
user_keymap = parse_configurator_json(cli.args.filename)
|
||||
command = compile_configurator_json(user_keymap, parallel=parallel, **envs)
|
||||
|
||||
elif keyboard and keymap:
|
||||
if multiple_compiles:
|
||||
command = 'multiple'
|
||||
else:
|
||||
command = create_make_command(keyboard, keymap, target=target, parallel=parallel, silent=multiple_compiles, **envs)
|
||||
|
||||
elif not keyboard:
|
||||
cli.log.error('Could not determine keyboard!')
|
||||
|
||||
elif not keymap:
|
||||
cli.log.error('Could not determine keymap!')
|
||||
|
||||
# Compile the firmware, if we're able to
|
||||
if command == 'multiple':
|
||||
cli.log.info('Building {fg_cyan}%s{fg_reset} with keymap {fg_cyan}%s', keyboard, keymap)
|
||||
|
||||
returncodes = []
|
||||
for keyboard, keymap in keyboard_keymap_iter(keyboard, keymap, filters):
|
||||
command = create_make_command(keyboard, keymap, target=target, parallel=1, silent=multiple_compiles, **envs)
|
||||
while threading.active_count() >= parallel + 1:
|
||||
sleep(1)
|
||||
threading.Thread(target=_execute_compile, args=(keyboard, keymap, command, target, returncodes)).start()
|
||||
|
||||
while threading.active_count() > 1:
|
||||
sleep(1)
|
||||
|
||||
if any(returncodes):
|
||||
print()
|
||||
cli.log.error('Could not compile all targets, look above this message for more details. Failing target(s):')
|
||||
|
||||
for i, returncode in enumerate(returncodes):
|
||||
if returncode != 0:
|
||||
keyboard, keymap, command = returncodes[i]
|
||||
cli.echo('\tkeyboard: {fg_cyan}%s{fg_reset} keymap: {fg_cyan}%s', keyboard, keymap)
|
||||
|
||||
elif command:
|
||||
if target:
|
||||
cli.log.info('Building {fg_cyan}%s{fg_reset} with keymap {fg_cyan}%s{fg_reset} and target {fg_cyan}%s', keyboard, keymap, target)
|
||||
else:
|
||||
cli.log.info('Building {fg_cyan}%s{fg_reset} with keymap {fg_cyan}%s', keyboard, keymap)
|
||||
|
||||
if _execute_compile(keyboard, keymap, command, target) != 0:
|
||||
print()
|
||||
cli.log.error('Could not compile all targets, look above this message for more details. Failing target(s):')
|
||||
cli.echo('\tkeyboard: {fg_cyan}%s{fg_reset} keymap: {fg_cyan}%s', keyboard, keymap)
|
||||
|
||||
elif filters:
|
||||
cli.log.error('No keyboards found after applying filter(s)!')
|
||||
return False
|
||||
|
||||
else:
|
||||
cli.log.error('You must supply a configurator export, both `--keyboard` and `--keymap`, or be in a directory for a keyboard or keymap.')
|
||||
cli.print_help()
|
||||
return False
|
||||
|
||||
|
||||
def _execute_compile(keyboard, keymap, command, target, returncodes=None):
|
||||
if not returncodes:
|
||||
returncodes = []
|
||||
|
||||
if keymap not in qmk.keymap.list_keymaps(keyboard):
|
||||
cli.log.debug('Skipping keyboard %s, no %s keymap found.', keyboard, keymap)
|
||||
return 0
|
||||
|
||||
cli.log.debug('Running make command: {fg_blue}%s', ' '.join(command))
|
||||
|
||||
if not cli.args.dry_run:
|
||||
compile = cli.run(command, combined_output=True)
|
||||
|
||||
cli.acquire_lock()
|
||||
returncodes.append(compile.returncode)
|
||||
cli.release_lock()
|
||||
|
||||
if compile.returncode != 0:
|
||||
cli.log.info('Could not build firmware for {fg_cyan}%s{fg_reset} with keymap {fg_cyan}%s', keyboard, keymap)
|
||||
print(compile.stdout)
|
||||
|
||||
|
||||
@lru_cache()
|
||||
def _keyboard_list(keyboard):
|
||||
"""Returns a list of keyboards matching keyboard.
|
||||
"""
|
||||
if keyboard == 'all' or keyboard.startswith('all-'):
|
||||
return list_keyboards()
|
||||
|
||||
return [keyboard]
|
||||
|
||||
|
||||
def keyboard_keymap_iter(cli_keyboard, cli_keymap, filters):
|
||||
"""Iterates over the keyboard/keymap for this command and yields a pairing of each.
|
||||
"""
|
||||
for keyboard in _keyboard_list(cli_keyboard):
|
||||
continue_flag = False
|
||||
|
||||
if filters:
|
||||
info_data = dotty(info_json(keyboard))
|
||||
|
||||
for key, value in filters.items():
|
||||
if info_data.get(key) != value:
|
||||
continue_flag = True
|
||||
break
|
||||
|
||||
if continue_flag:
|
||||
continue
|
||||
|
||||
if cli_keymap == 'all':
|
||||
for keymap in qmk.keymap.list_keymaps(keyboard):
|
||||
yield keyboard, keymap
|
||||
|
||||
else:
|
||||
yield keyboard, cli_keymap
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
Gratefully adapted from https://stackoverflow.com/a/241506
|
||||
"""
|
||||
import re
|
||||
from functools import lru_cache
|
||||
|
||||
comment_pattern = re.compile(r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"', re.DOTALL | re.MULTILINE)
|
||||
|
||||
@@ -14,6 +15,7 @@ def _comment_stripper(match):
|
||||
return ' ' if s.startswith('/') else s
|
||||
|
||||
|
||||
@lru_cache(maxsize=0)
|
||||
def comment_remover(text):
|
||||
"""Remove C/C++ style comments from text.
|
||||
"""
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
"""Functions to convert to and from QMK formats
|
||||
"""
|
||||
from collections import OrderedDict
|
||||
from functools import lru_cache
|
||||
|
||||
|
||||
@lru_cache(maxsize=0)
|
||||
def kle2qmk(kle):
|
||||
"""Convert a KLE layout to QMK's layout format.
|
||||
"""
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
"""Functions that help us generate and use info.json files.
|
||||
"""
|
||||
from functools import lru_cache
|
||||
from glob import glob
|
||||
from pathlib import Path
|
||||
|
||||
@@ -12,37 +13,22 @@ from qmk.c_parse import find_layouts
|
||||
from qmk.json_schema import deep_update, json_load, validate
|
||||
from qmk.keyboard import config_h, rules_mk
|
||||
from qmk.keymap import list_keymaps
|
||||
from qmk.makefile import parse_rules_mk_file
|
||||
from qmk.math import compute
|
||||
|
||||
true_values = ['1', 'on', 'yes']
|
||||
false_values = ['0', 'off', 'no']
|
||||
from qmk.metadata import basic_info_json, info_log_error, info_log_warning, true_values, false_values
|
||||
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def _valid_community_layout(layout):
|
||||
"""Validate that a declared community list exists
|
||||
"""
|
||||
return (Path('layouts/default') / layout).exists()
|
||||
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def info_json(keyboard):
|
||||
"""Generate the info.json data for a specific keyboard.
|
||||
"""
|
||||
cur_dir = Path('keyboards')
|
||||
rules = parse_rules_mk_file(cur_dir / keyboard / 'rules.mk')
|
||||
if 'DEFAULT_FOLDER' in rules:
|
||||
keyboard = rules['DEFAULT_FOLDER']
|
||||
rules = parse_rules_mk_file(cur_dir / keyboard / 'rules.mk', rules)
|
||||
|
||||
info_data = {
|
||||
'keyboard_name': str(keyboard),
|
||||
'keyboard_folder': str(keyboard),
|
||||
'keymaps': {},
|
||||
'layouts': {},
|
||||
'parse_errors': [],
|
||||
'parse_warnings': [],
|
||||
'maintainer': 'qmk',
|
||||
}
|
||||
info_data = basic_info_json(keyboard)
|
||||
|
||||
# Populate the list of JSON keymaps
|
||||
for keymap in list_keymaps(keyboard, c=False, fullpath=True):
|
||||
@@ -81,20 +67,20 @@ def info_json(keyboard):
|
||||
_find_missing_layouts(info_data, keyboard)
|
||||
|
||||
if not info_data.get('layouts'):
|
||||
_log_error(info_data, 'No LAYOUTs defined! Need at least one layout defined in the keyboard.h or info.json.')
|
||||
info_log_error(info_data, 'No LAYOUTs defined! Need at least one layout defined in the keyboard.h or info.json.')
|
||||
|
||||
# Filter out any non-existing community layouts
|
||||
for layout in info_data.get('community_layouts', []):
|
||||
if not _valid_community_layout(layout):
|
||||
# Ignore layout from future checks
|
||||
info_data['community_layouts'].remove(layout)
|
||||
_log_error(info_data, 'Claims to support a community layout that does not exist: %s' % (layout))
|
||||
info_log_error(info_data, 'Claims to support a community layout that does not exist: %s' % (layout))
|
||||
|
||||
# Make sure we supply layout macros for the community layouts we claim to support
|
||||
for layout in info_data.get('community_layouts', []):
|
||||
layout_name = 'LAYOUT_' + layout
|
||||
if layout_name not in info_data.get('layouts', {}) and layout_name not in info_data.get('layout_aliases', {}):
|
||||
_log_error(info_data, 'Claims to support community layout %s but no %s() macro found' % (layout, layout_name))
|
||||
info_log_error(info_data, 'Claims to support community layout %s but no %s() macro found' % (layout, layout_name))
|
||||
|
||||
# Check that the reported matrix size is consistent with the actual matrix size
|
||||
_check_matrix(info_data)
|
||||
@@ -130,7 +116,7 @@ def _extract_features(info_data, rules):
|
||||
info_data['features'] = {}
|
||||
|
||||
if key in info_data['features']:
|
||||
_log_warning(info_data, 'Feature %s is specified in both info.json and rules.mk, the rules.mk value wins.' % (key,))
|
||||
info_log_warning(info_data, 'Feature %s is specified in both info.json and rules.mk, the rules.mk value wins.' % (key,))
|
||||
|
||||
info_data['features'][key] = value
|
||||
info_data['config_h_features'][key] = value
|
||||
@@ -209,7 +195,7 @@ def _extract_split_main(info_data, config_c):
|
||||
info_data['split'] = {}
|
||||
|
||||
if 'main' in info_data['split']:
|
||||
_log_warning(info_data, 'Split main hand is specified in both config.h (SPLIT_HAND_PIN) and info.json (split.main) (Value: %s), the config.h value wins.' % info_data['split']['main'])
|
||||
info_log_warning(info_data, 'Split main hand is specified in both config.h (SPLIT_HAND_PIN) and info.json (split.main) (Value: %s), the config.h value wins.' % info_data['split']['main'])
|
||||
|
||||
info_data['split']['main'] = 'pin'
|
||||
|
||||
@@ -218,7 +204,7 @@ def _extract_split_main(info_data, config_c):
|
||||
info_data['split'] = {}
|
||||
|
||||
if 'main' in info_data['split']:
|
||||
_log_warning(info_data, 'Split main hand is specified in both config.h (SPLIT_HAND_MATRIX_GRID) and info.json (split.main) (Value: %s), the config.h value wins.' % info_data['split']['main'])
|
||||
info_log_warning(info_data, 'Split main hand is specified in both config.h (SPLIT_HAND_MATRIX_GRID) and info.json (split.main) (Value: %s), the config.h value wins.' % info_data['split']['main'])
|
||||
|
||||
info_data['split']['main'] = 'matrix_grid'
|
||||
info_data['split']['matrix_grid'] = _extract_pins(config_c['SPLIT_HAND_MATRIX_GRID'])
|
||||
@@ -228,7 +214,7 @@ def _extract_split_main(info_data, config_c):
|
||||
info_data['split'] = {}
|
||||
|
||||
if 'main' in info_data['split']:
|
||||
_log_warning(info_data, 'Split main hand is specified in both config.h (EE_HANDS) and info.json (split.main) (Value: %s), the config.h value wins.' % info_data['split']['main'])
|
||||
info_log_warning(info_data, 'Split main hand is specified in both config.h (EE_HANDS) and info.json (split.main) (Value: %s), the config.h value wins.' % info_data['split']['main'])
|
||||
|
||||
info_data['split']['main'] = 'eeprom'
|
||||
|
||||
@@ -237,7 +223,7 @@ def _extract_split_main(info_data, config_c):
|
||||
info_data['split'] = {}
|
||||
|
||||
if 'main' in info_data['split']:
|
||||
_log_warning(info_data, 'Split main hand is specified in both config.h (MASTER_RIGHT) and info.json (split.main) (Value: %s), the config.h value wins.' % info_data['split']['main'])
|
||||
info_log_warning(info_data, 'Split main hand is specified in both config.h (MASTER_RIGHT) and info.json (split.main) (Value: %s), the config.h value wins.' % info_data['split']['main'])
|
||||
|
||||
info_data['split']['main'] = 'right'
|
||||
|
||||
@@ -246,7 +232,7 @@ def _extract_split_main(info_data, config_c):
|
||||
info_data['split'] = {}
|
||||
|
||||
if 'main' in info_data['split']:
|
||||
_log_warning(info_data, 'Split main hand is specified in both config.h (MASTER_LEFT) and info.json (split.main) (Value: %s), the config.h value wins.' % info_data['split']['main'])
|
||||
info_log_warning(info_data, 'Split main hand is specified in both config.h (MASTER_LEFT) and info.json (split.main) (Value: %s), the config.h value wins.' % info_data['split']['main'])
|
||||
|
||||
info_data['split']['main'] = 'left'
|
||||
|
||||
@@ -261,7 +247,7 @@ def _extract_split_transport(info_data, config_c):
|
||||
info_data['split']['transport'] = {}
|
||||
|
||||
if 'protocol' in info_data['split']['transport']:
|
||||
_log_warning(info_data, 'Split transport is specified in both config.h (USE_I2C) and info.json (split.transport.protocol) (Value: %s), the config.h value wins.' % info_data['split']['transport'])
|
||||
info_log_warning(info_data, 'Split transport is specified in both config.h (USE_I2C) and info.json (split.transport.protocol) (Value: %s), the config.h value wins.' % info_data['split']['transport'])
|
||||
|
||||
info_data['split']['transport']['protocol'] = 'i2c'
|
||||
|
||||
@@ -285,7 +271,7 @@ def _extract_split_right_pins(info_data, config_c):
|
||||
|
||||
if row_pins and col_pins:
|
||||
if info_data.get('split', {}).get('matrix_pins', {}).get('right') in info_data:
|
||||
_log_warning(info_data, 'Right hand matrix data is specified in both info.json and config.h, the config.h values win.')
|
||||
info_log_warning(info_data, 'Right hand matrix data is specified in both info.json and config.h, the config.h values win.')
|
||||
|
||||
if 'split' not in info_data:
|
||||
info_data['split'] = {}
|
||||
@@ -303,7 +289,7 @@ def _extract_split_right_pins(info_data, config_c):
|
||||
|
||||
if direct_pins:
|
||||
if info_data.get('split', {}).get('matrix_pins', {}).get('right', {}):
|
||||
_log_warning(info_data, 'Right hand matrix data is specified in both info.json and config.h, the config.h values win.')
|
||||
info_log_warning(info_data, 'Right hand matrix data is specified in both info.json and config.h, the config.h values win.')
|
||||
|
||||
if 'split' not in info_data:
|
||||
info_data['split'] = {}
|
||||
@@ -341,7 +327,7 @@ def _extract_matrix_info(info_data, config_c):
|
||||
|
||||
if 'MATRIX_ROWS' in config_c and 'MATRIX_COLS' in config_c:
|
||||
if 'matrix_size' in info_data:
|
||||
_log_warning(info_data, 'Matrix size is specified in both info.json and config.h, the config.h values win.')
|
||||
info_log_warning(info_data, 'Matrix size is specified in both info.json and config.h, the config.h values win.')
|
||||
|
||||
info_data['matrix_size'] = {
|
||||
'cols': compute(config_c.get('MATRIX_COLS', '0')),
|
||||
@@ -350,14 +336,14 @@ def _extract_matrix_info(info_data, config_c):
|
||||
|
||||
if row_pins and col_pins:
|
||||
if 'matrix_pins' in info_data and 'cols' in info_data['matrix_pins'] and 'rows' in info_data['matrix_pins']:
|
||||
_log_warning(info_data, 'Matrix pins are specified in both info.json and config.h, the config.h values win.')
|
||||
info_log_warning(info_data, 'Matrix pins are specified in both info.json and config.h, the config.h values win.')
|
||||
|
||||
info_snippet['cols'] = _extract_pins(col_pins)
|
||||
info_snippet['rows'] = _extract_pins(row_pins)
|
||||
|
||||
if direct_pins:
|
||||
if 'matrix_pins' in info_data and 'direct' in info_data['matrix_pins']:
|
||||
_log_warning(info_data, 'Direct pins are specified in both info.json and config.h, the config.h values win.')
|
||||
info_log_warning(info_data, 'Direct pins are specified in both info.json and config.h, the config.h values win.')
|
||||
|
||||
info_snippet['direct'] = _extract_direct_matrix(direct_pins)
|
||||
|
||||
@@ -369,7 +355,7 @@ def _extract_matrix_info(info_data, config_c):
|
||||
|
||||
if config_c.get('CUSTOM_MATRIX', 'no') != 'no':
|
||||
if 'matrix_pins' in info_data and 'custom' in info_data['matrix_pins']:
|
||||
_log_warning(info_data, 'Custom Matrix is specified in both info.json and config.h, the config.h values win.')
|
||||
info_log_warning(info_data, 'Custom Matrix is specified in both info.json and config.h, the config.h values win.')
|
||||
|
||||
info_snippet['custom'] = True
|
||||
|
||||
@@ -398,7 +384,7 @@ def _extract_config_h(info_data):
|
||||
try:
|
||||
if config_key in config_c and info_dict.get('to_json', True):
|
||||
if dotty_info.get(info_key) and info_dict.get('warn_duplicate', True):
|
||||
_log_warning(info_data, '%s in config.h is overwriting %s in info.json' % (config_key, info_key))
|
||||
info_log_warning(info_data, '%s in config.h is overwriting %s in info.json' % (config_key, info_key))
|
||||
|
||||
if key_type.startswith('array'):
|
||||
if '.' in key_type:
|
||||
@@ -429,7 +415,7 @@ def _extract_config_h(info_data):
|
||||
dotty_info[info_key] = config_c[config_key]
|
||||
|
||||
except Exception as e:
|
||||
_log_warning(info_data, f'{config_key}->{info_key}: {e}')
|
||||
info_log_warning(info_data, f'{config_key}->{info_key}: {e}')
|
||||
|
||||
info_data.update(dotty_info)
|
||||
|
||||
@@ -470,7 +456,7 @@ def _extract_rules_mk(info_data):
|
||||
try:
|
||||
if rules_key in rules and info_dict.get('to_json', True):
|
||||
if dotty_info.get(info_key) and info_dict.get('warn_duplicate', True):
|
||||
_log_warning(info_data, '%s in rules.mk is overwriting %s in info.json' % (rules_key, info_key))
|
||||
info_log_warning(info_data, '%s in rules.mk is overwriting %s in info.json' % (rules_key, info_key))
|
||||
|
||||
if key_type.startswith('array'):
|
||||
if '.' in key_type:
|
||||
@@ -501,7 +487,7 @@ def _extract_rules_mk(info_data):
|
||||
dotty_info[info_key] = rules[rules_key]
|
||||
|
||||
except Exception as e:
|
||||
_log_warning(info_data, f'{rules_key}->{info_key}: {e}')
|
||||
info_log_warning(info_data, f'{rules_key}->{info_key}: {e}')
|
||||
|
||||
info_data.update(dotty_info)
|
||||
|
||||
@@ -544,11 +530,11 @@ def _check_matrix(info_data):
|
||||
|
||||
if col_count != actual_col_count and col_count != (actual_col_count / 2):
|
||||
# FIXME: once we can we should detect if split is enabled to do the actual_col_count/2 check.
|
||||
_log_error(info_data, f'MATRIX_COLS is inconsistent with the size of MATRIX_COL_PINS: {col_count} != {actual_col_count}')
|
||||
info_log_error(info_data, f'MATRIX_COLS is inconsistent with the size of MATRIX_COL_PINS: {col_count} != {actual_col_count}')
|
||||
|
||||
if row_count != actual_row_count and row_count != (actual_row_count / 2):
|
||||
# FIXME: once we can we should detect if split is enabled to do the actual_row_count/2 check.
|
||||
_log_error(info_data, f'MATRIX_ROWS is inconsistent with the size of MATRIX_ROW_PINS: {row_count} != {actual_row_count}')
|
||||
info_log_error(info_data, f'MATRIX_ROWS is inconsistent with the size of MATRIX_ROW_PINS: {row_count} != {actual_row_count}')
|
||||
|
||||
|
||||
def _search_keyboard_h(keyboard):
|
||||
@@ -577,7 +563,7 @@ def _find_missing_layouts(info_data, keyboard):
|
||||
|
||||
If we don't find any layouts from info.json or keyboard.h we widen our search. This is error prone which is why we want to encourage people to follow the standard above.
|
||||
"""
|
||||
_log_warning(info_data, '%s: Falling back to searching for KEYMAP/LAYOUT macros.' % (keyboard))
|
||||
info_log_warning(info_data, '%s: Falling back to searching for KEYMAP/LAYOUT macros.' % (keyboard))
|
||||
|
||||
for file in glob('keyboards/%s/*.h' % keyboard):
|
||||
these_layouts, these_aliases = find_layouts(file)
|
||||
@@ -596,20 +582,6 @@ def _find_missing_layouts(info_data, keyboard):
|
||||
info_data['layout_aliases'][alias] = alias_text
|
||||
|
||||
|
||||
def _log_error(info_data, message):
|
||||
"""Send an error message to both JSON and the log.
|
||||
"""
|
||||
info_data['parse_errors'].append(message)
|
||||
cli.log.error('%s: %s', info_data.get('keyboard_folder', 'Unknown Keyboard!'), message)
|
||||
|
||||
|
||||
def _log_warning(info_data, message):
|
||||
"""Send a warning message to both JSON and the log.
|
||||
"""
|
||||
info_data['parse_warnings'].append(message)
|
||||
cli.log.warning('%s: %s', info_data.get('keyboard_folder', 'Unknown Keyboard!'), message)
|
||||
|
||||
|
||||
def arm_processor_rules(info_data, rules):
|
||||
"""Setup the default info for an ARM board.
|
||||
"""
|
||||
@@ -668,7 +640,7 @@ def merge_info_jsons(keyboard, info_data):
|
||||
new_info_data = json_load(info_file)
|
||||
|
||||
if not isinstance(new_info_data, dict):
|
||||
_log_error(info_data, "Invalid file %s, root object should be a dictionary." % (str(info_file),))
|
||||
info_log_error(info_data, "Invalid file %s, root object should be a dictionary." % (str(info_file),))
|
||||
continue
|
||||
|
||||
try:
|
||||
@@ -686,13 +658,13 @@ def merge_info_jsons(keyboard, info_data):
|
||||
|
||||
for layout_name, layout in new_info_data.get('layouts', {}).items():
|
||||
if layout_name in info_data.get('layout_aliases', {}):
|
||||
_log_warning(info_data, f"info.json uses alias name {layout_name} instead of {info_data['layout_aliases'][layout_name]}")
|
||||
info_log_warning(info_data, f"info.json uses alias name {layout_name} instead of {info_data['layout_aliases'][layout_name]}")
|
||||
layout_name = info_data['layout_aliases'][layout_name]
|
||||
|
||||
if layout_name in info_data['layouts']:
|
||||
if len(info_data['layouts'][layout_name]['layout']) != len(layout['layout']):
|
||||
msg = '%s: %s: Number of elements in info.json does not match! info.json:%s != %s:%s'
|
||||
_log_error(info_data, msg % (info_data['keyboard_folder'], layout_name, len(layout['layout']), layout_name, len(info_data['layouts'][layout_name]['layout'])))
|
||||
info_log_error(info_data, msg % (info_data['keyboard_folder'], layout_name, len(layout['layout']), layout_name, len(info_data['layouts'][layout_name]['layout'])))
|
||||
else:
|
||||
for new_key, existing_key in zip(layout['layout'], info_data['layouts'][layout_name]['layout']):
|
||||
existing_key.update(new_key)
|
||||
@@ -720,15 +692,18 @@ def find_info_json(keyboard):
|
||||
|
||||
# Add DEFAULT_FOLDER before parents, if present
|
||||
rules = rules_mk(keyboard)
|
||||
|
||||
if 'DEFAULT_FOLDER' in rules:
|
||||
info_jsons.append(Path(rules['DEFAULT_FOLDER']) / 'info.json')
|
||||
|
||||
# Add in parent folders for least specific
|
||||
for _ in range(5):
|
||||
info_jsons.append(keyboard_parent / 'info.json')
|
||||
this_info_json = keyboard_parent / 'info.json'
|
||||
|
||||
if this_info_json.exists():
|
||||
yield this_info_json
|
||||
|
||||
if keyboard_parent.parent == base_path:
|
||||
break
|
||||
keyboard_parent = keyboard_parent.parent
|
||||
|
||||
# Return a list of the info.json files that actually exist
|
||||
return [info_json for info_json in info_jsons if info_json.exists()]
|
||||
keyboard_parent = keyboard_parent.parent
|
||||
|
||||
@@ -10,6 +10,7 @@ import jsonschema
|
||||
from milc import cli
|
||||
|
||||
|
||||
@lru_cache(maxsize=0)
|
||||
def json_load(json_file):
|
||||
"""Load a json file from disk.
|
||||
|
||||
@@ -23,6 +24,8 @@ def json_load(json_file):
|
||||
exit(1)
|
||||
except Exception as e:
|
||||
cli.log.error('Unknown error attempting to load {fg_cyan}%s{fg_reset}:\n\t{fg_red}%s', json_file, e)
|
||||
if cli.args.verbose:
|
||||
cli.log.exception(e)
|
||||
exit(1)
|
||||
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
"""Functions that help us work with keyboards.
|
||||
"""
|
||||
import os
|
||||
from array import array
|
||||
from functools import lru_cache
|
||||
from glob import glob
|
||||
from math import ceil
|
||||
from pathlib import Path
|
||||
import os
|
||||
from glob import glob
|
||||
|
||||
import qmk.path
|
||||
from qmk.c_parse import parse_config_h_file
|
||||
@@ -64,6 +65,17 @@ def find_readme(keyboard):
|
||||
return cur_dir / 'readme.md'
|
||||
|
||||
|
||||
def is_keyboard_target(keyboard_target):
|
||||
"""Checks to make sure the supplied keyboard_target is valid.
|
||||
|
||||
This is mainly used by commands that accept --keyboard.
|
||||
"""
|
||||
if keyboard_target in ['all', 'all-avr', 'all-chibios', 'all-arm_atsam']:
|
||||
return keyboard_target
|
||||
|
||||
return keyboard_folder(keyboard_target)
|
||||
|
||||
|
||||
def keyboard_folder(keyboard):
|
||||
"""Returns the actual keyboard folder.
|
||||
|
||||
@@ -206,6 +218,7 @@ def render_layout(layout_data, render_ascii, key_labels=None):
|
||||
return '\n'.join(lines)
|
||||
|
||||
|
||||
@lru_cache(maxsize=0)
|
||||
def render_layouts(info_json, render_ascii):
|
||||
"""Renders all the layouts from an `info_json` structure.
|
||||
"""
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"""
|
||||
import json
|
||||
import sys
|
||||
from functools import lru_cache
|
||||
from pathlib import Path
|
||||
from subprocess import DEVNULL
|
||||
|
||||
@@ -14,6 +15,7 @@ from pygments import lex
|
||||
import qmk.path
|
||||
from qmk.keyboard import find_keyboard_from_dir, rules_mk
|
||||
from qmk.errors import CppError
|
||||
from qmk.metadata import basic_info_json
|
||||
|
||||
# The `keymap.c` template to use when a keyboard doesn't have its own
|
||||
DEFAULT_KEYMAP_C = """#include QMK_KEYBOARD_H
|
||||
@@ -30,6 +32,7 @@ __KEYMAP_GOES_HERE__
|
||||
"""
|
||||
|
||||
|
||||
@lru_cache(maxsize=0)
|
||||
def template_json(keyboard):
|
||||
"""Returns a `keymap.json` template for a keyboard.
|
||||
|
||||
@@ -47,6 +50,7 @@ def template_json(keyboard):
|
||||
return template
|
||||
|
||||
|
||||
@lru_cache(maxsize=0)
|
||||
def template_c(keyboard):
|
||||
"""Returns a `keymap.c` template for a keyboard.
|
||||
|
||||
@@ -122,6 +126,7 @@ def keymap_completer(prefix, action, parser, parsed_args):
|
||||
return []
|
||||
|
||||
|
||||
@lru_cache(maxsize=0)
|
||||
def is_keymap_dir(keymap, c=True, json=True, additional_files=None):
|
||||
"""Return True if Path object `keymap` has a keymap file inside.
|
||||
|
||||
@@ -180,6 +185,7 @@ def generate_json(keymap, keyboard, layout, layers):
|
||||
return new_keymap
|
||||
|
||||
|
||||
@lru_cache(maxsize=0)
|
||||
def generate_c(keyboard, layout, layers):
|
||||
"""Returns a `keymap.c` or `keymap.json` for the specified keyboard, layout, and layers.
|
||||
|
||||
@@ -266,6 +272,7 @@ def write(keyboard, keymap, layout, layers):
|
||||
return write_file(keymap_file, keymap_content)
|
||||
|
||||
|
||||
@lru_cache(maxsize=0)
|
||||
def locate_keymap(keyboard, keymap):
|
||||
"""Returns the path to a keymap for a specific keyboard.
|
||||
"""
|
||||
@@ -305,6 +312,7 @@ def locate_keymap(keyboard, keymap):
|
||||
return community_layout / 'keymap.c'
|
||||
|
||||
|
||||
@lru_cache(maxsize=0)
|
||||
def list_keymaps(keyboard, c=True, json=True, additional_files=None, fullpath=False):
|
||||
"""List the available keymaps for a keyboard.
|
||||
|
||||
@@ -327,40 +335,38 @@ def list_keymaps(keyboard, c=True, json=True, additional_files=None, fullpath=Fa
|
||||
Returns:
|
||||
a sorted list of valid keymap names.
|
||||
"""
|
||||
# parse all the rules.mk files for the keyboard
|
||||
rules = rules_mk(keyboard)
|
||||
info_data = basic_info_json(keyboard)
|
||||
names = set()
|
||||
|
||||
if rules:
|
||||
keyboards_dir = Path('keyboards')
|
||||
kb_path = keyboards_dir / keyboard
|
||||
keyboards_dir = Path('keyboards')
|
||||
kb_path = keyboards_dir / info_data['keyboard_folder']
|
||||
|
||||
# walk up the directory tree until keyboards_dir
|
||||
# and collect all directories' name with keymap.c file in it
|
||||
while kb_path != keyboards_dir:
|
||||
keymaps_dir = kb_path / "keymaps"
|
||||
# walk up the directory tree until keyboards_dir
|
||||
# and collect all directories' name with keymap.c file in it
|
||||
while kb_path != keyboards_dir:
|
||||
keymaps_dir = kb_path / "keymaps"
|
||||
|
||||
if keymaps_dir.is_dir():
|
||||
for keymap in keymaps_dir.iterdir():
|
||||
if is_keymap_dir(keymap, c, json, additional_files):
|
||||
keymap = keymap if fullpath else keymap.name
|
||||
names.add(keymap)
|
||||
if keymaps_dir.is_dir():
|
||||
for keymap in keymaps_dir.iterdir():
|
||||
if is_keymap_dir(keymap, c, json, additional_files):
|
||||
keymap = keymap if fullpath else keymap.name
|
||||
names.add(keymap)
|
||||
|
||||
kb_path = kb_path.parent
|
||||
kb_path = kb_path.parent
|
||||
|
||||
# if community layouts are supported, get them
|
||||
if "LAYOUTS" in rules:
|
||||
for layout in rules["LAYOUTS"].split():
|
||||
cl_path = Path('layouts/community') / layout
|
||||
if cl_path.is_dir():
|
||||
for keymap in cl_path.iterdir():
|
||||
if is_keymap_dir(keymap, c, json, additional_files):
|
||||
keymap = keymap if fullpath else keymap.name
|
||||
names.add(keymap)
|
||||
# if community layouts are supported, get them
|
||||
for layout in info_data.get('community_layouts', []):
|
||||
cl_path = Path('layouts/community') / layout
|
||||
if cl_path.is_dir():
|
||||
for keymap in cl_path.iterdir():
|
||||
if is_keymap_dir(keymap, c, json, additional_files):
|
||||
keymap = keymap if fullpath else keymap.name
|
||||
names.add(keymap)
|
||||
|
||||
return sorted(names)
|
||||
|
||||
|
||||
@lru_cache(maxsize=0)
|
||||
def _c_preprocess(path, stdin=DEVNULL):
|
||||
""" Run a file through the C pre-processor
|
||||
|
||||
@@ -380,6 +386,7 @@ def _c_preprocess(path, stdin=DEVNULL):
|
||||
return pre_processed_keymap.stdout
|
||||
|
||||
|
||||
@lru_cache(maxsize=0)
|
||||
def _get_layers(keymap): # noqa C901 : until someone has a good idea how to simplify/split up this code
|
||||
""" Find the layers in a keymap.c file.
|
||||
|
||||
@@ -500,6 +507,7 @@ def _get_layers(keymap): # noqa C901 : until someone has a good idea how to sim
|
||||
return layers
|
||||
|
||||
|
||||
@lru_cache(maxsize=0)
|
||||
def parse_keymap_c(keymap_file, use_cpp=True):
|
||||
""" Parse a keymap.c file.
|
||||
|
||||
@@ -529,6 +537,7 @@ def parse_keymap_c(keymap_file, use_cpp=True):
|
||||
return keymap
|
||||
|
||||
|
||||
@lru_cache(maxsize=0)
|
||||
def c2json(keyboard, keymap, keymap_file, use_cpp=True):
|
||||
""" Convert keymap.c to keymap.json
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
""" Functions for working with Makefiles
|
||||
"""
|
||||
from functools import lru_cache
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
@lru_cache(maxsize=0)
|
||||
def parse_rules_mk_file(file, rules_mk=None):
|
||||
"""Turn a rules.mk file into a dictionary.
|
||||
|
||||
|
||||
@@ -3,12 +3,22 @@
|
||||
Gratefully copied from https://stackoverflow.com/a/9558001
|
||||
"""
|
||||
import ast
|
||||
import operator as op
|
||||
import operator
|
||||
from functools import lru_cache
|
||||
|
||||
# supported operators
|
||||
operators = {ast.Add: op.add, ast.Sub: op.sub, ast.Mult: op.mul, ast.Div: op.truediv, ast.Pow: op.pow, ast.BitXor: op.xor, ast.USub: op.neg}
|
||||
operators = {
|
||||
ast.Add: operator.add,
|
||||
ast.Sub: operator.sub,
|
||||
ast.Mult: operator.mul,
|
||||
ast.Div: operator.truediv,
|
||||
ast.Pow: operator.pow,
|
||||
ast.BitXor: operator.xor,
|
||||
ast.USub: operator.neg,
|
||||
}
|
||||
|
||||
|
||||
@lru_cache(maxsize=0)
|
||||
def compute(expr):
|
||||
"""Parse a mathematical expression and return the answer.
|
||||
|
||||
@@ -22,6 +32,7 @@ def compute(expr):
|
||||
return _eval(ast.parse(expr, mode='eval').body)
|
||||
|
||||
|
||||
@lru_cache(maxsize=0)
|
||||
def _eval(node):
|
||||
if isinstance(node, ast.Num): # <number>
|
||||
return node.n
|
||||
|
||||
533
lib/python/qmk/metadata.py
Normal file
533
lib/python/qmk/metadata.py
Normal file
@@ -0,0 +1,533 @@
|
||||
"""Functions that help us generate and use info.json files.
|
||||
"""
|
||||
from functools import lru_cache
|
||||
from glob import glob
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
import jsonschema
|
||||
from dotty_dict import dotty
|
||||
from milc import cli
|
||||
|
||||
from qmk.constants import CHIBIOS_PROCESSORS, LUFA_PROCESSORS, VUSB_PROCESSORS
|
||||
from qmk.c_parse import find_layouts
|
||||
from qmk.json_schema import deep_update, json_load, validate
|
||||
from qmk.keyboard import config_h, rules_mk
|
||||
from qmk.makefile import parse_rules_mk_file
|
||||
from qmk.math import compute
|
||||
|
||||
true_values = ['1', 'on', 'yes', 'true']
|
||||
false_values = ['0', 'off', 'no', 'false']
|
||||
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def basic_info_json(keyboard):
|
||||
"""Generate a subset of info.json for a specific keyboard.
|
||||
|
||||
This does minimal validation, and should only be used as needed to avoid loops or when performance is critical.
|
||||
"""
|
||||
cur_dir = Path('keyboards')
|
||||
rules = parse_rules_mk_file(cur_dir / keyboard / 'rules.mk')
|
||||
|
||||
if 'DEFAULT_FOLDER' in rules:
|
||||
keyboard = rules['DEFAULT_FOLDER']
|
||||
rules = parse_rules_mk_file(cur_dir / keyboard / 'rules.mk', rules)
|
||||
|
||||
info_data = {
|
||||
'keyboard_name': str(keyboard),
|
||||
'keyboard_folder': str(keyboard),
|
||||
'keymaps': {},
|
||||
'layouts': {},
|
||||
'parse_errors': [],
|
||||
'parse_warnings': [],
|
||||
'maintainer': 'qmk',
|
||||
}
|
||||
|
||||
# Populate layout data
|
||||
layouts, aliases = _find_all_layouts(info_data, keyboard)
|
||||
|
||||
if aliases:
|
||||
info_data['layout_aliases'] = aliases
|
||||
|
||||
for layout_name, layout_json in layouts.items():
|
||||
if not layout_name.startswith('LAYOUT_kc'):
|
||||
layout_json['c_macro'] = True
|
||||
info_data['layouts'][layout_name] = layout_json
|
||||
|
||||
# Merge in the data from info.json, config.h, and rules.mk
|
||||
info_data = merge_info_jsons(keyboard, info_data)
|
||||
info_data = _extract_config_h(info_data)
|
||||
info_data = _extract_rules_mk(info_data)
|
||||
|
||||
return info_data
|
||||
|
||||
|
||||
def _extract_features(info_data, rules):
|
||||
"""Find all the features enabled in rules.mk.
|
||||
"""
|
||||
# Special handling for bootmagic which also supports a "lite" mode.
|
||||
if rules.get('BOOTMAGIC_ENABLE') == 'lite':
|
||||
rules['BOOTMAGIC_LITE_ENABLE'] = 'on'
|
||||
del rules['BOOTMAGIC_ENABLE']
|
||||
if rules.get('BOOTMAGIC_ENABLE') == 'full':
|
||||
rules['BOOTMAGIC_ENABLE'] = 'on'
|
||||
|
||||
# Skip non-boolean features we haven't implemented special handling for
|
||||
for feature in 'HAPTIC_ENABLE', 'QWIIC_ENABLE':
|
||||
if rules.get(feature):
|
||||
del rules[feature]
|
||||
|
||||
# Process the rest of the rules as booleans
|
||||
for key, value in rules.items():
|
||||
if key.endswith('_ENABLE'):
|
||||
key = '_'.join(key.split('_')[:-1]).lower()
|
||||
value = True if value.lower() in true_values else False if value.lower() in false_values else value
|
||||
|
||||
if 'config_h_features' not in info_data:
|
||||
info_data['config_h_features'] = {}
|
||||
|
||||
if 'features' not in info_data:
|
||||
info_data['features'] = {}
|
||||
|
||||
if key in info_data['features']:
|
||||
info_log_warning(info_data, 'Feature %s is specified in both info.json and rules.mk, the rules.mk value wins.' % (key,))
|
||||
|
||||
info_data['features'][key] = value
|
||||
info_data['config_h_features'][key] = value
|
||||
|
||||
return info_data
|
||||
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def _pin_name(pin):
|
||||
"""Returns the proper representation for a pin.
|
||||
"""
|
||||
pin = pin.strip()
|
||||
|
||||
if not pin:
|
||||
return None
|
||||
|
||||
elif pin.isdigit():
|
||||
return int(pin)
|
||||
|
||||
elif pin == 'NO_PIN':
|
||||
return None
|
||||
|
||||
return pin
|
||||
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def _extract_pins(pins):
|
||||
"""Returns a list of pins from a comma separated string of pins.
|
||||
"""
|
||||
return [_pin_name(pin) for pin in pins.split(',')]
|
||||
|
||||
|
||||
def _extract_direct_matrix(info_data, direct_pins):
|
||||
"""
|
||||
"""
|
||||
info_data['matrix_pins'] = {}
|
||||
direct_pin_array = []
|
||||
|
||||
while direct_pins[-1] != '}':
|
||||
direct_pins = direct_pins[:-1]
|
||||
|
||||
for row in direct_pins.split('},{'):
|
||||
if row.startswith('{'):
|
||||
row = row[1:]
|
||||
|
||||
if row.endswith('}'):
|
||||
row = row[:-1]
|
||||
|
||||
direct_pin_array.append([])
|
||||
|
||||
for pin in row.split(','):
|
||||
if pin == 'NO_PIN':
|
||||
pin = None
|
||||
|
||||
direct_pin_array[-1].append(pin)
|
||||
|
||||
return direct_pin_array
|
||||
|
||||
|
||||
def _extract_matrix_info(info_data, config_c):
|
||||
"""Populate the matrix information.
|
||||
"""
|
||||
row_pins = config_c.get('MATRIX_ROW_PINS', '').replace('{', '').replace('}', '').strip()
|
||||
col_pins = config_c.get('MATRIX_COL_PINS', '').replace('{', '').replace('}', '').strip()
|
||||
direct_pins = config_c.get('DIRECT_PINS', '').replace(' ', '')[1:-1]
|
||||
|
||||
if 'MATRIX_ROWS' in config_c and 'MATRIX_COLS' in config_c:
|
||||
if 'matrix_size' in info_data:
|
||||
info_log_warning(info_data, 'Matrix size is specified in both info.json and config.h, the config.h values win.')
|
||||
|
||||
info_data['matrix_size'] = {
|
||||
'cols': compute(config_c.get('MATRIX_COLS', '0')),
|
||||
'rows': compute(config_c.get('MATRIX_ROWS', '0')),
|
||||
}
|
||||
|
||||
if row_pins and col_pins:
|
||||
if 'matrix_pins' in info_data:
|
||||
info_log_warning(info_data, 'Matrix pins are specified in both info.json and config.h, the config.h values win.')
|
||||
|
||||
info_data['matrix_pins'] = {
|
||||
'cols': _extract_pins(col_pins),
|
||||
'rows': _extract_pins(row_pins),
|
||||
}
|
||||
|
||||
if direct_pins:
|
||||
if 'matrix_pins' in info_data:
|
||||
info_log_warning(info_data, 'Direct pins are specified in both info.json and config.h, the config.h values win.')
|
||||
|
||||
info_data['matrix_pins']['direct'] = _extract_direct_matrix(info_data, direct_pins)
|
||||
|
||||
return info_data
|
||||
|
||||
|
||||
def _extract_config_h(info_data):
|
||||
"""Pull some keyboard information from existing config.h files
|
||||
"""
|
||||
config_c = config_h(info_data['keyboard_folder'])
|
||||
|
||||
# Pull in data from the json map
|
||||
dotty_info = dotty(info_data)
|
||||
info_config_map = json_load(Path('data/mappings/info_config.json'))
|
||||
|
||||
for config_key, info_dict in info_config_map.items():
|
||||
info_key = info_dict['info_key']
|
||||
key_type = info_dict.get('value_type', 'str')
|
||||
|
||||
try:
|
||||
if config_key in config_c and info_dict.get('to_json', True):
|
||||
if dotty_info.get(info_key) and info_dict.get('warn_duplicate', True):
|
||||
info_log_warning(info_data, '%s in config.h is overwriting %s in info.json' % (config_key, info_key))
|
||||
|
||||
if key_type.startswith('array'):
|
||||
if '.' in key_type:
|
||||
key_type, array_type = key_type.split('.', 1)
|
||||
else:
|
||||
array_type = None
|
||||
|
||||
config_value = config_c[config_key].replace('{', '').replace('}', '').strip()
|
||||
|
||||
if array_type == 'int':
|
||||
dotty_info[info_key] = list(map(int, config_value.split(',')))
|
||||
else:
|
||||
dotty_info[info_key] = config_value.split(',')
|
||||
|
||||
elif key_type == 'bool':
|
||||
dotty_info[info_key] = config_c[config_key] in true_values
|
||||
|
||||
elif key_type == 'hex':
|
||||
dotty_info[info_key] = '0x' + config_c[config_key][2:].upper()
|
||||
|
||||
elif key_type == 'list':
|
||||
dotty_info[info_key] = config_c[config_key].split()
|
||||
|
||||
elif key_type == 'int':
|
||||
dotty_info[info_key] = int(config_c[config_key])
|
||||
|
||||
else:
|
||||
dotty_info[info_key] = config_c[config_key]
|
||||
|
||||
except Exception as e:
|
||||
info_log_warning(info_data, f'{config_key}->{info_key}: {e}')
|
||||
|
||||
info_data.update(dotty_info)
|
||||
|
||||
# Pull data that easily can't be mapped in json
|
||||
_extract_matrix_info(info_data, config_c)
|
||||
|
||||
return info_data
|
||||
|
||||
|
||||
def _extract_rules_mk(info_data):
|
||||
"""Pull some keyboard information from existing rules.mk files
|
||||
"""
|
||||
rules = rules_mk(info_data['keyboard_folder'])
|
||||
info_data['processor'] = rules.get('MCU', info_data.get('processor', 'atmega32u4'))
|
||||
|
||||
if info_data['processor'] in CHIBIOS_PROCESSORS:
|
||||
arm_processor_rules(info_data, rules)
|
||||
|
||||
elif info_data['processor'] in LUFA_PROCESSORS + VUSB_PROCESSORS:
|
||||
avr_processor_rules(info_data, rules)
|
||||
|
||||
else:
|
||||
cli.log.warning("%s: Unknown MCU: %s" % (info_data['keyboard_folder'], info_data['processor']))
|
||||
unknown_processor_rules(info_data, rules)
|
||||
|
||||
# Pull in data from the json map
|
||||
dotty_info = dotty(info_data)
|
||||
info_rules_map = json_load(Path('data/mappings/info_rules.json'))
|
||||
|
||||
for rules_key, info_dict in info_rules_map.items():
|
||||
info_key = info_dict['info_key']
|
||||
key_type = info_dict.get('value_type', 'str')
|
||||
|
||||
try:
|
||||
if rules_key in rules and info_dict.get('to_json', True):
|
||||
if dotty_info.get(info_key) and info_dict.get('warn_duplicate', True):
|
||||
info_log_warning(info_data, '%s in rules.mk is overwriting %s in info.json' % (rules_key, info_key))
|
||||
|
||||
if key_type.startswith('array'):
|
||||
if '.' in key_type:
|
||||
key_type, array_type = key_type.split('.', 1)
|
||||
else:
|
||||
array_type = None
|
||||
|
||||
rules_value = rules[rules_key].replace('{', '').replace('}', '').strip()
|
||||
|
||||
if array_type == 'int':
|
||||
dotty_info[info_key] = list(map(int, rules_value.split(',')))
|
||||
else:
|
||||
dotty_info[info_key] = rules_value.split(',')
|
||||
|
||||
elif key_type == 'list':
|
||||
dotty_info[info_key] = rules[rules_key].split()
|
||||
|
||||
elif key_type == 'bool':
|
||||
dotty_info[info_key] = rules[rules_key] in true_values
|
||||
|
||||
elif key_type == 'hex':
|
||||
dotty_info[info_key] = '0x' + rules[rules_key][2:].upper()
|
||||
|
||||
elif key_type == 'int':
|
||||
dotty_info[info_key] = int(rules[rules_key])
|
||||
|
||||
else:
|
||||
dotty_info[info_key] = rules[rules_key]
|
||||
|
||||
except Exception as e:
|
||||
info_log_warning(info_data, f'{rules_key}->{info_key}: {e}')
|
||||
|
||||
info_data.update(dotty_info)
|
||||
|
||||
# Merge in config values that can't be easily mapped
|
||||
_extract_features(info_data, rules)
|
||||
|
||||
return info_data
|
||||
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def _search_keyboard_h(path):
|
||||
current_path = Path('keyboards/')
|
||||
aliases = {}
|
||||
layouts = {}
|
||||
|
||||
for directory in path.parts:
|
||||
current_path = current_path / directory
|
||||
keyboard_h = '%s.h' % (directory,)
|
||||
keyboard_h_path = current_path / keyboard_h
|
||||
if keyboard_h_path.exists():
|
||||
new_layouts, new_aliases = find_layouts(keyboard_h_path)
|
||||
layouts.update(new_layouts)
|
||||
|
||||
for alias, alias_text in new_aliases.items():
|
||||
if alias_text in layouts:
|
||||
aliases[alias] = alias_text
|
||||
|
||||
return layouts, aliases
|
||||
|
||||
|
||||
def _find_all_layouts(info_data, keyboard):
|
||||
"""Looks for layout macros associated with this keyboard.
|
||||
"""
|
||||
layouts, aliases = _search_keyboard_h(Path(keyboard))
|
||||
|
||||
if not layouts:
|
||||
# If we don't find any layouts from info.json or keyboard.h we widen our search. This is error prone which is why we want to encourage people to follow the standard above.
|
||||
info_data['parse_warnings'].append('%s: Falling back to searching for KEYMAP/LAYOUT macros.' % (keyboard))
|
||||
layouts, new_aliases = _deep_search_layouts(keyboard)
|
||||
aliases.update(new_aliases)
|
||||
|
||||
return layouts, aliases
|
||||
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def _deep_search_layouts(keyboard):
|
||||
"""Do a wider (error-prone) search for layout macros.
|
||||
"""
|
||||
layouts = {}
|
||||
aliases = {}
|
||||
|
||||
for file in glob('keyboards/%s/*.h' % keyboard):
|
||||
if file.endswith('.h'):
|
||||
these_layouts, these_aliases = find_layouts(file)
|
||||
|
||||
if these_layouts:
|
||||
layouts.update(these_layouts)
|
||||
|
||||
for alias, alias_text in these_aliases.items():
|
||||
if alias_text in layouts:
|
||||
aliases[alias] = alias_text
|
||||
|
||||
return layouts, aliases
|
||||
|
||||
|
||||
def info_log_error(info_data, message):
|
||||
"""Send an error message to both JSON and the log.
|
||||
"""
|
||||
info_data['parse_errors'].append(message)
|
||||
cli.log.error('%s: %s', info_data.get('keyboard_folder', 'Unknown Keyboard!'), message)
|
||||
|
||||
|
||||
def info_log_warning(info_data, message):
|
||||
"""Send a warning message to both JSON and the log.
|
||||
"""
|
||||
info_data['parse_warnings'].append(message)
|
||||
cli.log.warning('%s: %s', info_data.get('keyboard_folder', 'Unknown Keyboard!'), message)
|
||||
|
||||
|
||||
def arm_processor_rules(info_data, rules):
|
||||
"""Setup the default info for an ARM board.
|
||||
"""
|
||||
info_data['processor_type'] = 'arm'
|
||||
info_data['protocol'] = 'ChibiOS'
|
||||
|
||||
if 'bootloader' not in info_data:
|
||||
if 'STM32' in info_data['processor']:
|
||||
info_data['bootloader'] = 'stm32-dfu'
|
||||
else:
|
||||
info_data['bootloader'] = 'unknown'
|
||||
|
||||
if 'STM32' in info_data['processor']:
|
||||
info_data['platform'] = 'STM32'
|
||||
elif 'MCU_SERIES' in rules:
|
||||
info_data['platform'] = rules['MCU_SERIES']
|
||||
elif 'ARM_ATSAM' in rules:
|
||||
info_data['platform'] = 'ARM_ATSAM'
|
||||
|
||||
return info_data
|
||||
|
||||
|
||||
def avr_processor_rules(info_data, rules):
|
||||
"""Setup the default info for an AVR board.
|
||||
"""
|
||||
info_data['processor_type'] = 'avr'
|
||||
info_data['platform'] = rules['ARCH'] if 'ARCH' in rules else 'unknown'
|
||||
info_data['protocol'] = 'V-USB' if rules.get('MCU') in VUSB_PROCESSORS else 'LUFA'
|
||||
|
||||
if 'bootloader' not in info_data:
|
||||
info_data['bootloader'] = 'atmel-dfu'
|
||||
|
||||
# FIXME(fauxpark/anyone): Eventually we should detect the protocol by looking at PROTOCOL inherited from mcu_selection.mk:
|
||||
# info_data['protocol'] = 'V-USB' if rules.get('PROTOCOL') == 'VUSB' else 'LUFA'
|
||||
|
||||
return info_data
|
||||
|
||||
|
||||
def unknown_processor_rules(info_data, rules):
|
||||
"""Setup the default keyboard info for unknown boards.
|
||||
"""
|
||||
info_data['bootloader'] = 'unknown'
|
||||
info_data['platform'] = 'unknown'
|
||||
info_data['processor'] = 'unknown'
|
||||
info_data['processor_type'] = 'unknown'
|
||||
info_data['protocol'] = 'unknown'
|
||||
|
||||
return info_data
|
||||
|
||||
|
||||
def store_mtime(file):
|
||||
"""Stores the mtime for a json file.
|
||||
"""
|
||||
cli.log.debug('store_mtime(%s)', file)
|
||||
mtime = str(os.stat(file).st_mtime)
|
||||
cache_file = f'.build/json_times/{file}'
|
||||
cache_dir = os.path.dirname(cache_file)
|
||||
os.makedirs(cache_dir, exist_ok=True)
|
||||
with open(cache_file, 'w') as fd:
|
||||
fd.write(mtime)
|
||||
|
||||
|
||||
def has_been_validated(file):
|
||||
"""Returns True if file is in the json cache.
|
||||
"""
|
||||
cli.log.debug('has_been_validated(%s)', file)
|
||||
mtime_file = f'.build/json_times/{file}'
|
||||
if os.path.exists(mtime_file):
|
||||
with open(mtime_file) as fd:
|
||||
cache_mtime = fd.read()
|
||||
cache_mtime = cache_mtime.strip()
|
||||
file_mtime = str(os.stat(file).st_mtime)
|
||||
if cache_mtime == file_mtime:
|
||||
return True
|
||||
else:
|
||||
os.remove(mtime_file)
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def merge_info_jsons(keyboard, info_data):
|
||||
"""Return a merged copy of all the info.json files for a keyboard.
|
||||
"""
|
||||
for info_file in find_info_json(keyboard):
|
||||
# Load and validate the JSON data
|
||||
new_info_data = json_load(info_file)
|
||||
|
||||
if not isinstance(new_info_data, dict):
|
||||
info_log_error(info_data, "Invalid file %s, root object should be a dictionary." % (str(info_file),))
|
||||
continue
|
||||
|
||||
if not has_been_validated(info_file):
|
||||
try:
|
||||
validate(new_info_data, 'qmk.keyboard.v1')
|
||||
except jsonschema.ValidationError as e:
|
||||
json_path = '.'.join([str(p) for p in e.absolute_path])
|
||||
cli.log.error('Not including data from file: %s', info_file)
|
||||
cli.log.error('\t%s: %s', json_path, e.message)
|
||||
continue
|
||||
|
||||
store_mtime(info_file)
|
||||
|
||||
# Merge layout data in
|
||||
if 'layout_aliases' in new_info_data:
|
||||
info_data['layout_aliases'] = {**info_data.get('layout_aliases', {}), **new_info_data['layout_aliases']}
|
||||
del new_info_data['layout_aliases']
|
||||
|
||||
for layout_name, layout in new_info_data.get('layouts', {}).items():
|
||||
if layout_name in info_data.get('layout_aliases', {}):
|
||||
info_log_warning(info_data, f"info.json uses alias name {layout_name} instead of {info_data['layout_aliases'][layout_name]}")
|
||||
layout_name = info_data['layout_aliases'][layout_name]
|
||||
|
||||
if layout_name in info_data['layouts']:
|
||||
for new_key, existing_key in zip(layout['layout'], info_data['layouts'][layout_name]['layout']):
|
||||
existing_key.update(new_key)
|
||||
else:
|
||||
layout['c_macro'] = False
|
||||
info_data['layouts'][layout_name] = layout
|
||||
|
||||
# Update info_data with the new data
|
||||
if 'layouts' in new_info_data:
|
||||
del new_info_data['layouts']
|
||||
|
||||
deep_update(info_data, new_info_data)
|
||||
|
||||
return info_data
|
||||
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def find_info_json(keyboard):
|
||||
"""Finds all the info.json files associated with a keyboard.
|
||||
"""
|
||||
# Find the most specific first
|
||||
base_path = Path('keyboards')
|
||||
keyboard_path = base_path / keyboard
|
||||
keyboard_parent = keyboard_path.parent
|
||||
info_jsons = [keyboard_path / 'info.json']
|
||||
|
||||
# Add DEFAULT_FOLDER before parents, if present
|
||||
rules = rules_mk(keyboard)
|
||||
if 'DEFAULT_FOLDER' in rules:
|
||||
info_jsons.append(Path(rules['DEFAULT_FOLDER']) / 'info.json')
|
||||
|
||||
# Add in parent folders for least specific
|
||||
for _ in range(5):
|
||||
info_jsons.append(keyboard_parent / 'info.json')
|
||||
if keyboard_parent.parent == base_path:
|
||||
break
|
||||
keyboard_parent = keyboard_parent.parent
|
||||
|
||||
# Return a list of the info.json files that actually exist
|
||||
return [info_json for info_json in info_jsons if info_json.exists()]
|
||||
@@ -3,12 +3,14 @@
|
||||
import logging
|
||||
import os
|
||||
import argparse
|
||||
from functools import lru_cache
|
||||
from pathlib import Path
|
||||
|
||||
from qmk.constants import MAX_KEYBOARD_SUBFOLDERS, QMK_FIRMWARE
|
||||
from qmk.errors import NoSuchKeyboardError
|
||||
|
||||
|
||||
@lru_cache(maxsize=0)
|
||||
def is_keyboard(keyboard_name):
|
||||
"""Returns True if `keyboard_name` is a keyboard we can compile.
|
||||
"""
|
||||
@@ -19,6 +21,7 @@ def is_keyboard(keyboard_name):
|
||||
return rules_mk.exists()
|
||||
|
||||
|
||||
@lru_cache(maxsize=0)
|
||||
def under_qmk_firmware():
|
||||
"""Returns a Path object representing the relative path under qmk_firmware, or None.
|
||||
"""
|
||||
@@ -30,12 +33,14 @@ def under_qmk_firmware():
|
||||
return None
|
||||
|
||||
|
||||
@lru_cache(maxsize=0)
|
||||
def keyboard(keyboard_name):
|
||||
"""Returns the path to a keyboard's directory relative to the qmk root.
|
||||
"""
|
||||
return Path('keyboards') / keyboard_name
|
||||
|
||||
|
||||
@lru_cache(maxsize=0)
|
||||
def keymap(keyboard_name):
|
||||
"""Locate the correct directory for storing a keymap.
|
||||
|
||||
@@ -56,6 +61,7 @@ def keymap(keyboard_name):
|
||||
raise NoSuchKeyboardError('Could not find keymaps directory for: %s' % keyboard_name)
|
||||
|
||||
|
||||
@lru_cache(maxsize=0)
|
||||
def normpath(path):
|
||||
"""Returns a `pathlib.Path()` object for a given path.
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
"""Functions for working with QMK's submodules.
|
||||
"""
|
||||
from functools import lru_cache
|
||||
from milc import cli
|
||||
|
||||
|
||||
@lru_cache(maxsize=0)
|
||||
def status():
|
||||
"""Returns a dictionary of submodules.
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ def test_hello():
|
||||
def test_format_python():
|
||||
result = check_subcommand('format-python', '--dry-run')
|
||||
check_returncode(result)
|
||||
assert 'Python code in `bin/qmk` and `lib/python` is correctly formatted.' in result.stdout
|
||||
assert 'Python code in `lib/python` is correctly formatted.' in result.stdout
|
||||
|
||||
|
||||
def test_list_keyboards():
|
||||
|
||||
@@ -12,6 +12,13 @@ let
|
||||
# files if the requirements*.txt files change
|
||||
pythonEnv = poetry2nix.mkPoetryEnv {
|
||||
projectDir = ./util/nix;
|
||||
overrides = poetry2nix.overrides.withDefaults (self: super: {
|
||||
qmk = super.qmk.overridePythonAttrs(old: {
|
||||
# Allow QMK CLI to run "qmk" as a subprocess (the wrapper changes
|
||||
# $PATH and breaks these invocations).
|
||||
dontWrapPythonPrograms = true;
|
||||
});
|
||||
});
|
||||
};
|
||||
in
|
||||
|
||||
|
||||
@@ -81,5 +81,5 @@ fi
|
||||
-e ALT_GET_KEYBOARDS=true \
|
||||
-e SKIP_GIT="$SKIP_GIT" \
|
||||
-e MAKEFLAGS="$MAKEFLAGS" \
|
||||
qmkfm/base_container \
|
||||
qmkfm/qmk_cli \
|
||||
make "$keyboard${keymap:+:$keymap}${target:+:$target}"
|
||||
|
||||
163
util/nix/poetry.lock
generated
163
util/nix/poetry.lock
generated
@@ -43,29 +43,18 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
name = "coverage"
|
||||
version = "5.5"
|
||||
description = "Code coverage measurement for Python"
|
||||
category = "main"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
|
||||
|
||||
[package.extras]
|
||||
toml = ["toml"]
|
||||
|
||||
[[package]]
|
||||
name = "dotty-dict"
|
||||
version = "1.3.0"
|
||||
description = "Dictionary wrapper for quick access to deeply nested keys."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[package.dependencies]
|
||||
setuptools_scm = "*"
|
||||
|
||||
[[package]]
|
||||
name = "flake8"
|
||||
version = "3.9.2"
|
||||
description = "the modular source code checker: pep8 pyflakes and co"
|
||||
category = "main"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
|
||||
|
||||
@@ -151,13 +140,13 @@ colorama = ">=0.3.9"
|
||||
name = "mccabe"
|
||||
version = "0.6.1"
|
||||
description = "McCabe checker, plugin for flake8"
|
||||
category = "main"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "milc"
|
||||
version = "1.4.2"
|
||||
version = "1.6.2"
|
||||
description = "Opinionated Batteries-Included Python 3 CLI Framework."
|
||||
category = "main"
|
||||
optional = false
|
||||
@@ -174,7 +163,7 @@ spinners = "*"
|
||||
name = "nose2"
|
||||
version = "0.10.0"
|
||||
description = "unittest2 with plugins, the succesor to nose"
|
||||
category = "main"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
@@ -188,20 +177,21 @@ dev = ["Sphinx (>=1.6.5)", "sphinx-rtd-theme", "mock", "coverage"]
|
||||
|
||||
[[package]]
|
||||
name = "pep8-naming"
|
||||
version = "0.11.1"
|
||||
version = "0.12.1"
|
||||
description = "Check PEP-8 naming conventions, plugin for flake8"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[package.dependencies]
|
||||
flake8 = ">=3.9.1"
|
||||
flake8-polyfill = ">=1.0.2,<2"
|
||||
|
||||
[[package]]
|
||||
name = "pycodestyle"
|
||||
version = "2.7.0"
|
||||
description = "Python style guide checker"
|
||||
category = "main"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
|
||||
@@ -209,13 +199,13 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
name = "pyflakes"
|
||||
version = "2.3.1"
|
||||
description = "passive checker of Python programs"
|
||||
category = "main"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
|
||||
[[package]]
|
||||
name = "pygments"
|
||||
version = "2.9.0"
|
||||
version = "2.10.0"
|
||||
description = "Pygments is a syntax highlighting package written in Python."
|
||||
category = "main"
|
||||
optional = false
|
||||
@@ -223,50 +213,44 @@ python-versions = ">=3.5"
|
||||
|
||||
[[package]]
|
||||
name = "pyrsistent"
|
||||
version = "0.17.3"
|
||||
version = "0.18.0"
|
||||
description = "Persistent/Functional/Immutable data structures"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
|
||||
[[package]]
|
||||
name = "pyusb"
|
||||
version = "1.1.1"
|
||||
description = "Python USB access module"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "qmk"
|
||||
version = "0.0.51"
|
||||
description = "A program to help users work with QMK Firmware."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[package.dependencies]
|
||||
dotty-dict = "*"
|
||||
flake8 = "*"
|
||||
hid = "*"
|
||||
hjson = "*"
|
||||
jsonschema = ">=3"
|
||||
milc = ">=1.4.0"
|
||||
nose2 = "*"
|
||||
pygments = "*"
|
||||
pyusb = "*"
|
||||
yapf = "*"
|
||||
|
||||
[[package]]
|
||||
name = "setuptools-scm"
|
||||
version = "6.0.1"
|
||||
description = "the blessed package to manage your versions by scm tags"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
|
||||
[package.extras]
|
||||
toml = ["toml"]
|
||||
[[package]]
|
||||
name = "pyusb"
|
||||
version = "1.2.1"
|
||||
description = "Python USB access module"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6.0"
|
||||
|
||||
[[package]]
|
||||
name = "qmk"
|
||||
version = "1.0.0"
|
||||
description = "A program to help users work with QMK Firmware."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[package.dependencies]
|
||||
hid = "*"
|
||||
hjson = "*"
|
||||
jsonschema = ">=3"
|
||||
milc = ">=1.4.2"
|
||||
pygments = "*"
|
||||
pyusb = "*"
|
||||
qmk-dotty-dict = "*"
|
||||
|
||||
[[package]]
|
||||
name = "qmk-dotty-dict"
|
||||
version = "1.3.0.post1"
|
||||
description = "Dictionary wrapper for quick access to deeply nested keys."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "six"
|
||||
@@ -294,16 +278,16 @@ python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "yapf"
|
||||
version = "0.30.0"
|
||||
version = "0.31.0"
|
||||
description = "A formatter for Python code."
|
||||
category = "main"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[metadata]
|
||||
lock-version = "1.1"
|
||||
python-versions = "^3.8"
|
||||
content-hash = "5e181d51536240d08c74ba6a46bd0988ee4ca72ac3d5b388965ca8023e9b9a99"
|
||||
content-hash = "468ae51aaddfe2ce62938f131c688bbc447e41608d4dd7d30db36391c38bda20"
|
||||
|
||||
[metadata.files]
|
||||
appdirs = [
|
||||
@@ -376,9 +360,6 @@ coverage = [
|
||||
{file = "coverage-5.5-pp37-none-any.whl", hash = "sha256:2a3859cb82dcbda1cfd3e6f71c27081d18aa251d20a17d87d26d4cd216fb0af4"},
|
||||
{file = "coverage-5.5.tar.gz", hash = "sha256:ebe78fe9a0e874362175b02371bdfbee64d8edc42a044253ddf4ee7d3c15212c"},
|
||||
]
|
||||
dotty-dict = [
|
||||
{file = "dotty_dict-1.3.0.tar.gz", hash = "sha256:eb0035a3629ecd84397a68f1f42f1e94abd1c34577a19cd3eacad331ee7cbaf0"},
|
||||
]
|
||||
flake8 = [
|
||||
{file = "flake8-3.9.2-py2.py3-none-any.whl", hash = "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907"},
|
||||
{file = "flake8-3.9.2.tar.gz", hash = "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b"},
|
||||
@@ -412,16 +393,16 @@ mccabe = [
|
||||
{file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"},
|
||||
]
|
||||
milc = [
|
||||
{file = "milc-1.4.2-py2.py3-none-any.whl", hash = "sha256:65ee004caa769b1ee144b15be7908d1f623920ab6f356e5c5c95be9457aa15d8"},
|
||||
{file = "milc-1.4.2.tar.gz", hash = "sha256:c6b2f19e3196b00a0060f8c883533e356f2054a9f81692b7b97ccee0d01626fd"},
|
||||
{file = "milc-1.6.2-py2.py3-none-any.whl", hash = "sha256:cb26404c7f3d6797c9c42005de732161e45e21294cde85845e914b279321bdad"},
|
||||
{file = "milc-1.6.2.tar.gz", hash = "sha256:779710a0b9300bef3c5748158887e6c734659e147d55548d9e4701d7a7d5dddf"},
|
||||
]
|
||||
nose2 = [
|
||||
{file = "nose2-0.10.0-py2.py3-none-any.whl", hash = "sha256:aa620e759f2c5018d9ba041340391913e282ecebd3c392027f1575847b093ec6"},
|
||||
{file = "nose2-0.10.0.tar.gz", hash = "sha256:886ba617a96de0130c54b24479bd5c2d74d5c940d40f3809c3a275511a0c4a60"},
|
||||
]
|
||||
pep8-naming = [
|
||||
{file = "pep8-naming-0.11.1.tar.gz", hash = "sha256:a1dd47dd243adfe8a83616e27cf03164960b507530f155db94e10b36a6cd6724"},
|
||||
{file = "pep8_naming-0.11.1-py2.py3-none-any.whl", hash = "sha256:f43bfe3eea7e0d73e8b5d07d6407ab47f2476ccaeff6937c84275cd30b016738"},
|
||||
{file = "pep8-naming-0.12.1.tar.gz", hash = "sha256:bb2455947757d162aa4cad55dba4ce029005cd1692f2899a21d51d8630ca7841"},
|
||||
{file = "pep8_naming-0.12.1-py2.py3-none-any.whl", hash = "sha256:4a8daeaeb33cfcde779309fc0c9c0a68a3bbe2ad8a8308b763c5068f86eb9f37"},
|
||||
]
|
||||
pycodestyle = [
|
||||
{file = "pycodestyle-2.7.0-py2.py3-none-any.whl", hash = "sha256:514f76d918fcc0b55c6680472f0a37970994e07bbb80725808c17089be302068"},
|
||||
@@ -432,23 +413,43 @@ pyflakes = [
|
||||
{file = "pyflakes-2.3.1.tar.gz", hash = "sha256:f5bc8ecabc05bb9d291eb5203d6810b49040f6ff446a756326104746cc00c1db"},
|
||||
]
|
||||
pygments = [
|
||||
{file = "Pygments-2.9.0-py3-none-any.whl", hash = "sha256:d66e804411278594d764fc69ec36ec13d9ae9147193a1740cd34d272ca383b8e"},
|
||||
{file = "Pygments-2.9.0.tar.gz", hash = "sha256:a18f47b506a429f6f4b9df81bb02beab9ca21d0a5fee38ed15aef65f0545519f"},
|
||||
{file = "Pygments-2.10.0-py3-none-any.whl", hash = "sha256:b8e67fe6af78f492b3c4b3e2970c0624cbf08beb1e493b2c99b9fa1b67a20380"},
|
||||
{file = "Pygments-2.10.0.tar.gz", hash = "sha256:f398865f7eb6874156579fdf36bc840a03cab64d1cde9e93d68f46a425ec52c6"},
|
||||
]
|
||||
pyrsistent = [
|
||||
{file = "pyrsistent-0.17.3.tar.gz", hash = "sha256:2e636185d9eb976a18a8a8e96efce62f2905fea90041958d8cc2a189756ebf3e"},
|
||||
{file = "pyrsistent-0.18.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f4c8cabb46ff8e5d61f56a037974228e978f26bfefce4f61a4b1ac0ba7a2ab72"},
|
||||
{file = "pyrsistent-0.18.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:da6e5e818d18459fa46fac0a4a4e543507fe1110e808101277c5a2b5bab0cd2d"},
|
||||
{file = "pyrsistent-0.18.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:5e4395bbf841693eaebaa5bb5c8f5cdbb1d139e07c975c682ec4e4f8126e03d2"},
|
||||
{file = "pyrsistent-0.18.0-cp36-cp36m-win32.whl", hash = "sha256:527be2bfa8dc80f6f8ddd65242ba476a6c4fb4e3aedbf281dfbac1b1ed4165b1"},
|
||||
{file = "pyrsistent-0.18.0-cp36-cp36m-win_amd64.whl", hash = "sha256:2aaf19dc8ce517a8653746d98e962ef480ff34b6bc563fc067be6401ffb457c7"},
|
||||
{file = "pyrsistent-0.18.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:58a70d93fb79dc585b21f9d72487b929a6fe58da0754fa4cb9f279bb92369396"},
|
||||
{file = "pyrsistent-0.18.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:4916c10896721e472ee12c95cdc2891ce5890898d2f9907b1b4ae0f53588b710"},
|
||||
{file = "pyrsistent-0.18.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:73ff61b1411e3fb0ba144b8f08d6749749775fe89688093e1efef9839d2dcc35"},
|
||||
{file = "pyrsistent-0.18.0-cp37-cp37m-win32.whl", hash = "sha256:b29b869cf58412ca5738d23691e96d8aff535e17390128a1a52717c9a109da4f"},
|
||||
{file = "pyrsistent-0.18.0-cp37-cp37m-win_amd64.whl", hash = "sha256:097b96f129dd36a8c9e33594e7ebb151b1515eb52cceb08474c10a5479e799f2"},
|
||||
{file = "pyrsistent-0.18.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:772e94c2c6864f2cd2ffbe58bb3bdefbe2a32afa0acb1a77e472aac831f83427"},
|
||||
{file = "pyrsistent-0.18.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:c1a9ff320fa699337e05edcaae79ef8c2880b52720bc031b219e5b5008ebbdef"},
|
||||
{file = "pyrsistent-0.18.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:cd3caef37a415fd0dae6148a1b6957a8c5f275a62cca02e18474608cb263640c"},
|
||||
{file = "pyrsistent-0.18.0-cp38-cp38-win32.whl", hash = "sha256:e79d94ca58fcafef6395f6352383fa1a76922268fa02caa2272fff501c2fdc78"},
|
||||
{file = "pyrsistent-0.18.0-cp38-cp38-win_amd64.whl", hash = "sha256:a0c772d791c38bbc77be659af29bb14c38ced151433592e326361610250c605b"},
|
||||
{file = "pyrsistent-0.18.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d5ec194c9c573aafaceebf05fc400656722793dac57f254cd4741f3c27ae57b4"},
|
||||
{file = "pyrsistent-0.18.0-cp39-cp39-manylinux1_i686.whl", hash = "sha256:6b5eed00e597b5b5773b4ca30bd48a5774ef1e96f2a45d105db5b4ebb4bca680"},
|
||||
{file = "pyrsistent-0.18.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:48578680353f41dca1ca3dc48629fb77dfc745128b56fc01096b2530c13fd426"},
|
||||
{file = "pyrsistent-0.18.0-cp39-cp39-win32.whl", hash = "sha256:f3ef98d7b76da5eb19c37fda834d50262ff9167c65658d1d8f974d2e4d90676b"},
|
||||
{file = "pyrsistent-0.18.0-cp39-cp39-win_amd64.whl", hash = "sha256:404e1f1d254d314d55adb8d87f4f465c8693d6f902f67eb6ef5b4526dc58e6ea"},
|
||||
{file = "pyrsistent-0.18.0.tar.gz", hash = "sha256:773c781216f8c2900b42a7b638d5b517bb134ae1acbebe4d1e8f1f41ea60eb4b"},
|
||||
]
|
||||
pyusb = [
|
||||
{file = "pyusb-1.1.1-py3-none-any.whl", hash = "sha256:f18eb813d3a1439918071234589162c2f209a19adbeffeb1377ce078a4aebc70"},
|
||||
{file = "pyusb-1.1.1.tar.gz", hash = "sha256:7d449ad916ce58aff60b89aae0b65ac130f289c24d6a5b7b317742eccffafc38"},
|
||||
{file = "pyusb-1.2.1-py3-none-any.whl", hash = "sha256:2b4c7cb86dbadf044dfb9d3a4ff69fd217013dbe78a792177a3feb172449ea36"},
|
||||
{file = "pyusb-1.2.1.tar.gz", hash = "sha256:a4cc7404a203144754164b8b40994e2849fde1cfff06b08492f12fff9d9de7b9"},
|
||||
]
|
||||
qmk = [
|
||||
{file = "qmk-0.0.51-py2.py3-none-any.whl", hash = "sha256:5f676f389b2450b0956d7eb8e7e378d2e6690d5859a887c91876da0a5faf75ed"},
|
||||
{file = "qmk-0.0.51.tar.gz", hash = "sha256:efeef209cde1df92b9823db686d9684962cd00aae9f45ba5e3d494aa5b3c6b9a"},
|
||||
{file = "qmk-1.0.0-py2.py3-none-any.whl", hash = "sha256:63d69b97a533d91b0cfa7887e68cac7df52c6f7bddf4bf44d17ef1241d85ffff"},
|
||||
{file = "qmk-1.0.0.tar.gz", hash = "sha256:da62eec73c4548cc37b0b9be3937202dc3a301dc2f2663610ecca751a610f9ca"},
|
||||
]
|
||||
setuptools-scm = [
|
||||
{file = "setuptools_scm-6.0.1-py3-none-any.whl", hash = "sha256:c3bd5f701c8def44a5c0bfe8d407bef3f80342217ef3492b951f3777bd2d915c"},
|
||||
{file = "setuptools_scm-6.0.1.tar.gz", hash = "sha256:d1925a69cb07e9b29416a275b9fadb009a23c148ace905b2fb220649a6c18e92"},
|
||||
qmk-dotty-dict = [
|
||||
{file = "qmk_dotty_dict-1.3.0.post1-py3-none-any.whl", hash = "sha256:a9cb7fc3ff9631190fee0ecac14986a0ac7b4b6892347dc9d7486a4c4ea24492"},
|
||||
{file = "qmk_dotty_dict-1.3.0.post1.tar.gz", hash = "sha256:3b611e393660bfaa6835c68e94784bae80fe07b8490978b5ecab03a0d2fc7ea2"},
|
||||
]
|
||||
six = [
|
||||
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
|
||||
@@ -462,6 +463,6 @@ termcolor = [
|
||||
{file = "termcolor-1.1.0.tar.gz", hash = "sha256:1d6d69ce66211143803fbc56652b41d73b4a400a2891d7bf7a1cdf4c02de613b"},
|
||||
]
|
||||
yapf = [
|
||||
{file = "yapf-0.30.0-py2.py3-none-any.whl", hash = "sha256:3abf61ba67cf603069710d30acbc88cfe565d907e16ad81429ae90ce9651e0c9"},
|
||||
{file = "yapf-0.30.0.tar.gz", hash = "sha256:3000abee4c28daebad55da6c85f3cd07b8062ce48e2e9943c8da1b9667d48427"},
|
||||
{file = "yapf-0.31.0-py2.py3-none-any.whl", hash = "sha256:e3a234ba8455fe201eaa649cdac872d590089a18b661e39bbac7020978dd9c2e"},
|
||||
{file = "yapf-0.31.0.tar.gz", hash = "sha256:408fb9a2b254c302f49db83c59f9aa0b4b0fd0ec25be3a5c51181327922ff63d"},
|
||||
]
|
||||
|
||||
@@ -9,23 +9,27 @@ authors = []
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.8"
|
||||
appdirs = "^1.4.4"
|
||||
argcomplete = "^1.12.2"
|
||||
colorama = "^0.4.4"
|
||||
dotty-dict = "^1.3.0"
|
||||
hjson = "^3.0.2"
|
||||
jsonschema = "^3.2.0"
|
||||
milc = "^1.3.0"
|
||||
Pygments = "^2.8.0"
|
||||
appdirs = "*"
|
||||
argcomplete = "*"
|
||||
colorama = "*"
|
||||
hid = "*"
|
||||
hjson = "*"
|
||||
jsonschema = ">=3"
|
||||
milc = ">=1.4.2"
|
||||
Pygments = "*"
|
||||
pyusb = "*"
|
||||
qmk-dotty-dict = "*"
|
||||
|
||||
# This dependency is not mentioned in requirements.txt (QMK CLI is not a
|
||||
# library package that is required by the Python code in qmk_firmware), but is
|
||||
# required to build a proper nix-shell environment.
|
||||
qmk = "*"
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
nose2 = "^0.10.0"
|
||||
flake8 = "^3.8.4"
|
||||
hid = "^1.0.4"
|
||||
pep8-naming = "^0.11.1"
|
||||
pyusb = "^1.1.1"
|
||||
yapf = "^0.30.0"
|
||||
nose2 = "*"
|
||||
flake8 = "*"
|
||||
pep8-naming = "*"
|
||||
yapf = "*"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core>=1.0.0"]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM qmkfm/base_container
|
||||
FROM qmkfm/qmk_cli
|
||||
|
||||
# Basic upgrades; install sudo and SSH.
|
||||
RUN apt-get update && apt-get install --no-install-recommends -y \
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# QMK Vagrant Utilities
|
||||
|
||||
## Dockerfile
|
||||
Vagrant-friendly `qmkfm/base_container`.
|
||||
Vagrant-friendly `qmkfm/qmk_cli`.
|
||||
|
||||
In order for the Docker provider and `vagrant ssh` to function the container has a few extra requirements.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user