Merge pull request #138 from KMKfw/topic-prep-for-ckeys2019
Prep for ckeys2019: Round One
This commit is contained in:
commit
8100b91dbc
@ -1,26 +1,24 @@
|
||||
---
|
||||
version: 2
|
||||
jobs:
|
||||
test:
|
||||
build:
|
||||
docker:
|
||||
- image: 'kmkfw/base'
|
||||
|
||||
environment:
|
||||
KMK_TEST: 1
|
||||
PIPENV_VENV_IN_PROJECT: 1
|
||||
KMK_TEST: 1
|
||||
|
||||
steps:
|
||||
- checkout
|
||||
- restore_cache:
|
||||
keys:
|
||||
- v2-kmk-venv-{{ checksum "Pipfile.lock" }}
|
||||
|
||||
- run: make test
|
||||
- run: make dist
|
||||
- run: make dist-deploy
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
build-deploy:
|
||||
jobs:
|
||||
- test:
|
||||
- build:
|
||||
filters:
|
||||
branches:
|
||||
only: /.*/
|
||||
|
6
.gitignore
vendored
6
.gitignore
vendored
@ -102,6 +102,7 @@ venv.bak/
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.compiled/
|
||||
|
||||
.ampy
|
||||
.submodules
|
||||
@ -119,3 +120,8 @@ venv.bak/
|
||||
# Mountpoints
|
||||
mnt/
|
||||
mnt2/
|
||||
|
||||
# build artifacts
|
||||
kmk/release_info.py
|
||||
kmk/release_info.mpy
|
||||
*.mpy
|
||||
|
81
.s3cfg
Normal file
81
.s3cfg
Normal file
@ -0,0 +1,81 @@
|
||||
[default]
|
||||
access_key =
|
||||
access_token =
|
||||
add_encoding_exts =
|
||||
add_headers =
|
||||
bucket_location = US
|
||||
ca_certs_file =
|
||||
cache_file =
|
||||
check_ssl_certificate = True
|
||||
check_ssl_hostname = True
|
||||
cloudfront_host = cloudfront.amazonaws.com
|
||||
content_disposition =
|
||||
content_type =
|
||||
default_mime_type = binary/octet-stream
|
||||
delay_updates = False
|
||||
delete_after = False
|
||||
delete_after_fetch = False
|
||||
delete_removed = False
|
||||
dry_run = False
|
||||
enable_multipart = True
|
||||
encoding = UTF-8
|
||||
encrypt = False
|
||||
expiry_date =
|
||||
expiry_days =
|
||||
expiry_prefix =
|
||||
follow_symlinks = False
|
||||
force = False
|
||||
get_continue = False
|
||||
gpg_command = /usr/bin/gpg
|
||||
gpg_decrypt = %(gpg_command)s -d --verbose --no-use-agent --batch --yes --passphrase-fd %(passphrase_fd)s -o %(output_file)s %(input_file)s
|
||||
gpg_encrypt = %(gpg_command)s -c --verbose --no-use-agent --batch --yes --passphrase-fd %(passphrase_fd)s -o %(output_file)s %(input_file)s
|
||||
gpg_passphrase =
|
||||
guess_mime_type = True
|
||||
host_base = sfo2.digitaloceanspaces.com
|
||||
host_bucket = %(bucket)s.sfo2.digitaloceanspaces.com
|
||||
human_readable_sizes = False
|
||||
invalidate_default_index_on_cf = False
|
||||
invalidate_default_index_root_on_cf = True
|
||||
invalidate_on_cf = False
|
||||
kms_key =
|
||||
limit = -1
|
||||
limitrate = 0
|
||||
list_md5 = False
|
||||
log_target_prefix =
|
||||
long_listing = False
|
||||
max_delete = -1
|
||||
mime_type =
|
||||
multipart_chunk_size_mb = 15
|
||||
multipart_max_chunks = 10000
|
||||
preserve_attrs = True
|
||||
progress_meter = True
|
||||
proxy_host =
|
||||
proxy_port = 0
|
||||
put_continue = False
|
||||
recursive = False
|
||||
recv_chunk = 65536
|
||||
reduced_redundancy = False
|
||||
requester_pays = False
|
||||
restore_days = 1
|
||||
restore_priority = Standard
|
||||
secret_key =
|
||||
send_chunk = 65536
|
||||
server_side_encryption = False
|
||||
signature_v2 = False
|
||||
signurl_use_https = False
|
||||
simpledb_host = sdb.amazonaws.com
|
||||
skip_existing = False
|
||||
socket_timeout = 300
|
||||
stats = False
|
||||
stop_on_error = False
|
||||
storage_class =
|
||||
throttle_max = 100
|
||||
upload_id =
|
||||
urlencoding_mode = normal
|
||||
use_http_expect = False
|
||||
use_https = True
|
||||
use_mime_magic = True
|
||||
verbosity = WARNING
|
||||
website_endpoint = http://%(bucket)s.s3-website-%(location)s.amazonaws.com/
|
||||
website_error =
|
||||
website_index = index.html
|
20
Dockerfile
Normal file
20
Dockerfile
Normal file
@ -0,0 +1,20 @@
|
||||
FROM python:3.7-alpine
|
||||
|
||||
RUN mkdir -p /app
|
||||
WORKDIR /app
|
||||
|
||||
RUN apk update && apk add alpine-sdk coreutils curl gettext git git-lfs openssh rsync wget zip
|
||||
|
||||
RUN pip install pipenv
|
||||
|
||||
### Get a local copy of CircuitPython and its dependencies
|
||||
# Our absolute baseline is 4.0.0, which (as of writing) shares MPY compat
|
||||
# with all future versions. Our baseline will need to update as MPY compat
|
||||
# changes
|
||||
RUN git clone --branch 4.0.0 --depth 1 https://github.com/adafruit/CircuitPython /opt/circuitpython
|
||||
RUN git -C /opt/circuitpython submodule update --init
|
||||
|
||||
### Build the MPY compiler
|
||||
RUN make -C /opt/circuitpython/mpy-cross
|
||||
|
||||
ENV PATH=/opt/circuitpython/mpy-cross:${PATH}
|
@ -1,21 +0,0 @@
|
||||
# vim: ft=dockerfile
|
||||
|
||||
# Not using python:3.7 here because team-gcc-arm-embedded/ppa does not support
|
||||
# Ubuntu Cosmic or Debian Stretch, and Alpine, bizarrely, does not seem to
|
||||
# package GCC cross compilers
|
||||
FROM ubuntu:bionic
|
||||
|
||||
# Set up PPAs we'll need for Python and for GCC ARM
|
||||
RUN apt-get update && apt-get install -y software-properties-common
|
||||
RUN add-apt-repository ppa:deadsnakes/ppa
|
||||
RUN add-apt-repository ppa:team-gcc-arm-embedded/ppa
|
||||
|
||||
# Install Python
|
||||
RUN apt-get update && apt-get install -y python3.7 python3.7-dev build-essential pkg-config libffi-dev curl
|
||||
RUN curl https://bootstrap.pypa.io/get-pip.py | python3.7
|
||||
# Downgrade pip to work around https://github.com/pypa/pipenv/issues/2924
|
||||
RUN python3.7 -m pip install pip==18.0
|
||||
RUN python3.7 -m pip install pipenv==2018.7.1
|
||||
|
||||
# Install KMK CI and/or build-time dependencies
|
||||
RUN apt-get install -y gcc-arm-embedded gettext ssh wget unzip rsync git locales libusb-dev
|
75
Makefile
75
Makefile
@ -6,20 +6,73 @@
|
||||
|
||||
.DEFAULT: all
|
||||
|
||||
DIST_DESCRIBE_CMD = git describe --always --abbrev=0 --dirty --broken
|
||||
|
||||
DOCKER_BASE_TAG ?= latest
|
||||
DOCKER_TAG ?= latest
|
||||
|
||||
AMPY_PORT ?= /dev/ttyUSB0
|
||||
AMPY_BAUD ?= 115200
|
||||
AMPY_DELAY ?= 1.5
|
||||
ARDUINO ?= /usr/share/arduino
|
||||
PIPENV ?= $(shell which pipenv)
|
||||
PIPENV ?= $(shell which pipenv 2>/dev/null)
|
||||
|
||||
MPY_CROSS ?= $(shell which mpy-cross 2>/dev/null)
|
||||
MPY_FLAGS ?= '-O2'
|
||||
MPY_SOURCES = 'kmk/'
|
||||
MPY_TARGET_DIR ?= .compiled
|
||||
PY_KMK_TREE = $(shell find $(MPY_SOURCES) -name "*.py")
|
||||
DIST_DESCRIBE = $(shell $(DIST_DESCRIBE_CMD))
|
||||
|
||||
all: copy-kmk copy-bootpy copy-keymap
|
||||
|
||||
.docker_base: Dockerfile_base
|
||||
compile: $(MPY_TARGET_DIR)/.mpy.compiled
|
||||
|
||||
$(MPY_TARGET_DIR)/.mpy.compiled: $(PY_KMK_TREE)
|
||||
ifeq ($(MPY_CROSS),)
|
||||
@echo "===> Could not find mpy-cross in PATH, exiting"
|
||||
@false
|
||||
endif
|
||||
@echo "===> Compiling all py files to mpy with flags $(MPY_FLAGS)"
|
||||
@mkdir -p $(MPY_TARGET_DIR)
|
||||
@echo "KMK_RELEASE = '$(DIST_DESCRIBE)'" > $(MPY_SOURCES)/release_info.py
|
||||
@find $(MPY_SOURCES) -name "*.py" -exec sh -c 'mkdir -p $(MPY_TARGET_DIR)/$$(dirname {}) && mpy-cross $(MPY_FLAGS) {} -o $(MPY_TARGET_DIR)/$$(dirname {})/$$(basename -s .py {}).mpy' \;
|
||||
@rm -rf $(MPY_SOURCES)/release_info.py
|
||||
@touch $(MPY_TARGET_DIR)/.mpy.compiled
|
||||
|
||||
dist: dist/kmk-latest.zip dist/kmk-latest.unoptimized.zip dist/$(DIST_DESCRIBE).zip dist/$(DIST_DESCRIBE).unoptimized.zip
|
||||
|
||||
dist-deploy: devdeps dist
|
||||
@echo "===> Uploading artifacts to https://cdn.kmkfw.io/"
|
||||
@$(PIPENV) run s3cmd -c .s3cfg put -P dist/kmk-$(DIST_DESCRIBE).zip dist/kmk-$(DIST_DESCRIBE).unoptimized.zip s3://kmk-releases/ >/dev/null
|
||||
@[[ "$${CIRCLE_BRANCH}" == "master" ]] && echo "====> Uploading artifacts as 'latest' to https://cdn.kmkfw.io/" || true
|
||||
@[[ "$${CIRCLE_BRANCH}" == "master" ]] && $(PIPENV) run s3cmd -c .s3cfg put -P dist/kmk-latest.zip dist/kmk-latest.unoptimized.zip s3://kmk-releases/ >/dev/null || true
|
||||
@[[ -n "$${CIRCLE_TAG}" ]] && echo "====> Uploading artifacts as '$${CIRCLE_TAG}' to https://cdn.kmkfw.io/" || true
|
||||
@[[ -n "$${CIRCLE_TAG}" ]] && $(PIPENV) run s3cmd -c .s3cfg put -P dist/kmk-latest.zip s3://kmk-releases/$${CIRCLE_TAG}.zip >/dev/null || true
|
||||
@[[ -n "$${CIRCLE_TAG}" ]] && $(PIPENV) run s3cmd -c .s3cfg put -P dist/kmk-latest.unoptimized.zip s3://kmk-releases/$${CIRCLE_TAG}.unoptimized.zip >/dev/null || true
|
||||
|
||||
dist/kmk-latest.zip: compile
|
||||
@echo "===> Building optimized ZIP"
|
||||
@mkdir -p dist
|
||||
@cd $(MPY_TARGET_DIR) && zip -r ../dist/kmk-latest.zip kmk 2>&1 >/dev/null
|
||||
|
||||
dist/$(DIST_DESCRIBE).zip: dist/kmk-latest.zip
|
||||
@echo "===> Aliasing optimized ZIP"
|
||||
@cp dist/kmk-latest.zip dist/kmk-$(DIST_DESCRIBE).zip
|
||||
|
||||
dist/kmk-latest.unoptimized.zip: $(PY_KMK_TREE)
|
||||
@echo "===> Building unoptimized ZIP"
|
||||
@mkdir -p dist
|
||||
@echo "KMK_RELEASE = '$(DIST_DESCRIBE)'" > kmk/release_info.py
|
||||
@zip -r dist/kmk-latest.unoptimized.zip kmk 2>&1 >/dev/null
|
||||
@rm -rf kmk/release_info.py
|
||||
|
||||
dist/$(DIST_DESCRIBE).unoptimized.zip: dist/kmk-latest.unoptimized.zip
|
||||
@echo "===> Aliasing unoptimized ZIP"
|
||||
@cp dist/kmk-latest.unoptimized.zip dist/kmk-$(DIST_DESCRIBE).unoptimized.zip
|
||||
|
||||
.docker_base: Dockerfile
|
||||
@echo "===> Building Docker base image kmkfw/base:${DOCKER_BASE_TAG}"
|
||||
@docker build -f Dockerfile_base -t kmkfw/base:${DOCKER_BASE_TAG} .
|
||||
@docker build -t kmkfw/base:${DOCKER_BASE_TAG} .
|
||||
@touch .docker_base
|
||||
|
||||
docker-base: .docker_base
|
||||
@ -30,7 +83,7 @@ docker-base-deploy: docker-base
|
||||
|
||||
.devdeps: Pipfile.lock
|
||||
@echo "===> Installing dependencies with pipenv"
|
||||
@$(PIPENV) install --dev --ignore-pipfile
|
||||
@$(PIPENV) sync --dev
|
||||
@touch .devdeps
|
||||
|
||||
devdeps: .devdeps
|
||||
@ -41,14 +94,14 @@ lint: devdeps
|
||||
fix-isort: devdeps
|
||||
@find kmk/ tests/ user_keymaps/ -name "*.py" | xargs $(PIPENV) run isort
|
||||
|
||||
clean: clean-build-log
|
||||
clean:
|
||||
@echo "===> Cleaning build artifacts"
|
||||
@rm -rf .devdeps build
|
||||
|
||||
clean-build-log:
|
||||
@echo "===> Clearing previous .build.log"
|
||||
@rm -rf .build.log
|
||||
@rm -rf .devdeps build dist $(MPY_TARGET_DIR)
|
||||
|
||||
# This is mostly a leftover from the days we vendored stuff from
|
||||
# micropython-lib via submodules. Leaving this here mostly in case someone goes
|
||||
# exploring through the history of KMK's repo and manages to screw up their
|
||||
# repo state (those were glitchy times...)
|
||||
powerwash: clean
|
||||
@echo "===> Removing vendor/ to force a re-pull"
|
||||
@rm -rf vendor
|
||||
|
15
Pipfile
15
Pipfile
@ -4,19 +4,20 @@ verify_ssl = true
|
||||
name = "pypi"
|
||||
|
||||
[packages]
|
||||
pydux = "*"
|
||||
|
||||
[dev-packages]
|
||||
adafruit-ampy = "*"
|
||||
"flake8" = "*"
|
||||
"flake8-comprehensions" = "*"
|
||||
ipython = "*"
|
||||
ipdb = "*"
|
||||
"flake8-commas" = "*"
|
||||
isort = "*"
|
||||
"flake8-comprehensions" = "*"
|
||||
"flake8-isort" = "*"
|
||||
neovim = "*"
|
||||
"flake8-per-file-ignores" = "*"
|
||||
"python-magic" = "*"
|
||||
adafruit-ampy = "*"
|
||||
ipdb = "*"
|
||||
ipython = "*"
|
||||
isort = "*"
|
||||
neovim = "*"
|
||||
s3cmd = "*"
|
||||
|
||||
[requires]
|
||||
python_version = "3.7"
|
||||
|
214
Pipfile.lock
generated
214
Pipfile.lock
generated
@ -1,7 +1,7 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "96625b372d35c7f5ed0fd3289ba61afd0bcc034ddad31feb958a107e2751fb0a"
|
||||
"sha256": "8f51706fcfb278497a6d3083109744210150dc3c644ead11eda3e3cd806e2e14"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
@ -15,23 +15,15 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"default": {
|
||||
"pydux": {
|
||||
"hashes": [
|
||||
"sha256:5cb9217be9d8c7ff79b028f6f02597bbb055b107ce8eecbe5f631f3fc76d793f",
|
||||
"sha256:bed123b5255d566f792b9ceebad87e3f9c1d2d85abed4b9a9475ffc831035879"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.2.2"
|
||||
}
|
||||
},
|
||||
"default": {},
|
||||
"develop": {
|
||||
"adafruit-ampy": {
|
||||
"hashes": [
|
||||
"sha256:1055827874010f48c7dbd3cde4b1d7c6f6732661fad193b188a398e88961fc62"
|
||||
"sha256:46cbb1ebb585c2c01b9d34625dbef618df95c4256a1fc6ac13cb13bbd4a8b6c0",
|
||||
"sha256:cd8d6b831a1c76d712e30e224e3945428f77bb0c6cccbf06239b31aaf4d4e5b7"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.0.5"
|
||||
"version": "==1.0.7"
|
||||
},
|
||||
"backcall": {
|
||||
"hashes": [
|
||||
@ -42,25 +34,25 @@
|
||||
},
|
||||
"click": {
|
||||
"hashes": [
|
||||
"sha256:29f99fc6125fbc931b758dc053b3114e55c77a6e4c6c3a2674a2dc986016381d",
|
||||
"sha256:f15516df478d5a56180fbf80e68f206010e6d160fc39fa508b65e035fd75130b"
|
||||
"sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13",
|
||||
"sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7"
|
||||
],
|
||||
"version": "==6.7"
|
||||
"version": "==7.0"
|
||||
},
|
||||
"decorator": {
|
||||
"hashes": [
|
||||
"sha256:2c51dff8ef3c447388fe5e4453d24a2bf128d3a4c32af3fabef1f01c6851ab82",
|
||||
"sha256:c39efa13fbdeb4506c476c9b3babf6a718da943dab7811c206005a4a956c080c"
|
||||
"sha256:86156361c50488b84a3f148056ea716ca587df2f0de1d34750d35c21312725de",
|
||||
"sha256:f069f3a01830ca754ba5258fde2278454a0b5b79e0d7f5c13b3b97e57d4acff6"
|
||||
],
|
||||
"version": "==4.3.0"
|
||||
"version": "==4.4.0"
|
||||
},
|
||||
"flake8": {
|
||||
"hashes": [
|
||||
"sha256:7253265f7abd8b313e3892944044a365e3f4ac3fcdcfb4298f55ee9ddf188ba0",
|
||||
"sha256:c7841163e2b576d435799169b78703ad6ac1bbb0f199994fc05f700b2a90ea37"
|
||||
"sha256:6a35f5b8761f45c5513e3405f110a86bea57982c3b75b766ce7b65217abe1670",
|
||||
"sha256:c01f8a3963b3571a8e6bd7a4063359aff90749e160778e03817cd9b71c9e07d2"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.5.0"
|
||||
"version": "==3.6.0"
|
||||
},
|
||||
"flake8-commas": {
|
||||
"hashes": [
|
||||
@ -72,27 +64,27 @@
|
||||
},
|
||||
"flake8-comprehensions": {
|
||||
"hashes": [
|
||||
"sha256:b83891fec0e680b07aa1fd92e53eb6993be29a0f3673a09badbe8da307c445e0",
|
||||
"sha256:e4ccf1627f75f192eb7fde640f5edb81c98d04b1390df9d4145ffd7710bb1ef2"
|
||||
"sha256:35f826956e87f230415cde9c3b8b454e785736cf5ff0be551c441b41b937f699",
|
||||
"sha256:f0b61d983d608790abf3664830d68efd3412265c2d10f6a4ba1a353274dbeb64"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.4.1"
|
||||
"version": "==2.1.0"
|
||||
},
|
||||
"flake8-isort": {
|
||||
"hashes": [
|
||||
"sha256:298d7904ac3a46274edf4ce66fd7e272c2a60c34c3cc999dea000608d64e5e6e",
|
||||
"sha256:5992850626ce96547b1f1c7e8a7f0ef49ab2be44eca2177934566437b636fa3c"
|
||||
"sha256:1e67b6b90a9b980ac3ff73782087752d406ce0a729ed928b92797f9fa188917e",
|
||||
"sha256:81a8495eefed3f2f63f26cd2d766c7b1191e923a15b9106e6233724056572c68"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.5"
|
||||
"version": "==2.7.0"
|
||||
},
|
||||
"flake8-per-file-ignores": {
|
||||
"hashes": [
|
||||
"sha256:3c4b1d770fa509aaad997ca147bd3533b730c3f6c48290b69a4265072c465522",
|
||||
"sha256:4ee4f24cbea5e18e1fefdfccb043e819caf483d16d08e39cb6df5d18b0407275"
|
||||
"sha256:2ee2b61e23cc84e7e76b8f7b2ffc135ec0c3331cba776bb5c03ab5d562b0f40c",
|
||||
"sha256:aeac75cc29425b3b4b73eaa92941939dbe16b83f689381ebaef1471982fdcb47"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.6"
|
||||
"version": "==0.8.1"
|
||||
},
|
||||
"greenlet": {
|
||||
"hashes": [
|
||||
@ -120,18 +112,18 @@
|
||||
},
|
||||
"ipdb": {
|
||||
"hashes": [
|
||||
"sha256:7081c65ed7bfe7737f83fa4213ca8afd9617b42ff6b3f1daf9a3419839a2a00a"
|
||||
"sha256:dce2112557edfe759742ca2d0fee35c59c97b0cc7a05398b791079d78f1519ce"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.11"
|
||||
"version": "==0.12"
|
||||
},
|
||||
"ipython": {
|
||||
"hashes": [
|
||||
"sha256:007dcd929c14631f83daff35df0147ea51d1af420da303fd078343878bd5fb62",
|
||||
"sha256:b0f2ef9eada4a68ef63ee10b6dde4f35c840035c50fd24265f8052c98947d5a4"
|
||||
"sha256:11067ab11d98b1e6c7f0993506f7a5f8a91af420f7e82be6575fcb7a6ca372a0",
|
||||
"sha256:60bc55c2c1d287161191cc2469e73c116d9b634cff25fe214a43cba7cec94c79"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==6.5.0"
|
||||
"version": "==7.6.1"
|
||||
},
|
||||
"ipython-genutils": {
|
||||
"hashes": [
|
||||
@ -142,19 +134,18 @@
|
||||
},
|
||||
"isort": {
|
||||
"hashes": [
|
||||
"sha256:1153601da39a25b14ddc54955dbbacbb6b2d19135386699e2ad58517953b34af",
|
||||
"sha256:b9c40e9750f3d77e6e4d441d8b0266cf555e7cdabdcff33c4fd06366ca761ef8",
|
||||
"sha256:ec9ef8f4a9bc6f71eec99e1806bfa2de401650d996c59330782b89a5555c1497"
|
||||
"sha256:54da7e92468955c4fceacd0c86bd0ec997b0e1ee80d97f67c35a78b719dccab1",
|
||||
"sha256:6e811fcb295968434526407adb8796944f1988c5b65e8139058f2014cbe100fd"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==4.3.4"
|
||||
"version": "==4.3.21"
|
||||
},
|
||||
"jedi": {
|
||||
"hashes": [
|
||||
"sha256:b409ed0f6913a701ed474a614a3bb46e6953639033e31f769ca7581da5bd1ec1",
|
||||
"sha256:c254b135fb39ad76e78d4d8f92765ebc9bf92cbc76f49e97ade1d5f5121e1f6f"
|
||||
"sha256:53c850f1a7d3cfcd306cc513e2450a54bdf5cacd7604b74e42dd1f0758eaaf36",
|
||||
"sha256:e07457174ef7cb2342ff94fa56484fe41cec7ef69b0059f01d3f812379cb6f7c"
|
||||
],
|
||||
"version": "==0.12.1"
|
||||
"version": "==0.14.1"
|
||||
},
|
||||
"mccabe": {
|
||||
"hashes": [
|
||||
@ -165,37 +156,39 @@
|
||||
},
|
||||
"msgpack": {
|
||||
"hashes": [
|
||||
"sha256:0b3b1773d2693c70598585a34ca2715873ba899565f0a7c9a1545baef7e7fbdc",
|
||||
"sha256:0bae5d1538c5c6a75642f75a1781f3ac2275d744a92af1a453c150da3446138b",
|
||||
"sha256:0ee8c8c85aa651be3aa0cd005b5931769eaa658c948ce79428766f1bd46ae2c3",
|
||||
"sha256:1369f9edba9500c7a6489b70fdfac773e925342f4531f1e3d4c20ac3173b1ae0",
|
||||
"sha256:22d9c929d1d539f37da3d1b0e16270fa9d46107beab8c0d4d2bddffffe895cee",
|
||||
"sha256:2ff43e3247a1e11d544017bb26f580a68306cec7a6257d8818893c1fda665f42",
|
||||
"sha256:31a98047355d34d047fcdb55b09cb19f633cf214c705a765bd745456c142130c",
|
||||
"sha256:8767eb0032732c3a0da92cbec5ac186ef89a3258c6edca09161472ca0206c45f",
|
||||
"sha256:8acc8910218555044e23826980b950e96685dc48124a290c86f6f41a296ea172",
|
||||
"sha256:ab189a6365be1860a5ecf8159c248f12d33f79ea799ae9695fa6a29896dcf1d4",
|
||||
"sha256:cfd6535feb0f1cf1c7cdb25773e965cc9f92928244a8c3ef6f8f8a8e1f7ae5c4",
|
||||
"sha256:e274cd4480d8c76ec467a85a9c6635bbf2258f0649040560382ab58cabb44bcf",
|
||||
"sha256:f86642d60dca13e93260187d56c2bef2487aa4d574a669e8ceefcf9f4c26fd00",
|
||||
"sha256:f8a57cbda46a94ed0db55b73e6ab0c15e78b4ede8690fa491a0e55128d552bb0",
|
||||
"sha256:fcea97a352416afcbccd7af9625159d80704a25c519c251c734527329bb20d0e"
|
||||
"sha256:26cb40116111c232bc235ce131cc3b4e76549088cb154e66a2eb8ff6fcc907ec",
|
||||
"sha256:300fd3f2c664a3bf473d6a952f843b4a71454f4c592ed7e74a36b205c1782d28",
|
||||
"sha256:3129c355342853007de4a2a86e75eab966119733eb15748819b6554363d4e85c",
|
||||
"sha256:31f6d645ee5a97d59d3263fab9e6be76f69fa131cddc0d94091a3c8aca30d67a",
|
||||
"sha256:3ce7ef7ee2546c3903ca8c934d09250531b80c6127e6478781ae31ed835aac4c",
|
||||
"sha256:4008c72f5ef2b7936447dcb83db41d97e9791c83221be13d5e19db0796df1972",
|
||||
"sha256:62bd8e43d204580308d477a157b78d3fee2fb4c15d32578108dc5d89866036c8",
|
||||
"sha256:70cebfe08fb32f83051971264466eadf183101e335d8107b80002e632f425511",
|
||||
"sha256:72cb7cf85e9df5251abd7b61a1af1fb77add15f40fa7328e924a9c0b6bc7a533",
|
||||
"sha256:7c55649965c35eb32c499d17dadfb8f53358b961582846e1bc06f66b9bccc556",
|
||||
"sha256:86b963a5de11336ec26bc4f839327673c9796b398b9f1fe6bb6150c2a5d00f0f",
|
||||
"sha256:8c73c9bcdfb526247c5e4f4f6cf581b9bb86b388df82cfcaffde0a6e7bf3b43a",
|
||||
"sha256:8e68c76c6aff4849089962d25346d6784d38e02baa23ffa513cf46be72e3a540",
|
||||
"sha256:97ac6b867a8f63debc64f44efdc695109d541ecc361ee2dce2c8884ab37360a1",
|
||||
"sha256:9d4f546af72aa001241d74a79caec278bcc007b4bcde4099994732e98012c858",
|
||||
"sha256:a28e69fe5468c9f5251c7e4e7232286d71b7dfadc74f312006ebe984433e9746",
|
||||
"sha256:fd509d4aa95404ce8d86b4e32ce66d5d706fd6646c205e1c2a715d87078683a2"
|
||||
],
|
||||
"version": "==0.5.6"
|
||||
"version": "==0.6.1"
|
||||
},
|
||||
"neovim": {
|
||||
"hashes": [
|
||||
"sha256:6ce58a742e0427491c0e1c8108556ee72ba33844209bd9e226b8da9538299276"
|
||||
"sha256:a6a0e7a5b4433bf4e6ddcbc5c5ff44170be7d84259d002b8e8d8fb4ee78af60f"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.2.6"
|
||||
"version": "==0.3.1"
|
||||
},
|
||||
"parso": {
|
||||
"hashes": [
|
||||
"sha256:35704a43a3c113cce4de228ddb39aab374b8004f4f2407d070b6a2ca784ce8a2",
|
||||
"sha256:895c63e93b94ac1e1690f5fdd40b65f07c8171e3e53cbd7793b5b96c0e0a7f24"
|
||||
"sha256:63854233e1fadb5da97f2744b6b24346d2750b85965e7e399bec1620232797dc",
|
||||
"sha256:666b0ee4a7a1220f65d367617f2cd3ffddff3e205f3f16a0284df30e774c2a9c"
|
||||
],
|
||||
"version": "==0.3.1"
|
||||
"version": "==0.5.1"
|
||||
},
|
||||
"pathmatch": {
|
||||
"hashes": [
|
||||
@ -205,26 +198,26 @@
|
||||
},
|
||||
"pexpect": {
|
||||
"hashes": [
|
||||
"sha256:2a8e88259839571d1251d278476f3eec5db26deb73a70be5ed5dc5435e418aba",
|
||||
"sha256:3fbd41d4caf27fa4a377bfd16fef87271099463e6fa73e92a52f92dfee5d425b"
|
||||
"sha256:2094eefdfcf37a1fdbfb9aa090862c1a4878e5c7e0e7e7088bdb511c558e5cd1",
|
||||
"sha256:9e2c1fd0e6ee3a49b28f95d4b33bc389c89b20af6a1255906e90ff1262ce62eb"
|
||||
],
|
||||
"markers": "sys_platform != 'win32'",
|
||||
"version": "==4.6.0"
|
||||
"version": "==4.7.0"
|
||||
},
|
||||
"pickleshare": {
|
||||
"hashes": [
|
||||
"sha256:84a9257227dfdd6fe1b4be1319096c20eb85ff1e82c7932f36efccfe1b09737b",
|
||||
"sha256:c9a2541f25aeabc070f12f452e1f2a8eae2abd51e1cd19e8430402bdf4c1d8b5"
|
||||
"sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca",
|
||||
"sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56"
|
||||
],
|
||||
"version": "==0.7.4"
|
||||
"version": "==0.7.5"
|
||||
},
|
||||
"prompt-toolkit": {
|
||||
"hashes": [
|
||||
"sha256:1df952620eccb399c53ebb359cc7d9a8d3a9538cb34c5a1344bdbeb29fbcc381",
|
||||
"sha256:3f473ae040ddaa52b52f97f6b4a493cfa9f5920c255a12dc56a7d34397a398a4",
|
||||
"sha256:858588f1983ca497f1cf4ffde01d978a3ea02b01c8a26a8bbc5cd2e66d816917"
|
||||
"sha256:11adf3389a996a6d45cc277580d0d53e8a5afd281d0c9ec71b28e6f121463780",
|
||||
"sha256:2519ad1d8038fd5fc8e770362237ad0364d16a7650fb5724af6997ed5515e3c1",
|
||||
"sha256:977c6583ae813a37dc1c2e1b715892461fcbdaa57f6fc62f33a528c4886c8f55"
|
||||
],
|
||||
"version": "==1.0.15"
|
||||
"version": "==2.0.9"
|
||||
},
|
||||
"ptyprocess": {
|
||||
"hashes": [
|
||||
@ -235,24 +228,30 @@
|
||||
},
|
||||
"pycodestyle": {
|
||||
"hashes": [
|
||||
"sha256:682256a5b318149ca0d2a9185d365d8864a768a28db66a84a2ea946bcc426766",
|
||||
"sha256:6c4245ade1edfad79c3446fadfc96b0de2759662dc29d07d80a6f27ad1ca6ba9"
|
||||
"sha256:cbc619d09254895b0d12c2c691e237b2e91e9b2ecf5e84c26b35400f93dcfb83",
|
||||
"sha256:cbfca99bd594a10f674d0cd97a3d802a1fdef635d4361e1a2658de47ed261e3a"
|
||||
],
|
||||
"version": "==2.3.1"
|
||||
"version": "==2.4.0"
|
||||
},
|
||||
"pyflakes": {
|
||||
"hashes": [
|
||||
"sha256:08bd6a50edf8cffa9fa09a463063c425ecaaf10d1eb0335a7e8b1401aef89e6f",
|
||||
"sha256:8d616a382f243dbf19b54743f280b80198be0bca3a5396f1d2e1fca6223e8805"
|
||||
"sha256:9a7662ec724d0120012f6e29d6248ae3727d821bba522a0e6b356eff19126a49",
|
||||
"sha256:f661252913bc1dbe7fcfcbf0af0db3f42ab65aabd1a6ca68fe5d466bace94dae"
|
||||
],
|
||||
"version": "==1.6.0"
|
||||
"version": "==2.0.0"
|
||||
},
|
||||
"pygments": {
|
||||
"hashes": [
|
||||
"sha256:78f3f434bcc5d6ee09020f92ba487f95ba50f1e3ef83ae96b9d5ffa1bab25c5d",
|
||||
"sha256:dbae1046def0efb574852fab9e90209b23f556367b5a320c0bcb871c77c3e8cc"
|
||||
"sha256:71e430bc85c88a430f000ac1d9b331d2407f681d6f6aec95e8bcfbc3df5b0127",
|
||||
"sha256:881c4c157e45f30af185c1ffe8d549d48ac9127433f2c380c24b84572ad66297"
|
||||
],
|
||||
"version": "==2.2.0"
|
||||
"version": "==2.4.2"
|
||||
},
|
||||
"pynvim": {
|
||||
"hashes": [
|
||||
"sha256:cf6490c4e586c9da01a32f3e0ae21c61342d7ea171e06025bda210bdc95cbe05"
|
||||
],
|
||||
"version": "==0.3.2"
|
||||
},
|
||||
"pyserial": {
|
||||
"hashes": [
|
||||
@ -261,32 +260,49 @@
|
||||
],
|
||||
"version": "==3.4"
|
||||
},
|
||||
"python-dateutil": {
|
||||
"hashes": [
|
||||
"sha256:7e6584c74aeed623791615e26efd690f29817a27c73085b78e4bad02493df2fb",
|
||||
"sha256:c89805f6f4d64db21ed966fda138f8a5ed7a4fdbc1a8ee329ce1b74e3c74da9e"
|
||||
],
|
||||
"version": "==2.8.0"
|
||||
},
|
||||
"python-dotenv": {
|
||||
"hashes": [
|
||||
"sha256:122290a38ece9fe4f162dc7c95cae3357b983505830a154d3c98ef7f6c6cea77",
|
||||
"sha256:4a205787bc829233de2a823aa328e44fd9996fedb954989a21f1fc67c13d7a77"
|
||||
"sha256:debd928b49dbc2bf68040566f55cdb3252458036464806f4094487244e2a4093",
|
||||
"sha256:f157d71d5fec9d4bd5f51c82746b6344dffa680ee85217c123f4a0c8117c4544"
|
||||
],
|
||||
"version": "==0.9.1"
|
||||
"version": "==0.10.3"
|
||||
},
|
||||
"simplegeneric": {
|
||||
"python-magic": {
|
||||
"hashes": [
|
||||
"sha256:dc972e06094b9af5b855b3df4a646395e43d1c9d0d39ed345b7393560d0b9173"
|
||||
"sha256:f2674dcfad52ae6c49d4803fa027809540b130db1dec928cfbb9240316831375",
|
||||
"sha256:f3765c0f582d2dfc72c15f3b5a82aecfae9498bd29ca840d72f37d7bd38bfcd5"
|
||||
],
|
||||
"version": "==0.8.1"
|
||||
"index": "pypi",
|
||||
"version": "==0.4.15"
|
||||
},
|
||||
"s3cmd": {
|
||||
"hashes": [
|
||||
"sha256:231fe00daedb13095ce38ccf264bbe81d133f6e82f1484ef2f5efdc3f21b9ee8",
|
||||
"sha256:6d7a3a49a12048a6c8e5fbb5ef42a83101e2fc69f16013d292b7f37ecfc574a0"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.0.2"
|
||||
},
|
||||
"six": {
|
||||
"hashes": [
|
||||
"sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9",
|
||||
"sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb"
|
||||
"sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c",
|
||||
"sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"
|
||||
],
|
||||
"version": "==1.11.0"
|
||||
"version": "==1.12.0"
|
||||
},
|
||||
"testfixtures": {
|
||||
"hashes": [
|
||||
"sha256:334497d26344e8c0c5d01b4d785a1c83464573151e6a5f7ab250eb7981d452ec",
|
||||
"sha256:53c06c1feb0bf378d63c54d1d96858978422d5a34793b39f0dcb0e44f8ec26f4"
|
||||
"sha256:665a298976c8d77f311b65c46f16b7cda7229a47dff5ad7c822e5b3371a439e2",
|
||||
"sha256:9d230c5c80746f9f86a16a1f751a5cf5d8e317d4cc48243a19fb180d22303bce"
|
||||
],
|
||||
"version": "==6.3.0"
|
||||
"version": "==6.10.0"
|
||||
},
|
||||
"traitlets": {
|
||||
"hashes": [
|
||||
@ -297,11 +313,11 @@
|
||||
},
|
||||
"typing": {
|
||||
"hashes": [
|
||||
"sha256:4027c5f6127a6267a435201981ba156de91ad0d1d98e9ddc2aa173453453492d",
|
||||
"sha256:57dcf675a99b74d64dacf6fba08fb17cf7e3d5fdff53d4a30ea2a5e7e52543d4",
|
||||
"sha256:a4c8473ce11a65999c8f59cb093e70686b6c84c98df58c1dae9b3b196089858a"
|
||||
"sha256:38566c558a0a94d6531012c8e917b1b8518a41e418f7f15f00e129cc80162ad3",
|
||||
"sha256:53765ec4f83a2b720214727e319607879fec4acde22c4fbb54fa2604e79e44ce",
|
||||
"sha256:84698954b4e6719e912ef9a42a2431407fe3755590831699debda6fba92aac55"
|
||||
],
|
||||
"version": "==3.6.6"
|
||||
"version": "==3.7.4"
|
||||
},
|
||||
"wcwidth": {
|
||||
"hashes": [
|
||||
|
201
README.md
201
README.md
@ -1,99 +1,136 @@
|
||||
# KMK: Python-based keyboard firmware for humans (and ARM microcontrollers)
|
||||
# KMK: Clackety Keyboards Powered by Python
|
||||
|
||||
[](https://circleci.com/gh/KMKfw/kmk_firmware/tree/master)[](https://cla-assistant.io/KMKfw/kmk_firmware)
|
||||
KMK is a feature-rich and beginner-friendly firmware for computer keyboards
|
||||
written and configured in
|
||||
[CircuitPython](https://github.com/adafruit/circuitpython). **KMK is currently
|
||||
in public beta, however should handle almost all workflows without major
|
||||
issues**.
|
||||
|
||||
#### [Join our Matrix community for chat and support!](https://matrix.to/#/+kmk:kmkfw.io)
|
||||
You can always find the latest releases on our CDN, in [compiled and
|
||||
optimized](https://cdn.kmkfw.io/kmk-latest.zip) and [raw, hackable text
|
||||
file](https://cdn.kmkfw.io/kmk-latest.unoptimized.zip) forms. These follow the
|
||||
`master` branch here on GitHub.
|
||||
|
||||
[Or, head directly to the #support channel](https://matrix.to/#/#support:kmkfw.io)
|
||||
> If you need support with KMK or just want to say hi, find us in
|
||||
> [#general:kmkfw.io on Matrix](https://matrix.to/#/#general:kmkfw.io). Other
|
||||
> channels exist in [the same community](https://matrix.to/#/+kmk:kmkfw.io).
|
||||
> These channels are bridged to Discord [here](https://discordapp.com/widget?id=493256121075761173&theme=dark)
|
||||
> for convenience.
|
||||
>
|
||||
> If you ask for help on chat or open a bug report, if possible please give us
|
||||
> your commit SHA, found by running `from kmk.consts import KMK_RELEASE;
|
||||
> print(KMK_RELEASE)` in the REPL on your controller.
|
||||
|
||||
If you can't or won't use the Matrix infrastructure, a (possibly fragile) bridge
|
||||
to Discord exists
|
||||
[here](https://discordapp.com/widget?id=493256121075761173&theme=dark).
|
||||
## Features
|
||||
|
||||
<hr/>
|
||||
- Fully configured through a single, easy to understand Python file that lives
|
||||
on a "flash-drive"-esque space on your microcontroller - edit on the go
|
||||
without DFU or other devtooling available!
|
||||
- Single-piece or [two-piece split
|
||||
keyboards](https://github.com/KMKfw/kmk_firmware/blob/master/docs/split_keyboards.md)
|
||||
are supported
|
||||
- [Chainable
|
||||
keys](https://github.com/KMKfw/kmk_firmware/blob/master/docs/keys.md) such as
|
||||
`KC.LWIN(KC.L)` to lock the screen on a Windows PC
|
||||
- [Built-in unicode macros, including
|
||||
emojis](https://github.com/KMKfw/kmk_firmware/blob/master/docs/sequences.md)
|
||||
- [Multiple vim-inspired leader key
|
||||
modes](https://github.com/KMKfw/kmk_firmware/blob/master/docs/leader.md)
|
||||
- [RGB underglow](https://github.com/KMKfw/kmk_firmware/blob/master/docs/rgb.md)
|
||||
and [LED
|
||||
backlights](https://github.com/KMKfw/kmk_firmware/blob/master/docs/led.md)
|
||||
- One key can turn into many more based on [how many times you tap
|
||||
it](https://github.com/KMKfw/kmk_firmware/blob/master/docs/tapdance.md)
|
||||
|
||||
KMK is a firmware for (usually mechanical) keyboards, running on
|
||||
[CircuitPython](https://github.com/adafruit/circuitpython). It aims to provide a
|
||||
means to write complex keyboard configurations quickly, without having to learn
|
||||
much "real" programming, while preserving at least some of the hackability and
|
||||
DIY spirit of CircuitPython. Learn more about the rationale of KMK in `Why KMK?`
|
||||
below.
|
||||
Coming (hopefully) soon: Bluetooth support! Stay tuned.
|
||||
|
||||
This project is currently written and maintained by:
|
||||
## Getting Started
|
||||
|
||||
- [Josh Klar (@klardotsh)](https://github.com/klardotsh)
|
||||
- Start by grabbing a supported microcontroller. Broadly speaking, KMK supports
|
||||
any device CircuitPython does, but KMK requires a decent bit of RAM, and in
|
||||
general requires a working USB HID stack, which leads us to recommend the
|
||||
following controllers:
|
||||
|
||||
* [Adafruit ItsyBitsy M4 Express](https://www.adafruit.com/product/3800)\*
|
||||
* [Adafruit Feather M4 Express](https://www.adafruit.com/product/3857)
|
||||
* [Adafruit Feather nRF52840 Express](https://www.adafruit.com/product/4062)
|
||||
* [MakerDiary nRF52840 MDK](https://store.makerdiary.com/collections/frontpage/products/nrf52840-mdk-iot-development-kit)
|
||||
* [SparkFun Pro nRF52840 Mini](https://www.sparkfun.com/products/15025)
|
||||
|
||||
> \* The ItsyBitsy M4 Express is the only controller we currently support in
|
||||
> non-handwired configurations, using our [ItsyBitsy to Pro Micro converter
|
||||
> PCB](https://github.com/KMKfw/kmk_firmware/tree/master/hardware) designed by
|
||||
> @siddacious and @kdb424. It is our most-recommended MCU until [the ItsyBitsy is
|
||||
> updated with an nRF52840
|
||||
> chip](https://blog.adafruit.com/2019/01/26/comingsoon-itsybitsy-nrf52480-runs-circuitpython-adafruit-circuitpython-adafruit-circuitpython/)
|
||||
|
||||
> Some other controllers, such as the [Feather M0 Express](https://www.adafruit.com/product/3403),
|
||||
> are usable in reduced functionality modes and may require custom hackery.
|
||||
> For example, @kdb424 uses a ItsyBitsy M0 Express as a barebones matrix scanner
|
||||
> in a split keyboard configuration
|
||||
> [here](https://github.com/KMKfw/kmk_firmware/commit/1f84079dc8aadeb9627c4762d9f9fb855292c4a2).
|
||||
> Use such controllers at your own risk.
|
||||
|
||||
- Ensure CircuitPython 4.0.0 or newer is installed on your controller. We
|
||||
recommend the latest stable version from
|
||||
[circuitpython.org](https://circuitpython.org/downloads). Flashing
|
||||
instructions vary by device: all Adafruit boards can be flashed [using their
|
||||
instructions](https://learn.adafruit.com/welcome-to-circuitpython/installing-circuitpython),
|
||||
other boards generally have their instructions [in the CircuitPython
|
||||
repository](https://github.com/adafruit/circuitpython) under the
|
||||
`ports/atmel-samd/boards/<your board here>` and `ports/nrf/boards/<your board
|
||||
here>` directories. If all else fails, consult your device's official
|
||||
documentation.
|
||||
|
||||
- [Download the latest KMK release](https://cdn.kmkfw.io/kmk-latest.zip) and
|
||||
extract the zip to the USB drive exposed by CircuitPython, typically labeled
|
||||
`CIRCUITPY`. Again, [we'll defer to Adafruit's
|
||||
documentation](https://learn.adafruit.com/welcome-to-circuitpython/circuitpython-libraries)
|
||||
on adding libraries to a CircuitPython installation.
|
||||
|
||||
- Define your keyboard in a file called `main.py` on this `CIRCUITPY` drive and
|
||||
get tinkering! Examples of both handwired and ProMicro-\>ItsyBitsy converted
|
||||
boards exist under the `user_keymaps/` tree, and feel free to submit a pull
|
||||
request of your own definitions! At this point, you'll want to look through
|
||||
`docs/` in the source tree to explore the functionality at your disposal.
|
||||
|
||||
> Linux, BSD, and MacOS users can also make use of the `Makefile` provided in
|
||||
> this source tree to flash KMK and a keymap using `rsync`. This is advanced
|
||||
> functionality outside the scope of this README, but it's documented in the
|
||||
> `docs/` tree.
|
||||
|
||||
## The KMK Team
|
||||
|
||||
KMK is primarily written and maintained by @klardotsh and @kdb424, but
|
||||
contributions are welcome from all, whether it's in the form of code,
|
||||
documentation, hardware designs, feature ideas, or anything else that comes to
|
||||
mind. KMK's contributors and other helpers are listed alphabetically by username
|
||||
below (we'll try to keep this up to date!):
|
||||
|
||||
- [Dan Halbert (@dhalbert)](https://github.com/dhalbert)
|
||||
- [Elvis Pfützenreuter (@elvis-epx)](https://github.com/elvis-epx)
|
||||
- [Kyle Brown (@kdb424)](https://github.com/kdb424)
|
||||
|
||||
With community help from:
|
||||
|
||||
- [Josh Klar (@klardotsh)](https://github.com/klardotsh)
|
||||
- [Limor Fried (@ladyada)](https://github.com/ladyada)
|
||||
- [Ryan Karpinski (@rk463345)](https://github.com/rk463345)
|
||||
- [@siddacious](https://github.com/siddacious)
|
||||
- [Scott Shawcroft (@tannewt)](https://github.com/tannewt)
|
||||
|
||||
> Scott is the lead developer of the CircuitPython project itself at Adafruit.
|
||||
> KMK, however, is not officially sponsored by Adafruit, and is an independent
|
||||
> project.
|
||||
|
||||
Lastly, we'd like to make a couple of shoutouts to people not directly
|
||||
affiliated with the project in any way, but who have helped or inspired us along
|
||||
the way:
|
||||
|
||||
- [Jack Humbert (@jackhumbert)](https://jackhumbert.com/), for writing QMK.
|
||||
Without QMK, I'd have never been exposed to the wonderful world of
|
||||
programmable keyboards. He's also just an awesometastic human in general, if
|
||||
you ever catch him on Discord/Reddit/etc. Jack also makes fantastic hardware -
|
||||
check out [his store](https://olkb.com)!
|
||||
|
||||
- [Dan Halbert (@dhalbert)](https://danhalbert.org/), for his amazing and
|
||||
unjudgemental support of two random dudes on Github asking all sorts of
|
||||
bizzare (okay... and occasionally dumb) questions on the MicroPython and
|
||||
CircuitPython Github projects and the Adafruit Discord. Dan, without your help
|
||||
and pointers (even when those pointers are "Remember you're working with a
|
||||
microcontroller with a few MHz of processing speed and a few KB of RAM"), this
|
||||
project would have never gotten off the ground. Thank you, and an extended
|
||||
thanks to Adafruit.
|
||||
|
||||
## Why KMK?
|
||||
|
||||
A question we get from time to time is, "why bother with KMK when QMK already
|
||||
exists?", so here's a short bulleted list of our thoughts on the matter (in no
|
||||
particular order):
|
||||
|
||||
- Python is awesome
|
||||
- Python is super easy to write
|
||||
- KMK cut all the "tech debt" of supporting AVR controllers, and frankly even
|
||||
most ARM controllers with under 256KB of flash. This let us make some very
|
||||
user-friendly (in our biased opinions) design decisions that should make it
|
||||
simple for users to create even fairly complex keyboards - want a key on your
|
||||
board that sends a shruggie (`¯\_(ツ)_/¯`)? No problem - it's supported out of
|
||||
the box. Want a single key that can act as all 26 alphabet characters
|
||||
depending on the number of times it's tapped? You're insane, but our simple
|
||||
Tap Dance implementation has you covered (without a single line of matrix
|
||||
mangling or timer madness)
|
||||
- KMK supports a few small features QMK doesn't - most are probably not
|
||||
deal-closers, but they exist no less..
|
||||
- KMK plans to support some fairly powerful hardware that would enable things
|
||||
like connecting halves (or thirds, or whatever) of a split keyboard to each
|
||||
other via Bluetooth. This stuff is still in very early R&D.
|
||||
|
||||
## So how do I use it?
|
||||
|
||||
Since KMK is still in beta currently. Flashing KMK to a
|
||||
board is still a process that requires a few lines of shell scripting. Check out
|
||||
`docs/flashing.md` for instructions/details, though note that for now, the
|
||||
instructions mostly assume Unix (Linux/MacOS/BSD) usage. You may want to check
|
||||
out the Windows Subsystem for Linux if you're on Windows.
|
||||
> While Adafruit employees and affiliates are included in the above list and
|
||||
> their help has been crucial to KMK's success, KMK is not an official Adafruit
|
||||
> project, and the Core team is not compensated by Adafruit for its development.
|
||||
|
||||
## License, Copyright, and Legal
|
||||
|
||||
Most files in this project are licensed
|
||||
[GPLv3](https://tldrlegal.com/license/gnu-general-public-license-v3-(gpl-3)) -
|
||||
see `LICENSE.md` at the top of this source tree for exceptions and the full
|
||||
license text.
|
||||
All software in this repository is licensed under the [GNU Public License,
|
||||
verison 3](https://tldrlegal.com/license/gnu-general-public-license-v3-(gpl-3)).
|
||||
All documentation and hardware designs are licensed under the [Creative Commons
|
||||
Attribution-ShareAlike 4.0](https://creativecommons.org/licenses/by-sa/4.0/)
|
||||
license. Contributions to this repository must use these licenses unless
|
||||
otherwise agreed to by the Core team.
|
||||
|
||||
When contributing for the first time, you'll need to sign a Contributor
|
||||
When you open your first pull request, you'll be asked to sign a Contributor
|
||||
Licensing Agreement which is based on the Free Software Foundation's CLA. The
|
||||
CLA is basically a two-way promise that this code is and remains yours, but will
|
||||
be distributed as part of a larger GPLv3 project. If you'd like to get it out of
|
||||
the way early, you can find said CLA [here](
|
||||
https://cla-assistant.io/kmkfw/kmk_firmware). If you forget, the bots will
|
||||
remind you when you open the pull request, no worries!
|
||||
CLA is basically a two-way promise that your code is and remains yours, but will
|
||||
be distributed as part of a larger GPL project. This CLA can be read and/or
|
||||
signed [here](https://cla-assistant.io/kmkfw/kmk_firmware).
|
||||
|
@ -1,45 +1,35 @@
|
||||
# Flashing Instructions
|
||||
|
||||
KMK sits on top of an existing CircuitPython install, flash that for your board
|
||||
as appropriate (see [Adafruit's
|
||||
documentation](https://learn.adafruit.com/welcome-to-circuitpython/installing-circuitpython),
|
||||
though it doesn't cover all CircuitPython boards - you may need to glance around
|
||||
the CircuitPython source or ask on Discord). We primarily target CircuitPython
|
||||
4.0-alpha1 to 4.0-alpha2. You'll only need
|
||||
to flash CircuitPython once (unless we update our baseline supported version).
|
||||
In general, we recommend using the instructions in `README.md`, however, mostly
|
||||
as a development artifact, another method of flashing KMK exists (tested and
|
||||
supported only on Linux, though it should also work on MacOS, the BSDs, and
|
||||
other Unix-likes. It may also work on Cygwin and the Windows Subsystem for
|
||||
Linux).
|
||||
|
||||
After CircuitPython has been flashed, a `CIRCUITPY` drive should show up on your
|
||||
computer most likely. If not, check out the troubleshooting section below.
|
||||
Given `make` and `rsync` are available on your system (in `$PATH`), the
|
||||
following will copy the `kmk` tree to your CircuitPython device, and will copy
|
||||
the file defined as `USER_KEYMAP` as your `main.py`. If any of these files exist
|
||||
on your CircuitPython device already, they will be overwritten without a prompt.
|
||||
|
||||
# Windows
|
||||
Currently, we do not have an official "flasher" for windows. You can manually install it fairly easily and we recommend
|
||||
checking out the support page to join the community if you have any questions. An actual tool is in development.
|
||||
Alternatively, you can flash from any linux like tool set (Cygwin, WSL, ect) using the Linux guide below.
|
||||
|
||||
# Mac
|
||||
Until an interactive installer is created, please follow the linux instructions replacing /mnt with /Volumes
|
||||
|
||||
# Linux
|
||||
|
||||
While in the directory for kmk, simply run this, changing the mount point and keymap name to whatever is appropriate.
|
||||
If you get permissions errors here, **don't run make as root or with sudo**. See
|
||||
`Troubleshooting` below.
|
||||
|
||||
```sh
|
||||
make MOUNTPOINT=/mnt/CIRCUITPY USER_KEYMAP=user_keymaps/nameofyourkeymap.py
|
||||
make MOUNTPOINT=/media/CIRCUITPY USER_KEYMAP=user_keymaps/nameofyourkeymap.py
|
||||
```
|
||||
|
||||
# Troubleshooting
|
||||
## Windows
|
||||
Please check out our support page to get in contact with us and the community and we can gladly help you out.
|
||||
|
||||
## Mac
|
||||
Please check out our support page to get in contact with us and the community and we can gladly help you out.
|
||||
|
||||
## Linux/BSD
|
||||
Check to see if your drive may have mounted elsewhere with a gui tool. Most will give you the directory in the GUI.
|
||||
If it's not mounted, you can read up on how to mount a drive manually [here](https://wiki.archlinux.org/index.php/File_systems#Mount_a_file_system)
|
||||
|
||||
It would look something like this
|
||||
Check to see if your drive may have mounted elsewhere with a GUI tool or other
|
||||
automounter. Most of these tools will mount your device under `/media`, probably
|
||||
as `/media/CIRCUITPY`. If it's not mounted, you can read up on how to mount a
|
||||
drive manually
|
||||
[here](https://wiki.archlinux.org/index.php/File_systems#Mount_a_file_system).
|
||||
|
||||
`sudo mount -o uid=1000,gid=1000 /dev/sdf1 ~/mnt`
|
||||
For example,
|
||||
|
||||
If you still are having issues, check out our support page to see where you can come say hi and the community will gladly help you out.
|
||||
`sudo mount -o uid=$(id -u),gid=$(id -g) /dev/disk/by-label/CIRCUITPY ~/mnt`
|
||||
|
||||
If you're still having issues, check out our support page to see where you can
|
||||
come say hi and the community will gladly help you out.
|
||||
|
@ -5,17 +5,17 @@ Keymaps in KMK are simple Python class objects with various attributes assigned
|
||||
|
||||
The basics of what you'll need to get started are:
|
||||
|
||||
- Import the `Firmware` object for your keyboard from `kmk.boards` (or, if
|
||||
handwiring your keyboard, import `Firmware` from the appropriate MCU for your
|
||||
- Import the `KeyboardConfig` object for your keyboard from `kmk.boards` (or, if
|
||||
handwiring your keyboard, import `KeyboardConfig` from the appropriate MCU for your
|
||||
board from `kmk.mcus`. See `hardware.md` for the list of supported boards and
|
||||
map this to the correct Python module under either of those paths.
|
||||
|
||||
- Add a file to `user_keymaps/your_username` called whatever you'd like
|
||||
|
||||
- Assign a `Firmware` instance to a variable (ex. `keyboard = Firmware()` - note
|
||||
- Assign a `KeyboardConfig` instance to a variable (ex. `keyboard = KeyboardConfig()` - note
|
||||
the parentheses)
|
||||
|
||||
- Make sure this `Firmware` instance is actually run at the end of the file with
|
||||
- Make sure this `KeyboardConfig` instance is actually run at the end of the file with
|
||||
a block such as the following:
|
||||
|
||||
```python
|
||||
@ -85,14 +85,14 @@ matrix pins (in somewhat of a "spider" setup), utilizing most of the above
|
||||
features:
|
||||
|
||||
```python
|
||||
from kmk.boards.klarank import Firmware
|
||||
from kmk.boards.klarank import KeyboardConfig
|
||||
from kmk.consts import UnicodeMode
|
||||
from kmk.keycodes import KC
|
||||
from kmk.keycodes import generate_leader_dictionary_seq as glds
|
||||
from kmk.macros.simple import send_string
|
||||
from kmk.macros.unicode import compile_unicode_string_sequences as cuss
|
||||
|
||||
keyboard = Firmware()
|
||||
keyboard = KeyboardConfig()
|
||||
|
||||
keyboard.debug_enabled = True
|
||||
keyboard.unicode_mode = UnicodeMode.LINUX
|
||||
|
@ -40,11 +40,11 @@ Here's an example of all this in action:
|
||||
|
||||
```python
|
||||
# user_keymaps/some_silly_example.py
|
||||
from kmk.boards.klarank import Firmware
|
||||
from kmk.boards.klarank import KeyboardConfig
|
||||
from kmk.keycodes import KC
|
||||
from kmk.macros.simple import send_string
|
||||
|
||||
keyboard = Firmware()
|
||||
keyboard = KeyboardConfig()
|
||||
|
||||
keyboard.tap_time = 750
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
from kmk.consts import DiodeOrientation
|
||||
from kmk.mcus.circuitpython_samd51 import Firmware as _Firmware
|
||||
from kmk.mcus.circuitpython_usbhid import KeyboardConfig as _KeyboardConfig
|
||||
from kmk.pins import Pin as P
|
||||
|
||||
|
||||
class Firmware(_Firmware):
|
||||
class KeyboardConfig(_KeyboardConfig):
|
||||
col_pins = (P.D9, P.D10, P.D11, P.D12, P.D13, P.SCL)
|
||||
row_pins = (P.A3, P.A4, P.A5, P.SCK, P.MOSI)
|
||||
diode_orientation = DiodeOrientation.COLUMNS
|
||||
|
@ -1,11 +1,11 @@
|
||||
import board
|
||||
|
||||
from kmk.consts import DiodeOrientation
|
||||
from kmk.mcus.circuitpython_samd51 import Firmware as _Firmware
|
||||
from kmk.mcus.circuitpython_usbhid import KeyboardConfig as _KeyboardConfig
|
||||
from kmk.pins import Pin as P
|
||||
|
||||
|
||||
class Firmware(_Firmware):
|
||||
class KeyboardConfig(_KeyboardConfig):
|
||||
col_pins = (P.A0, P.A1, P.A2, P.A3, P.A4, P.A5, P.SCK, P.MOSI)
|
||||
row_pins = (P.TX, P.RX, P.SDA, P.SCL, P.D13, P.D12, P.D11, P.D10)
|
||||
diode_orientation = DiodeOrientation.COLUMNS
|
||||
|
@ -1,11 +1,11 @@
|
||||
import board
|
||||
|
||||
from kmk.consts import DiodeOrientation
|
||||
from kmk.mcus.circuitpython_samd51 import Firmware as _Firmware
|
||||
from kmk.mcus.circuitpython_usbhid import KeyboardConfig as _KeyboardConfig
|
||||
from kmk.pins import Pin as P
|
||||
|
||||
|
||||
class Firmware(_Firmware):
|
||||
class KeyboardConfig(_KeyboardConfig):
|
||||
col_pins = (P.RX, P.D13, P.A0, P.D11, P.A4, P.A5, P.D10, P.D9, P.SCK)
|
||||
diode_orientation = DiodeOrientation.COLUMNS
|
||||
rgb_pixel_pin = board.TX
|
||||
|
@ -1,11 +1,11 @@
|
||||
import board
|
||||
|
||||
from kmk.consts import DiodeOrientation
|
||||
from kmk.mcus.circuitpython_samd51 import Firmware as _Firmware
|
||||
from kmk.mcus.circuitpython_usbhid import KeyboardConfig as _KeyboardConfig
|
||||
from kmk.pins import Pin as P
|
||||
|
||||
|
||||
class Firmware(_Firmware):
|
||||
class KeyboardConfig(_KeyboardConfig):
|
||||
col_pins = (P.A1, P.A2, P.A3, P.A4, P.A5, P.SCK, P.MOSI)
|
||||
row_pins = (P.A0, P.D11, P.D10, P.D9)
|
||||
diode_orientation = DiodeOrientation.COLUMNS
|
||||
|
@ -1,11 +1,11 @@
|
||||
import board
|
||||
|
||||
from kmk.consts import DiodeOrientation
|
||||
from kmk.mcus.circuitpython_samd51 import Firmware as _Firmware
|
||||
from kmk.mcus.circuitpython_usbhid import KeyboardConfig as _KeyboardConfig
|
||||
from kmk.pins import Pin as P
|
||||
|
||||
|
||||
class Firmware(_Firmware):
|
||||
class KeyboardConfig(_KeyboardConfig):
|
||||
col_pins = (P.A2, P.A3, P.A4, P.A5, P.SCK, P.MOSI)
|
||||
row_pins = (P.D11, P.D10, P.D9, P.D7, P.D13)
|
||||
diode_orientation = DiodeOrientation.COLUMNS
|
||||
|
@ -1,12 +1,12 @@
|
||||
import board
|
||||
|
||||
from kmk.consts import DiodeOrientation
|
||||
from kmk.mcus.circuitpython_samd51 import Firmware as _Firmware
|
||||
from kmk.mcus.circuitpython_usbhid import KeyboardConfig as _KeyboardConfig
|
||||
from kmk.pins import Pin as P
|
||||
from kmk.util import intify_coordinate as ic
|
||||
|
||||
|
||||
class Firmware(_Firmware):
|
||||
class KeyboardConfig(_KeyboardConfig):
|
||||
# Pin mappings for converter board found at hardware/README.md
|
||||
# QMK: MATRIX_COL_PINS { F6, F7, B1, B3, B2, B6 }
|
||||
# QMK: MATRIX_ROW_PINS { D7, E6, B4, D2, D4 }
|
||||
|
@ -1,11 +1,11 @@
|
||||
import board
|
||||
|
||||
from kmk.consts import DiodeOrientation
|
||||
from kmk.mcus.circuitpython_samd51 import Firmware as _Firmware
|
||||
from kmk.mcus.circuitpython_usbhid import KeyboardConfig as _KeyboardConfig
|
||||
from kmk.pins import Pin as P
|
||||
|
||||
|
||||
class Firmware(_Firmware):
|
||||
class KeyboardConfig(_KeyboardConfig):
|
||||
col_pins = (P.SDA, P.A2, P.A3, P.A4, P.A5, P.SCK, P.MOSI)
|
||||
row_pins = (P.TX, P.A0, P.RX, P.A1, P.D11, P.D9, P.D12, P.D10)
|
||||
diode_orientation = DiodeOrientation.COLUMNS
|
||||
|
@ -1,11 +1,11 @@
|
||||
import board
|
||||
|
||||
from kmk.consts import DiodeOrientation
|
||||
from kmk.mcus.circuitpython_samd51 import Firmware as _Firmware
|
||||
from kmk.mcus.circuitpython_usbhid import KeyboardConfig as _KeyboardConfig
|
||||
from kmk.pins import Pin as P
|
||||
|
||||
|
||||
class Firmware(_Firmware):
|
||||
class KeyboardConfig(_KeyboardConfig):
|
||||
col_pins = (P.A2, P.A3, P.A4, P.A5, P.SCK, P.A0)
|
||||
row_pins = (P.D11, P.D10, P.D9, P.D7)
|
||||
diode_orientation = DiodeOrientation.COLUMNS
|
||||
|
@ -1,11 +1,11 @@
|
||||
import board
|
||||
|
||||
from kmk.consts import DiodeOrientation
|
||||
from kmk.mcus.circuitpython_samd51 import Firmware as _Firmware
|
||||
from kmk.mcus.circuitpython_usbhid import KeyboardConfig as _KeyboardConfig
|
||||
from kmk.pins import Pin as P
|
||||
|
||||
|
||||
class Firmware(_Firmware):
|
||||
class KeyboardConfig(_KeyboardConfig):
|
||||
col_pins = (P.A2, P.A3, P.A4, P.A5, P.SCK, P.MOSI)
|
||||
row_pins = (P.D13, P.D11, P.D10, P.D9)
|
||||
diode_orientation = DiodeOrientation.COLUMNS
|
||||
|
@ -1,11 +1,11 @@
|
||||
import board
|
||||
|
||||
from kmk.consts import DiodeOrientation
|
||||
from kmk.mcus.circuitpython_samd51 import Firmware as _Firmware
|
||||
from kmk.mcus.circuitpython_usbhid import KeyboardConfig as _KeyboardConfig
|
||||
from kmk.pins import Pin as P
|
||||
|
||||
|
||||
class Firmware(_Firmware):
|
||||
class KeyboardConfig(_KeyboardConfig):
|
||||
col_pins = (P.A2, P.A3, P.A4, P.A5, P.SCK, P.MOSI)
|
||||
row_pins = (P.D13, P.D11, P.D10, P.D9, P.D7)
|
||||
diode_orientation = DiodeOrientation.COLUMNS
|
||||
|
@ -1,11 +1,11 @@
|
||||
import board
|
||||
|
||||
from kmk.consts import DiodeOrientation
|
||||
from kmk.mcus.circuitpython_samd51 import Firmware as _Firmware
|
||||
from kmk.mcus.circuitpython_usbhid import KeyboardConfig as _KeyboardConfig
|
||||
from kmk.pins import Pin as P
|
||||
|
||||
|
||||
class Firmware(_Firmware):
|
||||
class KeyboardConfig(_KeyboardConfig):
|
||||
col_pins = (P.RX, P.A1, P.A2, P.A3, P.A4, P.A5)
|
||||
row_pins = (P.D13, P.D11, P.D10, P.D9, P.D7)
|
||||
diode_orientation = DiodeOrientation.COLUMNS
|
||||
|
@ -1,11 +1,11 @@
|
||||
import board
|
||||
|
||||
from kmk.consts import DiodeOrientation
|
||||
from kmk.mcus.circuitpython_samd51 import Firmware as _Firmware
|
||||
from kmk.mcus.circuitpython_usbhid import KeyboardConfig as _KeyboardConfig
|
||||
from kmk.pins import Pin as P
|
||||
|
||||
|
||||
class Firmware(_Firmware):
|
||||
class KeyboardConfig(_KeyboardConfig):
|
||||
# Will need additional work and testing
|
||||
col_pins = (P.A1, P.A2, P.A3, P.A4, P.A5, P.SCK, P.MOSI, P.D12)
|
||||
row_pins = (P.A0, P.D13, P.D11, P.D10, P.D9, P.D7)
|
||||
|
@ -1,11 +1,11 @@
|
||||
import board
|
||||
|
||||
from kmk.consts import DiodeOrientation
|
||||
from kmk.mcus.circuitpython_samd51 import Firmware as _Firmware
|
||||
from kmk.mcus.circuitpython_usbhid import KeyboardConfig as _KeyboardConfig
|
||||
from kmk.pins import Pin as P
|
||||
|
||||
|
||||
class Firmware(_Firmware):
|
||||
class KeyboardConfig(_KeyboardConfig):
|
||||
col_pins = (P.A2, P.A3, P.A4, P.A5, P.SCK, P.MOSI)
|
||||
row_pins = (P.D11, P.D10, P.D9, P.RX, P.D13)
|
||||
diode_orientation = DiodeOrientation.COLUMNS
|
||||
|
@ -1,9 +1,9 @@
|
||||
from kmk.consts import DiodeOrientation
|
||||
from kmk.mcus.circuitpython_samd51 import Firmware as _Firmware
|
||||
from kmk.mcus.circuitpython_usbhid import KeyboardConfig as _KeyboardConfig
|
||||
from kmk.pins import Pin as P
|
||||
|
||||
|
||||
class Firmware(_Firmware):
|
||||
class KeyboardConfig(_KeyboardConfig):
|
||||
col_pins = (P.A0, P.A1, P.A2, P.A3, P.A4, P.A5, P.SCK, P.MOSI)
|
||||
row_pins = (P.TX, P.RX, P.SDA, P.SCL, P.D9, P.D10, P.D12, P.D11, P.D13)
|
||||
diode_orientation = DiodeOrientation.COLUMNS
|
||||
|
@ -1,11 +1,11 @@
|
||||
import board
|
||||
|
||||
from kmk.consts import DiodeOrientation
|
||||
from kmk.mcus.circuitpython_samd51 import Firmware as _Firmware
|
||||
from kmk.mcus.circuitpython_usbhid import KeyboardConfig as _KeyboardConfig
|
||||
from kmk.pins import Pin as P
|
||||
|
||||
|
||||
class Firmware(_Firmware):
|
||||
class KeyboardConfig(_KeyboardConfig):
|
||||
col_pins = (P.A1, P.A2, P.A3, P.A4, P.A5, P.SCK, P.MOSI)
|
||||
row_pins = (P.D13, P.D11, P.D10, P.D9, P.D7)
|
||||
diode_orientation = DiodeOrientation.COLUMNS
|
||||
|
@ -1,11 +1,11 @@
|
||||
import board
|
||||
|
||||
from kmk.consts import DiodeOrientation
|
||||
from kmk.mcus.circuitpython_samd51 import Firmware as _Firmware
|
||||
from kmk.mcus.circuitpython_usbhid import KeyboardConfig as _KeyboardConfig
|
||||
from kmk.pins import Pin as P
|
||||
|
||||
|
||||
class Firmware(_Firmware):
|
||||
class KeyboardConfig(_KeyboardConfig):
|
||||
col_pins = (P.A0, P.A1, P.A2, P.A3, P.A4, P.A5, P.SCK)
|
||||
row_pins = (P.D13, P.D11, P.D10, P.D9, P.D7)
|
||||
diode_orientation = DiodeOrientation.COLUMNS
|
||||
|
@ -1,11 +1,11 @@
|
||||
import board
|
||||
|
||||
from kmk.consts import DiodeOrientation
|
||||
from kmk.mcus.circuitpython_samd51 import Firmware as _Firmware
|
||||
from kmk.mcus.circuitpython_usbhid import KeyboardConfig as _KeyboardConfig
|
||||
from kmk.pins import Pin as P
|
||||
|
||||
|
||||
class Firmware(_Firmware):
|
||||
class KeyboardConfig(_KeyboardConfig):
|
||||
col_pins = (P.A5, P.A4, P.A3, P.A2, P.A1, P.A0)
|
||||
row_pins = (P.D7, P.D9, P.D10, P.D11)
|
||||
diode_orientation = DiodeOrientation.COLUMNS
|
||||
|
@ -1,11 +1,11 @@
|
||||
import board
|
||||
|
||||
from kmk.consts import DiodeOrientation
|
||||
from kmk.mcus.circuitpython_samd51 import Firmware as _Firmware
|
||||
from kmk.mcus.circuitpython_usbhid import KeyboardConfig as _KeyboardConfig
|
||||
from kmk.pins import Pin as P
|
||||
|
||||
|
||||
class Firmware(_Firmware):
|
||||
class KeyboardConfig(_KeyboardConfig):
|
||||
col_pins = (P.MOSI, P.SCK, P.A5, P.A4, P.A3, P.A2)
|
||||
row_pins = (P.D11, P.D10, P.D9, P.D7)
|
||||
diode_orientation = DiodeOrientation.COLUMNS
|
||||
|
@ -1,9 +1,9 @@
|
||||
from kmk.consts import DiodeOrientation
|
||||
from kmk.mcus.circuitpython_samd51 import Firmware as _Firmware
|
||||
from kmk.mcus.circuitpython_usbhid import KeyboardConfig as _KeyboardConfig
|
||||
from kmk.pins import Pin as P
|
||||
from kmk.util import intify_coordinate as ic
|
||||
|
||||
# Implements what used to be handled by Firmware.swap_indicies for this
|
||||
# Implements what used to be handled by KeyboardConfig.swap_indicies for this
|
||||
# board, by flipping various row3 (bottom physical row) keys so their
|
||||
# coord_mapping matches what the user pressed (even if the wiring
|
||||
# underneath is sending different coordinates)
|
||||
@ -24,7 +24,7 @@ def r3_swap(col):
|
||||
return col
|
||||
|
||||
|
||||
class Firmware(_Firmware):
|
||||
class KeyboardConfig(_KeyboardConfig):
|
||||
# physical, visible cols (SCK, MO, MI, RX, TX, D4)
|
||||
# physical, visible rows (10, 11, 12, 13) (9, 6, 5, SCL)
|
||||
col_pins = (P.SCK, P.MOSI, P.MISO, P.RX, P.TX, P.D4)
|
||||
|
@ -1,3 +1,8 @@
|
||||
try:
|
||||
from kmk.release_info import KMK_RELEASE
|
||||
except Exception:
|
||||
KMK_RELEASE = 'copied-from-git'
|
||||
|
||||
CIRCUITPYTHON = 'CircuitPython'
|
||||
MICROPYTHON = 'MicroPython'
|
||||
|
||||
|
@ -101,10 +101,8 @@ def tt_pressed(key, state, *args, **kwargs):
|
||||
|
||||
|
||||
def tt_released(key, state, *args, **kwargs):
|
||||
if (
|
||||
state.start_time['tt'] is None or
|
||||
ticks_diff(ticks_ms(), state.start_time['tt']) >= state.config.tap_time
|
||||
):
|
||||
tap_timed_out = ticks_diff(ticks_ms(), state.start_time['tt']) >= state.config.tap_time
|
||||
if state.start_time['tt'] is None or tap_timed_out:
|
||||
# On first press, works like MO. On second press, does nothing unless let up within
|
||||
# time window, then acts like TG.
|
||||
state.start_time['tt'] = None
|
||||
|
@ -183,10 +183,7 @@ else:
|
||||
self.devices[HIDReportTypes.MOUSE] = device
|
||||
continue
|
||||
|
||||
if (
|
||||
up == HIDUsagePage.SYSCONTROL and
|
||||
us == HIDUsage.SYSCONTROL
|
||||
):
|
||||
if up == HIDUsagePage.SYSCONTROL and us == HIDUsage.SYSCONTROL:
|
||||
self.devices[HIDReportTypes.SYSCONTROL] = device
|
||||
continue
|
||||
|
||||
|
@ -200,10 +200,10 @@ class InternalState:
|
||||
if changed_key not in self.tap_side_effects:
|
||||
self.tap_side_effects[changed_key] = None
|
||||
else:
|
||||
if (
|
||||
self.tap_side_effects[changed_key] is not None or
|
||||
self.tap_dance_counts[changed_key] == len(changed_key.codes)
|
||||
):
|
||||
has_side_effects = self.tap_side_effects[changed_key] is not None
|
||||
hit_max_defined_taps = self.tap_dance_counts[changed_key] == len(changed_key.codes)
|
||||
|
||||
if has_side_effects or hit_max_defined_taps:
|
||||
self._end_tap_dance(changed_key)
|
||||
|
||||
return self
|
||||
|
@ -27,7 +27,7 @@ import kmk.kmktime # isort:skip
|
||||
import kmk.types # isort:skip
|
||||
import kmk.util # isort:skip
|
||||
|
||||
from kmk.consts import LeaderMode, UnicodeMode # isort:skip
|
||||
from kmk.consts import LeaderMode, UnicodeMode, KMK_RELEASE # isort:skip
|
||||
from kmk.hid import USB_HID # isort:skip
|
||||
from kmk.internal_state import InternalState # isort:skip
|
||||
from kmk.keys import KC # isort:skip
|
||||
@ -53,7 +53,7 @@ from kmk.util import intify_coordinate as ic
|
||||
from kmk import led, rgb # isort:skip
|
||||
|
||||
|
||||
class Firmware:
|
||||
class KeyboardConfig:
|
||||
debug_enabled = False
|
||||
|
||||
keymap = None
|
||||
@ -95,7 +95,7 @@ class Firmware:
|
||||
|
||||
def __repr__(self):
|
||||
return (
|
||||
'Firmware('
|
||||
'KeyboardConfig('
|
||||
'debug_enabled={} '
|
||||
'keymap=truncated '
|
||||
'coord_mapping=truncated '
|
||||
@ -152,7 +152,7 @@ class Firmware:
|
||||
|
||||
if self.debug_enabled:
|
||||
if init:
|
||||
print('KMKInit()')
|
||||
print('KMKInit(release={})'.format(KMK_RELEASE))
|
||||
|
||||
print(self)
|
||||
print(self._state)
|
@ -110,8 +110,11 @@ class led:
|
||||
def effect_breathing(self):
|
||||
# http://sean.voisen.org/blog/2011/10/breathing-led-with-arduino/
|
||||
# https://github.com/qmk/qmk_firmware/blob/9f1d781fcb7129a07e671a46461e501e3f1ae59d/quantum/rgblight.c#L806
|
||||
self.brightness = int((exp(sin((self.pos / 255.0) * pi)) - self.breathe_center / e) *
|
||||
(self.brightness_limit / (e - 1 / e)))
|
||||
sined = sin((self.pos / 255.0) * pi)
|
||||
multip_1 = exp(sined) - self.breathe_center / e
|
||||
multip_2 = self.brightness_limit / (e - 1 / e)
|
||||
|
||||
self.brightness = int(multip_1 * multip_2)
|
||||
self.pos = (self.pos + self.animation_speed) % 256
|
||||
self.set_brightness(self.brightness)
|
||||
|
||||
|
@ -1,6 +0,0 @@
|
||||
from kmk.firmware import Firmware as _Firmware
|
||||
from kmk.hid import CircuitPythonUSB_HID
|
||||
|
||||
|
||||
class Firmware(_Firmware):
|
||||
hid_helper = CircuitPythonUSB_HID
|
6
kmk/mcus/circuitpython_usbhid.py
Normal file
6
kmk/mcus/circuitpython_usbhid.py
Normal file
@ -0,0 +1,6 @@
|
||||
from kmk.hid import CircuitPythonUSB_HID
|
||||
from kmk.keyboard_config import KeyboardConfig as _KeyboardConfig
|
||||
|
||||
|
||||
class KeyboardConfig(_KeyboardConfig):
|
||||
hid_helper = CircuitPythonUSB_HID
|
@ -424,8 +424,11 @@ class RGB:
|
||||
def effect_breathing(self):
|
||||
# http://sean.voisen.org/blog/2011/10/breathing-led-with-arduino/
|
||||
# https://github.com/qmk/qmk_firmware/blob/9f1d781fcb7129a07e671a46461e501e3f1ae59d/quantum/rgblight.c#L806
|
||||
self.val = int((exp(sin((self.pos / 255.0) * pi)) - self.breathe_center / e) *
|
||||
(self.val_limit / (e - 1 / e)))
|
||||
sined = sin((self.pos / 255.0) * pi)
|
||||
multip_1 = exp(sined) - self.breathe_center / e
|
||||
multip_2 = self.val_limit / (e - 1 / e)
|
||||
|
||||
self.val = int(multip_1 * multip_2)
|
||||
self.pos = (self.pos + self.animation_speed) % 256
|
||||
self.set_hsv_fill(self.hue, self.sat, self.val)
|
||||
|
||||
|
@ -1 +0,0 @@
|
||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="df11", GROUP="uucp", MODE="0660"
|
@ -7,7 +7,7 @@ per-file-ignores =
|
||||
user_keymaps/**/*.py: F401,E501,E241,E131
|
||||
tests/test_data/keymaps/**/*.py: F401,E501
|
||||
# Forgive me for my RAM hack sins
|
||||
kmk/firmware.py: I001,I003,I004,F401
|
||||
kmk/keyboard_config.py: I001,I003,I004,F401
|
||||
|
||||
[isort]
|
||||
known_third_party = analogio,bitbangio,bleio,board,busio,digitalio,framebuf,gamepad,gc,microcontroller,micropython,pulseio,pyb,pydux,uio,ubluepy,machine,pyb,uos
|
||||
|
@ -1,7 +1,7 @@
|
||||
from kmk.boards.converter.fourtypercentclub.luddite import Firmware
|
||||
from kmk.boards.converter.fourtypercentclub.luddite import KeyboardConfig
|
||||
from kmk.keys import KC
|
||||
|
||||
keyboard = Firmware()
|
||||
keyboard = KeyboardConfig()
|
||||
|
||||
_______ = KC.TRNS
|
||||
XXXXXXX = KC.NO
|
||||
|
@ -1,7 +1,7 @@
|
||||
from kmk.boards.converter.keebio.nyquist_r2 import Firmware
|
||||
from kmk.boards.converter.keebio.nyquist_r2 import KeyboardConfig
|
||||
from kmk.keys import KC
|
||||
|
||||
keyboard = Firmware()
|
||||
keyboard = KeyboardConfig()
|
||||
|
||||
_______ = KC.TRNS
|
||||
XXXXXXX = KC.NO
|
||||
|
@ -2,11 +2,11 @@ from kmk.consts import DiodeOrientation, UnicodeMode
|
||||
from kmk.handlers.sequences import (compile_unicode_string_sequences,
|
||||
send_string)
|
||||
from kmk.keys import KC
|
||||
from kmk.mcus.circuitpython_samd51 import Firmware
|
||||
from kmk.mcus.circuitpython_usbhid import KeyboardConfig
|
||||
from kmk.pins import Pin as P
|
||||
from kmk.types import AttrDict
|
||||
|
||||
keyboard = Firmware()
|
||||
keyboard = KeyboardConfig()
|
||||
|
||||
'''
|
||||
Converter/handwire:
|
||||
|
@ -2,11 +2,11 @@ from kmk.consts import DiodeOrientation, UnicodeMode
|
||||
from kmk.handlers.sequences import (compile_unicode_string_sequences,
|
||||
send_string)
|
||||
from kmk.keys import KC
|
||||
from kmk.mcus.circuitpython_samd51 import Firmware
|
||||
from kmk.mcus.circuitpython_usbhid import KeyboardConfig
|
||||
from kmk.pins import Pin as P
|
||||
from kmk.types import AttrDict
|
||||
|
||||
keyboard = Firmware()
|
||||
keyboard = KeyboardConfig()
|
||||
|
||||
keyboard.col_pins = (P.A0, P.A1, P.A2, P.A3, P.A4, P.A5, P.SCK, P.MOSI, P.MISO, P.RX, P.TX, P.D4)
|
||||
keyboard.row_pins = (P.D10, P.D11, P.D12, P.D13)
|
||||
|
@ -1,9 +1,9 @@
|
||||
from kmk.boards.converter.keebio.levinson_r2 import Firmware
|
||||
from kmk.boards.converter.keebio.levinson_r2 import KeyboardConfig
|
||||
from kmk.consts import LeaderMode, UnicodeMode
|
||||
from kmk.handlers.sequences import compile_unicode_string_sequences
|
||||
from kmk.keys import KC
|
||||
|
||||
keyboard = Firmware()
|
||||
keyboard = KeyboardConfig()
|
||||
|
||||
# ------------------User level config variables ---------------------------------------
|
||||
keyboard.leader_mode = LeaderMode.TIMEOUT
|
||||
|
@ -1,7 +1,7 @@
|
||||
from kmk.boards.converter.fourtypercentclub.luddite import Firmware
|
||||
from kmk.boards.converter.fourtypercentclub.luddite import KeyboardConfig
|
||||
from kmk.keys import KC
|
||||
|
||||
keyboard = Firmware()
|
||||
keyboard = KeyboardConfig()
|
||||
|
||||
# ---------------------------------- Config --------------------------------------------
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
from kmk.boards.converter.keebio.nyquist_r2 import Firmware
|
||||
from kmk.boards.converter.keebio.nyquist_r2 import KeyboardConfig
|
||||
from kmk.keys import KC
|
||||
|
||||
keyboard = Firmware()
|
||||
keyboard = KeyboardConfig()
|
||||
|
||||
# ------------------User level config variables ---------------------------------------
|
||||
keyboard.tap_time = 150
|
||||
|
@ -1,10 +1,10 @@
|
||||
from kmk.boards.converter.keebio.iris_r2 import Firmware
|
||||
from kmk.boards.converter.keebio.iris_r2 import KeyboardConfig
|
||||
from kmk.consts import LeaderMode, UnicodeMode
|
||||
from kmk.handlers.sequences import compile_unicode_string_sequences as cuss
|
||||
from kmk.handlers.sequences import send_string
|
||||
from kmk.keys import KC
|
||||
|
||||
keyboard = Firmware()
|
||||
keyboard = KeyboardConfig()
|
||||
|
||||
keyboard.debug_enabled = False
|
||||
keyboard.unicode_mode = UnicodeMode.LINUX
|
||||
|
@ -1,10 +1,10 @@
|
||||
from kmk.boards.klarank import Firmware
|
||||
from kmk.boards.klarank import KeyboardConfig
|
||||
from kmk.consts import LeaderMode, UnicodeMode
|
||||
from kmk.handlers.sequences import compile_unicode_string_sequences as cuss
|
||||
from kmk.handlers.sequences import send_string
|
||||
from kmk.keys import KC, make_key
|
||||
|
||||
keyboard = Firmware()
|
||||
keyboard = KeyboardConfig()
|
||||
|
||||
keyboard.debug_enabled = True
|
||||
keyboard.unicode_mode = UnicodeMode.LINUX
|
||||
|
@ -1,9 +1,9 @@
|
||||
from kmk.boards.converter.keebio.levinson_r2 import Firmware
|
||||
from kmk.boards.converter.keebio.levinson_r2 import KeyboardConfig
|
||||
from kmk.consts import LeaderMode, UnicodeMode
|
||||
from kmk.handlers.sequences import compile_unicode_string_sequences
|
||||
from kmk.keys import KC
|
||||
|
||||
keyboard = Firmware()
|
||||
keyboard = KeyboardConfig()
|
||||
|
||||
# ------------------User level config variables ---------------------------------------
|
||||
keyboard.leader_mode = LeaderMode.TIMEOUT
|
||||
|
Loading…
x
Reference in New Issue
Block a user