Author SHA1 Message Date
Kyle Brown 6c069776fb Added stargazers to readme 2021-08-30 12:22:21 -07:00
Athul Cyriac Ajay 586d1deb4e chore: Fix URL and added a space for cleaner look 2021-08-23 23:06:04 -07:00
AndersonTorres 796b7733f5 ptBR translation: docs/ptBR/kmkpython_vs_circuitpython.md 2021-08-19 15:44:53 -07:00
AndersonTorres 9eb86d2069 ptBR translation: docs/ptBR/Officially_Supported_Microcontrollers.md 2021-08-19 15:44:53 -07:00
AndersonTorres a08ed5dc25 ptBR translation: docs/ptBR/Getting_Started.md 2021-08-19 15:44:53 -07:00
Josh Klar 7e477e1aa8 Merge pull request #225 from KMKfw/badges
Added badges
2021-08-16 05:48:22 +00:00
Kyle Brown 3be9f9b9ad Formatting 2021-08-13 19:48:38 -07:00
Kyle Brown e0786e6118 Added badges 2021-08-13 18:11:51 -07:00
razel 9340579031 Translated Getting_Started.md to Japanese. 2021-08-13 07:15:48 -07:00
FHA d43c712301 Requested updates before push into main
1. Space before "If you're wondering"
2. Replaced "with certain boards ... pico" by "with most boards"
2021-07-29 11:53:38 -07:00
FHA c75b52f94b Update keycodes.md
Precision on KC.APPLICATION position on the keyboard
2021-07-29 11:53:38 -07:00
FHA 3525a5f1a5 Update keycodes.md
typo  : interNATIOnal
2021-07-29 11:53:38 -07:00
FHA 10a1447adc Update keycodes.md
Added international (ISO) keys as defined in the code
2021-07-29 11:53:38 -07:00
FHA 24a4a4da11 Proofread & typos 2021-07-29 11:53:38 -07:00
FHA 9aaebbcf54 typos 2021-07-29 11:53:38 -07:00
FHA 081590f85d Update Getting_Started.md
Added direct references to various existing doc pages
2021-07-29 11:53:38 -07:00
FHA 2db4682264 Update Getting_Started.md
Name of the main file updated (code.py or main.py)
2021-07-29 11:53:38 -07:00
FHA f256c49727 Rename kmk_vs_circuitpython.md to kmkpython_vs_circuitpython.md 2021-07-29 11:53:38 -07:00
FHA 0247de4988 Update Getting_Started.md 2021-07-29 11:53:38 -07:00
FHA 4139c97b22 clarify the diff between KMK and KMKPython 2021-07-29 11:53:38 -07:00
FHA 917afe5f57 Create kmk_vs_circuitpython.md
Move KMK vs CircuitPython from main guide to dedicated page
2021-07-29 11:53:38 -07:00
FHA 9e731bce1e Update Getting_Started.md
various precisions
2021-07-29 11:53:38 -07:00
FHA 3f10abc6fd Update Getting_Started.md
Review structure. Provide TLDR example as a quickstart
2021-07-29 11:53:38 -07:00
Kyle Brown 4eba21a2fd typo 2021-07-19 21:37:51 -07:00
pullenrcandRyan Pullen 15918db7ac Encoder module! (#211)
* added atreus62 board

* Uploaded module for encoder support

* Update README.md


Co-authored-by: Ryan Pullen <rpullen@martinuav.com>
2021-07-19 08:30:28 -07:00
Josh Klar eb5756f530 Merge pull request #214 from KMKfw/josh/topic-corne-2040-plus-plus
Fix many broken keys
2021-07-12 18:19:02 +00:00
Kyle Brown cd3e10ba13 unbreak kdb corne 2021-07-09 11:21:00 -07:00
Josh Klar 083e4a701a fix(keys): fix shifted keys bug, make lazy key defs more readable 2021-07-09 11:21:00 -07:00
Josh Klar ab6aa1838c chore: whatever it just took to get my PM2040 to boot 2021-07-09 11:21:00 -07:00
Kyle Brown 270be1fa28 initial support for RP2040 Pro Micro corne 2021-07-09 11:21:00 -07:00
enbyautumn 76e7ee4027 Rename Offiially_Supported_Microcontrollers.md to Officially_Supported_Microcontrollers.md 2021-07-09 09:50:41 -07:00
Kyle Brown 7310bdd780 add shorthand for KC_NO 2021-07-07 12:53:17 -07:00
Kyle Brown a77fee7f04 Add shifted keynames to register unshifted versions 2021-07-07 12:53:17 -07:00
Josh Klar e208dd64f3 docs: update/refresh README
Resolves #212
2021-07-06 12:53:34 -07:00
21 changed files with 1417 additions and 783 deletions

No files matched your search

+32 -21
View File
@@ -1,25 +1,35 @@
# KMK: Clackety Keyboards Powered by Python
![GitHub](
https://img.shields.io/github/license/KMKfw/kmk_firmware
)![GitHub contributors](
https://img.shields.io/github/contributors/KMKfw/kmk_firmware
)![Discord](
https://img.shields.io/discord/493256121075761173?logo=Discord
)![Lines of code](https://img.shields.io/tokei/lines/github/KMKfw/kmk_firmware
)![GitHub issues](https://img.shields.io/github/issues-raw/KMKfw/kmk_firmware
)![GitHub closed issues](https://img.shields.io/github/issues-closed/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, and transitioning to a new core, however should handle almost
all workflows without major issues**.
in public beta, however should handle most workflows without major issues**.
<!--
@klardotsh 06 July 2021: commented for now because CDN builds have been broken
for ages and folks are (reasonably) getting confused.
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.
-->
> If you need support with KMK or just want to say hi, find us in
> [#kmkfw:klar.sh on Matrix](https://matrix.to/#/#kmkfw:klar.sh). This channel
> is 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.
## Features
@@ -42,28 +52,22 @@ file](https://cdn.kmkfw.io/kmk-latest.unoptimized.zip) forms. These follow the
- Bluetooth HID and split keyboards. No more wires.
## Getting Started
Our getting started guide can be found [here](https://github.com/KMKfw/docs/Getting_Started.md)
Our getting started guide can be found
[here](https://github.com/KMKfw/kmk_firmware/blob/master/docs/Getting_Started.md)
## 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!):
mind. A list of KMK's contributors can be found [on
GitHub](https://github.com/KMKfw/kmk_firmware/graphs/contributors).
- [Dan Halbert (@dhalbert)](https://github.com/dhalbert)
- [Elvis Pfützenreuter (@elvis-epx)](https://github.com/elvis-epx)
- [Kyle Brown (@kdb424)](https://github.com/kdb424)
- [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)
> 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.
> While Adafruit employees and affiliates are occasionally found in the commit
> log 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.
## Code Style
@@ -84,3 +88,10 @@ 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.
## Stargazers over time
[![Stargazers over time](https://starchart.cc/KMKfw/kmk_firmware.svg)](https://starchart.cc/KMKfw/kmk_firmware)
+16
View File
@@ -0,0 +1,16 @@
# Atreus62
![Atreus62](https://assets.bigcartel.com/product_images/189335282/BIlqCtd.jpg?auto=format&fit=max&w=1200)
Atreus62 is a 60% column staggered keyboard pinky stagger
kb.py is designed to work with the Teensy 4.1
Retailers (USA)
[Atreus62](https://shop.profetkeyboards.com/product/atreus62-keyboard)
Extentions enabled by default
- [Layers](https://github.com/KMKfw/kmk_firmware/tree/master/docs/layers.md) Need more keys than switches? Use layers.
- [RGB](https://github.com/KMKfw/kmk_firmware/tree/master/docs/rgb.md) Light it up
- [Encoder](https://github.com/KMKfw/kmk_firmware/tree/master/docs/encoder.md) Twist control for all the things
+28
View File
@@ -0,0 +1,28 @@
import board
from kmk.kmk_keyboard import KMKKeyboard as _KMKKeyboard
from kmk.matrix import DiodeOrientation
# from kmk.matrix import intify_coordinate as ic
class KMKKeyboard(_KMKKeyboard):
col_pins = (
board.D24,
board.D25,
board.D26,
board.D27,
board.D28,
board.D29,
board.D30,
board.D31,
board.D32,
board.D33,
board.D34,
board.D35,
)
row_pins = (board.D3, board.D4, board.D5, board.D6, board.D7, board.D8)
diode_orientation = DiodeOrientation.ROWS
# diode_orientation = DiodeOrientation.COLUMNS
+220
View File
@@ -0,0 +1,220 @@
import board
from kb import KMKKeyboard
from kmk.handlers.sequences import send_string, simple_key_sequence
from kmk.keys import KC
from kmk.modules.encoder import EncoderHandler
from kmk.modules.layers import Layers
# local_increment = None
# local_decrement = None
keyboard = KMKKeyboard()
# custom keys used for encoder actions
Zoom_in = KC.LCTRL(KC.EQUAL)
Zoom_out = KC.LCTRL(KC.MINUS)
# standard filler keys
_______ = KC.TRNS
XXXXXXX = KC.NO
# for use in the encoder extension
encoder_map = [
[
(
KC.VOLU,
KC.VOLD,
2,
), # Only 1 encoder is being used, so only one tuple per layer is required
],
[
(Zoom_in, Zoom_out, 1),
],
[
(_______, _______, 1), # no action taken by the encoder on this layer
],
]
layers_ext = Layers()
encoder_ext = EncoderHandler([board.D40], [board.D41], encoder_map)
encoder_ext.encoders[0].is_inverted = True
keyboard.modules = [layers_ext, encoder_ext]
keyboard.tap_time = 250
keyboard.debug_enabled = False
# custom keys
NEW = KC.LCTL(KC.N)
NEW_DIR = KC.LCTL(KC.LSFT(KC.N))
CAD = KC.LCTL(KC.LALT(KC.DEL))
RES = KC.LCTL(KC.LSFT(KC.ESC))
FE = KC.LGUI(KC.E)
LT1_DEL = KC.LT(1, KC.DEL)
LT2_ENT = KC.LT(2, KC.ENT)
SAVE_AS = KC.LCTL(KC.LSFT(KC.S))
PSCR = KC.LGUI(KC.PSCR)
SNIP = simple_key_sequence(
(
KC.LGUI,
KC.MACRO_SLEEP_MS(25),
KC.S,
KC.N,
KC.I,
KC.P,
KC.MACRO_SLEEP_MS(25),
KC.ENT,
)
)
# programming layer keys
UINT = simple_key_sequence(
(
KC.U,
KC.I,
KC.N,
KC.T,
)
)
INT = simple_key_sequence(
(
KC.I,
KC.N,
KC.T,
)
)
DOUBLE = simple_key_sequence(
(
KC.D,
KC.O,
KC.U,
KC.B,
KC.L,
KC.E,
)
)
BOOL = simple_key_sequence(
(
KC.B,
KC.O,
KC.O,
KC.L,
)
)
BYTE = simple_key_sequence(
(
KC.B,
KC.Y,
KC.T,
KC.E,
)
)
SBYTE = simple_key_sequence(
(
KC.S,
KC.B,
KC.Y,
KC.T,
KC.E,
)
)
CHAR = simple_key_sequence(
(
KC.C,
KC.H,
KC.A,
KC.R,
)
)
GETSET = simple_key_sequence(
(
KC.LBRC,
KC.SPC,
KC.G,
KC.E,
KC.T,
KC.SCLN,
KC.SPC,
KC.S,
KC.E,
KC.T,
KC.SCLN,
KC.SPC,
KC.RBRC,
)
)
PUBLIC = simple_key_sequence(
(
KC.P,
KC.U,
KC.B,
KC.L,
KC.I,
KC.C,
)
)
DEBUGWL = simple_key_sequence(
(
KC.LSFT(KC.D),
KC.E,
KC.B,
KC.U,
KC.G,
KC.DOT,
KC.LSFT(KC.W),
KC.R,
KC.I,
KC.T,
KC.E,
KC.LSFT(KC.L),
KC.I,
KC.N,
KC.E,
KC.LSFT(KC.N9),
)
)
PRINT = simple_key_sequence(
(
KC.P,
KC.R,
KC.I,
KC.N,
KC.T,
)
)
# make keymap
keyboard.keymap = [
[ # qwerty
KC.ESC, KC.N1, KC.N2, KC.N3, KC.N4, KC.N5, KC.N6, KC.N7, KC.N8, KC.N9, KC.N0, KC.MINS,
KC.CAPS, KC.Q, KC.W, KC.E, KC.R, KC.T, KC.Y, KC.U, KC.I, KC.O, KC.P, KC.PSLS,
KC.TAB, KC.A, KC.S, KC.D, KC.F, KC.G, KC.H, KC.J, KC.K, KC.L, KC.SCLN, KC.QUOT,
KC.TRNS, KC.Z, KC.X, KC.C, KC.V, KC.B, KC.N, KC.M, KC.COMM, KC.DOT, KC.SLSH, FE,
KC.BSPC, KC.DEL, KC.LALT, KC.LSFT, KC.LCTL, KC.BSPC, KC.SPC, KC.ENT, KC.RSFT, KC.RCTL, KC.ENT, KC.RGUI,
XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, KC.MO(1), KC.MO(2), KC.MUTE, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
],
[ # navnum
KC.TRNS, SAVE_AS, PSCR, SNIP, KC.LGUI, NEW_DIR, KC.PSLS, KC.RGUI, KC.NO, KC.NO, KC.NO, KC.MINS,
KC.BSLS, KC.NO, KC.HOME, KC.UP, KC.END, NEW, KC.N5, KC.N6, KC.N7, KC.N8, KC.N9, KC.BSLS,
KC.F2, KC.NO, KC.LEFT, KC.DOWN, KC.RGHT, KC.HASH, KC.N0, KC.N1, KC.N2, KC.N3, KC.N4, KC.QUOT,
KC.LSFT, KC.NO, KC.NO, KC.NO, KC.TAB, KC.UNDS, KC.MINS, KC.PPLS, KC.MINS, KC.PAST, KC.PSLS, KC.LBRC,
KC.BSPC, KC.NO, KC.NO, KC.NO, KC.NO, KC.TRNS, KC.SPC, KC.EQL, KC.N0, KC.DOT, KC.ENT, KC.RGUI,
XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, KC.TRNS, KC.TRNS, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
],
[ # sym/prog
KC.TRNS, KC.NO, KC.NO, KC.NO, KC.F2, KC.AMPR, PRINT, DEBUGWL, SAVE_AS, KC.NO, KC.NO, KC.NO,
KC.BSLS, KC.NO, KC.NO, KC.LCBR, KC.RCBR, KC.AT, INT, GETSET, KC.UP, KC.NO, KC.NO, KC.NO,
KC.TAB, KC.NO, KC.NO, KC.LPRN, KC.RPRN, KC.DLR, BOOL, KC.LEFT, KC.DOWN, KC.RGHT, KC.NO, KC.NO,
KC.LSFT, KC.NO, KC.NO, KC.LBRC, KC.RBRC, KC.PERC, UINT, DOUBLE, KC.NO, KC.NO, KC.NO, KC.NO,
KC.BSPC, KC.LGUI, KC.LALT, KC.LSFT, KC.LCTL, KC.DEL, KC.TRNS, PUBLIC, KC.RCTL, KC.RALT, KC.ENT, KC.RESET,
XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, KC.TRNS, KC.TRNS, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
],
]
if __name__ == '__main__':
keyboard.go()
+1 -1
View File
@@ -4,7 +4,7 @@
![Crkbd](https://boardsource.imgix.net/9cbd31b7-3b37-42c6-919e-3be35a2578f6.jpg?raw=true)
A split keyboard with a 3x6 collumnar stagger and 3 thumb keys.
A split keyboard with a 3x6 columnar stagger and 3 thumb keys.
kb.py is designed to work with the nice!nano
+29
View File
@@ -0,0 +1,29 @@
import board
from kmk.kmk_keyboard import KMKKeyboard as _KMKKeyboard
from kmk.matrix import DiodeOrientation
from kmk.matrix import intify_coordinate as ic
class KMKKeyboard(_KMKKeyboard):
col_pins = (
board.A3,
board.A2,
board.A1,
board.A0,
board.SCK,
board.MISO,
)
row_pins = (board.D4, board.D5, board.D6, board.D7)
diode_orientation = DiodeOrientation.COLUMNS
data_pin = board.RX
rgb_pixel_pin = board.D0
i2c = board.I2C
coord_mapping = []
coord_mapping.extend(ic(0, x) for x in range(12))
coord_mapping.extend(ic(1, x) for x in range(12))
coord_mapping.extend(ic(2, x) for x in range(12))
# And now, to handle R3, which at this point is down to just six keys
coord_mapping.extend(ic(3, x) for x in range(3, 9))
+2 -2
View File
@@ -1,4 +1,4 @@
from kb import KMKKeyboard, rgb_pixel_pin
from kb import KMKKeyboard
from kmk.extensions.rgb import RGB
from kmk.keys import KC
from kmk.modules.layers import Layers
@@ -7,7 +7,7 @@ from kmk.modules.split import Split, SplitSide, SplitType
keyboard = KMKKeyboard()
# Adding extensions
rgb = RGB(pixel_pin=rgb_pixel_pin, num_pixels=27, val_limit=100, hue_default=190, sat_default=100, val_default=5)
rgb = RGB(pixel_pin=keyboard.rgb_pixel_pin, num_pixels=27, val_limit=100, hue_default=190, sat_default=100, val_default=5)
# TODO Comment one of these on each side
split_side = SplitSide.LEFT
+78 -55
View File
@@ -1,67 +1,84 @@
# Getting Started
## Microcontrollers
KMK will run on most microcontrollers supported by
[Circuitpython](https://circuitpython.org/downloads). Our recommended
microcontrollers are found [here](Officially_Supported_Microcontrollers.md)
## Firmware
### KMKPython
KMKPython is a fork of Circuitpython, but with libraries for most extensions
built in. This saves you from having to get them all and keep them updated
yourself. There may be other features added in the future that are exclusive to
KMKPython. For the nice!nano, this is highly recommended, and used in place of
Circuitpython.
Notable differences include
- Built in libraries for bluetooth, RGB, and more
- Saves space as builds are optimized for keyboards
- Microcontrollers like the nice!nano will be able to access all features out of
the box.
> Life was like a box of chocolates. You never know what you're gonna get.
### Circuitpython
Circuitpython can be installed by following this guide using the guide
[here](https://learn.adafruit.com/welcome-to-circuitpython/installing-circuitpython).
It's recommended to run the latest stable version that is at least 5.0 or higher.
Beta versions may work, but expect limited support.
#### Notable differences include
- Supports more devices
- Less built in libraries. If using RGB, bluetooth, and more, you will have to
add these libraries yourself
- Some devices such as the nice!nano don't have much free space, so not all
features can be installed at the same time
## Getting KMK
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. Just get the KMK folder
and drop this directly in the CIRCUITPYTHON directory (not in a sub folder).
Make sure to extract the zip, and put the `kmk` folder on the root of the
CIRCUITPY drive on the microcontroller
KMK is a keyboard focused layer that sits on top of [CircuitPython](https://circuitpython.org/). As such, it should work with most [boards that support CircuitPython](https://circuitpython.org/downloads). It is best to use the last stable version (>5.0).
Known working and recommended devices can be found [here](Officially_Supported_Microcontrollers.md)
## Turning a controller into a keyboard
### Supported keyboards
If your keyboard and microcontroller are officially supported, simply visit the
page for your files, and dropping them on the root of the "flash drive". Those
pages can be found [here](https://github.com/KMKfw/boards). You will need the
`kb.py` and `main.py`. More advanced instructions can be found
[here](config_and_keymap.md). If using Curcuitpython and NOT KMKPython, you will
also need [boot.py](https://github.com/KMKfw/kmk_firmware/blob/master/boot.py)
We are also providing a keyboard optimized version of CircuitPython (simplified to cope with memory limits of certain boards and with a selection of preinstalled relevant modules). If you're wondering why use KMKPython rather than barebone CircuitPython, we tried to compare both approaches [here](kmkpython_vs_circuitpython.md)
### Porting a keyboard
If you are porting a board to KMK, check the page [here](porting_to_kmk.md).
<br>
### Handwired Keyboard
If you are doing a hand wire, check [here](handwiring.md)
## TL;DR Quick start guide
> To infinity and beyond!
1. [Install CircuitPython on your board](https://learn.adafruit.com/welcome-to-circuitpython/installing-circuitpython). With most boards, it should be as easy as drag and dropping the firmware on the drive
2. Get a [copy of KMK](https://github.com/KMKfw/kmk_firmware/archive/refs/heads/master.zip) from the master branch
3. Unzip it and copy the KMK folder and the boot.py file at the root of the USB drive corresponding to your board (often appearing as CIRCUITPY)
4. Create a new *code.py* or *main.py* file in the same root directory (same level as boot.py) with the example content hereunder:
## Additional features
Want to have fun features such as RGB, split keyboards and more? Check out what
extensions can do [here](extensions.md)
## Debugging
Debugging help can be found [here](debugging.md)
***IMPORTANT:*** adapt the GP0 / GP1 pins to your specific board ! <br>
```
print("Starting")
import board
from kmk.kmk_keyboard import KMKKeyboard
from kmk.keys import KC
from kmk.matrix import DiodeOrientation
keyboard = KMKKeyboard()
keyboard.col_pins = (board.GP0,)
keyboard.row_pins = (board.GP1,)
keyboard.diode_orientation = DiodeOrientation.COLUMNS
keyboard.keymap = [
[KC.A,]
]
if __name__ == '__main__':
keyboard.go()
```
5. With a wire / paperclip / whatever, connect GPIO 0 & GPIO 1 together (or the pins you chose for your boards)
6. If it prints a "A" (or a "Q" or ... depending on your keyboard layout), you're done!
<br>
## Now that you're up and running, you may want to go further...
> This is your last chance. After this, there is no turning back. You take the blue pill—the story ends, you wake up in your bed and believe whatever you want to believe. You take the red pill—you stay in Wonderland, and I show you how deep the rabbit hole goes. Remember: all I'm offering is the truth. Nothing more.
### You're extremely lucky and you have a fully supported keyboard
If your keyboard and microcontroller are officially supported, simply visit the page for your files, and dropping them on the root of the "flash drive". Those pages can be found [here](https://github.com/KMKfw/boards). You will need the `kb.py` and `main.py`. More advanced instructions can be found [here](config_and_keymap.md).
Please note that we recommend using [KMKPython](https://github.com/KMKfw/kmkpython) for these boards as it is optimized for them. If using Circuitpython and NOT KMKPython, you will also need [boot.py](https://github.com/KMKfw/kmk_firmware/blob/master/boot.py)
### You've got another, maybe DIY, board and want to customise KMK for it
First, be sure to understand how your device work, and particularly its specific matrix configuration. You can have a look [here](http://pcbheaven.com/wikipages/How_Key_Matrices_Works/) or read the [guide](https://docs.qmk.fm/#/hand_wire) provided by the QMK team for handwired keyboards
<br>Once you've got the gist of it:
- You can have a look [here](config_and_keymap.md) and [here](keys.md) to start customizing your code.py / main.py file
- There's a [reference](keycodes.md) of the available keycodes
- [International](international.md) extension adds keys for non US layouts and [Media Keys](media_keys.md) adds keys for ... media
And to go even further:
- [Sequences](sequences.md) are used for sending multiple keystrokes in a single action
- [Layers](layers.md) can transform the whole way your keyboard is behaving with a single touch
- [ModTap](modtap.md) allow you tu customize the way a key behaves wether it is tapped or hold, and [TapDance](tapdance.md) depending on the number of times it is pressed
Want to have fun features such as RGB, split keyboards and more? Check out what builtin [modules](modules.md) and [extensions](extensions.md) can do!
You can also get ideas from the various [user examples](https://github.com/KMKfw/user_keymaps) that we provide and dig into our [documentation](https://github.com/KMKfw/kmk_firmware/tree/master/docs)
<br>
## Additional help and support
> Roads? Where we're going we don't need roads.
In case you need it, debugging help can be found [here](debugging.md)
If you need support with KMK or just want to say hi, find us in
[#kmkfw:klar.sh on Matrix](https://matrix.to/#/#kmkfw:klar.sh). This channel is
bridged to Discord [here](https://discordapp.com/widget?id=493256121075761173&theme=dark)
@@ -69,3 +86,9 @@ 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.
+58
View File
@@ -0,0 +1,58 @@
# Encoder
Add twist control to your keyboard! Volume, zoom, anything you want.
## Enabling the extension
The constructor takes a minimun of 3 arguments: a list of pad_a pins, a list of pad_b pins,
and an encoder_map. The encoder_map is modeled after the keymap and works the
same way. It should have as many layers as your keymap, and use KC.NO keys for
layers that you don't require any action. The encoder supports a velocity mode
if you desire to make something for video or sound editing. The direction of
increment/decrement can be changed to make sense for the direction the knob is
turning by setting the is_inverted flag.
## Configuration
There is a complete example in the Atreus62 main.py
Create your special keys:
```python
Zoom_in = KC.LCTRL(KC.EQUAL)
Zoom_out = KC.LCTRL(KC.MINUS)
```
Create the encoder_map.
Anatomy of an encoder_map tuple: (increment_key, decrement_key, keys presses per encoder click)
```python
# create the encoder map, modeled after the keymap
encoder_map = [
[
# Only 1 encoder is being used, so only one tuple per layer is required
# Increment key is volume up, decrement key is volume down, and sends 2
# key presses for every "click" felt while turning the encoder.
(KC.VOLU,KC.VOLD,2),
[
# only one key press sent per encoder click
(Zoom_in, Zoom_out,1),
],
[
# No action keys sent here, the resolution is a dummy number, to be
# removed in the future.
(_______,_______,1),#
]
]
# create the encoder instance, and pass in a list of pad a pins, a lsit of pad b
# pins, and the encoder map created above
encoder_ext = EncoderHandler([board.D40],[board.D41], encoder_map)
# if desired, you can flip the incrfement/decrement direction of the knob by
# setting the is_inerted flag to True. If you turn the knob to the right and
# the volume goes down, setting this flag will make it go up. It's default
# setting is False
encoder_ext.encoders[0].is_inverted = True
# Make sure to add the encoder_ext to the modules list
keyboard.modules = [encoder_ext]
```
+2 -2
View File
@@ -1,6 +1,6 @@
# Handwire keyboards
This guide will not talk about the physical wiring. Check out our
[recommended microcontrollers](Offiially_Supported_Microcontrollers.md) and
follow the amazing guide for that[here](https://docs.qmk.fm/#/hand_wire). That
[recommended microcontrollers](Officially_Supported_Microcontrollers.md) and
follow the amazing guide for that [here](https://docs.qmk.fm/#/hand_wire). That
guide can be followed until you are setting up the firmware. After wiring the
keyboard, you can refer to our porting guide [here](porting_to_kmk.md)
+110
View File
@@ -0,0 +1,110 @@
# はじめに
> Life was like a box of chocolates. You never know what you're gonna get.
KMKは[CircuitPython](https://circuitpython.org/)の上に配置されるキーボード用の実装レイヤーです。
そのため、[CircuitPythonをサポートするほとんどのボード](https://circuitpython.org/downloads)と互換性があります。
最新の安定したバージョンを使用することをおすすめします。(>5.0)
使用可能やおすすめなデバイスは[こちら](Officially_Supported_Microcontrollers.md)から確認できます。
CircuitPythonの最適化バージョン(特定のボードの容量制限に対処した、プリインストールされた関連モジュールの選択が可能なバージョン)も提供しています。
なぜCircuitPythonよりKMKPythonを使用するか気になっていたら、両方を比較した[実績](kmkpython_vs_circuitpython.md)があります。
<br>
## TL;DR クイックスタートガイド
> To infinity and beyond!
1. CircuitPythonをボードに[インストール](https://learn.adafruit.com/welcome-to-circuitpython/installing-circuitpython)する。
2. マスターブランチから[KMKのコピー](https://github.com/KMKfw/kmk_firmware/archive/refs/heads/master.zip)を取得。
3. ファイルを展開し、KMKフォルダーとboot.pyファイルをUSBドライブのルート(CIRCUITPYと表示されることが多い)にコピーする。
4. 同じルートディレクトリー(boot.pyと同レベル)に新規で*code.py* または *main.py*のファイルを作成する。中身は以下の例とする。
***重要:*** GP0 / GP1 ピンを使用ボードに合わせて下さい!<br>
```
print("Starting")
import board
from kmk.kmk_keyboard import KMKKeyboard
from kmk.keys import KC
from kmk.matrix import DiodeOrientation
keyboard = KMKKeyboard()
keyboard.col_pins = (board.GP0,)
keyboard.row_pins = (board.GP1,)
keyboard.diode_orientation = DiodeOrientation.COLUMNS
keyboard.keymap = [
[KC.A,]
]
if __name__ == '__main__':
keyboard.go()
```
1. ワイヤーなどでGPIO 0とGPIO 1(またはほかに指定したピン)を接続する。
2. "A"や"Q"(キーボードのレイアウトによって異なる)が表示されたら、完成!
<br>
## とりあえず一通り動くようになったので、もっとに先へ進みたい場合
> This is your last chance. After this, there is no turning back. You take the blue pill—the story ends, you wake up in your bed and believe whatever you want to believe. You take the red pill—you stay in Wonderland, and I show you how deep the rabbit hole goes. Remember: all I'm offering is the truth. Nothing more.
### フルサポートされているキーボードを持っている場合
あなたのキーボードとマイコンが正式にサポートされている場合、[こちらのページ](https://github.com/KMKfw/boards)から`kb.py` と `main.py`を"flash drive"のルートに落とす必要があります。より高度な手順は[こちら](config_and_keymap.md)から確認できます。
このボードに最適化されているため、 [KMKPython](https://github.com/KMKfw/kmkpython) の使用を推奨します。
Circuitpythonを使用する場合、 [boot.py](https://github.com/KMKfw/kmk_firmware/blob/master/boot.py)も必要になります。
### ほかに自作ボードなどを持っていて、カスタマイズされたKMKを導入したい場合
最初にデバイスの動作や具体的なマトリックス構成についてしっかり理解してください。
QMKチームが提供している手配線キーボード用の[ガイド](https://docs.qmk.fm/#/hand_wire)と[ドキュメント](http://pcbheaven.com/wikipages/How_Key_Matrices_Works/) を確認できます。
<br>要旨をつかめてきたら:
- [ここ](config_and_keymap.md) と [ここ](keys.md)を見て、code.py / main.py ファイルをカスタイマイズできます。
- 使用可能なキーコードの[リファレンス](keycodes.md)があります。
- [インターナショナル](international.md)は、US配列以外のキーボードにキーを追加する拡張機能で、[メディアキー](media_keys.md)は・・・メディアにキーを追加する拡張機能です。
さらに先へ進むと:
- [シーケンス](sequences.md) 一つのアクションで複数のキーストロークを送信するために使用します。
- [レイヤー](layers.md)でタッチ一つでキーボードの全体の動きを変えることができます。
- [モドタップ](modtap.md) でキーの押し/長押しの動作を設定し、何回押されたかによって[タップダンス](tapdance.md)を設定します。
RGBや分裂型などの機能を楽しめたい場合は、ビルトイン[モジュール](modules.md)と[拡張機能](extensions.md)を見てみてください!
私たちが提供する、いろんな [ユーザー事例](https://github.com/KMKfw/user_keymaps)や[ドキュメント](https://github.com/KMKfw/kmk_firmware/tree/master/docs)からアイデアを得ることもできます。
<br>
## ヘルプ/サポート
> Roads? Where we're going we don't need roads.
デバッグについてのヘルプが必要な場合は[こちら](debugging.md)。
KMKについてサポートが必要な場合や、コミュニケーションをとりたい場合は[こちら](https://matrix.to/#/#kmkfw:klar.sh)。
このチャネルは[Discord](https://discordapp.com/widget?id=493256121075761173&theme=dark) からも見ることができます。
チャットやバグ報告などでヘルプを求める場合、可能な限り、コントローラーのREPLに`from kmk.consts import KMK_RELEASE; print(KMK_RELEASE)`を実行することによって表示されるコミットSHAを記載してください。
+25
View File
@@ -165,6 +165,31 @@
|`KC.RIGHT_ANGLE_BRACKET`|`KC.RABK`, `KC.GT` |`>` |
|`KC.QUESTION` |`KC.QUES` |`?` |
## [International Keys]
|Key |Aliases |Description |
|------------------------|------------------------------|-----------------------|
|`KC.NONUS_HASH` |`KC.NUHS` |ISO Right of LSHIFT |
|`KC.NONUS_BSLASH` |`KC.NUBS` |ISO Left of Return |
|`KC.APPLICATION` |`KC.APP`,`KC.SEL`,`KC.WINMENU`|Menu Key (Near RCTRL) |
|`KC.INT1` |`KC.RO` | |
|`KC.INT2` |`KC.KANA` | |
|`KC.INT3` |`KC.JYEN` | |
|`KC.INT4` |`KC.HENK` | |
|`KC.INT5` |`KC.MHEN` | |
|`KC.INT6` | | |
|`KC.INT7` | | |
|`KC.INT8` | | |
|`KC.INT9` | | |
|`KC.LANG1` |`HAEN` | |
|`KC.LANG2` |`HAEJ` | |
|`KC.LANG3` | | |
|`KC.LANG4` | | |
|`KC.LANG5` | | |
|`KC.LANG6` | | |
|`KC.LANG7` | | |
|`KC.LANG8` | | |
|`KC.LANG9` | | |
## [Internal Keys]
+24
View File
@@ -0,0 +1,24 @@
## Firmware of choice
### KMKPython
KMKPython is a fork of Circuitpython, but with libraries for most extensions
built in. This saves you from having to get them all and keep them updated
yourself. There may be other features added in the future that are exclusive to
KMKPython. For the nice!nano, this is highly recommended, and used in place of
Circuitpython.
Notable differences include
- Built in libraries for bluetooth, RGB, and more
- Saves space as builds are optimized for keyboards
- Microcontrollers like the nice!nano will be able to access all features out of
the box.
### Circuitpython
Circuitpython can be installed by following this guide using the guide
[here](https://learn.adafruit.com/welcome-to-circuitpython/installing-circuitpython).
It's recommended to run the latest stable version that is at least 5.0 or higher.
Beta versions may work, but expect limited support.
#### Notable differences include
- Supports more devices
- Less built in libraries. If using RGB, bluetooth, and more, you will have to
add these libraries yourself
- Some devices such as the nice!nano don't have much free space, so not all
features can be installed at the same time
+140
View File
@@ -0,0 +1,140 @@
# Começando
> A vida era como uma caixa de chocolates. Você nunca saberia o que iria
> encontrar.
KMK é uma camada focada em teclados que assenta-se em cima de
[CircuitPython](https://circuitpython.org/). Como tal, ela deve funcionar com a
maior parte das [placas que suportam
CircuitPython](https://circuitpython.org/downloads). É melhor usar a última
versão estável (>5.0). Dispositivos funcionais e recomendados podem ser
encontrados [aqui](Officially_Supported_Microcontrollers.md)
Também fornecemos uma versão de CircuitPython otimizada para teclados
(simplificada para lidar com os limites de certas placas e com a seleção dos
módulos relevantes pré-instalados). Se você estiver se perguntando por que usar
KMKPython em vez do CircuitPython cru, tentamos comparar ambas as abordagens
[aqui](kmkpython_vs_circuitpython.md)
<br>
## Guia Rápido
> Ao Infinito e Além!
1. [Installe CircuitPython na tua
placa](https://learn.adafruit.com/welcome-to-circuitpython/installing-circuitpython).
Com a maioria das placas, deve ser algo tão fácil quanto copiar e colar o
firmware no drive.
2. Obtenha uma [cópia do
KMK](https://github.com/KMKfw/kmk_firmware/archive/refs/heads/master.zip) a
partir do ramo master.
3. Descompacte e cole o diretório KMK e o arquivo boot.py na raiz do drive USB
correspondente à tua placa (geralmente aparecendo como CIRCUITPY).
4. Crie um novo arquivo *code.py* ou *main.py* no mesmo diretório raiz (no
mesmo nível de boot.py) com o exemplo contido abaixo:
***IMPORTANTE:*** adapte os pinos GP0 / GP1 para a tua placa específica! <br>
```
print("Starting")
import board
from kmk.kmk_keyboard import KMKKeyboard
from kmk.keys import KC
from kmk.matrix import DiodeOrientation
keyboard = KMKKeyboard()
keyboard.col_pins = (board.GP0,)
keyboard.row_pins = (board.GP1,)
keyboard.diode_orientation = DiodeOrientation.COLUMNS
keyboard.keymap = [
[KC.A,]
]
if __name__ == '__main__':
keyboard.go()
```
5. Usando um fio, um clipe de papel ou o que seja, conecte o GPIO 0 e o GPIO 1
(ou os pinos que você escolheu para tua placa).
6. Se ela imprimir um "A" (ou um "Q" ou o que depender do teu layout de
teclado), você conseguiu!
<br>
## Agora que tudo está no seu lugar, você pode querer ir além...
> Esta é tua última chance. Após isso Esta é sua última chance. Depois não há
> como voltar. Se tomar a pílula azul a história acaba, e você acordará na sua
> cama acreditando no que quiser. Se tomar a pílula vermelha ficará no País das
> Maravilhas e eu te mostrarei até onde vai a toca do coelho. Lembre-se: tudo o
> que estou te oferecendo é a verdade. Nada mais.
### Você é extremamente sortudo e tem um teclado totalmente suportado
Se seu teclado e micro-controlador são suportados oficialmente, simplesmente
visite a webpage com os seus arquivos e coloque-os na raiz do "flash drive".
Estas webpages podem ser vistas [aqui](https://github.com/KMKfw/boards). Você
precisará dos arquivos `kb.py` e `main.py`. Instruções mais avançadas podem ser
vistas [aqui*](config_and_keymap.md).
Note que recomendamos utilizar [KMKPython](https://github.com/KMKfw/kmkpython)
para essas placas pois ele é otimizado para elas. Se você usar o Circuitpython
em vez do KMKPython, você também vai precisar do
[boot.py](https://github.com/KMKfw/kmk_firmware/blob/master/boot.py).
### Você obteve outro teclado, possivelmente artesanal, e quer customizar o KMK para ele
Primeiro, certifique-se de entender como o seu teclado funciona, e em particular
sua configuração matricial específica. Você pode observar
[aqui](http://pcbheaven.com/wikipages/How_Key_Matrices_Works/) ou ler o
[guia](https://docs.qmk.fm/#/hand_wire) feito pelo time da QMK para teclados
artesanais.
<br>Uma vez que você compreendeu a essência da coisa:
- Você pode dar uma olhada [aqui*](config_and_keymap.md) e [aqui*](keys.md) para
começar a customizar seu arquivo code.py / main.py.
- Eis uma [referência*](keycodes.md) dos códigos de teclas (*keycodes*)
disponíveis.
- A extensão [internacional](international.md) acrescenta teclas para layouts
não-americanos, e as [teclas de mídia](media_keys.md) acrecentam teclas
para... mídia.
E para ir mais além:
- [Sequências*](sequences.md) são usadas para enviar múltiplas teclas em uma ação
só;
- [Camadas*](layers.md) podem transformar totalmente como seu teclado age com um
simples toque.
- [ModTap*](modtap.md) te permite customizar a maneira que uma tecla age quando é
pressionada ou "segurada"; e o
- [TapDance*](tapdance.md) dependendo do número de vezes que ela é pressionada.
Você quer extensões divertidas como RGB, teclados divididos ao meio e mais?
Confira o que os [módulos*](modules.md) e [extensões*](extensions.md) podem
fazer!
Você também pode obter ideias dos vários [exemplos de
usuários](https://github.com/KMKfw/user_keymaps) que fornecemos e fuce nossa
[documentação](https://github.com/KMKfw/kmk_firmware/tree/master/docs).
<br>
## Ajuda e Suporte Adicionais
> Roads? Where we're going we don't need roads.
Caso precise, ajuda para depuração pode ser encontrada [aqui](debugging.md).
Se você precisa de suporte com o KMK ou quer somente dizer oi, encontre-nos no
canal [#kmkfw:klar.sh no Matrix](https://matrix.to/#/#kmkfw:klar.sh). Este canal
tem uma ponte no Discord
[aqui](https://discordapp.com/widget?id=493256121075761173&theme=dark) por
conveniência. Se você precisa de ajuda ou pretende abrir um bug report, se
possível forneça o hash SHA do *commit* utilizado, o qual pode ser obtido
executando este comando no REPL de seu controlador:
`from kmk.consts import KMK_RELEASE; print(KMK_RELEASE)`
@@ -0,0 +1,72 @@
# Micro-Controladores Oficialmente Suportados
Enquanto a maioria dos dispositivos com Circuitpython são muito bons para
teclados artesanais, amaioria dos teclados é projetada para aceitar um Pro
Micro. As placas listadas abaixo ou são, ou podem ser adaptadas para essa
pinagem a fim de usar teclados comuns já presentes no mercado.
## Nice!Nano
Características:
- Pinagem Pro Micro
- Suporte a USB HID e Bluetooth
- Pode ser usado para teclados divididos Bluetooth sem fio
- Suporte a bateria, incluindo carga
Desvantagens:
- 25 dólares por micro-controladores na maioria das revendedoras
Varejistas comund:
- [Boardsource](https://boardsource.xyz/store/5f4a1733bbaa5c635b83ed67)
- [NiceKeyboards](https://nicekeyboards.com/collections/group-buy/products/nice-nano-v1-0).
## ItsyBitsy M4 Express
Características:
- Preços acessíveis a partir de 15 dólares
- Pode rodar a maior parte das vantagens do KMK, incluindo RGB
Desvantagens:
- Precisa de adaptadir para funcionar com a pinagem do Pro Micro. O adaptador
pode ser encontrado
[AQUI](https://github.com/KMKfw/kmk_firmware/tree/master/hardware)
Varejistas Comuns:
- [Adafruit](https://www.adafruit.com/product/3800)
## RP2040
Características:
- Preço bastante acessível
- Bastante poderosa dado o preço
Desvantagens:
- Pouco suporte para kits de teclado
Varejistas comuns:
- [Adafruit](https://www.adafruit.com/pico?src=raspberrypi)
- [Sparkfun](https://www.sparkfun.com/products/17829?src=raspberrypi)
## Adafruit ItsyBitsy nRF52840 Express
Características:
- Suporte a USB HID e Bluetooth
- Mais acessível que o Nice!Nano, apenas 18 dólares
Desvantagens:
- Precisa de adaptador para funcionar com teclados de pinagem Pro Micro pinout
keyboards. O adaptador pode ser encontrado
[AQUI](https://github.com/KMKfw/kmk_firmware/tree/master/hardware)
- O suporte à bateria precisa de uma placa adicional encontrada
[AQUI](https://www.adafruit.com/product/2124)
Varejistas comuns:
- [Adafruit](https://www.adafruit.com/product/4481)
## Outros Micro-Controladores
O mínimo que você vai precisar:
- CircuitPython/KMKpython
- 256KB de armazenamento flash
- HID sobre USB e/ou Bluetooth.
+31
View File
@@ -0,0 +1,31 @@
## Comparação de Firmware
### KMKPython
KMKPython é um *fork* do Circuitpython, mas com bibliotecas para a maior parte
das extensões já embutidas. Isto te poupa de ter que reuni-las e atualizá-las
manualmente. Pode haver outras características adicionadas no futuro exclusivas
para o KMKPython. Para o nice!nano, o KMKPython é altamente recomendado e usado
em lugar do Circuitpython.
#### Diferenças Notáveis
- Bibliotecas embutidas para Bluetooth, RGB etc.
- Economiza espaço, pois os binários gerados são otimizados para teclados.
- micro-controladores como o nice!nano poderão acessar todas as vantagens
diretamente.
### Circuitpython
Circuitpython pode ser instalado seguindo [este
guia](https://learn.adafruit.com/welcome-to-circuitpython/installing-circuitpython).
É recomendável utilizar a versão mais recente, 5.0 ou superior. Versões beta
podem funcionar, mas espere suporte limitado.
#### Diferenças Notáveis
- Suporta mais dispositivos.
- Menos bibliotecas embutidas. Se precisar de RGB, Bluetooth e mais, você terá
que adicionar estas bibliotecas manualmente.
- Alguns dispositivos como o nice!nano não dispõem de muito espaço livre, então
nem todas as vantagens podem ser instaladas ao mesmo tempo.
+273 -405
View File
@@ -10,6 +10,8 @@ from kmk.key_validators import (
)
from kmk.types import AttrDict, UnicodeModeKeyMeta
DEBUG_OUTPUT = False
FIRST_KMK_INTERNAL_KEY = const(1000)
NEXT_AVAILABLE_KEY = 1000
@@ -17,416 +19,85 @@ KEY_SIMPLE = const(0)
KEY_MODIFIER = const(1)
KEY_CONSUMER = const(2)
ALL_ALPHAS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
ALL_NUMBERS = '1234567890'
# since KC.1 isn't valid Python, alias to KC.N1
ALL_NUMBER_ALIASES = tuple(f'N{x}' for x in ALL_NUMBERS)
class InfiniteLoopDetected(Exception):
pass
# this is a bit of an FP style thing - combining a pipe operator a-la F# with
# a bootleg Maybe monad to clean up these make_key sequences
def left_pipe_until_some(candidate, functor, *args_iter):
for args in args_iter:
result = functor(candidate, *args)
if result is not None:
return result
def first_truthy(candidate, *funcs):
for func in funcs:
result = func(candidate)
if result is not None:
return result
def maybe_make_mod_key(candidate, code, names):
if candidate in names:
return make_mod_key(code=code, names=names)
def maybe_make_key(candidate, code, names):
if candidate in names:
return make_key(code=code, names=names)
def maybe_make_shifted_key(candidate, target_name, names):
if candidate in names:
return make_shifted_key(target_name=target_name, names=names)
def maybe_make_consumer_key(candidate, code, names):
if candidate in names:
return make_consumer_key(code=code, names=names)
class KeyAttrDict(AttrDict):
def __getattr__(self, key):
def __getattr__(self, key, depth=0):
if depth > 1:
raise InfiniteLoopDetected()
try:
return super(KeyAttrDict, self).__getattr__(key)
except Exception:
pass
# Modifiers
if key in ('LEFT_CONTROL', 'LCTRL', 'LCTL'):
make_mod_key(code=0x01, names=('LEFT_CONTROL', 'LCTRL', 'LCTL'))
elif key in ('LEFT_SHIFT', 'LSHIFT', 'LSFT'):
make_mod_key(code=0x02, names=('LEFT_SHIFT', 'LSHIFT', 'LSFT'))
elif key in ('LEFT_ALT', 'LALT'):
make_mod_key(code=0x04, names=('LEFT_ALT', 'LALT'))
elif key in ('LEFT_SUPER', 'LGUI', 'LCMD', 'LWIN'):
make_mod_key(code=0x08, names=('LEFT_SUPER', 'LGUI', 'LCMD', 'LWIN'))
elif key in ('RIGHT_CONTROL', 'RCTRL', 'RCTL'):
make_mod_key(code=0x10, names=('RIGHT_CONTROL', 'RCTRL', 'RCTL'))
elif key in ('RIGHT_SHIFT', 'RSHIFT', 'RSFT'):
make_mod_key(code=0x20, names=('RIGHT_SHIFT', 'RSHIFT', 'RSFT'))
elif key in ('RIGHT_ALT', 'RALT'):
make_mod_key(code=0x40, names=('RIGHT_ALT', 'RALT'))
elif key in ('RIGHT_SUPER', 'RGUI', 'RCMD', 'RWIN'):
make_mod_key(code=0x80, names=('RIGHT_SUPER', 'RGUI', 'RCMD', 'RWIN'))
# MEH = LCTL | LALT | LSFT# MEH = LCTL |
elif key in ('MEH',):
make_mod_key(code=0x07, names=('MEH',))
# HYPR = LCTL | LALT | LSFT | LGUI
elif key in ('HYPER', 'HYPR'):
make_mod_key(code=0x0F, names=('HYPER', 'HYPR'))
# Basic ASCII letters
elif key in ('A',):
make_key(code=4, names=('A',))
elif key in ('B',):
make_key(code=5, names=('B',))
elif key in ('C',):
make_key(code=6, names=('C',))
elif key in ('D',):
make_key(code=7, names=('D',))
elif key in ('E',):
make_key(code=8, names=('E',))
elif key in ('F',):
make_key(code=9, names=('F',))
elif key in ('G',):
make_key(code=10, names=('G',))
elif key in ('H',):
make_key(code=11, names=('H',))
elif key in ('I',):
make_key(code=12, names=('I',))
elif key in ('J',):
make_key(code=13, names=('J',))
elif key in ('K',):
make_key(code=14, names=('K',))
elif key in ('L',):
make_key(code=15, names=('L',))
elif key in ('M',):
make_key(code=16, names=('M',))
elif key in ('N',):
make_key(code=17, names=('N',))
elif key in ('O',):
make_key(code=18, names=('O',))
elif key in ('P',):
make_key(code=19, names=('P',))
elif key in ('Q',):
make_key(code=20, names=('Q',))
elif key in ('R',):
make_key(code=21, names=('R',))
elif key in ('S',):
make_key(code=22, names=('S',))
elif key in ('T',):
make_key(code=23, names=('T',))
elif key in ('U',):
make_key(code=24, names=('U',))
elif key in ('V',):
make_key(code=25, names=('V',))
elif key in ('W',):
make_key(code=26, names=('W',))
elif key in ('X',):
make_key(code=27, names=('X',))
elif key in ('Y',):
make_key(code=28, names=('Y',))
elif key in ('Z',):
make_key(code=29, names=('Z',))
# Basic ASCII letters/numbers don't need anything fancy, so check those
# in the laziest way
if key in ALL_ALPHAS:
make_key(code=4 + ALL_ALPHAS.index(key), names=(key,))
elif key in ALL_NUMBERS or key in ALL_NUMBER_ALIASES:
try:
offset = ALL_NUMBERS.index(key)
except ValueError:
offset = ALL_NUMBER_ALIASES.index(key)
# Numbers
# Aliases to play nicely with AttrDict, since KC.1 isn't a valid
# attribute key in Python, but KC.N1 is
elif key in ('1', 'N1'):
make_key(code=30, names=('1', 'N1'))
elif key in ('2', 'N2'):
make_key(code=31, names=('2', 'N2'))
elif key in ('3', 'N3'):
make_key(code=32, names=('3', 'N3'))
elif key in ('4', 'N4'):
make_key(code=33, names=('4', 'N4'))
elif key in ('5', 'N5'):
make_key(code=34, names=('5', 'N5'))
elif key in ('6', 'N6'):
make_key(code=35, names=('6', 'N6'))
elif key in ('7', 'N7'):
make_key(code=36, names=('7', 'N7'))
elif key in ('8', 'N8'):
make_key(code=37, names=('8', 'N8'))
elif key in ('9', 'N9'):
make_key(code=38, names=('9', 'N9'))
elif key in ('0', 'N0'):
make_key(code=39, names=('0', 'N0'))
names = (ALL_NUMBERS[offset], ALL_NUMBER_ALIASES[offset])
make_key(code=30 + offset, names=names)
# More ASCII standard keys
elif key in ('ENTER', 'ENT', '\n'):
make_key(code=40, names=('ENTER', 'ENT', '\n'))
elif key in ('ESCAPE', 'ESC'):
make_key(code=41, names=('ESCAPE', 'ESC'))
elif key in ('BACKSPACE', 'BSPC', 'BKSP'):
make_key(code=42, names=('BACKSPACE', 'BSPC', 'BKSP'))
elif key in ('TAB', '\t'):
make_key(code=43, names=('TAB', '\t'))
elif key in ('SPACE', 'SPC', ' '):
make_key(code=44, names=('SPACE', 'SPC', ' '))
elif key in ('MINUS', 'MINS', '-'):
make_key(code=45, names=('MINUS', 'MINS', '-'))
elif key in ('EQUAL', 'EQL', '='):
make_key(code=46, names=('EQUAL', 'EQL', '='))
elif key in ('LBRACKET', 'LBRC', '['):
make_key(code=47, names=('LBRACKET', 'LBRC', '['))
elif key in ('RBRACKET', 'RBRC', ']'):
make_key(code=48, names=('RBRACKET', 'RBRC', ']'))
elif key in ('BACKSLASH', 'BSLASH', 'BSLS', '\\'):
make_key(code=49, names=('BACKSLASH', 'BSLASH', 'BSLS', '\\'))
elif key in ('SEMICOLON', 'SCOLON', 'SCLN', ';'):
make_key(code=51, names=('SEMICOLON', 'SCOLON', 'SCLN', ';'))
elif key in ('QUOTE', 'QUOT', "'"):
make_key(code=52, names=('QUOTE', 'QUOT', "'"))
elif key in ('GRAVE', 'GRV', 'ZKHK', '`'):
make_key(code=53, names=('GRAVE', 'GRV', 'ZKHK', '`'))
elif key in ('COMMA', 'COMM', ','):
make_key(code=54, names=('COMMA', 'COMM', ','))
elif key in ('DOT', '.'):
make_key(code=55, names=('DOT', '.'))
elif key in ('SLASH', 'SLSH'):
make_key(code=56, names=('SLASH', 'SLSH'))
# Function Keys
elif key in ('F1',):
make_key(code=58, names=('F1',))
elif key in ('F2',):
make_key(code=59, names=('F2',))
elif key in ('F3',):
make_key(code=60, names=('F3',))
elif key in ('F4',):
make_key(code=61, names=('F4',))
elif key in ('F5',):
make_key(code=62, names=('F5',))
elif key in ('F6',):
make_key(code=63, names=('F6',))
elif key in ('F7',):
make_key(code=64, names=('F7',))
elif key in ('F8',):
make_key(code=65, names=('F8',))
elif key in ('F9',):
make_key(code=66, names=('F9',))
elif key in ('F10',):
make_key(code=67, names=('F10',))
elif key in ('F11',):
make_key(code=68, names=('F11',))
elif key in ('F12',):
make_key(code=69, names=('F12',))
elif key in ('F13',):
make_key(code=104, names=('F13',))
elif key in ('F14',):
make_key(code=105, names=('F14',))
elif key in ('F15',):
make_key(code=106, names=('F15',))
elif key in ('F16',):
make_key(code=107, names=('F16',))
elif key in ('F17',):
make_key(code=108, names=('F17',))
elif key in ('F18',):
make_key(code=109, names=('F18',))
elif key in ('F19',):
make_key(code=110, names=('F19',))
elif key in ('F20',):
make_key(code=111, names=('F20',))
elif key in ('F21',):
make_key(code=112, names=('F21',))
elif key in ('F22',):
make_key(code=113, names=('F22',))
elif key in ('F23',):
make_key(code=114, names=('F23',))
elif key in ('F24',):
make_key(code=115, names=('F24',))
# Lock Keys, Navigation, etc.
elif key in ('CAPS_LOCK', 'CAPSLOCK', 'CLCK', 'CAPS'):
make_key(code=57, names=('CAPS_LOCK', 'CAPSLOCK', 'CLCK', 'CAPS'))
# FIXME: Investigate whether this key actually works, and
# uncomment when/if it does.
# elif key in ('LOCKING_CAPS', 'LCAP'):
# # make_key(code=130, names=('LOCKING_CAPS', 'LCAP'))
elif key in ('PRINT_SCREEN', 'PSCREEN', 'PSCR'):
make_key(code=70, names=('PRINT_SCREEN', 'PSCREEN', 'PSCR'))
elif key in ('SCROLL_LOCK', 'SCROLLLOCK', 'SLCK'):
make_key(code=71, names=('SCROLL_LOCK', 'SCROLLLOCK', 'SLCK'))
# FIXME: Investigate whether this key actually works, and
# uncomment when/if it does.
# elif key in ('LOCKING_SCROLL', 'LSCRL'):
# make_key(code=132, names=('LOCKING_SCROLL', 'LSCRL'))
elif key in ('PAUSE', 'PAUS', 'BRK'):
make_key(code=72, names=('PAUSE', 'PAUS', 'BRK'))
elif key in ('INSERT', 'INS'):
make_key(code=73, names=('INSERT', 'INS'))
elif key in ('HOME',):
make_key(code=74, names=('HOME',))
elif key in ('PGUP',):
make_key(code=75, names=('PGUP',))
elif key in ('DELETE', 'DEL'):
make_key(code=76, names=('DELETE', 'DEL'))
elif key in ('END',):
make_key(code=77, names=('END',))
elif key in ('PGDOWN', 'PGDN'):
make_key(code=78, names=('PGDOWN', 'PGDN'))
elif key in ('RIGHT', 'RGHT'):
make_key(code=79, names=('RIGHT', 'RGHT'))
elif key in ('LEFT',):
make_key(code=80, names=('LEFT',))
elif key in ('DOWN',):
make_key(code=81, names=('DOWN',))
elif key in ('UP',):
make_key(code=82, names=('UP',))
# Numpad
elif key in ('NUM_LOCK', 'NUMLOCK', 'NLCK'):
make_key(code=83, names=('NUM_LOCK', 'NUMLOCK', 'NLCK'))
# FIXME: Investigate whether this key actually works, and
# uncomment when/if it does.
# elif key in ('LOCKING_NUM', 'LNUM'):
# make_key(code=131, names=('LOCKING_NUM', 'LNUM'))
elif key in ('KP_SLASH', 'NUMPAD_SLASH', 'PSLS'):
make_key(code=84, names=('KP_SLASH', 'NUMPAD_SLASH', 'PSLS'))
elif key in ('KP_ASTERISK', 'NUMPAD_ASTERISK', 'PAST'):
make_key(code=85, names=('KP_ASTERISK', 'NUMPAD_ASTERISK', 'PAST'))
elif key in ('KP_MINUS', 'NUMPAD_MINUS', 'PMNS'):
make_key(code=86, names=('KP_MINUS', 'NUMPAD_MINUS', 'PMNS'))
elif key in ('KP_PLUS', 'NUMPAD_PLUS', 'PPLS'):
make_key(code=87, names=('KP_PLUS', 'NUMPAD_PLUS', 'PPLS'))
elif key in ('KP_ENTER', 'NUMPAD_ENTER', 'PENT'):
make_key(code=88, names=('KP_ENTER', 'NUMPAD_ENTER', 'PENT'))
elif key in ('KP_1', 'P1', 'NUMPAD_1'):
make_key(code=89, names=('KP_1', 'P1', 'NUMPAD_1'))
elif key in ('KP_2', 'P2', 'NUMPAD_2'):
make_key(code=90, names=('KP_2', 'P2', 'NUMPAD_2'))
elif key in ('KP_3', 'P3', 'NUMPAD_3'):
make_key(code=91, names=('KP_3', 'P3', 'NUMPAD_3'))
elif key in ('KP_4', 'P4', 'NUMPAD_4'):
make_key(code=92, names=('KP_4', 'P4', 'NUMPAD_4'))
elif key in ('KP_5', 'P5', 'NUMPAD_5'):
make_key(code=93, names=('KP_5', 'P5', 'NUMPAD_5'))
elif key in ('KP_6', 'P6', 'NUMPAD_6'):
make_key(code=94, names=('KP_6', 'P6', 'NUMPAD_6'))
elif key in ('KP_7', 'P7', 'NUMPAD_7'):
make_key(code=95, names=('KP_7', 'P7', 'NUMPAD_7'))
elif key in ('KP_8', 'P8', 'NUMPAD_8'):
make_key(code=96, names=('KP_8', 'P8', 'NUMPAD_8'))
elif key in ('KP_9', 'P9', 'NUMPAD_9'):
make_key(code=97, names=('KP_9', 'P9', 'NUMPAD_9'))
elif key in ('KP_0', 'P0', 'NUMPAD_0'):
make_key(code=98, names=('KP_0', 'P0', 'NUMPAD_0'))
elif key in ('KP_DOT', 'PDOT', 'NUMPAD_DOT'):
make_key(code=99, names=('KP_DOT', 'PDOT', 'NUMPAD_DOT'))
elif key in ('KP_EQUAL', 'PEQL', 'NUMPAD_EQUAL'):
make_key(code=103, names=('KP_EQUAL', 'PEQL', 'NUMPAD_EQUAL'))
elif key in ('KP_COMMA', 'PCMM', 'NUMPAD_COMMA'):
make_key(code=133, names=('KP_COMMA', 'PCMM', 'NUMPAD_COMMA'))
elif key in ('KP_EQUAL_AS400', 'NUMPAD_EQUAL_AS400'):
make_key(code=134, names=('KP_EQUAL_AS400', 'NUMPAD_EQUAL_AS400'))
# Making life better for folks on tiny keyboards especially: exposes
# the 'shifted' keys as raw keys. Under the hood we're still
# sending Shift+(whatever key is normally pressed) to get these, so
# for example `KC_AT` will hold shift and press 2.
elif key in ('TILDE', 'TILD', '~'):
make_shifted_key('GRAVE', names=('TILDE', 'TILD', '~'))
elif key in ('EXCLAIM', 'EXLM', '!'):
make_shifted_key('1', names=('EXCLAIM', 'EXLM', '!'))
elif key in ('AT', '@'):
make_shifted_key('2', names=('AT', '@'))
elif key in ('HASH', 'POUND', '#'):
make_shifted_key('3', names=('HASH', 'POUND', '#'))
elif key in ('DOLLAR', 'DLR', '$'):
make_shifted_key('4', names=('DOLLAR', 'DLR', '$'))
elif key in ('PERCENT', 'PERC', '%'):
make_shifted_key('5', names=('PERCENT', 'PERC', '%'))
elif key in ('CIRCUMFLEX', 'CIRC', '^'):
make_shifted_key('6', names=('CIRCUMFLEX', 'CIRC', '^'))
elif key in ('AMPERSAND', 'AMPR', '&'):
make_shifted_key('7', names=('AMPERSAND', 'AMPR', '&'))
elif key in ('ASTERISK', 'ASTR', '*'):
make_shifted_key('8', names=('ASTERISK', 'ASTR', '*'))
elif key in ('LEFT_PAREN', 'LPRN', '('):
make_shifted_key('9', names=('LEFT_PAREN', 'LPRN', '('))
elif key in ('RIGHT_PAREN', 'RPRN', ')'):
make_shifted_key('0', names=('RIGHT_PAREN', 'RPRN', ')'))
elif key in ('UNDERSCORE', 'UNDS', '_'):
make_shifted_key('MINUS', names=('UNDERSCORE', 'UNDS', '_'))
elif key in ('PLUS', '+'):
make_shifted_key('EQUAL', names=('PLUS', '+'))
elif key in ('LEFT_CURLY_BRACE', 'LCBR', '{'):
make_shifted_key('LBRACKET', names=('LEFT_CURLY_BRACE', 'LCBR', '{'))
elif key in ('RIGHT_CURLY_BRACE', 'RCBR', '}'):
make_shifted_key('RBRACKET', names=('RIGHT_CURLY_BRACE', 'RCBR', '}'))
elif key in ('PIPE', '|'):
make_shifted_key('BACKSLASH', names=('PIPE', '|'))
elif key in ('COLON', 'COLN', ':'):
make_shifted_key('SEMICOLON', names=('COLON', 'COLN', ':'))
elif key in ('DOUBLE_QUOTE', 'DQUO', 'DQT', '"'):
make_shifted_key('QUOTE', names=('DOUBLE_QUOTE', 'DQUO', 'DQT', '"'))
elif key in ('LEFT_ANGLE_BRACKET', 'LABK', '<'):
make_shifted_key('COMMA', names=('LEFT_ANGLE_BRACKET', 'LABK', '<'))
elif key in ('RIGHT_ANGLE_BRACKET', 'RABK', '>'):
make_shifted_key('DOT', names=('RIGHT_ANGLE_BRACKET', 'RABK', '>'))
elif key in ('QUESTION', 'QUES', '?'):
make_shifted_key('SLSH', names=('QUESTION', 'QUES', '?'))
# International
elif key in ('NONUS_HASH', 'NUHS'):
make_key(code=50, names=('NONUS_HASH', 'NUHS'))
elif key in ('NONUS_BSLASH', 'NUBS'):
make_key(code=100, names=('NONUS_BSLASH', 'NUBS'))
elif key in ('APP', 'APPLICATION', 'SEL', 'WINMENU'):
make_key(code=101, names=('APP', 'APPLICATION', 'SEL', 'WINMENU'))
elif key in ('INT1', 'RO'):
make_key(code=135, names=('INT1', 'RO'))
elif key in ('INT2', 'KANA'):
make_key(code=136, names=('INT2', 'KANA'))
elif key in ('INT3', 'JYEN'):
make_key(code=137, names=('INT3', 'JYEN'))
elif key in ('INT4', 'HENK'):
make_key(code=138, names=('INT4', 'HENK'))
elif key in ('INT5', 'MHEN'):
make_key(code=139, names=('INT5', 'MHEN'))
elif key in ('INT6',):
make_key(code=140, names=('INT6',))
elif key in ('INT7',):
make_key(code=141, names=('INT7',))
elif key in ('INT8',):
make_key(code=142, names=('INT8',))
elif key in ('INT9',):
make_key(code=143, names=('INT9',))
elif key in ('LANG1', 'HAEN'):
make_key(code=144, names=('LANG1', 'HAEN'))
elif key in ('LANG2', 'HAEJ'):
make_key(code=145, names=('LANG2', 'HAEJ'))
elif key in ('LANG3',):
make_key(code=146, names=('LANG3',))
elif key in ('LANG4',):
make_key(code=147, names=('LANG4',))
elif key in ('LANG5',):
make_key(code=148, names=('LANG5',))
elif key in ('LANG6',):
make_key(code=149, names=('LANG6',))
elif key in ('LANG7',):
make_key(code=150, names=('LANG7',))
elif key in ('LANG8',):
make_key(code=151, names=('LANG8',))
elif key in ('LANG9',):
make_key(code=152, names=('LANG9',))
# Consumer ("media") keys. Most known keys aren't supported here. A much
# longer list used to exist in this file, but the codes were almost certainly
# incorrect, conflicting with each other, or otherwise 'weird'. We'll add them
# back in piecemeal as needed. PRs welcome.
#
# A super useful reference for these is http://www.freebsddiary.org/APC/usb_hid_usages.php
# Note that currently we only have the PC codes. Recent MacOS versions seem to
# support PC media keys, so I don't know how much value we would get out of
# adding the old Apple-specific consumer codes, but again, PRs welcome if the
# lack of them impacts you.
elif key in ('AUDIO_MUTE', 'MUTE'):
make_consumer_key(code=226, names=('AUDIO_MUTE', 'MUTE')) # 0xE2
elif key in ('AUDIO_VOL_UP', 'VOLU'):
make_consumer_key(code=233, names=('AUDIO_VOL_UP', 'VOLU')) # 0xE9
elif key in ('AUDIO_VOL_DOWN', 'VOLD'):
make_consumer_key(code=234, names=('AUDIO_VOL_DOWN', 'VOLD')) # 0xEA
elif key in ('MEDIA_NEXT_TRACK', 'MNXT'):
make_consumer_key(code=181, names=('MEDIA_NEXT_TRACK', 'MNXT')) # 0xB5
elif key in ('MEDIA_PREV_TRACK', 'MPRV'):
make_consumer_key(code=182, names=('MEDIA_PREV_TRACK', 'MPRV')) # 0xB6
elif key in ('MEDIA_STOP', 'MSTP'):
make_consumer_key(code=183, names=('MEDIA_STOP', 'MSTP')) # 0xB7
elif key in ('MEDIA_PLAY_PAUSE', 'MPLY'):
make_consumer_key(
code=205, names=('MEDIA_PLAY_PAUSE', 'MPLY')
) # 0xCD (this may not be right)
elif key in ('MEDIA_EJECT', 'EJCT'):
make_consumer_key(code=184, names=('MEDIA_EJECT', 'EJCT')) # 0xB8
elif key in ('MEDIA_FAST_FORWARD', 'MFFD'):
make_consumer_key(code=179, names=('MEDIA_FAST_FORWARD', 'MFFD')) # 0xB3
elif key in ('MEDIA_REWIND', 'MRWD'):
make_consumer_key(code=180, names=('MEDIA_REWIND', 'MRWD')) # 0xB4
# Now try all the other weird special cases to get them out of our way:
# Internal, diagnostic, or auxiliary/enhanced keys
# NO and TRNS are functionally identical in how they (don't) mutate
# the state, but are tracked semantically separately, so create
# two keys with the exact same functionality
elif key in ('NO',):
elif key in ('NO', 'XXXXXXX'):
make_key(
names=('NO',),
names=('NO', 'XXXXXXX'),
on_press=handlers.passthrough,
on_release=handlers.passthrough,
)
@@ -447,12 +118,6 @@ class KeyAttrDict(AttrDict):
on_press=handlers.debug_pressed,
on_release=handlers.passthrough,
)
elif key in ('GESC',):
make_key(
names=('GESC',),
on_press=handlers.gesc_pressed,
on_release=handlers.gesc_released,
)
elif key in ('BKDL',):
make_key(
names=('BKDL',),
@@ -514,8 +179,204 @@ class KeyAttrDict(AttrDict):
elif key in ('HID_SWITCH', 'HID'):
make_key(names=('HID_SWITCH', 'HID'), on_press=handlers.hid_switch)
else:
raise ValueError('Invalid key')
return self.__getattr__(key)
maybe_key = first_truthy(
key,
# Modifiers
lambda key: left_pipe_until_some(
key,
maybe_make_mod_key,
(0x01, ('LEFT_CONTROL', 'LCTRL', 'LCTL')),
(0x02, ('LEFT_SHIFT', 'LSHIFT', 'LSFT')),
(0x04, ('LEFT_ALT', 'LALT')),
(0x08, ('LEFT_SUPER', 'LGUI', 'LCMD', 'LWIN')),
(0x10, ('RIGHT_CONTROL', 'RCTRL', 'RCTL')),
(0x20, ('RIGHT_SHIFT', 'RSHIFT', 'RSFT')),
(0x40, ('RIGHT_ALT', 'RALT')),
(0x80, ('RIGHT_SUPER', 'RGUI', 'RCMD', 'RWIN')),
# MEH = LCTL | LALT | LSFT# MEH = LCTL |
(0x07, ('MEH',)),
# HYPR = LCTL | LALT | LSFT | LGUI
(0x0F, ('HYPER', 'HYPR')),
),
lambda key: left_pipe_until_some(
key,
maybe_make_key,
# More ASCII standard keys
(40, ('ENTER', 'ENT', '\n')),
(41, ('ESCAPE', 'ESC')),
(42, ('BACKSPACE', 'BSPC', 'BKSP')),
(43, ('TAB', '\t')),
(44, ('SPACE', 'SPC', ' ')),
(45, ('MINUS', 'MINS', '-')),
(46, ('EQUAL', 'EQL', '=')),
(47, ('LBRACKET', 'LBRC', '[')),
(48, ('RBRACKET', 'RBRC', ']')),
(49, ('BACKSLASH', 'BSLASH', 'BSLS', '\\')),
(51, ('SEMICOLON', 'SCOLON', 'SCLN', ';')),
(52, ('QUOTE', 'QUOT', "'")),
(53, ('GRAVE', 'GRV', 'ZKHK', '`')),
(54, ('COMMA', 'COMM', ',')),
(55, ('DOT', '.')),
(56, ('SLASH', 'SLSH')),
# Function Keys
(58, ('F1',)),
(59, ('F2',)),
(60, ('F3',)),
(61, ('F4',)),
(62, ('F5',)),
(63, ('F6',)),
(64, ('F7',)),
(65, ('F8',)),
(66, ('F9',)),
(67, ('F10',)),
(68, ('F11',)),
(69, ('F12',)),
(104, ('F13',)),
(105, ('F14',)),
(106, ('F15',)),
(107, ('F16',)),
(108, ('F17',)),
(109, ('F18',)),
(110, ('F19',)),
(111, ('F20',)),
(112, ('F21',)),
(113, ('F22',)),
(114, ('F23',)),
(115, ('F24',)),
# Lock Keys, Navigation, etc.
(57, ('CAPS_LOCK', 'CAPSLOCK', 'CLCK', 'CAPS')),
# FIXME: Investigate whether this key actually works, and
# uncomment when/if it does.
# (130, ('LOCKING_CAPS', 'LCAP')),
(70, ('PRINT_SCREEN', 'PSCREEN', 'PSCR')),
(71, ('SCROLL_LOCK', 'SCROLLLOCK', 'SLCK')),
# FIXME: Investigate whether this key actually works, and
# uncomment when/if it does.
# (132, ('LOCKING_SCROLL', 'LSCRL')),
(72, ('PAUSE', 'PAUS', 'BRK')),
(73, ('INSERT', 'INS')),
(74, ('HOME',)),
(75, ('PGUP',)),
(76, ('DELETE', 'DEL')),
(77, ('END',)),
(78, ('PGDOWN', 'PGDN')),
(79, ('RIGHT', 'RGHT')),
(80, ('LEFT',)),
(81, ('DOWN',)),
(82, ('UP',)),
# Numpad
(83, ('NUM_LOCK', 'NUMLOCK', 'NLCK')),
# FIXME: Investigate whether this key actually works, and
# uncomment when/if it does.
# (131, names=('LOCKING_NUM', 'LNUM')),
(84, ('KP_SLASH', 'NUMPAD_SLASH', 'PSLS')),
(85, ('KP_ASTERISK', 'NUMPAD_ASTERISK', 'PAST')),
(86, ('KP_MINUS', 'NUMPAD_MINUS', 'PMNS')),
(87, ('KP_PLUS', 'NUMPAD_PLUS', 'PPLS')),
(88, ('KP_ENTER', 'NUMPAD_ENTER', 'PENT')),
(89, ('KP_1', 'P1', 'NUMPAD_1')),
(90, ('KP_2', 'P2', 'NUMPAD_2')),
(91, ('KP_3', 'P3', 'NUMPAD_3')),
(92, ('KP_4', 'P4', 'NUMPAD_4')),
(93, ('KP_5', 'P5', 'NUMPAD_5')),
(94, ('KP_6', 'P6', 'NUMPAD_6')),
(95, ('KP_7', 'P7', 'NUMPAD_7')),
(96, ('KP_8', 'P8', 'NUMPAD_8')),
(97, ('KP_9', 'P9', 'NUMPAD_9')),
(98, ('KP_0', 'P0', 'NUMPAD_0')),
(99, ('KP_DOT', 'PDOT', 'NUMPAD_DOT')),
(103, ('KP_EQUAL', 'PEQL', 'NUMPAD_EQUAL')),
(133, ('KP_COMMA', 'PCMM', 'NUMPAD_COMMA')),
(134, ('KP_EQUAL_AS400', 'NUMPAD_EQUAL_AS400')),
),
# Making life better for folks on tiny keyboards especially: exposes
# the 'shifted' keys as raw keys. Under the hood we're still
# sending Shift+(whatever key is normally pressed) to get these, so
# for example `KC_AT` will hold shift and press 2.
lambda key: left_pipe_until_some(
key,
maybe_make_shifted_key,
('GRAVE', ('TILDE', 'TILD', '~')),
('1', ('EXCLAIM', 'EXLM', '!')),
('2', ('AT', '@')),
('3', ('HASH', 'POUND', '#')),
('4', ('DOLLAR', 'DLR', '$')),
('5', ('PERCENT', 'PERC', '%')),
('6', ('CIRCUMFLEX', 'CIRC', '^')),
('7', ('AMPERSAND', 'AMPR', '&')),
('8', ('ASTERISK', 'ASTR', '*')),
('9', ('LEFT_PAREN', 'LPRN', '(')),
('0', ('RIGHT_PAREN', 'RPRN', ')')),
('MINUS', ('UNDERSCORE', 'UNDS', '_')),
('EQUAL', ('PLUS', '+')),
('LBRACKET', ('LEFT_CURLY_BRACE', 'LCBR', '{')),
('RBRACKET', ('RIGHT_CURLY_BRACE', 'RCBR', '}')),
('BACKSLASH', ('PIPE', '|')),
('SEMICOLON', ('COLON', 'COLN', ':')),
('QUOTE', ('DOUBLE_QUOTE', 'DQUO', 'DQT', '"')),
('COMMA', ('LEFT_ANGLE_BRACKET', 'LABK', '<')),
('DOT', ('RIGHT_ANGLE_BRACKET', 'RABK', '>')),
('SLSH', ('QUESTION', 'QUES', '?')),
),
# International
lambda key: left_pipe_until_some(
key,
maybe_make_key,
(50, ('NONUS_HASH', 'NUHS')),
(100, ('NONUS_BSLASH', 'NUBS')),
(101, ('APP', 'APPLICATION', 'SEL', 'WINMENU')),
(135, ('INT1', 'RO')),
(136, ('INT2', 'KANA')),
(137, ('INT3', 'JYEN')),
(138, ('INT4', 'HENK')),
(139, ('INT5', 'MHEN')),
(140, ('INT6',)),
(141, ('INT7',)),
(142, ('INT8',)),
(143, ('INT9',)),
(144, ('LANG1', 'HAEN')),
(145, ('LANG2', 'HAEJ')),
(146, ('LANG3',)),
(147, ('LANG4',)),
(148, ('LANG5',)),
(149, ('LANG6',)),
(150, ('LANG7',)),
(151, ('LANG8',)),
(152, ('LANG9',)),
),
# Consumer ("media") keys. Most known keys aren't supported here. A much
# longer list used to exist in this file, but the codes were almost certainly
# incorrect, conflicting with each other, or otherwise 'weird'. We'll add them
# back in piecemeal as needed. PRs welcome.
#
# A super useful reference for these is http://www.freebsddiary.org/APC/usb_hid_usages.php
# Note that currently we only have the PC codes. Recent MacOS versions seem to
# support PC media keys, so I don't know how much value we would get out of
# adding the old Apple-specific consumer codes, but again, PRs welcome if the
# lack of them impacts you.
lambda key: left_pipe_until_some(
key,
maybe_make_consumer_key,
(226, ('AUDIO_MUTE', 'MUTE')), # 0xE2
(233, ('AUDIO_VOL_UP', 'VOLU')), # 0xE9
(234, ('AUDIO_VOL_DOWN', 'VOLD')), # 0xEA
(181, ('MEDIA_NEXT_TRACK', 'MNXT')), # 0xB5
(182, ('MEDIA_PREV_TRACK', 'MPRV')), # 0xB6
(183, ('MEDIA_STOP', 'MSTP')), # 0xB7
(205, ('MEDIA_PLAY_PAUSE', 'MPLY')), # 0xCD (this may not be right)
(184, ('MEDIA_EJECT', 'EJCT')), # 0xB8
(179, ('MEDIA_FAST_FORWARD', 'MFFD')), # 0xB3
(180, ('MEDIA_REWIND', 'MRWD')), # 0xB4
),
)
if DEBUG_OUTPUT:
print(f'{key}: {maybe_key}')
if not maybe_key:
raise ValueError('Invalid key')
return self.__getattr__(key, depth=depth + 1)
# Global state, will be filled in througout this file, and
@@ -810,12 +671,19 @@ def make_key(code=None, names=tuple(), type=KEY_SIMPLE, **kwargs): # NOQA
return key
def make_mod_key(*args, **kwargs):
return make_key(*args, **kwargs, type=KEY_MODIFIER)
def make_mod_key(code, names, *args, **kwargs):
return make_key(code, names, *args, **kwargs, type=KEY_MODIFIER)
def make_shifted_key(target_name, names=tuple()): # NOQA
key = KC.LSFT(KC[target_name])
# For... probably a few years, a bug existed here where keys were looked
# up by `KC[...]`, but that's incorrect: an AttrDit exposes a dictionary
# with attributes, but key-based dictionary access with brackets does
# *not* implicitly call __getattr__. We got away with this when key defs
# were not lazily created, but now that they are, shifted keys would
# sometimes break, complaining that they couldn't find their underlying
# key to shift. Fixed!
key = KC.LSFT(getattr(KC, target_name))
register_key_names(key, names)
+230
View File
@@ -0,0 +1,230 @@
import digitalio
from kmk.kmktime import ticks_ms
from kmk.modules import Module
class EncoderPadState:
OFF = False
ON = True
class EndcoderDirection:
Left = False
Right = True
class Encoder:
def __init__(
self,
pad_a,
pad_b,
button_pin=None,
):
self.pad_a = self.PreparePin(pad_a) # board pin for enc pin a
self.pad_a_state = False
self.pad_b = self.PreparePin(pad_b) # board pin for enc pin b
self.pad_b_state = False
self.button_pin = self.PreparePin(button_pin) # board pin for enc btn
self.button_state = None # state of pushbutton on encoder if enabled
self.encoder_value = 0 # clarify what this value is
self.encoder_state = (
self.pad_a_state,
self.pad_b_state,
) # quaderature encoder state
self.encoder_direction = None # arbitrary, tells direction of knob
self.last_encoder_state = None # not used yet
self.resolution = 2 # number of keys sent per position change
self.revolution_count = 20 # position changes per revolution
self.has_button = False # enable/disable button functionality
self.encoder_data = None # 6tuple containing all encoder data
self.position_change = None # revolution count, inc/dec as knob turns
self.last_encoder_value = 0 # not used
self.is_inverted = False # switch to invert knob direction
self.vel_mode = False # enable the velocity output
self.vel_ts = None # velocity timestamp
self.last_vel_ts = 0 # last velocity timestamp
self.encoder_speed = None # ms per position change(4 states)
self.encoder_map = None
self.eps = EncoderPadState()
self.encoder_pad_lookup = {
False: self.eps.OFF,
True: self.eps.ON,
}
self.edr = EndcoderDirection() # lookup for current encoder direction
self.encoder_dir_lookup = {
False: self.edr.Left,
True: self.edr.Right,
}
def __repr__(self, idx):
return 'ENCODER_{}({})'.format(idx, self._to_dict())
def _to_dict(self):
return {
'Encoder_State': self.encoder_state,
'Direction': self.encoder_direction,
'Value': self.encoder_value,
'Position_Change': self.position_change,
'Speed': self.encoder_speed,
'Button_State': self.button_state,
}
# adapted for CircuitPython from raspi
def PreparePin(self, num):
if num is not None:
pad = digitalio.DigitalInOut(num)
pad.direction = digitalio.Direction.INPUT
pad.pull = digitalio.Pull.UP
return pad
else:
return None
# checks encoder pins, reports encoder data
def report(self):
new_encoder_state = (
self.encoder_pad_lookup[int(self.pad_a.value)],
self.encoder_pad_lookup[int(self.pad_b.value)],
)
if self.encoder_state == (self.eps.ON, self.eps.ON): # Resting position
if new_encoder_state == (self.eps.ON, self.eps.OFF): # Turned right 1
self.encoder_direction = self.edr.Right
elif new_encoder_state == (self.eps.OFF, self.eps.ON): # Turned left 1
self.encoder_direction = self.edr.Left
elif self.encoder_state == (self.eps.ON, self.eps.OFF): # R1 or L3 position
if new_encoder_state == (self.eps.OFF, self.eps.OFF): # Turned right 1
self.encoder_direction = self.edr.Right
elif new_encoder_state == (self.eps.ON, self.eps.ON): # Turned left 1
if self.encoder_direction == self.edr.Left:
self.encoder_value = self.encoder_value - 1
elif self.encoder_state == (self.eps.OFF, self.eps.ON): # R3 or L1
if new_encoder_state == (self.eps.OFF, self.eps.OFF): # Turned left 1
self.encoder_direction = self.edr.Left
elif new_encoder_state == (self.eps.ON, self.eps.ON): # Turned right 1
if self.encoder_direction == self.edr.Right:
self.encoder_value = self.encoder_value + 1
else: # self.encoder_state == '11'
if new_encoder_state == (self.eps.ON, self.eps.OFF): # Turned left 1
self.encoder_direction = self.edr.Left
elif new_encoder_state == (self.eps.OFF, self.eps.ON): # Turned right 1
self.encoder_direction = self.edr.Right # 'R'
elif new_encoder_state == (
self.eps.ON,
self.eps.ON,
): # Skipped intermediate 01 or 10 state, however turn completed
if self.encoder_direction == self.edr.Left:
self.encoder_value = self.encoder_value - 1
elif self.encoder_direction == self.edr.Right:
self.encoder_value = self.encoder_value + 1
self.encoder_state = new_encoder_state
if self.vel_mode:
self.vel_ts = ticks_ms()
if self.encoder_state != self.last_encoder_state:
self.position_change = self.invert_rotation(
self.encoder_value, self.last_encoder_value
)
self.last_encoder_state = self.encoder_state
self.last_encoder_value = self.encoder_value
if self.position_change > 0:
self._to_dict()
# return self.increment_key
return 0
elif self.position_change < 0:
self._to_dict()
# return self.decrement_key
return 1
else:
return None
# invert knob direction if encoder pins are soldered backwards
def invert_rotation(self, new, old):
if self.is_inverted:
return -(new - old)
else:
return new - old
# returns knob velocity as milliseconds between position changes(detents)
def vel_report(self):
self.encoder_speed = self.vel_ts - self.last_vel_ts
self.last_vel_ts = self.vel_ts
return self.encoder_speed
class EncoderHandler(Module):
encoders = []
debug_enabled = False # not working as inttended, do not use for now
def __init__(self, pad_a, pad_b, encoder_map):
self.pad_a = pad_a
self.pad_b = pad_b
self.encoder_count = len(self.pad_a)
self.encoder_map = encoder_map
self.make_encoders()
def on_runtime_enable(self, keyboard):
return
def on_runtime_disable(self, keyboard):
return
def during_bootup(self, keyboard):
return
def before_matrix_scan(self, keyboard):
'''
Return value will be injected as an extra matrix update
'''
return self.get_reports(keyboard)
def after_matrix_scan(self, keyboard):
'''
Return value will be replace matrix update if supplied
'''
return
def before_hid_send(self, keyboard):
return
def after_hid_send(self, keyboard):
return
def on_powersave_enable(self, keyboard):
return
def on_powersave_disable(self, keyboard):
return
def make_encoders(self):
for i in range(self.encoder_count):
self.encoders.append(
Encoder(
self.pad_a[i], # encoder pin a
self.pad_b[i], # encoder pin b
)
)
def send_encoder_keys(self, keyboard, encoder_key, encoder_idx):
# position in the encoder map tuple
encoder_resolution = 2
for _ in range(
self.encoder_map[keyboard.active_layers[0]][encoder_idx][encoder_resolution]
):
keyboard.tap_key(
self.encoder_map[keyboard.active_layers[0]][encoder_idx][encoder_key]
)
return keyboard
def get_reports(self, keyboard):
for idx in range(self.encoder_count):
if self.debug_enabled: # not working as inttended, do not use for now
print(self.encoders[idx].__repr__(idx))
encoder_key = self.encoders[idx].report()
if encoder_key is not None:
return self.send_encoder_keys(keyboard, encoder_key, idx)
+1 -1
View File
@@ -64,7 +64,7 @@ class Split(Module):
self.UARTService = UARTService
except ImportError:
print('BLE Import error')
pass # BLE isn't supported on this platform
return # BLE isn't supported on this platform
self._ble = BLERadio()
self._ble_last_scan = ticks_ms() - 5000
self._connection_count = 0
+45 -296
View File
@@ -7,11 +7,9 @@ import board
# from adafruit_display_text import label
from kb import KMKKeyboard
from kmk.extensions.rgb import RGB
from kmk.hid import HIDModes
from kmk.keys import KC
from kmk.modules.layers import Layers
from kmk.modules.power import Power
from kmk.modules.split import Split, SplitType
keyboard = KMKKeyboard()
@@ -20,36 +18,10 @@ keyboard = KMKKeyboard()
keyboard.tap_time = 320
keyboard.debug_enabled = False
rgb_ext = RGB(
pixel_pin=keyboard.rgb_pixel_pin,
num_pixels=6,
val_limit=100,
hue_default=190,
sat_default=100,
val_default=5,
)
split = Split(split_type=SplitType.BLE)
power = Power(powersave_pin=keyboard.powersave_pin)
split = Split(split_type=SplitType.UART)
layers = Layers()
keyboard.modules = [split, power, layers]
keyboard.extensions = [rgb_ext]
enable_oled = False
'''
if enable_oled:
displayio.release_displays()
i2c = board.I2C()
display_bus = displayio.I2CDisplay(i2c, device_address=0x3c)
display = adafruit_displayio_ssd1306.SSD1306(display_bus, width=128, height=32)
splash = displayio.Group(max_size=10)
display.show(splash)
else:
displayio.release_displays()
'''
keyboard.i2c_deinit_count += 1
keyboard.modules = [split, layers]
_______ = KC.TRNS
XXXXXXX = KC.NO
@@ -74,49 +46,12 @@ keyboard.keymap = [
#
[
# DVORAK
KC.GESC,
KC.QUOT,
KC.COMM,
KC.DOT,
KC.P,
KC.Y,
KC.F,
KC.G,
KC.C,
KC.R,
KC.L,
KC.BSPC,
TAB_SB,
KC.A,
KC.O,
KC.E,
KC.U,
KC.I,
KC.D,
KC.H,
KC.T,
KC.N,
KC.S,
KC.ENT,
KC.LSFT,
KC.SCLN,
KC.Q,
KC.J,
KC.K,
KC.X,
KC.B,
KC.M,
KC.W,
KC.V,
KC.Z,
KC.SLSH,
KC.LALT,
SUPER_L,
LT1_SP,
LT2_SP,
KC.LCTL,
KC.N0,
KC.GESC, KC.QUOT, KC.COMM, KC.DOT, KC.P, KC.Y, KC.F, KC.G, KC.C, KC.R, KC.L, KC.BSPC, \
TAB_SB, KC.A, KC.O, KC.E, KC.U, KC.I, KC.D, KC.H, KC.T, KC.N, KC.S, KC.ENT, \
KC.LSFT, KC.SCLN, KC.Q, KC.J, KC.K, KC.X, KC.B, KC.M, KC.W, KC.V, KC.Z, KC.SLSH, \
KC.LALT, SUPER_L, LT1_SP, LT2_SP, KC.LCTL, KC.NO,
],
# GAMING
# ,-----------------------------------------. ,-----------------------------------------.
# | Tab | ' | , | . | P | Y | | F | G | C | R | L | BKSP |
@@ -131,48 +66,10 @@ keyboard.keymap = [
#
[
# GAMING
KC.ESC,
KC.QUOT,
KC.COMM,
KC.DOT,
KC.P,
KC.Y,
KC.F,
KC.G,
KC.C,
KC.R,
KC.L,
KC.BSPC,
KC.LCTL,
KC.A,
KC.O,
KC.E,
KC.U,
KC.I,
KC.D,
KC.H,
KC.T,
KC.N,
KC.S,
KC.ENT,
KC.LSFT,
KC.SCLN,
KC.Q,
KC.J,
KC.K,
KC.X,
KC.B,
KC.M,
KC.W,
KC.V,
KC.Z,
KC.SLSH,
KC.LALT,
KC.SPC,
KC.SPC,
LT2_SP,
KC.LCTL,
KC.UP,
KC.ESC, KC.QUOT, KC.COMM, KC.DOT, KC.P, KC.Y, KC.F, KC.G, KC.C, KC.R, KC.L, KC.BSPC, \
KC.LCTL, KC.A, KC.O, KC.E, KC.U, KC.I, KC.D, KC.H, KC.T, KC.N, KC.S, KC.ENT, \
KC.LSFT, KC.SCLN, KC.Q, KC.J, KC.K, KC.X, KC.B, KC.M, KC.W, KC.V, KC.Z, KC.SLSH, \
KC.LALT, KC.SPC, KC.SPC, LT2_SP, KC.LCTL, KC.UP,
],
# RAISE1
# ,-----------------------------------------. ,-----------------------------------------.
@@ -188,48 +85,10 @@ keyboard.keymap = [
#
[
# RAISE1
_______,
_______,
_______,
_______,
_______,
_______,
KC.PS_TOG,
XXXXXXX,
KC.N7,
KC.N8,
KC.N9,
KC.DEL,
_______,
_______,
_______,
_______,
_______,
_______,
XXXXXXX,
XXXXXXX,
KC.N4,
KC.N5,
KC.N6,
KC.BSLS,
_______,
_______,
_______,
_______,
_______,
_______,
XXXXXXX,
XXXXXXX,
KC.N1,
KC.N2,
KC.N3,
KC.MINS,
_______,
_______,
_______,
_______,
KC.EQL,
KC.N0,
_______, _______, _______, _______, _______, _______, XXXXXXX, XXXXXXX, KC.N7, KC.N8, KC.N9, KC.DEL, \
_______, _______, _______, _______, _______, _______, XXXXXXX, XXXXXXX, KC.N4, KC.N5, KC.N6, KC.BSLS, \
_______, _______, _______, _______, _______, _______, XXXXXXX, XXXXXXX, KC.N1, KC.N2, KC.N3, KC.MINS, \
_______, _______, _______, _______, KC.EQL, KC.N0,
],
# RAISE2
# ,-----------------------------------------. ,-----------------------------------------.
@@ -243,50 +102,13 @@ keyboard.keymap = [
# | | |/ / \ \ | | |
# `---------------------' '------''-------------'
#
[
# RAISE2
_______,
KC.F9,
KC.F10,
KC.F11,
KC.F12,
_______,
_______,
_______,
_______,
KC.LBRC,
KC.RBRC,
KC.LSHIFT(KC.INS),
_______,
KC.F5,
KC.F6,
KC.F7,
KC.F8,
_______,
KC.HOME,
KC.LEFT,
KC.DOWN,
KC.UP,
KC.RGHT,
KC.END,
_______,
KC.F1,
KC.F2,
KC.F3,
KC.F4,
_______,
_______,
_______,
_______,
_______,
_______,
KC.BSLS,
_______,
_______,
_______,
_______,
KC.DF(0),
KC.DF(1),
_______, KC.F9, KC.F10, KC.F11, KC.F12, _______, _______, _______, _______, KC.LBRC, KC.RBRC, KC.LSHIFT(KC.INS), \
_______, KC.F5, KC.F6, KC.F7, KC.F8, _______, KC.HOME, KC.LEFT, KC.DOWN, KC.UP, KC.RGHT, KC.END, \
_______, KC.F1, KC.F2, KC.F3, KC.F4, _______, _______, _______, _______, _______, _______, KC.BSLS, \
_______, _______, _______, _______, KC.DF(0), KC.DF(1),
],
# GUI
# ,-----------------------------------------. ,-----------------------------------------.
@@ -299,109 +121,36 @@ keyboard.keymap = [
# | LALT | LGUI | /LT1_SP / \LT2_SP\ | | |
# | | |/ / \ \ | | |
# `---------------------' '------''-------------'
[
# GUI
_______,
KC.N1,
KC.N2,
KC.N3,
KC.N4,
KC.N5,
_______,
_______,
_______,
_______,
_______,
_______,
_______,
KC.N6,
KC.N7,
KC.N8,
KC.N9,
KC.N0,
_______,
_______,
_______,
_______,
_______,
_______,
_______,
_______,
_______,
_______,
_______,
_______,
_______,
_______,
_______,
_______,
_______,
_______,
_______,
_______,
_______,
_______,
_______,
_______,
_______, KC.N1, KC.N2, KC.N3, KC.N4, KC.N5, _______, _______, _______, _______, _______, _______, \
_______, KC.N6, KC.N7, KC.N8, KC.N9, KC.N0, _______, _______, _______, _______, _______, _______, \
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, \
_______, _______, _______, _______, _______, _______ \
],
# SYMBOLS
# ,-----------------------------------------. ,-----------------------------------------.
# | | ! | @ | # | $ | % | | ^ | & | * | ( | ) | Del |
# |------+------+------+------+------+------| |------+------+------+------+------+------|
# | | | | | | | | | | | [ | ] | |
# |------+------+------+------+------+------| |------+------+------+------+------+------|
# | | | | | | |-------. ,-------| | | | | | |
# `-----------------------------------------/ / \ \-----------------------------------------'
# | LALT | LGUI | /LT1_SP / \LT2_SP\ | | |
# | | |/ / \ \ | | |
# `---------------------' '------''-------------'
#
# SYMBOLS
# ,-----------------------------------------. ,-----------------------------------------.
# | | ! | @ | # | $ | % | | ^ | & | * | ( | ) | Del |
# |------+------+------+------+------+------| |------+------+------+------+------+------|
# | | | | | | | | | | | [ | ] | |
# |------+------+------+------+------+------| |------+------+------+------+------+------|
# | | | | | | |-------. ,-------| | | | | | |
# `-----------------------------------------/ / \ \-----------------------------------------'
# | LALT | LGUI | /LT1_SP / \LT2_SP\ | | |
# | | |/ / \ \ | | |
# `---------------------' '------''-------------'
#
[
# SYMBOLS
_______,
KC.EXLM,
KC.AT,
KC.HASH,
KC.DLR,
KC.PERC,
KC.CIRC,
KC.AMPR,
KC.ASTR,
KC.LPRN,
KC.RPRN,
KC.DEL,
_______,
KC.RGB_HUI,
KC.RGB_HUD,
KC.RGB_VAI,
KC.RGB_VAD,
_______,
_______,
_______,
_______,
KC.LBRC,
KC.RBRC,
_______,
_______,
KC.RGB_RST,
_______,
_______,
_______,
_______,
_______,
_______,
_______,
_______,
_______,
_______,
KC.RGB_TOG,
_______,
_______,
_______,
_______,
_______,
],
_______, KC.EXLM, KC.AT, KC.HASH, KC.DLR, KC.PERC, KC.CIRC, KC.AMPR, KC.ASTR, KC.LPRN, KC.RPRN, KC.DEL, \
_______, _______, _______, _______, _______, _______, _______, _______, _______, KC.LBRC, KC.RBRC, _______, \
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, \
_______, _______, _______, _______, _______, _______,
]
]
if __name__ == '__main__':
keyboard.go(hid_type=HIDModes.BLE)
keyboard.go(hid_type=HIDModes.USB)