Move docs/ to docs/en/

It allows comparison between the directories and helps translations.
This commit is contained in:
AndersonTorres
2022-09-11 16:28:09 -03:00
committed by Kyle Brown
parent 885359a8f4
commit 0ab6887fbe
49 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,83 @@
# Getting Started
> Life was like a box of chocolates. You never know what you're gonna get.
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). KMK requires CircuitPython version 7.0 or above.
Known working and recommended devices can be found [here](Officially_Supported_Microcontrollers.md)
<br>
## TL;DR Quick start guide
> To infinity and beyond!
1. [Install CircuitPython version 7.0 or higher 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:
***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.scanners import DiodeOrientation
keyboard = KMKKeyboard()
keyboard.col_pins = (board.GP0,)
keyboard.row_pins = (board.GP1,)
keyboard.diode_orientation = DiodeOrientation.COL2ROW
keyboard.keymap = [
[KC.A,]
]
if __name__ == '__main__':
keyboard.go()
```
5. With a wire / paperclip / whatever, connect the pins you selected for col_pin and row_pin together.
![feather and keeboar example pins](pins56.jpg)
6. If it prints the letter "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/kmk_firmware/tree/master/boards). You will need the `kb.py` and `main.py`. More advanced instructions can be found [here](config_and_keymap.md).
### You've got another, maybe DIY, board and want to customize 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 to customize the way a key behaves whether 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/kmk_firmware/tree/master/user_keymaps) that we provide and dig into our [documentation](README.md).
<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)
for convenience. If you ask for help in chat or open a bug report, if possible
make sure your copy of KMK is up-to-date.

View File

@@ -0,0 +1,67 @@
# Officially supported microcontrollers
While most CircuitPython devices are great for hand wired keyboards, most
keyboards are designed to accept a Pro Micro. The boards listed below either
are, or can be adapted to that pinout to use common keyboards already on the market.
## nice!nano
Features include
- Pro Micro pinout
- Both USB HID and Bluetooth support
- Can do Bluetooth split keyboards with no wires at all
- Has battery support including charging
Downsides
- $25 USD per microcontroller at most retailers
- Not enough space to run KMK without compiling
### Pre-compiling KMK for nice!nano
As the nice!nano has limited flash memory you'll need to compile KMK. To do that you'll need to download and install the [compatible mpy-cross](https://adafruit-circuit-python.s3.amazonaws.com/index.html?prefix=bin/mpy-cross/) for your Operating System. Don't forget to add it to your PATH, test by running `mpy-cross` from a shell (Powershell, Bash, Fish, etc). Once that's set up, run either `make compile` (if you have `make`) or `python util/compile.py`to generate the `.mpy` versions of KMK files. Then copy the whole compiled `kmk/` directory to your keyboard.
Common Retailers
- [Boardsource](https://boardsource.xyz/store/5f4a1733bbaa5c635b83ed67)
- [Nice Keyboards](https://nicekeyboards.com/nice-nano/)
## ItsyBitsy M4 Express
Features include
- Affordable at $15 USD
- Can run most features of KMK including RGB
Downsides
- Needs adapted to work with Pro Micro pinout keyboards. Adapter can be found
[HERE](https://github.com/KMKfw/kmk_firmware/tree/master/hardware)
Common Retailers
- [Adafruit](https://www.adafruit.com/product/3800)
## RP2040
Features include
- Very affordable
- Very powerful for the price
Downsides
- Little support for keyboard kits
Common Retailers
- [Adafruit](https://www.adafruit.com/pico?src=raspberrypi)
- [SparkFun](https://www.sparkfun.com/products/17829?src=raspberrypi)
## Adafruit ItsyBitsy nRF52840 Express
Features include
- Both USB HID and Bluetooth support
- More affordable than the nice!nano at only $18
Downsides
- Needs adapted to work with Pro Micro pinout keyboards. Adapter can be found
[HERE](https://github.com/KMKfw/kmk_firmware/tree/master/hardware)
- No battery support without addon board found
[HERE](https://www.adafruit.com/product/2124)
Common Retailers
- [Adafruit](https://www.adafruit.com/product/4481)
## Other microcontrollers
What you'll need to have at minimum
- CircuitPython
- 256KB of flash storage
- HID over USB and/or Bluetooth.

54
docs/en/README.md Normal file
View File

@@ -0,0 +1,54 @@
# Documentation index
> Before you look further, you probably want to start with our [getting started guide](https://github.com/KMKfw/kmk_firmware/blob/master/docs/Getting_Started.md)
## Basics
- [Getting Started](Getting_Started.md)
- [Bluetooth HID](ble_hid.md): Connect keyboard to PC or mobile device using BLE
- [Configuring KMK](config_and_keymap.md)
- [Porting to KMK](porting_to_kmk.md): Creating a `kb.py` file for a board
- [Debugging](debugging.md)
- [Keycodes](keycodes.md): List of all available keycodes
- [Officially supported microcontrollers](Officially_Supported_Microcontrollers.md)
- [Support](support.md)
- [Contributing](contributing.md)
## Advanced
- [Flashing instructions](flashing.md)
- [Handwiring](handwiring.md): Resources helpful when handwiring a keyboard circuit
- [Keys](keys.md): Technical explanation of key handling
- [Scanners](scanners.md): Setting up non-default key reading
## [Modules](modules.md)
- [Combos](combos.md): Adds chords and sequences
- [Layers](layers.md): Adds layer support (Fn key) to allow many more keys to be put on your keyboard
- [ModTap](modtap.md): Adds support for augmented modifier keys to act as one key when tapped, and modifier when held.
- [Mouse keys](mouse_keys.md): Adds mouse keycodes
- [OneShot](oneshot.md): Adds support for oneshot/sticky keys.
- [Power](power.md): Power saving features. This is mostly useful when on battery power.
- [SerialACE](serialace.md): [DANGER - _see module README_] Arbitrary Code Execution over the data serial.
- [Split](split_keyboards.md): Keyboards split in two. Seems ergonomic!
- [TapDance](tapdance.md): Different key actions depending on how often it is pressed.
### Peripherals
- [ADNS9800](adns9800.md): Controlling ADNS9800 optical sensor
- [Encoder](encoder.md): Handling rotary encoders
- [Pimoroni trackball](pimoroni_trackball.md): Handling a small I2C trackball made by Pimoroni
## [Extensions](extensions.md)
- [International](international.md): Adds international keycodes
- [LED](led.md): Adds backlight support. This is for monocolor backlight, not RGB
- [LockStatus](lock_status.md): Exposes host-side locks like caps or num lock.
- [MediaKeys](media_keys.md): Adds support for media keys such as volume
- [RGB](rgb.md): RGB lighting for underglow. Will work on most matrix RGB as will be treated the same as underglow.
- [Status LED](extension_statusled.md): Indicates which layer you are on with an array of single leds.
## Language versions
- [Japanese getting started](ja/Getting_Started.md)
- [Brazilian Portuguese](https://github.com/KMKfw/kmk_firmware/tree/master/docs/ptBR)

19
docs/en/adns9800.md Normal file
View File

@@ -0,0 +1,19 @@
# ADNS9800
Add this module for controlling ADNS9800 optical sensor.
```python
from kmk.modules.adns9800 import ADNS9800
keyboard.modules.append(ADNS9800(cs=board.GP0, sclk=board.GP2, miso=board.GP4, mosi=board.GP3, invert_y=True))
```
Firmware for this sensor has to be obtained separately and placed in `kmk\modules\adns9800_firmware.py`
```python
firmware = (
b'\x03'
b'\xa6'
...
)
```
## Constructor parameters
ADNS9800(cs=*cs_pin*, sclk=*clock_pin*, miso=*miso_pin*, mosi=*mosi_pin*, invert_x=*False*, invert_y=*False*)

33
docs/en/ble_hid.md Normal file
View File

@@ -0,0 +1,33 @@
# BLE HID
Bluetooth connections help clean up the wire mess!
## CircuitPython
If not running KMKPython, this does require the adafruit_ble library from Adafruit.
This can be downloaded
[here](https://github.com/adafruit/Adafruit_CircuitPython_BLE/tree/master/adafruit_ble).
It is part of the [Adafruit CircuitPython Bundle](https://github.com/adafruit/Adafruit_CircuitPython_Bundle).
Simply put this in the "root" of your CircuitPython device. If unsure, it's the folder with main.py in it, and should be the first folder you see when you open the device.
## Enabling BLE
To enable BLE hid, change the keyboard.go(). By default, the advertised name
will be the name of the "flash drive". By default this is CIRCUITPY
```python
from kmk.hid import HIDModes
if __name__ == '__main__':
keyboard.go(hid_type=HIDModes.BLE)
```
## Changing the advertise name
There are two ways to change the advertising name. The first would be to
[change the name of the drive](https://learn.adafruit.com/welcome-to-circuitpython/the-circuitpy-drive).
The second would be to change the keyboard.go() like this.
```python
if __name__ == '__main__':
keyboard.go(hid_type=HIDModes.BLE, ble_name='KMKeyboard')
```

65
docs/en/boot.md Normal file
View File

@@ -0,0 +1,65 @@
# boot.py
`boot.py` lives in the root of your keyboard when mounted as a storage device.
There is a more detailed explanation in the [circuit python docs](https://docs.circuitpython.org/en/latest/README.html),
however there are some common use cases for your keyboard listed here.
## Hiding device storage
You can hide your device from showing up as a USB storage by default (this can be overridden
at startup if desired, per the example code further down this page).
```python
storage.disable_usb_drive()
```
## Using your keyboard before the OS loads
You can make your keyboard work in your computer's BIOS and bootloader (useful if you dual-boot).
```python
usb_hid.enable(boot_device=1)
```
## Disabling serial communication
By default, you can connect to your board's serial console, which can be useful for debugging,
but may not be desired for everyday use.
```python
# Equivalent to usb_cdc.enable(console=False, data=False)
usb_cdc.disable()
```
## Example code
Below is a fully working example, which disables USB storage, CDC and enables BIOS mode.
```python
import supervisor
import board
import digitalio
import storage
import usb_cdc
import usb_hid
from kb import KMKKeyboard
from kmk.scanners import DiodeOrientation
# If this key is held during boot, don't run the code which hides the storage and disables serial
# This will use the first row/col pin. Feel free to change it if you want it to be another pin
col = digitalio.DigitalInOut(KMKKeyboard.col_pins[0])
row = digitalio.DigitalInOut(KMKKeyboard.row_pins[0])
if KMKKeyboard.diode_orientation == DiodeOrientation.COLUMNS:
col.switch_to_output(value=True)
row.switch_to_input(pull=digitalio.Pull.DOWN)
else:
col.switch_to_input(pull=digitalio.Pull.DOWN)
row.switch_to_output(value=True)
if not row.value:
storage.disable_usb_drive()
# Equivalent to usb_cdc.enable(console=False, data=False)
usb_cdc.disable()
usb_hid.enable(boot_device=1)
row.deinit()
col.deinit()
```

27
docs/en/capsword.md Normal file
View File

@@ -0,0 +1,27 @@
# CapsWord
The CapsWord module functions similar to caps lock but will deactivate automatically when its encounters a key that breaks the word or after inactivity timeout.
By default it will not deactivate CapsWord on numbers, alphabets, underscore, modifiers, minus, backspace and other keys like ModTap, Layers, etc.
Add it to your keyboard's modules list with:
```python
from kmk.modules.capsword import CapsWord
# default inactivity timeout is 8s
caps_word=CapsWord()
# change inactivity timeout
# caps_word=CapsWord(timeout=5000)
# for no inactivity timeout
# caps_word=CapsWord(timeout=0)
# add additional ignored keys
# caps_word.keys_ignored.append(KC.COMMA)
keyboard.modules.append(caps_word)
keyboard.keymap = [
[
KC.CW,
],
]
```
## Keycodes
|Key |Aliases |Description |
|-----------------------|--------------------|-----------------------------------------------|
|`KC.CW` |`KC.CAPSWORD` |Enables/disables CapsWord |

21
docs/en/cg_swap.md Normal file
View File

@@ -0,0 +1,21 @@
# Ctrl GUI Swap
This module allows to swap Ctrl with GUI and vice versa. This will reset on restart to the default implementation
## Enabling the module
```python
from kmk.modules.cg_swap import CgSwap
# cg_swap disabled on startup
cg_swap = CgSwap()
# cg_swap enabled on startup
# cg_swap = CgSwap(cg_swap_enable=True)
keyboard.modules.append(cg_swap)
keyboard.keymap = [
[
KC.CG_SWAP, # swap ctrl and gui
KC.CG_NORM, # unswap ctrl and gui
KC.CG_TOGG, # toggles ctrl and gui swap
],
]
```

52
docs/en/combos.md Normal file
View File

@@ -0,0 +1,52 @@
# Combos
Combos allow you to assign special functionality to combinations of key presses.
The two default behaviors are:
* Chords: match keys in random order, all pressed within 50ms.
* Sequences: match keys in order, pressed within 1s of one another.
You can define combos to listen to any valid KMK key, even internal or
functional keys, like HoldTap. When using internal KMK keys, be aware that the
order of modules matters.
The result of a combo is another key being pressed/released; if the desired
action isn't covered by KMK keys: create your own with `make_key` and attach
corresponding handlers.
Combos may overlap, i.e. share match keys amongst each other.
## Keycodes
|New Keycode |Description |
|------------|----------------------------------------------------|
|`KC.LEADER` | a dummy / convenience key for leader key sequences |
## Custom Combo Behavior
Optional arguments that customize individual combos:
* `fast_reset`: If True, allows tapping every key (default for sequences);
if False, allows holding at least one key and tapping the rest to repeatedly
activate the combo (default for chords).
* `per_key_timeout`: If True, reset timeout on every key press (default for
sequences).
* `timeout`: Set the time window within which the match has to happen in ms.
* `match_coord`: If True, matches key position in the matrix.
## Example Code
```python
from kmk.keys import KC, make_key
from kmk.modules.combos import Combos, Chord, Sequence
combos = Combos()
keyboard.modules.append(combos)
make_key(
names=('MYKEY',),
on_press=lambda *args: print('I pressed MYKEY'),
)
combos.combos = [
Chord((KC.A, KC.B), KC.LSFT),
Chord((KC.A, KC.B, KC.C), KC.LALT),
Chord((0, 1), KC.ESC, match_coord=True),
Chord((8, 9, 10), KC.MO(4), match_coord=True),
Sequence((KC.LEADER, KC.A, KC.B), KC.C),
Sequence((KC.E, KC.F), KC.MYKEY, timeout=500, per_key_timeout=False, fast_reset=False)
]
```

View File

@@ -0,0 +1,84 @@
# Configuring KMK
KMK is configured through a rather large plain-old-Python class called
`KMKKeyboard`. Subclasses of this configuration exist which pre-fill defaults
for various known keyboards (for example, many QMK, TMK, or ZMK keyboards
are supported with a nice!nano, or through our ItsyBitsy to Pro Micro pinout adapter.)
This class is the main interface between end users and the inner workings of KMK.
Let's dive in!
- Edit or create a file called `main.py` on your `CIRCUITPY` drive. You can also
keep this file on your computer (perhaps under `user_keymaps` - please feel
free to submit a pull request with your layout definitions!) and copy it over
(either manually or, if you're adept with developer tooling and/or a command
line, [our
Makefile](https://github.com/KMKfw/kmk_firmware/blob/master/docs/flashing.md)).
It's definitely recommended to keep a backup of your configuration somewhere
that isn't the microcontroller itself - MCUs die, CircuitPython may run into
corruption bugs, or you might just have bad luck and delete the wrong file
some day.
- Assign a `KMKKeyboard` instance to a variable (ex. `keyboard = KMKKeyboard()` - note
the parentheses)
- Make sure this `KMKKeyboard` instance is actually run at the end of the file with
a block such as the following:
```python
if __name__ == '__main__':
keyboard.go()
```
- Assign pins and your diode orientation (only necessary on handwire keyboards),
for example:
```python
import board
from kmk.scanners import DiodeOrientation
col_pins = (board.SCK, board.MOSI, board.MISO, board.RX, board.TX, board.D4)
row_pins = (board.D10, board.D11, board.D12, board.D13, board.D9, board.D6, board.D5, board.SCL)
rollover_cols_every_rows = 4
diode_orientation = DiodeOrientation.COL2ROW
```
The pins should be based on whatever CircuitPython calls pins on your particular
board. You can find these in the REPL on your CircuitPython device:
```python
import board
print(dir(board))
```
> Note: `rollover_cols_every_rows` is only supported with
> `DiodeOrientation.COLUMNS`/`DiodeOrientation.COL2ROW`, not `DiodeOrientation.ROWS`/`DiodeOrientation.ROW2COL`. It is used for boards
> such as the Planck Rev6 which reuse column pins to simulate a 4x12 matrix in
> the form of an 8x6 matrix
- Import the global list of key definitions with `from kmk.keys import KC`. You
can either print this out in the REPL as we did with `board` above, or simply
look at [our Key
documentation](https://github.com/KMKfw/kmk_firmware/blob/master/docs/keycodes.md).
We've tried to keep that listing reasonably up to date, but if it feels like
something is missing, you may need to read through `kmk/keys.py` (and then
open a ticket to tell us our docs are out of date, or open a PR and fix the
docs yourself!)
- Define a keymap, which is, in Python terms, a List of Lists of `Key` objects.
A very simple keymap, for a keyboard with just two physical keys on a single
layer, may look like this:
```python
keyboard.keymap = [[KC.A, KC.B]]
```
You can further define a bunch of other stuff:
- `keyboard.debug_enabled` which will spew a ton of debugging information to the serial
console. This is very rarely needed, but can provide very valuable information
if you need to open an issue.
- `keyboard.tap_time` which defines how long `KC.TT` and `KC.LT` will wait before
considering a key "held" (see `layers.md`)

68
docs/en/contributing.md Normal file
View File

@@ -0,0 +1,68 @@
# Contributing
KMK is a community effort and welcomes contributions of code and documentation from people
of all backgrounds and levels of technical skill. As such, these guidelines should serve
to make contributing as easy as possible for everyone while maintaining a consistent style.
## Contributing Code
The following guidelines should ensure that any code contributed can be merged in as
painlessly as possible. If you're unsure how to set up your development environment,
feel free to join the chat, [#kmkfw:klar.sh on Matrix](https://matrix.to/#/#kmkfw:klar.sh).
This channel is bridged to Discord [here](https://discord.gg/QBHUUpeGUd) for convenience.
### Code Style
KMK uses [Black](https://github.com/psf/black) with a Python 3.6 target and,
[(controversially?)](https://github.com/psf/black/issues/594) single quotes.
Further code styling is enforced with isort and flake8 with several plugins.
**NOTE:** before committing code, run `make fix-isort fix-formatting test` to
reduce workload for the project's maintainers and prevent the CI pipeline from
failing.
There are some limited exceptions to the code formatting rules, which can be
found in `setup.cfg`, notably around `user_keymaps` (which are also not subject
to Black formatting as documented in `pyproject.toml`)
### Tests
Unit tests within the `tests` folder mock various CircuitPython modules to allow
them to be executed in a desktop development environment.
Execute tests using the command `python -m unittest`.
## Contributing Documentation
While KMK welcomes documentation from anyone with and understanding of the issues
and a willingness to write them up, it's a good idea to familiarize yourself with
the docs. Documentation should be informative but concise.
### Styling
Docs are written and rendered in GitHub Markdown. A comprehensive guide to GitHub's
Markdown can be found [here](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax).
In particular, KMK's docs should include a title, demarcated with `#`, and subheadings
should be demarcated with `##`, `###`, and so on. Headings should be short and specific.
### Example Code
Where possible, practical code examples should be included in documentation to help
new users understand how to implement features. In general, it's better to have a code-
block with comments inside it rather than multiple blocks of code broken up with
explanation.
Code blocks should be formatted as Python code as follows:
````
```python
print('Hello, world!')
```
````
Inline code, indicated with `` `backticks` ``, should be used when calling out specific
functions or Python keywords within the body of paragraphs or in lists.
## License, Copyright, and Legal
All software in this repository is licensed under the [GNU Public License,
version 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.

11
docs/en/debugging.md Normal file
View File

@@ -0,0 +1,11 @@
# Debugging
Debug will output most of the useful state to the console. This can be enable in your firmware
by setting this in your keymap. NOTE that it will be slower, so only enable this when you
need debugging.
```python
keyboard.debug_enabled = True
```
The output can be viewed by connecting to the serial port of the keybord. Please refer to [THIS](https://learn.adafruit.com/welcome-to-circuitpython/kattni-connecting-to-the-serial-console) for
more information when connecting to serial console. For Linux users, we recommend [picocom](https://github.com/npat-efault/picocom) or
[screen](https://www.gnu.org/software/screen/manual/screen.html)

View File

@@ -0,0 +1,44 @@
# Dynamic Sequences
Dynamic sequences allow you to record a sequence just by typing it without modifying your keymap. Any sequence recorded this way is temporary and will remain available until your keyboard reboots.
### How to use
#### Recording
1. Press record
2. Type your sequence
3. Press stop
#### Playing
1. Press play to use your recorded sequence
## Enable dynamic sequences
```python
from kmk.modules.dynamic_sequences import DynamicSequences
keyboard.modules.append(DynamicSequences())
```
## Keycodes
|Key |Description |
|-------------------------------|---------------------------------------|
|`KC.RECORD_SEQUENCE()` |Start recording into the current slot |
|`KC.PLAY_SEQUENCE()` |Play the sequence in the current slot |
|`KC.STOP_SEQUENCE()` |Stop recording, playing, or configuring|
|`KC.SET_SEQUENCE(x)` |Change to the sequence in slot `x` |
|`KC.SET_SEQUENCE_REPETITIONS()`|Change to repepition config mode |
|`KC.SET_SEQUENCE_INTERVAL()` |Change to interval config mode |
## Config
```python
dynamicSequences = DynamicSequences(
slots=1, # The number of sequence slots to use
timeout=60000, # Maximum time to spend in record or config mode before stopping automatically, milliseconds
key_interval=0, # Milliseconds between key events while playing
use_recorded_speed=False # Whether to play the sequence at the speed it was typed
)
```
## Sequence slots
You can configure multiple slots that each store a different sequence. You can change to a specific slot with `KC.SET_SEQUENCE(x)`, where `x` is the sequence slot number (starting from `0`). Every keycode can take an optional number to change to a specific sequence slot before performing the action. For example `KC.PLAY_SEQUENCE(2)` will play the sequence in slot `2`. If a slot is not specified, the current slot will be used.
## Repeating sequences
Sequences can be set to repeat automatically. The number of repetitions and the interval between repetitions can be set using `KC.SET_SEQUENCE_REPETITIONS()` and `KC.SET_SEQUENCE_INTERVAL()`. Using one of these keys will put the keyboard in sequence config mode. In this mode, keypresses will not be sent to the OS and you can use your number keys to type the number of repetitions or the interval time in seconds. This mode ends when you press `KC.ENTER`, `KC.STOP_SEQUENCE()`, or automatically when the timeout is reached. Repeat settings are stored in the current slot.

25
docs/en/easypoint.md Normal file
View File

@@ -0,0 +1,25 @@
# AS5013 (aka 'EasyPoint')
Module handles the AM5013 Two-dimensional magnetic position sensor with digital coordinates output
Product page: https://www.mouser.dk/ProductDetail/ams/AS5013-IQFT?qs=abmNkq9no6D3ApA%252BrWSMNQ%3D%3D
### Usage
Declare I2C bus and add this module in your main class.
```python
from kmk.modules.easypoint import Easypoint
import busio
i2c = busio.I2C(scl=board.GP1, sda=board.GP0)
easypoint = Easypoint(i2c, address=0x40)
keyboard.modules.append(easypoint)
```
Further configuring the AS5013 involved x/y-offset, and deadzone.
```python
easypoint = Easypoint(i2c, address=0x40, y_offset=Y_OFFSET, x_offset=X_OFFSET, dead_x=DEAD_X, dead_y=DEAD_Y)
```

215
docs/en/encoder.md Normal file
View File

@@ -0,0 +1,215 @@
# Encoder module
Add twist control to your keyboard! Volume, zoom, anything you want.
I2C encoder type has been tested with the Adafruit I2C QT Rotary Encoder with NeoPixel.
**Note:** If you have a **split** keyboard and encoders on **both sides** should work, it's currently necessary to use the encoder-scanner explained at the bottom of [scanners docs](scanners.md).
## Enabling the extension
The constructor(`EncoderHandler` class) takes a list of encoders, each one defined as either:
* a list of `pad_a` pin, `pad_b` pin, `button_pin` and optionally a flag set to `True` if you want encoder direction to be reversed;
* a `busio.I2C`, address and optionally a flag set to `True` if you want it to be reversed.
The `encoder_map` is modeled after the keymap and works the same way. It should have as many layers (key pressed on "turned left", key pressed on "turned right", key pressed on "knob pressed") 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.
## How to use
Here is all you need to use this module in your `main.py` / `code.py` file.
1. Load the module: import encoder handler and add it to keyboard modules.
```python
from kmk.modules.encoder import EncoderHandler
encoder_handler = EncoderHandler()
keyboard.modules = [layers, modtap, encoder_handler]
```
2. Define the pins for each encoder: `pin_a`, `pin_b` for rotations, `pin_button` for the switch in the encoder. Set switch to `None` if the encoder's button is handled differently (as a part of matrix for example) or not at all. If you want to invert the direction of the encoder, set the 4th (optional) parameter `is_inverted` to `True`. 5th parameter is [encoder divisor](#encoder-resolution) (optional), it can be either `2` or `4`.
```python
# Regular GPIO Encoder
encoder_handler.pins = (
# regular direction encoder and a button
(board.GP17, board.GP15, board.GP14,), # encoder #1
# reversed direction encoder with no button handling and divisor of 2
(board.GP3, board.GP5, None, True, 2,), # encoder #2
)
```
Or in case you have an I2C encoder on a special PCB (e.g. Adafruit I2C QT Rotary Encoder), define I2C encoder as following.
```python
# I2C Encoder
# Setup i2c
SDA = board.GP0
SCL = board.GP1
i2c = busio.I2C(SCL, SDA)
encoder_handler.pins = ((i2c, 0x36, False), (encoder 2 definition), etc. )
```
3. Define the mapping of keys to be called for each layer.
```python
# You can optionally predefine combo keys as for your layout
Zoom_in = KC.LCTRL(KC.EQUAL)
Zoom_out = KC.LCTRL(KC.MINUS)
encoder_handler.map = [ (( KC.VOLD, KC.VOLU, KC.MUTE), (encoder 2 definition), etc. ), # Layer 1
((Zoom_out, Zoom_in, KC.NO), (encoder 2 definition), etc. ), # Layer 2
((KC.A, KC.Z, KC.N1), (encoder 2 definition), etc. ), # Layer 3
((KC.NO, KC.NO, KC.NO), (encoder 2 definition), etc. ), # Layer 4
]
```
## Encoder divisor
Depending on your encoder resolution, it may send 4 or 2 pulses (state changes) on every detent. This number is controlled by the `divisor` property. By default the divisor is set to 4, but if your encoder only activates on every second detent (skips pulses), set the divisor to 2. If the encoder activates twice on every detent, set the value to 4.
You can change the default globally for all encoders **before** initializing the encoder pins (`main.py` file):
```python
encoder_handler.divisor = 2
encoder_handler.pins = ( (board.GP14, board.GP15, None), (board.GP26, board.GP27, None), )
```
Or if you have different types of encoders, set divisor for each encoder individually:
```python
encoder_handler.pins = (
(board.GP14, board.GP15, None, False, 4),
(board.GP26, board.GP27, None, False, 2),
(board.GP26, board.GP27, None ), # will be set to global default
)
```
This setting is equivalent to `divisor` in the [rotaryio](https://docs.circuitpython.org/en/latest/shared-bindings/rotaryio/index.html#rotaryio.IncrementalEncoder.divisor) module.
The divisor of `1` for smooth encoders is not currently supported but you can use the divisor of `2` for them without issues and any noticeable difference.
## Handler methods overrides
Encoder methods `on_move_do` and `on_button_do` can be overridden for complex use cases.
## Connecting the encoder
Most EC11, EC12 and similar encoders have a common pinout shown below. For EVQWGD001 horizontal roller encoder, the pins are ordered `Pin A`, `Pin B`, `Ground`, and the fourth (furthest from the two switch pins) is not connected. This information is provided just for reference — always refer to the manufacturer datasheet for the correct pinout.
```
+----------+
Pin A ----| |
| |----- Ground
Ground ----| |
| |----- Switch Pin
Pin B ----| |
+----------+
```
In this configuration the encoder push button has its own dedicated pin. If the button should instead be a part of the matrix, it needs to be wired to Column and Row like other switches instead of ground.
---
## Full example (with 1 encoder)
```python
import board
from kmk.kmk_keyboard import KMKKeyboard
from kmk.consts import UnicodeMode
from kmk.keys import KC
from kmk.scanners import DiodeOrientation
from kmk.modules.layers import Layers
from kmk.modules.encoder import EncoderHandler
keyboard = KMKKeyboard()
layers = Layers()
encoder_handler = EncoderHandler()
keyboard.modules = [layers, encoder_handler]
keyboard.col_pins = (
board.GP0, board.GP1, board.GP2, board.GP3, board.GP4, board.GP5,
board.GP6, board.GP7, board.GP8, board.GP9, board.GP10, board.GP11,
board.GP12, board.GP13,
)
keyboard.row_pins = (board.GP28, board.GP27, board.GP22, board.GP26, board.GP21)
keyboard.diode_orientation = DiodeOrientation.COLUMNS
# I2C example
#import busio
#SDA = board.GP0
#SCL = board.GP1
#i2c = busio.I2C(SCL, SDA)
#encoder_handler.i2c = ((i2c, 0x36, False),)
# encoder_handler.divisor = 2 # for encoders with more precision
encoder_handler.pins = ((board.GP17, board.GP15, board.GP14, False),)
keyboard.tap_time = 250
keyboard.debug_enabled = False
# Filler keys
_______ = KC.TRNS
xxxxxxx = KC.NO
tbdtbd = KC.A
# Layers
LYR_STD, LYR_EXT, LYR_NUM, LYR_GAME = 0, 1, 2, 3
TO_STD = KC.DF(LYR_STD)
MT_EXT = KC.MO(LYR_EXT)
TO_NUM = KC.MO(LYR_NUM)
TO_GAME = KC.DF(LYR_GAME)
# Keymap
keyboard.keymap = [
# Standard (ISO) Layer
[
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.EQL , KC.BSPC,
KC.TAB , KC.Q , KC.W , KC.E , KC.R , KC.T , KC.Y , KC.U , KC.I , KC.O , KC.P , KC.LBRC, KC.RBRC, KC.DEL ,
xxxxxxx, KC.A , KC.S , KC.D , KC.F , KC.G , KC.H , KC.J , KC.K , KC.L , KC.SCLN, KC.QUOT, KC.NUHS, xxxxxxx,
KC.LSFT, KC.NUBS, KC.Z , KC.X , KC.C , KC.V , KC.B , KC.N , KC.M , KC.COMM, KC.DOT , KC.SLSH, KC.UP , KC.ENT ,
KC.LCTL, KC.LGUI, xxxxxxx, KC.LALT, MT_EXT , xxxxxxx, KC.SPC , xxxxxxx, KC.RALT, TO_NUM , KC.RSFT, KC.LEFT, KC.DOWN, KC.RGHT,
],
# Extra Keys Layer
[
TO_STD , KC.F1 , KC.F2 , KC.F3 , KC.F4 , KC.F5 , KC.F6 , KC.F7 , KC.F8 , KC.F9 , KC.F10 , KC.F11 , KC.F12 , KC.RESET,
_______, KC.N1 , KC.N2 , KC.N3 , KC.N4 , KC.N5 , KC.N6 , KC.N7 , KC.N8 , KC.N9 , KC.N0 , KC.MINS, KC.EQL , _______,
xxxxxxx, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, xxxxxxx,
KC.LSFT, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, KC.PGUP, _______,
KC.LCTL, KC.LGUI, xxxxxxx, KC.LALT, MT_EXT , xxxxxxx, _______, xxxxxxx, _______, TO_NUM , _______, KC.HOME, KC.PGDN, KC.END ,
],
# NumPad Layer
[
TO_STD , xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, KC.P7 , KC.P8 , KC.P9 , KC.PSLS, xxxxxxx, xxxxxxx, KC.BSPC,
xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, KC.P4 , KC.P5 , KC.P6 , KC.PAST, xxxxxxx, xxxxxxx, KC.DEL ,
xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, KC.LPRN, KC.P1 , KC.P2 , KC.P3 , KC.PPLS, xxxxxxx, xxxxxxx, xxxxxxx,
xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, KC.RPRN, KC.P0 , KC.PDOT, _______, KC.PMNS, xxxxxxx, xxxxxxx, KC.PENT,
xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, MT_EXT , xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, TO_NUM , xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx,
],
# Gaming Layer
[
TO_STD , xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx,
xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx,
xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx,
xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx,
xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, MT_EXT , xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx, TO_NUM , xxxxxxx, xxxxxxx, xxxxxxx, xxxxxxx,
],
]
# Rotary Encoder (1 encoder / 1 definition per layer)
encoder_handler.map = [ ((KC.UP, KC.DOWN, KC.MUTE),), # Standard
((KC.VOLD, KC.VOLU, KC.MUTE),), # Extra
((KC.A, KC.Z, KC.N1),), # NumPad not yet properly configured
((KC.A, KC.Z, KC.N1),), # Gaming not yet properly configured
]
if __name__ == "__main__":
keyboard.go()
```

View File

@@ -0,0 +1,47 @@
# Status LEDs
Indicate which layer you are on with an array of single leds.
During startup the leds light up to indicate that the bootup is finished.
For the time being just a simple consecutive single led
indicator. And when there are more layers than leds it
wraps around to the first led again.
(Also works for a single led, which just lights when any
layer is active)
_Most of the code comes from the Mono color LED backlight extension_.
## Enabling the extension
To enable the extension you need to define a list of `led_pins`. It can be a list of a one, two or three pins.
```python
from kmk.extensions.statusled import statusLED
import board
statusLED = statusLED(led_pins=[board.GP0, board.GP1, board.GP2])
keyboard.extensions.append(statusLED)
```
## [Keycodes]
| Key | Aliases | Description |
| ------------- | ------- | ------------------- |
| `KC.SLED_INC` | | Increase Brightness |
| `KC.SLED_DEC` | | Decrease Brightness |
## Configuration
All of these values can be set by default for when the keyboard boots.
```python
statusLED = statusLED(
led_pin=led_pin,
brightness=30,
brightness_step=5,
brightness_limit=100,
)
```
The brightness values are in percentages.

View File

@@ -0,0 +1,29 @@
# Stringy Keymaps
Enables referring to keys by `'NAME'` rather than `KC.NAME`.
For example:
```python
from kmk.extensions.stringy_keymaps import StringyKeymaps
# Normal
# keyboard.keymap = [[ KC.A, KC.B, KC.RESET ]]
# Indexed
# keyboard.keymap = [[ KC['A'], KC['B'], KC['RESET'] ]]
# String names
keyboard.keymap = [[ 'A' , 'B', 'RESET' ]]
stringyKeymaps = StringyKeymaps()
# Enabling debug will show each replacement or failure.
# This is recommended during the initial development of a keyboard.
# stringyKeymaps.debug_enable = True
keyboard.extensions.append(stringyKeymaps)
```
It should be noted that these are **not** ASCII. The string is **not** what
will be sent to the computer. The examples above have no functional difference.

19
docs/en/extensions.md Normal file
View File

@@ -0,0 +1,19 @@
# Extensions
Extensions add features that change the experience, but not the core features of
the keyboard. They are meant to be easy to add, and create your own. These live in
a sandbox to help prevent any bad code from crashing your keyboard.
## Core Extensions
These extensions are provided in all builds and can be enabled. Currently offered
extensions are
- [International](international.md): Adds international keycodes
- [LED](led.md): Adds backlight support. This is for monocolor backlight, not RGB
- [LockStatus](lock_status.md): Exposes host-side locks like caps or num lock.
- [MediaKeys](media_keys.md): Adds support for media keys such as volume
- [RGB](rgb.md): RGB lighting for underglow. Will work on most matrix RGB as will
be treated the same as underglow.
- [Status LED](extension_statusled.md): Indicates which layer you are on with an array of single leds.
- [Stringy Keymaps](extension_stringy_keymaps): Enables referring to keys by `'NAME'` rather than `KC.NAME`

38
docs/en/flashing.md Normal file
View File

@@ -0,0 +1,38 @@
# Flashing Instructions
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).
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`. It will also copy our
`boot.py`, which allocates a larger stack size (simply - more of the device's
RAM will be available to KMK and your keyboard config) than CircuitPython's
default. If any of these files exist on your CircuitPython device already, they
will be overwritten without a prompt.
If you get permissions errors here, **don't run make as root or with sudo**. See
`Troubleshooting` below.
```sh
make MOUNTPOINT=/media/CIRCUITPY USER_KEYMAP=user_keymaps/nameofyourkeymap.py BOARD=board/nameofyourboard/kb.py
```
# Troubleshooting
## Linux/BSD
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).
For example,
`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.

6
docs/en/handwiring.md Normal file
View File

@@ -0,0 +1,6 @@
# Handwire keyboards
This guide will not talk about the physical wiring. Check out our
[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)

35
docs/en/international.md Normal file
View File

@@ -0,0 +1,35 @@
# International Keycodes
International extension adds keys for non US layouts. It can simply be added to
the extensions list.
```python
from kmk.extensions.international import International
keyboard.extensions.append(International())
```
## Keycodes
|Key |Aliases |Description |
|-----------------------|--------------------|-----------------------------------------------|
|`KC.NONUS_HASH` |`KC.NUHS` |Non-US `#` and `~` |
|`KC.NONUS_BSLASH` |`KC.NUBS` |Non-US `\` and <code>&#124;</code> |
|`KC.INT1` |`KC.RO` |JIS `\` and <code>&#124;</code> |
|`KC.INT2` |`KC.KANA` |JIS Katakana/Hiragana |
|`KC.INT3` |`KC.JYEN` |JIS `¥` |
|`KC.INT4` |`KC.HENK` |JIS Henkan |
|`KC.INT5` |`KC.MHEN` |JIS Muhenkan |
|`KC.INT6` | |JIS Numpad `,` |
|`KC.INT7` | |International 7 |
|`KC.INT8` | |International 8 |
|`KC.INT9` | |International 9 |
|`KC.LANG1` |`KC.HAEN` |Hangul/English |
|`KC.LANG2` |`KC.HANJ` |Hanja |
|`KC.LANG3` | |JIS Katakana |
|`KC.LANG4` | |JIS Hiragana |
|`KC.LANG5` | |JIS Zenkaku/Hankaku |
|`KC.LANG6` | |Language 6 |
|`KC.LANG7` | |Language 7 |
|`KC.LANG8` | |Language 8 |
|`KC.LANG9` | |Language 9 |

226
docs/en/keycodes.md Normal file
View File

@@ -0,0 +1,226 @@
# Keys Overview
## [Basic Keys]
|Key |Aliases |Description |
|-----------------------|--------------------|-----------------------------------------------|
|`KC.NO` | |Ignore this key (NOOP) |
|`KC.TRANSPARENT` |`KC.TRNS` |Use the next lowest non-transparent key |
|`KC.A` | |`a` and `A` |
|`KC.B` | |`b` and `B` |
|`KC.C` | |`c` and `C` |
|`KC.D` | |`d` and `D` |
|`KC.E` | |`e` and `E` |
|`KC.F` | |`f` and `F` |
|`KC.G` | |`g` and `G` |
|`KC.H` | |`h` and `H` |
|`KC.I` | |`i` and `I` |
|`KC.J` | |`j` and `J` |
|`KC.K` | |`k` and `K` |
|`KC.L` | |`l` and `L` |
|`KC.M` | |`m` and `M` |
|`KC.N` | |`n` and `N` |
|`KC.O` | |`o` and `O` |
|`KC.P` | |`p` and `P` |
|`KC.Q` | |`q` and `Q` |
|`KC.R` | |`r` and `R` |
|`KC.S` | |`s` and `S` |
|`KC.T` | |`t` and `T` |
|`KC.U` | |`u` and `U` |
|`KC.V` | |`v` and `V` |
|`KC.W` | |`w` and `W` |
|`KC.X` | |`x` and `X` |
|`KC.Y` | |`y` and `Y` |
|`KC.Z` | |`z` and `Z` |
|`KC.N1` | |`1` and `!` |
|`KC.N2` | |`2` and `@` |
|`KC.N3` | |`3` and `#` |
|`KC.N4` | |`4` and `$` |
|`KC.N5` | |`5` and `%` |
|`KC.N6` | |`6` and `^` |
|`KC.N7` | |`7` and `&` |
|`KC.N8` | |`8` and `*` |
|`KC.N9` | |`9` and `(` |
|`KC.N0` | |`0` and `)` |
|`KC.ENTER` |`KC.ENT` |Return (Enter) |
|`KC.ESCAPE` |`KC.ESC` |Escape |
|`KC.BSPACE` |`KC.BSPC` |Delete (Backspace) |
|`KC.TAB` | |Tab |
|`KC.SPACE` |`KC.SPC` |Spacebar |
|`KC.MINUS` |`KC.MINS` |`-` and `_` |
|`KC.EQUAL` |`KC.EQL` |`=` and `+` |
|`KC.LBRACKET` |`KC.LBRC` |`[` and `{` |
|`KC.RBRACKET` |`KC.RBRC` |`]` and `}` |
|`KC.BSLASH` |`KC.BSLS` |`\` and <code>&#124;</code> |
|`KC.SCOLON` |`KC.SCLN` |`;` and `:` |
|`KC.QUOTE` |`KC.QUOT` |`'` and `"` |
|`KC.GRAVE` |`KC.GRV`, `KC.ZKHK` |<code>&#96;</code> and `~`, JIS Zenkaku/Hankaku|
|`KC.COMMA` |`KC.COMM` |`,` and `<` |
|`KC.DOT` | |`.` and `>` |
|`KC.SLASH` |`KC.SLSH` |`/` and `?` |
|`KC.CAPSLOCK` |`KC.CLCK`, `KC.CAPS`|Caps Lock |
|`KC.F1` | |F1 |
|`KC.F2` | |F2 |
|`KC.F3` | |F3 |
|`KC.F4` | |F4 |
|`KC.F5` | |F5 |
|`KC.F6` | |F6 |
|`KC.F7` | |F7 |
|`KC.F8` | |F8 |
|`KC.F9` | |F9 |
|`KC.F10` | |F10 |
|`KC.F11` | |F11 |
|`KC.F12` | |F12 |
|`KC.PSCREEN` |`KC.PSCR` |Print Screen |
|`KC.SCROLLLOCK` |`KC.SLCK` |Scroll Lock |
|`KC.PAUSE` |`KC.PAUS`, `KC.BRK` |Pause |
|`KC.INSERT` |`KC.INS` |Insert |
|`KC.HOME` | |Home |
|`KC.PGUP` | |Page Up |
|`KC.DELETE` |`KC.DEL` |Forward Delete |
|`KC.END` | |End |
|`KC.PGDOWN` |`KC.PGDN` |Page Down |
|`KC.RIGHT` |`KC.RGHT` |Right Arrow |
|`KC.LEFT` | |Left Arrow |
|`KC.DOWN` | |Down Arrow |
|`KC.UP` | |Up Arrow |
|`KC.NUMLOCK` |`KC.NLCK` |Keypad Num Lock and Clear |
|`KC.KP_SLASH` |`KC.PSLS` |Keypad `/` |
|`KC.KP_ASTERISK` |`KC.PAST` |Keypad `*` |
|`KC.KP_MINUS` |`KC.PMNS` |Keypad `-` |
|`KC.KP_PLUS` |`KC.PPLS` |Keypad `+` |
|`KC.KP_ENTER` |`KC.PENT` |Keypad Enter |
|`KC.KP_1` |`KC.P1` |Keypad `1` and End |
|`KC.KP_2` |`KC.P2` |Keypad `2` and Down Arrow |
|`KC.KP_3` |`KC.P3` |Keypad `3` and Page Down |
|`KC.KP_4` |`KC.P4` |Keypad `4` and Left Arrow |
|`KC.KP_5` |`KC.P5` |Keypad `5` |
|`KC.KP_6` |`KC.P6` |Keypad `6` and Right Arrow |
|`KC.KP_7` |`KC.P7` |Keypad `7` and Home |
|`KC.KP_8` |`KC.P8` |Keypad `8` and Up Arrow |
|`KC.KP_9` |`KC.P9` |Keypad `9` and Page Up |
|`KC.KP_0` |`KC.P0` |Keypad `0` and Insert |
|`KC.KP_DOT` |`KC.PDOT` |Keypad `.` and Delete |
|`KC.KP_EQUAL` |`KC.PEQL` |Keypad `=` |
|`KC.F13` | |F13 |
|`KC.F14` | |F14 |
|`KC.F15` | |F15 |
|`KC.F16` | |F16 |
|`KC.F17` | |F17 |
|`KC.F18` | |F18 |
|`KC.F19` | |F19 |
|`KC.F20` | |F20 |
|`KC.F21` | |F21 |
|`KC.F22` | |F22 |
|`KC.F23` | |F23 |
|`KC.F24` | |F24 |
|`KC.LOCKING_CAPS` |`KC.LCAP` |Locking Caps Lock |
|`KC.LOCKING_NUM` |`KC.LNUM` |Locking Num Lock |
|`KC.LOCKING_SCROLL` |`KC.LSCR` |Locking Scroll Lock |
|`KC.KP_COMMA` |`KC.PCMM` |Keypad `,` |
|`KC.KP_EQUAL_AS400` | |Keypad `=` on AS/400 keyboards |
|`KC.LCTRL` |`KC.LCTL` |Left Control |
|`KC.LSHIFT` |`KC.LSFT` |Left Shift |
|`KC.LALT` | |Left Alt |
|`KC.LGUI` |`KC.LCMD`, `KC.LWIN`|Left GUI (Windows/Command/Meta key) |
|`KC.RCTRL` |`KC.RCTL` |Right Control |
|`KC.RSHIFT` |`KC.RSFT` |Right Shift |
|`KC.RALT` | |Right Alt |
|`KC.RGUI` |`KC.RCMD`, `KC.RWIN`|Right GUI (Windows/Command/Meta key) |
## [US ANSI Shifted Symbols]
|Key |Aliases |Description |
|------------------------|-------------------|-------------------|
|`KC.TILDE` |`KC.TILD` |`~` |
|`KC.EXCLAIM` |`KC.EXLM` |`!` |
|`KC.AT` | |`@` |
|`KC.HASH` | |`#` |
|`KC.DOLLAR` |`KC.DLR` |`$` |
|`KC.PERCENT` |`KC.PERC` |`%` |
|`KC.CIRCUMFLEX` |`KC.CIRC` |`^` |
|`KC.AMPERSAND` |`KC.AMPR` |`&` |
|`KC.ASTERISK` |`KC.ASTR` |`*` |
|`KC.LEFT_PAREN` |`KC.LPRN` |`(` |
|`KC.RIGHT_PAREN` |`KC.RPRN` |`)` |
|`KC.UNDERSCORE` |`KC.UNDS` |`_` |
|`KC.PLUS` | |`+` |
|`KC.LEFT_CURLY_BRACE` |`KC.LCBR` |`{` |
|`KC.RIGHT_CURLY_BRACE` |`KC.RCBR` |`}` |
|`KC.PIPE` | |<code>&#124;</code>|
|`KC.COLON` |`KC.COLN` |`:` |
|`KC.DOUBLE_QUOTE` |`KC.DQUO`, `KC.DQT`|`"` |
|`KC.LEFT_ANGLE_BRACKET` |`KC.LABK`, `KC.LT` |`<` |
|`KC.RIGHT_ANGLE_BRACKET`|`KC.RABK`, `KC.GT` |`>` |
|`KC.QUESTION` |`KC.QUES` |`?` |
## [International Keys]
|Key |Aliases |Description |
|------------------------|------------------------------|-----------------------|
|`KC.NONUS_HASH` |`KC.NUHS` |ISO Left of Return |
|`KC.NONUS_BSLASH` |`KC.NUBS` |ISO Right of LSHIFT |
|`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]
|Key |Description |
|-----------------------|---------------------------------------------------------------------|
|`KC.RESET` |Restarts the keyboard |
|`KC.RELOAD`, `KC.RLD` |Reloads the keyboard software, preserving any serial connections |
|`KC.DEBUG` |Toggle `debug_enabled`, which enables log spew to serial console |
|`KC.GESC` |Escape when tapped, <code>&#96;</code> when pressed with Shift or GUI|
|`KC.BKDL` |Backspace when tapped, Delete when pressed with GUI |
|`KC.UC_MODE_NOOP` |Sets UnicodeMode to NOOP |
|`KC.UC_MODE_LINUX` |Sets UnicodeMode to Linux |
|`KC.UC_MODE_MACOS` |Sets UnicodeMode to macOS |
|`KC.UC_MODE_WINC` |Sets UnicodeMode to WinCompose |
|`KC.MACRO_SLEEP_MS(ms)`|Sleeps in a macro. See [SEQUENCES](/docs/sequences.md) for more information. |
## [Modifiers]
|Key |Description |
|-------------|----------------------------------------------------|
|`KC.HYPR` |Hold Left Control, Shift, Alt and GUI |
|`KC.MEH` |Hold Left Control, Shift and Alt |
|`KC.LCTL(kc)`|Hold Left Control and press `kc` |
|`KC.LSFT(kc)`|Hold Left Shift and press `kc` |
|`KC.LALT(kc)`|Hold Left Alt and press `kc` |
|`KC.LGUI(kc)`|Hold Left GUI and press `kc` |
|`KC.RCTL(kc)`|Hold Right Control and press `kc` |
|`KC.RSFT(kc)`|Hold Right Shift and press `kc` |
|`KC.RALT(kc)`|Hold Right Alt and press `kc` |
|`KC.RGUI(kc)`|Hold Right GUI and press `kc` |
## [Bluetooth Keys]
|Key |Aliases |Description |
|-----------------------------|-------------------|----------------------------------|
|`KC.BT_CLEAR_BONDS` |`KC.BT_CLR` |Clears all stored bondings |
|`KC.BT_NEXT_CONN` |`KC.BT_NXT` |Selects the next BT connection |
|`KC.BT_PREV_CONN` |`KC.BT_PRV` |Selects the previous BT connection|
## [Media Keys]
See [MediaKeys extension](media_keys.md).

187
docs/en/keys.md Normal file
View File

@@ -0,0 +1,187 @@
# Keys
> NOTE: This is not a lookup table of key objects provided by KMK. That listing
> can be found in [`keycodes.md`](/docs/keycodes.md). It's probably worth a look at the raw source if
> you're stumped: [`kmk/keys.py`](/kmk/keys.py).
This is a bunch of documentation about how a physical keypress translates to
events (and the lifecycle of said events) in KMK. It's somewhat technical, but
if you're looking to extend your keyboard's functionality with extra code,
you'll need at least some of this technical knowledge.
The first few steps in the process aren't all that interesting for most
workflows, which is why they're buried deep in KMK: we scan a bunch of GPIO
lanes (about as quickly as CircuitPython will let us) to see where, in a matrix
of keys, a key has been pressed. The technical details about this process [are
probably best left to
Wikipedia](https://en.wikipedia.org/wiki/Keyboard_matrix_circuit). Then, we scan
through the defined keymap, finding the first valid key at this index based on
the stack of currently active layers (this logic, if you want to read through
the code, is in [`kmk/kmk_keyboard.py`](/kmk/kmk_keyboard.py), method `_find_key_in_map`).
The next few steps are the interesting part, but to understand them, we need to
understand a bit about what a `Key` object is (found in [`kmk/keys.py`](/kmk/keys.py)). `Key`
objects have a few core pieces of information:
- Their `code`, which can be any integer. Integers below
`FIRST_KMK_INTERNAL_KEY` are sent through to the HID stack (and thus the
computer, which will translate that integer to something meaningful - for
example, `code=4` becomes `a` on a US QWERTY/Dvorak keyboard).
- Their attached modifiers (to implement things like shifted keys or `KC.HYPR`,
which are single key presses sending along more than one key in a single HID
report. This is a distinct concept from Sequences, which are a KMK feature
documented in [`sequences.md`](/docs/sequences.md)). For almost all purposes outside of KMK core,
this field should be ignored - it can be safely populated through far more
sane means than futzing with it by hand.
- Some data on whether the key should actually be pressed or released - this is
mostly an implementation detail of how Sequences work, where, for example,
`KC.RALT` may need to be held down for the entirety of a sequence, rather than
being released immediately before moving to the next character. Usually end
users shouldn't need to mess with this, but the fields are called `no_press`
and `no_release` and are referenced in a few places in the codebase if you
need examples.
- Handlers for "press" (sometimes known as "keydown") and "release" (sometimes
known as "keyup") events. KMK provides handlers for standard keyboard
functions and some special override keys (like `KC.GESC`, which is an enhanced
form of existing ANSI keys) in [`kmk/handlers/stock.py`](/kmk/handlers/stock.py), for layer switching in
[`kmk/modules/layers.py`](/kmk/modules/layers.py), and for everything related to Sequences (see
[`sequences.md`](/docs/sequences.md) again) in [`kmk/handlers/sequences.py`](/kmk/handlers/sequences.py). We'll discuss these more
shortly.
- Optional callbacks to be run before and/or after the above handlers. More on
that soon.
- A generic `meta` field, which is most commonly used for "argumented" keys -
objects in the `KC` object which are actually functions that return `Key`
instances, which often need to access the arguments passed into the "outer"
function. Many of these examples are related to layer switching - for example,
`KC.MO` is implemented as an argumented key - when the user adds `KC.MO(1)` to
their keymap, the function call returns a `Key` object with `meta` set to an
object containing `layer` and `kc` properties, for example. There's other uses
for `meta`, and examples can be found in [`kmk/types.py`](/kmk/types.py)
`Key` objects can also be chained together by calling them! To create a key
which holds Control and Shift simultaneously, we can simply do:
```python
CTRLSHFT = KC.LCTL(KC.LSFT)
keyboard.keymap = [ ... CTRLSHFT ... ]
```
When a key is pressed and we've pulled a `Key` object out of the keymap, the
following will happen:
- Pre-press callbacks will be run in the order they were assigned, with their
return values discarded (unless the user attached these, they will almost
never exist)
- The assigned press handler will be run (most commonly, this is provided by
KMK)
- Post-press callbacks will be run in the order they were assigned, with their
return values discarded (unless the user attached these, they will almost
never exist)
These same steps are run for when a key is released.
_So now... what's a handler, and what's a pre/post callback?!_
All of these serve roughly the same purpose: to _do something_ with the key's
data, or to fire off side effects. Most handlers are provided by KMK internally
and modify the `InternalState` in some way - adding the key to the HID queue,
changing layers, etc. The pre/post handlers are designed to allow functionality
to be bolted on at these points in the event flow without having to reimplement
(or import and manually call) the internal handlers.
All of these methods take the same arguments, and for this, I'll lift a
docstring straight out of the source:
> Receives the following:
>
> - self (this Key instance)
> - state (the current InternalState)
> - KC (the global KC lookup table, for convenience)
> - `coord_int` (an internal integer representation of the matrix coordinate
> for the pressed key - this is likely not useful to end users, but is
> provided for consistency with the internal handlers)
> - `coord_raw` (an X,Y tuple of the matrix coordinate - also likely not useful)
>
> The return value of the provided callback is discarded. Exceptions are _not_
> caught, and will likely crash KMK if not handled within your function.
>
> These handlers are run in attachment order: handlers provided by earlier
> calls of this method will be executed before those provided by later calls.
This means if you want to add things like underglow/LED support, or have a
button that triggers your GSM modem to call someone, or whatever else you can
hack up in CircuitPython, which also retaining layer-switching abilities or
whatever the stock handler is, you're covered. This also means you can add
completely new functionality to KMK by writing your own handler.
Here's an example of an after_press_handler to change the RGB lights with a layer change:
```python
LOWER = KC.DF(LYR_LOWER) #Set layer to LOWER
def low_lights(key, keyboard, *args):
print('Lower Layer') #serial feedback
keyboard.pixels.set_hsv_fill(0, 100, 255) #RGB extension call to set (H,S,V) values
LOWER.after_press_handler(low_lights) #call the key with the after_press_handler
```
Here's an example of a lifecycle hook to print a giant Shrek ASCII art. It
doesn't care about any of the arguments passed into it, because it has no
intentions of modifying the internal state. It is purely a [side
effect](<https://en.wikipedia.org/wiki/Side_effect_(computer_science)>) run every
time Left Alt is pressed:
```python
def shrek(*args, **kwargs):
print('⢀⡴⠑⡄⠀⠀⠀⠀⠀⠀⠀⣀⣀⣤⣤⣤⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀')
print('⠸⡇⠀⠿⡀⠀⠀⠀⣀⡴⢿⣿⣿⣿⣿⣿⣿⣿⣷⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀')
print('⠀⠀⠀⠀⠑⢄⣠⠾⠁⣀⣄⡈⠙⣿⣿⣿⣿⣿⣿⣿⣿⣆⠀⠀⠀⠀⠀⠀⠀⠀')
print('⠀⠀⠀⠀⢀⡀⠁⠀⠀⠈⠙⠛⠂⠈⣿⣿⣿⣿⣿⠿⡿⢿⣆⠀⠀⠀⠀⠀⠀⠀')
print('⠀⠀⠀⢀⡾⣁⣀⠀⠴⠂⠙⣗⡀⠀⢻⣿⣿⠭⢤⣴⣦⣤⣹⠀⠀⠀⢀⢴⣶⣆')
print('⠀⠀⢀⣾⣿⣿⣿⣷⣮⣽⣾⣿⣥⣴⣿⣿⡿⢂⠔⢚⡿⢿⣿⣦⣴⣾⠁⠸⣼⡿')
print('⠀⢀⡞⠁⠙⠻⠿⠟⠉⠀⠛⢹⣿⣿⣿⣿⣿⣌⢤⣼⣿⣾⣿⡟⠉⠀⠀⠀⠀⠀')
print('⠀⣾⣷⣶⠇⠀⠀⣤⣄⣀⡀⠈⠻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀')
print('⠀⠉⠈⠉⠀⠀⢦⡈⢻⣿⣿⣿⣶⣶⣶⣶⣤⣽⡹⣿⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀')
print('⠀⠀⠀⠀⠀⠀⠀⠉⠲⣽⡻⢿⣿⣿⣿⣿⣿⣿⣷⣜⣿⣿⣿⡇⠀⠀⠀⠀⠀⠀')
print('⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⣿⣷⣶⣮⣭⣽⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀')
print('⠀⠀⠀⠀⠀⠀⣀⣀⣈⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠇⠀⠀⠀⠀⠀⠀⠀')
print('⠀⠀⠀⠀⠀⠀⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠃⠀⠀⠀⠀⠀⠀⠀⠀')
print('⠀⠀⠀⠀⠀⠀⠀⠹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀')
print('⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠛⠻⠿⠿⠿⠿⠛⠉')
return False #Returning True will follow thru the normal handlers sending the ALT key to the OS
KC.LALT.before_press_handler(shrek)
```
You can also copy a key without any pre/post handlers attached with `.clone()`,
so for example, if I've already added Shrek to my `LALT` but want a Shrek-less
`LALT` key elsewhere in my keymap, I can just clone it, and the new key won't
have my handlers attached:
```python
SHREKLESS_ALT = KC.LALT.clone()
```
You can also refer to a key by index:
- `KC['A']`
- `KC['NO']`
- `KC['LALT']`
Or the `KC.get` function which has an optional default argument, which will
be returned if the key is not found (`default=None` unless otherwise specified):
- `KC.get('A')`
- `KC.get('NO', None)`
- `KC.get('NOT DEFINED', KC.RALT)`
Key names are case-sensitive. `KC['NO']` is different from `KC['no']`. It is recommended
that names are normally UPPER_CASE. The exception to this are alpha keys; `KC['A']` and
`KC['a']` will both return the same, unshifted, key.

View File

@@ -0,0 +1,26 @@
# THIS IS OUT OF DATE. DO NOT USE. ONLY FOR REFERENCE
## 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

93
docs/en/layers.md Normal file
View File

@@ -0,0 +1,93 @@
# Layers
Layers module adds keys for accessing other layers. It can simply be added to
the extensions list.
```python
from kmk.modules.layers import Layers
keyboard.modules.append(Layers())
```
## Keycodes
|Key |Description |
|-----------------|--------------------------------------------------------------------------|
|`KC.DF(layer)` |Switches the default layer until the next time the keyboard powers off |
|`KC.MO(layer)` |Momentarily activates layer, switches off when you let go |
|`KC.LM(layer, mod)` |As `MO(layer)` but with `mod` active |
|`KC.LT(layer, kc)` |Momentarily activates layer if held, sends kc if tapped |
|`KC.TG(layer)` |Toggles the layer (enables it if no active, and vise versa) |
|`KC.TO(layer)` |Activates layer and deactivates all other layers |
|`KC.TT(layer)` |Momentarily activates layer if held, toggles it if tapped repeatedly |
## Custom HoldTap Behavior
`KC.TT` and `KC.LT` use the same heuristic to determine taps and holds as
ModTap. Check out the [ModTap doc](modtap.md) to find out more.
## Working with Layers
When starting out, care should be taken when working with layers, since it's possible to lock
yourself to a layer with no way of returning to the base layer short of unplugging your
keyboard. This is especially easy to do when using the `KC.TO()` keycode, which deactivates
all other layers in the stack.
Some helpful guidelines to keep in mind as you design your layers:
- Only reference higher-numbered layers from a given layer
- Leave keys as `KC.TRNS` in higher layers when they would overlap with a layer-switch
### Using Multiple Base Layers
In some cases, you may want to have more than one base layer (for instance you want to use
both QWERTY and Dvorak layouts, or you have a custom gamepad that can switch between
different games). In this case, best practice is to have these layers be the lowest, i.e.
defined first in your keymap. These layers are mutually-exclusive, so treat changing default
layers with `KC.DF()` the same way that you would treat using `KC.TO()`
## Example Code
For our example, let's take a simple 3x3 macropad with two layers as follows:
```python
from kmk.modules.layers import Layers
keyboard.modules.append(Layers())
# Layer Keys
MOMENTARY = KC.MO(1)
MOD_LAYER = KC.LM(1, KC.RCTL)
LAYER_TAP = KC.LT(1, KC.END, prefer_hold=True, tap_interrupted=False, tap_time=250) # any tap longer than 250ms will be interpreted as a hold
keyboard.keymap = [
# Base layer
[
KC.NO, KC.UP, KC.NO,
KC.LEFT,KC.DOWN,KC.RGHT,
MOMENTARY, LAYER_TAP, MOD_LAYER,
],
# Function Layer
[
KC.F1, KC.F2, KC.F3,
KC.F4, KC.F5, KC.F6,
KC.TRNS,KC.TRNS,KC.TRNS,
],
]
```
## Advanced Example
A common question is: "How do I change RGB background based on my active layer?"
Here is _one_ (simple) way of many to go about it.
```python
from kmk.modules.layers import Layers as _Layers
from kmk.extensions.rgb import RGB
rgb = RGB(...) # your RGB configuration goes here
keyboard.extensions.append(rgb)
class Layers(_Layers):
last_top_layer = 0
hues = (4, 20, 69)
def after_hid_send(keyboard):
if keyboard.active_layers[0] != self.last_top_layer:
self.last_top_layer = keyboard.active_layers[0]
rgb.set_hsv_fill(self.hues[self.last_top_layer], 255, 255)
keyboard.modules.append(Layers())
```

57
docs/en/led.md Normal file
View File

@@ -0,0 +1,57 @@
# LED (Mono color backlight)
Want your keyboard to shine? Add some lights!
## Enabling the extension
The only required values that you need to give the LED extension would be the
`led_pin`. It can either be a single board pin, or a list of pins for multiple
LED's.
```python
from kmk.extensions.LED import LED
import board
led_ext = LED(led_pin=[board.GP0, board.GP1])
keyboard.extensions.append(led_ext)
```
## [Keycodes]
|Key |Aliases |Description |
|-----------------------------|-------------------|----------------------------|
|`KC.LED_TOG()` | |Toggles LED's |
|`KC.LED_INC()` | |Increase Brightness |
|`KC.LED_DEC()` | |Decrease Brightness |
|`KC.LED_SET()` | |Set Brightness |
|`KC.LED_ANI` | |Increase animation speed |
|`KC.LED_AND` | |Decrease animation speed |
|`KC.LED_MODE_PLAIN` |`LED_M_P` |Static LED's |
|`KC.LED_MODE_BREATHE` |`LED_M_B` |Breathing animation |
Keycodes with arguments can affect all, or a selection of LED's.
```python
# toggle all LEDs
LED_TOG_ALL = KC.LED_TOG()
# increase brightness of first LED
LED_INC_0 = KC.LED_INC(0)
# decrease brightness of second and third LED
LED_DEC_1_2 = KC.LED_DEC(1,2)
```
## Configuration
All of these values can be set by default for when the keyboard boots.
```python
from kmk.extensions.led import AnimationModes
led_ext = LED(
led_pin=led_pin,
brightness=50,
brightness_step=5,
brightness_limit=100,
breathe_center=1.5,
animation_mode=AnimationModes.STATIC,
animation_speed=1,
user_animation=None,
val=100,
)
```

63
docs/en/lock_status.md Normal file
View File

@@ -0,0 +1,63 @@
# Lock Status
This extension exposes host-side locks like caps or num lock.
## Enabling the extension
```python
from kmk.extensions.lock_status import LockStatus
locks = LockStatus()
keyboard.extensions.append(locks)
```
## Read Lock Status
Lock states can be retrieved with getter methods and are truth valued -- `True`
when the lock is enabled and `False` otherwise.
|Method |Description |
|--------------------------|------------|
|`locks.get_num_lock() ` |Num Lock |
|`locks.get_caps_lock() ` |Caps Lock |
|`locks.get_scroll_lock() `|Scroll Lock |
|`locks.get_compose() ` |Compose |
|`locks.get_kana() ` |Kana |
## React to Lock Status Changes
The best way to react to changes in lock status is to extend
the LockStatus class. When a lock status change happens,
the 'after_hid_send' function is envoked so you would override
LockStatus's to inject your own logic. Be aware though that
this function is also critically important to the functionality
of LockStatus so be sure to invoke the 'super()' version of your
class to trigger the default functionality of LockStatus.
```python
# in your main.py
from kb import KMKKeyboard
from kmk.extensions.lock_status import LockStatus
from kmk.extensions.LED import LED
keyboard = KMKKeyboard()
leds = LED(led_pin=[board.GP27, board.GP28])
class LEDLockStatus(LockStatus):
def set_lock_leds(self):
if self.get_caps_lock():
leds.set_brightness(50, leds=[0])
else:
leds.set_brightness(0, leds=[0])
if self.get_scroll_lock():
leds.set_brightness(50, leds=[1])
else:
leds.set_brightness(0, leds=[1])
def after_hid_send(self, sandbox):
super().after_hid_send(sandbox) # Critically important. Do not forget
if self.report_updated:
self.set_lock_leds()
keyboard.extensions.append(leds)
keyboard.extensions.append(LEDLockStatus())
```

25
docs/en/media_keys.md Normal file
View File

@@ -0,0 +1,25 @@
# Media Keys
Media keys extension adds keys for common media control keys. It can simply be
added to the extensions list.
```python
from kmk.extensions.media_keys import MediaKeys
keyboard.extensions.append(MediaKeys())
```
## Keycodes
|Key |Aliases |Description |
|-----------------------|--------------------|-----------------------------------------------|
|`KC.AUDIO_MUTE` |`KC.MUTE` |Mute |
|`KC.AUDIO_VOL_UP` |`KC.VOLU` |Volume Up |
|`KC.AUDIO_VOL_DOWN` |`KC.VOLD` |Volume Down |
|`KC.BRIGHTNESS_UP` |`KC.BRIU` |Brightness Up |
|`KC.BRIGHTNESS_DOWN` |`KC.BRID` |Brightness Down |
|`KC.MEDIA_NEXT_TRACK` |`KC.MNXT` |Next Track (Windows) |
|`KC.MEDIA_PREV_TRACK` |`KC.MPRV` |Previous Track (Windows) |
|`KC.MEDIA_STOP` |`KC.MSTP` |Stop Track (Windows) |
|`KC.MEDIA_PLAY_PAUSE` |`KC.MPLY` |Play/Pause Track |
|`KC.MEDIA_EJECT` |`KC.EJCT` |Eject (macOS) |
|`KC.MEDIA_FAST_FORWARD`|`KC.MFFD` |Next Track (macOS) |
|`KC.MEDIA_REWIND` |`KC.MRWD` |Previous Track (macOS) |

18
docs/en/midi.md Normal file
View File

@@ -0,0 +1,18 @@
# MIDI
The MIDI module adds keymap entries for sending MIDI data streams. It will require adding the `adafruit_midi` library from the [Adafruit CircuitPython Bundle](https://circuitpython.org/libraries) to your device's folder.
Add it to your keyboard's modules list with:
```python
from kmk.modules.midi import MidiKeys
keyboard.modules.append(MidiKeys())
```
## Keycodes
|Key |Description |
|-------------------------------|----------------------------------------------------------|
|`KC.MIDI_CC(ctrl, val)` |Sends a ControlChange message |
|`KC.MIDI_NOTE(note, velo)` |Sends a Note message |
|`KC.MIDI_PB(val)` |Sends a Pitch Wheel message |
|`KC.MIDI_PC(program)` |Sends a Program Change message |
|`KC.MIDI_START()` |Sends a Start message |
|`KC.MIDI_STOP()` |Sends a Stop message |

51
docs/en/modtap.md Normal file
View File

@@ -0,0 +1,51 @@
# ModTap Keycodes
Enabling ModTap will give you access to the following keycodes and can simply be
added to the modules list.
```python
from kmk.modules.modtap import ModTap
modtap = ModTap()
# optional: set a custom tap timeout in ms
# modtap.tap_time = 300
keyboard.modules.append(modtap)
```
## Keycodes
|New Keycode | Description |
|---------------------------------------------------------|-----------------------------------------------------------------|
|`LCTL = KC.MT(KC.SOMETHING, KC.LCTRL)` |`LCTRL` if held `kc` if tapped |
|`LSFT = KC.MT(KC.SOMETHING, KC.LSFT)` |`LSHIFT` if held `kc` if tapped |
|`LALT = KC.MT(KC.SOMETHING, KC.LALT)` |`LALT` if held `kc` if tapped |
|`LGUI = KC.MT(KC.SOMETHING, KC.LGUI)` |`LGUI` if held `kc` if tapped |
|`RCTL = KC.MT(KC.SOMETHING, KC.RCTRL)` |`RCTRL` if held `kc` if tapped |
|`RSFT = KC.MT(KC.SOMETHING, KC.RSFT)` |`RSHIFT` if held `kc` if tapped |
|`RALT = KC.MT(KC.SOMETHING, KC.RALT)` |`RALT` if held `kc` if tapped |
|`RGUI = KC.MT(KC.SOMETHING, KC.RGUI)` |`RGUI` if held `kc` if tapped |
|`SGUI = KC.MT(KC.SOMETHING, KC.LSHFT(KC.LGUI))` |`LSHIFT` and `LGUI` if held `kc` if tapped |
|`LCA = KC.MT(KC.SOMETHING, KC.LCTRL(KC.LALT))` |`LCTRL` and `LALT` if held `kc` if tapped |
|`LCAG = KC.MT(KC.SOMETHING, KC.LCTRL(KC.LALT(KC.LGUI)))` |`LCTRL` and `LALT` and `LGUI` if held `kc` if tapped |
|`MEH = KC.MT(KC.SOMETHING, KC.LCTRL(KC.LSFT(KC.LALT)))` |`CTRL` and `LSHIFT` and `LALT` if held `kc` if tapped |
|`HYPR = KC.MT(KC.SOMETHING, KC.HYPR)` |`LCTRL` and `LSHIFT` and `LALT` and `LGUI` if held `kc` if tapped|
## Custom HoldTap Behavior
The full ModTap signature is as follows:
```python
KC.MT(KC.TAP, KC.HOLD, prefer_hold=True, tap_interrupted=False, tap_time=None, repeat=HoldTapRepeat.NONE)
```
* `prefer_hold`: decides which keycode the ModTap key resolves to when another
key is pressed before the timeout finishes. When `True` the hold keycode is
chosen, the tap keycode when `False`.
* `tap_interrupted`: decides if the timeout will interrupt at the first other
key press/down, or after the first other key up/release. Set to `True` for
interrupt on release.
* `tap_time`: length of the tap timeout in milliseconds.
* `repeat`: decides how to interpret repeated presses if they happen within
`tap_time` after a release.
* `TAP`: repeat tap action, if previous action was a tap.
* `HOLD`: repeat hold action, if previous action was a hold.
* `ALL`: repeat all of the above.
* `NONE`: no repeat action (default), everything works as expected.
The `HoldTapRepeat` enum must be imported from `kmk.modules.holdtap`.
Each of these parameters can be set for every ModTap key individually.

34
docs/en/modules.md Normal file
View File

@@ -0,0 +1,34 @@
# Modules
Modules, unlike extensions, change how your keyboard works. These are meant to have
the ability to alter the core code in any way. Unlike extensions, these are not in a
sandbox, and can make massive changes to normal operation.
## Core Modules
These modules are provided in all builds and can be enabled. Currently offered
modules are
- [Combos](combos.md): Adds chords and sequences
- [Layers](layers.md): Adds layer support (Fn key) to allow many more keys to be
put on your keyboard.
- [ModTap](modtap.md): Adds support for augmented modifier keys to act as one key
when tapped, and modifier when held.
- [Mouse keys](mouse_keys.md): Adds mouse keycodes.
- [OneShot](oneshot.md): Adds support for oneshot/sticky keys.
- [Power](power.md): Power saving features. This is mostly useful when on battery power.
- [Split](split_keyboards.md): Keyboards split in two. Seems ergonomic!
- [SerialACE](serialace.md): [DANGER - _see module README_] Arbitrary Code Execution over the data serial.
- [TapDance](tapdance.md): Different key actions depending on how often it is pressed.
- [Dynamic Sequences](dynamic_sequences.md): Records a sequence of keypresses and plays it back.
### Require Libraries
These modules can be used without specific hardware, but require additional libraries such as the `Adafruit CircuitPython Bundle`.
- [MIDI](midi.md): Adds sending MIDI data in the form of keymap entries.
### Peripherals
These modules are for specific hardware and may require additional libraries to function.
- [ADNS9800](adns9800.md): Controlling ADNS9800 optical sensor.
- [Encoder](encoder.md): Handling rotary encoders.
- [Pimoroni trackball](pimoroni_trackball.md): Handling a small I2C trackball made by Pimoroni.
- [AS5013 aka EasyPoint](easypoint.md): Handling a small I2C magnetic position sensor made by AMS.

23
docs/en/mouse_keys.md Normal file
View File

@@ -0,0 +1,23 @@
# Mouse keys
To enable mouse cursor and/or mouse buttons control from the keyboard add this
module to list:
```python
from kmk.modules.mouse_keys import MouseKeys
keyboard.modules.append(MouseKeys())
```
# Keycodes
| Keycode | Description |
|---------------------------|--------------------------------------|
| `KC.MB_LMB` | Left mouse button |
| `KC.MB_RMB` | Right mouse button |
| `KC.MB_MMB` | Middle mouse button |
| `KC.MW_UP` | Mouse wheel up |
| `KC.MW_DOWN`, `KC.MW_DN` | Mouse wheel down |
| `KC.MS_UP` | Move mouse cursor up |
| `KC.MS_DOWN`, `KC.MS_DN` | Move mouse cursor down |
| `KC.MS_LEFT`, `KC.MS_LT` | Move mouse cursor left |
| `KC.MS_RIGHT`, `KC.MS_RT` | Move mouse cursor right |

104
docs/en/oneshot.md Normal file
View File

@@ -0,0 +1,104 @@
# OneShot Keycodes
OneShot keys or sticky keys enable you to have keys that keep staying pressed
for a certain time or until another key is pressed and released.
If the timeout expires or other keys are pressed, and the sticky key wasn't
released, it is handled as a regular key hold.
## Enable OneShot Keys
```python
from kmk.modules.oneshot import OneShot
oneshot = OneShot()
# optional: set a custom tap timeout in ms (default: 1000ms)
# oneshot.tap_time = 1500
keyboard.modules.append(oneshot)
```
## Keycodes
|Keycode | Aliases |Description |
|-----------------|--------------|----------------------------------|
|`KC.OS(KC.ANY)` | `KC.ONESHOT` |make a sticky version of `KC.ANY` |
`KC.ONESHOT` accepts any valid key code as argument, including modifiers and KMK
internal keys like momentary layer shifts.
## Custom OneShot Behavior
The full OneShot signature is as follows:
```python
KC.OS(
KC.TAP, # the sticky keycode
tap_time=None # length of the tap timeout in milliseconds
)
```
## OneShot Modifier Combinations
The OneShot module by default cannot apply two OneShot modifiers to another key. To get around this you can use the [Combos](combos.md) module. Below is a minimal example that allows for multiple OneShot modifiers to apply to the next key pressed. In this example you can tap either of the OneShot keys then tap the other and finally tap `p` and that will send `ctrl+shift+p`.
```python
from kmk.modules.combos import Chord, Combos
from kmk.modules.oneshot import OneShot
oneshot = OneShot()
keyboard.modules.append(oneshot)
OS_LCTL = KC.OS(KC.LCTL, tap_time=None)
OS_LSFT = KC.OS(KC.LSFT, tap_time=None)
combos = Combos()
keyboard.modules.append(combos)
combos.combos = [
Chord((OS_LCTL, OS_LSFT), OS_LCTL_LSFT, timeout=1000),
]
keyboard.keymap = [[OS_LSFT, OS_LCTL, KC.P]]
```
Below is the complete list of OneShot and Chords you need to allow any combination of modifiers (left modifiers only).
> <details>
> <summary>Long code chunk (click to load)</summary>
>
> ```python
> OS_LCTL = KC.OS(KC.LCTL, tap_time=None)
> OS_LSFT = KC.OS(KC.LSFT, tap_time=None)
> OS_LGUI = KC.OS(KC.LGUI, tap_time=None)
> OS_LALT = KC.OS(KC.LALT, tap_time=None)
>
> OS_LCTL_LSFT = KC.OS(KC.LCTL(OS_LSFT), tap_time=None)
> OS_LCTL_LALT = KC.OS(KC.LCTL(OS_LALT), tap_time=None)
> OS_LCTL_LGUI = KC.OS(KC.LCTL(OS_LGUI), tap_time=None)
> OS_LSFT_LALT = KC.OS(KC.LSFT(OS_LALT), tap_time=None)
> OS_LSFT_LGUI = KC.OS(KC.LSFT(OS_LGUI), tap_time=None)
> OS_LALT_LGUI = KC.OS(KC.LALT(OS_LGUI), tap_time=None)
>
> OS_LCTL_LSFT_LGUI = KC.OS(KC.LCTL(KC.LSFT(OS_LGUI)), tap_time=None)
> OS_LCTL_LSFT_LALT = KC.OS(KC.LCTL(KC.LSFT(OS_LALT)), tap_time=None)
> OS_LCTL_LALT_LGUI = KC.OS(KC.LCTL(KC.LALT(OS_LGUI)), tap_time=None)
> OS_LSFT_LALT_LGUI = KC.OS(KC.LSFT(KC.LALT(OS_LGUI)), tap_time=None)
>
> OS_LCTL_LSFT_LALT_LGUI = KC.OS(KC.LCTL(KC.LSFT(KC.LALT(OS_LGUI))), tap_time=None)
>
> combos.combos = [
> Chord((OS_LCTL, OS_LSFT), OS_LCTL_LSFT, timeout=1000),
> Chord((OS_LCTL, OS_LALT), OS_LCTL_LALT, timeout=1000),
> Chord((OS_LCTL, OS_LGUI), OS_LCTL_LGUI, timeout=1000),
> Chord((OS_LSFT, OS_LALT), OS_LSFT_LALT, timeout=1000),
> Chord((OS_LSFT, OS_LGUI), OS_LSFT_LGUI, timeout=1000),
> Chord((OS_LALT, OS_LGUI), OS_LALT_LGUI, timeout=1000),
>
> Chord((OS_LCTL, OS_LSFT, OS_LGUI), OS_LCTL_LSFT_LGUI, timeout=1000),
> Chord((OS_LCTL, OS_LSFT, OS_LALT), OS_LCTL_LSFT_LALT, timeout=1000),
> Chord((OS_LCTL, OS_LALT, OS_LGUI), OS_LCTL_LALT_LGUI, timeout=1000),
> Chord((OS_LSFT, OS_LALT, OS_LGUI), OS_LSFT_LALT_LGUI, timeout=1000),
>
> Chord((OS_LCTL, OS_LSFT, OS_LALT, OS_LGUI), OS_LCTL_LSFT_LALT_LGUI, timeout=1000),
> ]
> ```
>
> </details>

109
docs/en/peg_oled_display.md Normal file
View File

@@ -0,0 +1,109 @@
# Peg Oled Display
To use this you need to make some changes to your kb.py as well as you main.py I will break it into two sections for you.
### What you can and cant do
#### Can do
* Display images
* Display text
* Set images or text to react to your layer
#### Cant do yet / on the way
* React to battery percentage
* React to WPM
## Required Libs
You need these frozen into your circuitpython or in a lib folder at the root of your drive.
* [Adafruit_CircuitPython_DisplayIO_SSD1306](https://github.com/adafruit/Adafruit_CircuitPython_DisplayIO_SSD1306)
* [Adafruit_CircuitPython_Display_Text](https://github.com/adafruit/Adafruit_CircuitPython_Display_Text)
* [Download .mpy versions from here](https://github.com/adafruit/Adafruit_CircuitPython_Bundle/releases/download/20220415/adafruit-circuitpython-bundle-7.x-mpy-20220415.zip)
## kb.py
Your chosen board may already have these changes done If not you will need to add them.
You need to add SCL and SDA to your keyboard. The pins the oled are connected to on your controller may not be called "SCL"and "SDA" they could be "GP21" and "GP13" for example. The best way to find out what they are is look at the boards pinout.
```python
SCL=board.SCL
SDA=board.SDA
```
## Main.py
These are the changes that need to be made / added to your main.py
### Config
No mater how you are going to use the oled you need this part
```python
from kmk.extensions.peg_oled_Display import Oled,OledDisplayMode,OledReactionType,OledData
keyboard = KMKKeyboard()
# ... Other oled code
keyboard.extensions.append(oled_ext)
```
### Photos
So the config for photos is quite simple. Getting the photos maybe not so much. I will explain.
Oled takes 2-3 arguments
1. OledData
* OledData can take image **or** corner_one, corner_two, corner_three and corner_four
* Every item in OledData has 2 fields
* 0: This is the reaction type right now it can be OledReactionType.LAYER or OledReactionType.STATIC
* 1: An array of the items you want to show for the reaction. In this example 4 images to switch on the 4 layers
2. To display called as "toDisplay=OledDisplayMode.TXT" this takes a OledDisplayMode TXT or IMG.
* This tells the extension to load images or text.
3. Flip called as "flip= Boolean" this will simply flip your display.
```python
oled_ext = Oled(OledData(image={0:OledReactionType.LAYER,1:["1.bmp","2.bmp","1.bmp","2.bmp"]}),toDisplay=OledDisplayMode.IMG,flip=False)
```
In this code example we are saying to react to the layer change and load a image filed named "1.bmp" for layer one and "2.bmp" for layer two and so on.
### Preparing the images
So you need to include all the images in your circuitpython drive in the root along side main.py
Your images need to be 128x32px and should only be black and white. After you have made your image you can save as a "monochrome bmp" this will save you a lot of space.
### Text
Ok now we get into something that looks a lot more complicated but we will get though it.
Almost everything is the same We swap toDisplay to TXT and there are more items in the OledData Class, lets get into that.
1. Top left
2. Top right
3. Bottom left
4. Bottom right
After that is the same as the previous example. Each one has two fields 0:the reaction type. 1:what to display
In this code we will always display the word "layer" in the top left corner of the screen then the other 3 corners will swap depending on the layer.
```python
oled_ext = Oled(
OledData(
corner_one={0:OledReactionType.STATIC,1:["layer"]},
corner_two={0:OledReactionType.LAYER,1:["1","2","3","4"]},
corner_three={0:OledReactionType.LAYER,1:["base","raise","lower","adjust"]},
corner_four={0:OledReactionType.LAYER,1:["qwerty","nums","shifted","leds"]}
),
toDisplay=OledDisplayMode.TXT,flip=False)
```
### Note
Your oled data can be a variable as shown below with images.
```python
oled_display_data=OledData(image={0:OledReactionType.LAYER,1:["1.bmp","2.bmp","1.bmp","2.bmp"]})
oled_ext = Oled(oled_display_data,toDisplay=OledDisplayMode.IMG,flip=False)
```
### Text example
![example](https://boardsource.imgix.net/a4f155e0-bc83-11ec-a4ed-79d542ba3127.gif)

203
docs/en/peg_rgb_matrix.md Normal file
View File

@@ -0,0 +1,203 @@
# Peg RGB Matrix
## What you can and cannot do with this extension:
### Can Do
* Set any key's LED to be any color in a syntax very similar to your keymap
* Allows specific keys to be set to OFF
* Allows underglow LEDs to be a different color than per-key LEDs
* Allows modifier keys to be set to a different color than alpha keys
* Full split keyboard support
* Change brightness of LEDs from code or using keycodes
### Cannot Do (currently in progress)
* Adjust color at runtime. Currently the extension requires changes to main.py in order to make changes to your LEDs.
* Animations
* Change LED color based on current layer
## Keycodes
Currently this extension does not support changing LEDs at runtime, as a result there are only three keycodes available to interact with this extension,those are:
* `KC.RGB_TOG`. This keycode simply toggles all your LEDs on and off.
* `KC.RGB_BRI`. This keycode increases the brightness of the LEDs.
* `KC.RGB_BRD`. This keycode decreases the brightness of the LEDs.
## Required Libraries
The following libraries must be frozen in your CircuitPython distribution or in a 'lib' folder at the root of your drive.
* [Adafruit_CircuitPython_NeoPixel](https://github.com/adafruit/Adafruit_CircuitPython_NeoPixel)
* [Download .mpy versions from here](https://github.com/adafruit/Adafruit_CircuitPython_Bundle/releases/download/20220415/adafruit-circuitpython-bundle-7.x-mpy-20220415.zip)
## Required Changes to main.py and kb.py
In order to use this extension the user must make changes to both their kb.py and main.py files. Below you will find a more comprehensive list of changes required in order to use this extension.
### kb.py
It is possible your chosen board may already have these changes made, if not you will need to make these additions:
The board's kb.py needs 3 fields:
* LED Key Position `led_key_pos`
* Much like `coord_mapping` this tells the extension where the LEDs are on your board.
* Brightness Limit `brightness_limit`
* Limits your brightness and may be required in order to stabilize performance.
* Number of LEDs `num_pixels`
* Used for calculations in order to ensure the LEDs map to the correct keys.
#### Non-split Example:
Below shows a simple non-split example for a board containing 48 LEDs total and 38 keys with per-key LEDs.
This means we will have 10 underglow LEDs and 38 per-key LEDs.
For our example we will assume (because it is most common) the underglow LEDs are connected before the per-key LEDs.
Starting from 0, indexes 0-9 are all underglow, so our `led_key_pos` array starts at 10, the `led_key_pos` array always starts with the key in the upper left position on the board.
Our example is wired in such a way where the positions layout naturally and each row simply increases by 1 starting at the upper left of the board.
Of course if your board's LEDs are layed out different, your `led_key_pos` will need to match that layout.
Underglow LEDs always appear at the end of the `led_key_pos` array, because the array always starts with per-key LEDs.
```python
led_key_pos=[
10,11,12,13,14,15,16,17,18,19,
20,21,22,23,24,25,26,27,28,29,
30,31,32,33,34,35,36,37,38,39,
40,41,42,43,44,45,46,47,
5, 6, 7, 8, 9,
0, 1, 2, 3, 4
]
brightness_limit = 1.0
num_pixels = 48
```
#### Split Example:
Below shows a 58 key split keyboard's `led_key_pos` array for a board containing 70 LEDs in total.
The board has 58 keys, meaning we are left with 12 underglow LEDs total.
Since the board is a split and we can assume the LEDs are mirrored, that means each half has 29 per-key LEDs and 6 underglow LEDs.
Let's first focus on the left half of the board.
In this example the underglow LEDs are again connected first, and this half has 6 underglow LEDs.
Starting from position 0 this means 0-5 are underglow LEDs and our per-key lighting starts at 6.
Our example board is wired in such a way where the left half's first per-key LED is position in the upper right corner of that half.
The LEDs then incremement towards the right and follow a 'zig-zag' pattern until all are accounted for (6-34).
Examining the other half (the right side) you'll notice the LEDs are connected in a similar way but mirrored.
The right half's LEDs start in the upper left position of the board and increment towards the right, and then follow a 'zig-zag' pattern until all are accounted for (41-69).
Underglow LEDs always appear at the end of the `led_key_pos` array, because the array always starts with per-key LEDs.
```python
led_key_pos =[
11,10,9 ,8 ,7 ,6 , 41,42,43,44,45,46,
12,13,14,15,16,17, 52,51,50,49,48,47,
23,22,21,20,19,18, 53,54,55,56,57,58,
24,25,26,27,28,29,30, 65,64,63,62,61,60,59,
34,33,32,31, 66,67,68,69,
3 ,4 ,5 , 40,39,38,
2 ,1 ,0 , 35,36,37
]
brightness_limit = 1.0
num_pixels = 70
```
### main.py
It is possible your chosen board may already have these changes made, if not you will need to make these additions:
```python
from kmk.extensions.peg_rgb_matrix import Rgb_matrix,Rgb_matrix_data,Color
# ... Other code
rgb_ext = Rgb_matrix(...per key color data)
keyboard.extensions.append(rgb_ext)
```
Rgb_matrix extension requires one argument (`Rgb_matrix_data`), although additional arguments can be passed, here are all arguments that can be passed to
Rgb_matrix:
* LED Display `ledDisplay`
* This is our primary and only required field, this takes a `Rgb_matrix_data` class.
* Rgb_matrix_data only takes two fields:
* Keys: an array of colors with a length equal to the number of keys on your keyboard
* Underglow: an array of colors with a length equal to the number of underglow leds on your keyboard
* Split `split`
* This is an optional boolean and only to be used if the keyboard is a split.
* Right Side `rightSide`
* This is optional boolean only to be used if the keyboard is split. This signals that this configuration is targetting the right side (off side).
* RGB Order `rgb_order`
* This is optional and only needs to be set if you are not using a WS2812 based LED.
* Disable Auto Write `disable_auto_write`
* This is optional and only serves to make all your LEDs turn on at once instead of animate to their on state.
### Colors
Colors are RGB and can be provided in one of two ways.
Colors can be defined as an array of three numbers (0-255) or you can use the `Color` class with its default colors, see example below.
#### Passing RGB Codes
```python
Rgb_matrix_data(
keys=[[255,55,55],[55,55,55],[55,55,55],[55,55,55],[55,55,55],[55,55,55],"""... rest of colors""" ],
underglow=[[0,0,55],[0,0,55],"""... rest of colors""" ]
)
```
#### Using `Color` Class
```python
Rgb_matrix_data(
keys=[Color.RED, Color.GREEN, Color.BLUE, Color.WHITE, Color.YELLOW, Color.ORANGE,"""... rest of colors""" ],
underglow=[Color.PURPLE, Color.TEAL, Color.PINK, Color.OFF,"""... rest of colors""" ]
)
```
### Full Examples
```python
rgb_ext = Rgb_matrix(ledDisplay=Rgb_matrix_data(
keys=[
[255,55,55],[55,55,55],[55,55,55],[55,55,55],[55,55,55],[55,55,55], [55,55,55],[55,55,55],[55,55,55],[55,55,55],[55,55,55],[255,55,55],
[255,55,55],[55,55,55],[55,55,55],[55,55,55],[55,55,55],[55,55,55], [55,55,55],[55,55,55],[55,55,55],[55,55,55],[55,55,55],[255,55,55],
[255,55,55],[55,55,55],[55,55,55],[55,55,55],[55,55,55],[55,55,55], [55,55,55],[55,55,55],[55,55,55],[55,55,55],[55,55,55],[255,55,55],
[255,55,55],[55,55,55],[55,55,55],[55,55,55],[55,55,55],[55,55,55],[255,55,55],[255,55,55],[55,55,55],[55,55,55],[55,55,55],[55,55,55],[55,55,55],[255,55,55],
[255,55,55],[55,55,55],[55,55,55],[255,55,55],[255,55,55],[55,55,55],[55,55,55],[255,55,55]],
underglow=[
[0,0,55],[0,0,55],[0,0,55],[0,0,55],[0,0,55],[0,0,55],[0,0,55],[0,0,55],[0,0,55],[0,0,55],[0,0,55],[0,0,55]]
),
split=True,
rightSide=True,
disable_auto_write=True)
```
#### Bonus
Because creating `ledDisplay` can be time consuming, there is a utility avaiable that will generate a basic framework for you.
```python
Rgb_matrix_data.generate_led_map(58,10,Color.WHITE,Color.BLUE)
```
Call `Rgb_matrix_data.generate_led_map` before you do any configuration beyond imports and it will print an `Rgb_matrix_data` class to your CircuitPython REPL which you can view by using a tool like "screen" or "PUTTY".
Generate LED Map Arguments:
* Number of Keys
* Number of Underglow
* Key Color
* Underglow Color
Example Using Above Arguments:
```python
Rgb_matrix_data(keys=[[249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249], [249, 249, 249]],
underglow=[[0, 0, 255], [0, 0, 255], [0, 0, 255], [0, 0, 255], [0, 0, 255], [0, 0, 255], [0, 0, 255], [0, 0, 255], [0, 0, 255], [0, 0, 255]])
```
[Connecting to the Serial Console](https://learn.adafruit.com/welcome-to-circuitpython/kattni-connecting-to-the-serial-console)

View File

@@ -0,0 +1,61 @@
# Pimoroni Trackball
Module handles usage of Trackball Breakout by Pimoroni.
Product page: https://shop.pimoroni.com/products/trackball-breakout
### Usage
Declare I2C bus and add this module in your main class.
```python
from kmk.modules.pimoroni_trackball import Trackball, TrackballMode
import busio as io
i2c = io.I2C(scl=board.D3, sda=board.D2)
trackball = Trackball(i2c)
keyboard.modules.append(trackball)
```
Module will also work when you cannot use `busio` and do `import bitbangio as io` instead.
### Key inputs, other handler combinations
If you have used this thing on a mobile device, you will know it excels at cursor movement
```python
from kmk.modules.pimoroni_trackball import Trackball, TrackballMode, PointingHandler, KeyHandler, ScrollHandler, ScrollDirection
trackball = Trackball(i2c, mode=TrackballMode.MOUSE_MODE, handlers=[
# act like an encoder, input arrow keys
KeyHandler(KC.UP, KC.RIGHT, KC.DOWN, KC.LEFT, KC.ENTER),
# on layer 1 and above use the default pointing behavior
PointingHandler(),
# use ScrollDirection.NATURAL (default) or REVERSE to change the scrolling direction
ScrollHandler(scroll_direction=ScrollDirection.NATURAL)
])
# now you can use these KeyCodes:
KC.TB_NEXT_HANDLER # rotates through available
KC.TB_HANDLER(0) # activate KeyHandler
KC.TB_HANDLER(1) # activate MouseHandler
```
### Backlight
Setup backlight color using below commands:
```python
trackball.set_rgbw(r, g, b, w)
trackball.set_red(brightness)
trackball.set_green(brightness)
trackball.set_blue(brightness)
trackball.set_white(brightness)
```
This module exposes one keycode `TB_MODE`, which on hold switches between `MOUSE_MODE` and `SCROLL_MODE`.
To choose the default mode, pass it in `Trackball` constructor.

BIN
docs/en/pins56.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 222 KiB

129
docs/en/porting_to_kmk.md Normal file
View File

@@ -0,0 +1,129 @@
# Porting to KMK
Porting a board to KMK is quite simple, and follows this base format.
```python
import board
from kmk.kmk_keyboard import KMKKeyboard as _KMKKeyboard
from kmk.scanners import DiodeOrientation
{EXTENSIONS_IMPORT}
class KMKKeyboard(_KMKKeyboard):
{REQUIRED}
extensions = []
```
## REQUIRED
This is designed to be replaced with the defining pins of your keyboard. Rows,
columns and the diode direction (if any), should be defined like this
```python
row_pins = [board.p0_31, board.p0_29, board.p0_02, board.p1_15]
col_pins = [board.p0_22, board.p0_24, board.p1_00, board.p0_11, board.p1_04]
diode_orientation = DiodeOrientation.COL2ROW
```
## Additional pins for extensions
KMK includes built in extensions for RGB and split keyboards, and powersave. If
these are applicable on your keyboard/microcontroller, the pins should be added
here. Refer to the instructions on the respective extensions page on how to add
them. If not adding any extensions, leave this as an empty list as shown.
# Coord mapping
If your keyboard is not built electrically as a square (though most are), you can
provide a mapping directly. An example of this is the
[Corne](https://github.com/foostan/crkbd). That has 12 columns for 3 rows, and 6
columns for the bottom row. Split keyboards count as the total keyboard, not per
side, the right side being offset by the number of keys on the left side, as if
the rows were stacked.
That would look like this
```python
from kmk.scanners import intify_coordinate as ic
coord_mapping = []
coord_mapping.extend(ic(0, x, 6) for x in range(6))
coord_mapping.extend(ic(4, x, 6) for x in range(6))
coord_mapping.extend(ic(1, x, 6) for x in range(6))
coord_mapping.extend(ic(5, x, 6) for x in range(6))
coord_mapping.extend(ic(2, x, 6) for x in range(6))
coord_mapping.extend(ic(6, x, 6) for x in range(6))
# And now, to handle R3, which at this point is down to just six keys
coord_mapping.extend(ic(3, x, 6) for x in range(3, 6))
coord_mapping.extend(ic(7, x, 6) for x in range(0, 3))
```
`intify_coordinate` is the traditional way to generate key positions.
Here's an equivalent, maybe visually more explanatory version:
```python
coord_mapping = [
0, 1, 2, 3, 4, 5, 24, 25, 26, 27, 28, 29,
6, 7, 8, 9, 10, 11, 30, 31, 32, 33, 34, 35,
12, 13, 14, 15, 16, 17, 36, 37, 38, 39, 40, 41,
21, 22, 23, 42, 43, 44,
]
```
Note: Not all numbers are necessarily used ! The keyboard assumes
`number of line * number of rows` keys. Some of the possible keys might not be
used. For example a keyboard with 60 keys might have 8 rows, 8 cols, allowing
64 total combinations -- hence 64 keys. 4 numbers will then not be used for keys
in the `coord_mapping` (might be anyone of them depending of the wiring).
### Find your coord mapping
The following code will help you setup your `coord_mapping` by having every key
send its corresponding number. Use it after your pins and module definition
to define both `keyboard.coord_mapping` and `keyboard.keymap`.
```python
from kmk.handlers.sequences import simple_key_sequence
from kmk.keys import KC
# *2 for split keyboards, which will typically manage twice the number of keys
# of one side. Having this N too large will have no impact (maybe slower boot..)
N = len(keyboard.col_pins) * len(keyboard.row_pins) * 2
keyboard.coord_mapping = list(range(N))
layer = []
for i in range(N):
c, r = divmod(i, 100)
d, u = divmod(r, 10)
layer.append(
simple_key_sequence(
(
getattr(KC, 'N' + str(c)),
getattr(KC, 'N' + str(d)),
getattr(KC, 'N' + str(u)),
KC.SPC,
)
)
)
keyboard.keymap = [layer]
if __name__ == '__main__':
keyboard.go()
```
## Keymaps
Keymaps are organized as a list of lists. Keycodes are added for every key on
each layer. See [keycodes](keycodes.md) for more details on what keycodes are
available. If using layers or other extensions, also refer to the extensions
page for additional keycodes.
```python
from kb import KMKKeyboard
from kmk.keys import KC
keyboard = KMKKeyboard()
keyboard.keymap = [
[KC.A, KC.B],
[KC.C, KC.D],
]
if __name__ == '__main__':
keyboard.go()
```
## More information
More information on keymaps can be found [here](config_and_keymap.md)

42
docs/en/power.md Normal file
View File

@@ -0,0 +1,42 @@
# Power(save)
This module allows you to save power and is targeted to Bluetooth/battery
based keyboards.
## Keycodes
|Key |Description |
|-----------------------|-------------------------|
|`KC.PS_TOG ` |Toggles powersave on/off |
|`KC.PS_ON ` |Turns powersave on |
|`KC.PS_OFF ` |Turns powersave off |
# Enabling the extension
To turn on basic power saving, this is all that is required.
```python
from kmk.modules.power import Power
power = Power()
keyboard.modules.append(power)
```
## Optional extra power saving
On supported boards, such as the nice!nano, power can be cut on VCC saving extra
power if OLEDS or RGBs are installed. These drain power even when off, so this
will prevent them from doing so.
```python
from kmk.modules.power import Power
# Your kb.py may already have this set. If not, add it like this
# import board
# keyboard.powersave_pin = board.P0_13
power = Power(powersave_pin=keyboard.powersave_pin)
keyboard.modules.append(power)
```
Make sure that the pin is correct for your microcontroller. The example is for
the nice!nano. Not all microcontrollers have this feature and this can be omitted
if not and there will simply be less power saving.

50
docs/en/rapidfire.md Normal file
View File

@@ -0,0 +1,50 @@
# RapidFire
The RapidFire module lets a user send repeated key taps while a key is held.
Some instances where this may be useful are:
- MMOs and other games where you are encouraged to repeatedly spam a key
- More responsive volume up and volume down
- Faster cursor key navigation
- Combine with the [Mouse Keys](https://github.com/KMKfw/kmk_firmware/blob/master/docs/mouse_keys.md) module to create rapid-fire mouse clicks
- Anywhere else you may need an ergonomic alternative to repetitive key tapping
## Keycodes
| Key | Description |
| :---------- | :--------------------------------------------------- |
| `KC.RF(kc)` | Repeatedly sends the specified keycode while pressed |
## Usage
Each repeat counts as one full cycle of pressing and releasing. RapidFire works with chording (i.e., holding Shift plus a RapidFire key will repeatedly send the shifted version of that RapidFire key) and chaining (i.e., `KC.RF(KC.LSHIFT(KC.A))`. Multiple RapidFire keys can be held down at the same time, and their timers work independently of each other.
The RapidFire keycode has a few different options:
| Option | Default Value | Description |
| :-----------------------------: | :-----------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `interval` | `100` | The time between key taps sent in milliseconds. Note: `10` appears to be the minimum effective value. |
| `timeout` | `200` | The amount of time in milliseconds the key must be held down before RapidFire activates. Useful if you want to be able to type with keys that have a low `interval` value. A value of `0` will result in no waiting period. |
| `enable_interval_randomization` | `False` | Enable randomizing the value of `interval`. Useful for making the repetitive input look human in instances where you may be flagged as a bot otherwise. |
| `randomization_magnitude` | `15` | If `enable_interval_randomization` is `True`, the time between key taps sent will be `interval` plus or minus a random value up to this amount. |
| `toggle` | `False` | If set to `True`, activating RapidFire will toggle it on or off. Useful if you don't want to have to keep the button held. Set `timeout` to `0` if you would like to toggle on tap. |
### Example Code
```python
from kmk.modules.rapidfire import RapidFire
keyboard.modules.append(RapidFire())
# After 200 milliseconds, repeatedly send Shift+A every 75-125 milliseconds while the button is held
SPAM_A = KC.RF(KC.LSFT(KC.A), timeout=200, interval=100, enable_interval_randomization=True, randomization_magnitude=25)
# Immediately toggle repeatedly sending Enter every 50 milliseconds on tap
SPAM_ENTER = KC.RF(KC.ENT, toggle=True, timeout=0, interval=50)
keyboard.keymap = [[
SPAM_A, SPAM_ENTER
]]
```

187
docs/en/rgb.md Normal file
View File

@@ -0,0 +1,187 @@
# RGB/Underglow/NeoPixel
Want your keyboard to shine? Add some lights!
## CircuitPython
This does require the [NeoPixel library from Adafruit](https://github.com/adafruit/Adafruit_CircuitPython_NeoPixel/blob/main/neopixel.py).
It is part of the [Adafruit CircuitPython Bundle](https://github.com/adafruit/Adafruit_CircuitPython_Bundle).
Simply put this in the "root" of your CircuitPython device. If unsure, it's the folder with `main.py` in it, and should be the first folder you see when you open the device.
Currently we support the following addressable LEDs:
* WS2811, WS2812, WS2812B, WS2812C, etc.
* SK6812, SK6812MINI, SK6805
### Color Selection
KMK uses [Hue, Saturation, and Value](https://en.wikipedia.org/wiki/HSL_and_HSV) to select colors rather than RGB. The color wheel below demonstrates how this works.
Changing the **Hue** cycles around the circle.
Changing the **Saturation** moves between the inner and outer sections of the wheel, affecting the intensity of the color.
Changing the **Value** sets the overall brightness.
## Enabling the extension
The only required values that you need to give the RGB extension would be the board pin for the data line, and the number of pixels/LED's. If using a split keyboard, this number is per side, and not the total of both sides.
```python
import board
from kmk.extensions.RGB import RGB
rgb = RGB(pixel_pin=board.GP14, num_pixels=27)
keyboard.extensions.append(rgb)
```
## [Keycodes]
|Key |Aliases |Description |
|-----------------------------|-------------------|----------------------------|
|`KC.RGB_TOG` | |Toggles RGB |
|`KC.RGB_HUI` | |Increase Hue |
|`KC.RGB_HUD` | |Decrease Hue |
|`KC.RGB_SAI` | |Increase Saturation |
|`KC.RGB_SAD` | |Decrease Saturation |
|`KC.RGB_VAI` | |Increase Value |
|`KC.RGB_VAD` | |Decrease Value |
|`KC.RGB_ANI` | |Increase animation speed |
|`KC.RGB_AND` | |Decrease animation speed |
|`KC.RGB_MODE_PLAIN` |`RGB_M_P` |Static RGB |
|`KC.RGB_MODE_BREATHE` |`RGB_M_B` |Breathing animation |
|`KC.RGB_MODE_RAINBOW` |`RGB_M_R` |Rainbow animation |
|`KC.RGB_MODE_BREATHE_RAINBOW`|`RGB_M_BR` |Breathing rainbow animation |
|`KC.RGB_MODE_KNIGHT` |`RGB_M_K` |Knight Rider animation |
|`KC.RGB_MODE_SWIRL` |`RGB_M_S` |Swirl animation |
## Configuration
|Define |Default |Description |
|-------------------------------------|-------------|-----------------------------------------------------------------------------|
|`rgb.num_pixels`| |The number of LEDs connected |
|`rgb.rgb_order` |`(1, 0, 2)` |The order of the pixels R G B, and optionally white. Example(1, 0, 2, 3) |
|`rgb.hue_step` |`10` |The number of steps to cycle through the hue by |
|`rgb.sat_step` |`17` |The number of steps to change the saturation by |
|`rgb.val_step` |`17` |The number of steps to change the brightness by |
|`rgb.hue_default` |`0` |The default hue when the keyboard boots |
|`rgb.sat_default` |`255` |The default saturation when the keyboard boots |
|`rgb.val_default` |`255` |The default value (brightness) when the keyboard boots |
|`rgb.val_limit` |`255` |The maximum brightness level |
## Built-in Animation Configuration
|Define |Default |Description |
|----------------------------------------------|-------------|-------------------------------------------------------------------------------------|
|`rgb.breathe_center` |`1.5` |Used to calculate the curve for the breathing animation. Anywhere from 1.0 - 2.7 is valid|
|`rgb.knight_effect_length` |`4` |The number of LEDs to light up for the "Knight" animation |
## Functions
If you want to create your own animations, or for example, change the lighting in a macro, or a layer switch, here are some functions that are available.
|Function |Description |
|--------------------------------------------------|--------------------------------------------------------------------------------------------|
|`rgb.set_hsv_fill(hue, sat, val)` |Fills all LED's with HSV values |
|`rgb.set_hsv(hue, sat, val, index)` |Sets a single LED with HSV value |
|`rgb.set_rgb_fill((r, g, b))` |Fills all LED's with RGB(W) values |
|`rgb.set_rgb((r, g, b), index)` |Set's a single LED with RGB(W) values |
|`rgb.disable_auto_write(bool)` |When True, disables showing changes. Good for setting multiple LED's before a visible update|
|`rgb.increase_hue(step)` |Increases hue by a given step |
|`rgb.decrease_hue(step)` |Decreases hue by a given step |
|`rgb.increase_sat(step)` |Increases saturation by a given step |
|`rgb.decrease_sat(step)` |Decreases saturation by a given step |
|`rgb.increase_val(step)` |Increases value (brightness) by a given step |
|`rgb.decrease_val(step)` |Decreases value (brightness) by a given step |
|`rgb.increase_ani()` |Increases animation speed by 1. Maximum 10 |
|`rgb.decrease_ani()` |Decreases animation speed by 1. Minimum 10 |
|`rgb.off()` |Turns all LED's off |
|`rgb.show()` |Displays all stored configuration for LED's. Useful with disable_auto_write explained above |
## Direct variable access
|Define |Default |Description |
|-----------------------------------|-----------|-----------------------------------------------------------------------------------------------------------|
|`rgb.hue` |`0` |Sets the hue from 0-255 |
|`rgb.sat` |`255` |Sets the saturation from 0-255 |
|`rgb.val` |`255` |Sets the brightness from 0-255 |
|`rgb.reverse_animation`|`False` |If true, some animations will run in reverse. Can be safely used in user animations |
|`rgb.animation_mode` |`static` |This can be changed to any modes included, or to something custom for user animations. Any string is valid |
|`rgb.animation_speed` |`1` |Increases animation speed of most animations. Recommended 1-5, Maximum 10. |
```python
from kmk.extensions.rgb import AnimationModes
rgb = RGB(pixel_pin=rgb_pixel_pin,
num_pixels=27
val_limit=100,
hue_default=0,
sat_default=100,
rgb_order=(1, 0, 2), # GRB WS2812
val_default=100,
hue_step=5,
sat_step=5,
val_step=5,
animation_speed=1,
breathe_center=1, # 1.0-2.7
knight_effect_length=3,
animation_mode=AnimationModes.STATIC,
reverse_animation=False,
refresh_rate=60,
)
```
## Hardware Modification
To add RGB LED's to boards that don't support them directly, you will have to
add a 3 wires. The power wire will run on 3.3v or 5v (depending on the LED),
ground, and data pins will need added to an unused pin on your microcontroller
unless your keyboard has specific solder points for them. With those 3 wires
connected, set the `pixel_pin` as described above, and you are ready to use your
RGB LED's/NeoPixel.
## Troubleshooting
### Incorrect colors
If your colors are incorrect, check the pixel order of your specific LED's. Here are some common ones.
* WS2811, WS2812, WS2812B, WS2812C are all GRB (1, 0, 2)
* SK6812, SK6812MINI, SK6805 are all GRB (1, 0, 2)
* NeoPixels will vary depending on which one you buy. It will be listed on the product page.
### Lights don't turn on
Make sure that your board supports LED backlight by checking for a line with
`PIXEL_PIN`. If it does not, you can add it to your keymap. If you added the
LED's yourself, you will also need to set `num_pixels` to the number of
installed LED's in total.
## Alternate LED chipsets
Not all RGB LEDs are compatible with NeoPixels. To support these, the RGB
extension accepts an instance of a `Pixelbuf`-compatible object as an optional
parameter. If supplied, `pixel_pin` is ignored and the supplied Pixelbuf is
used instead of creating a NeoPixel object.
The RGB extension will figure out LED count from the pixelbuffer length if not
passed explicitly.
This works easily with APA102 ("DotStar") LEDs, but for most other RGB LED
chipsets you will need to provide a wrapper to match the expected interface.
A simple example using APA102:
```python
import adafruit_dotstar
from kmk.extensions.RGB import RGB
from kb import rgb_pixel_pin # This can be imported or defined manually
_LED_COUNT=12
pixels = adafruit_dotstar.DotStar(board.SCK, board.MOSI, _LED_COUNT)
rgb = RGB(pixel_pin=None, pixels=pixels)
keyboard.extensions.append(rgb)
```
### Multiple PixelBuffer
Similar to alternate drivers, the RGB module supports passing multiple `Pixelbuf`
objects as an iterable.
```python
from kmk.extensions.RGB import RGB
pixels = (
Neopixel(...),
DotStar(...),
CustomPixelBuf(...)
)
rgb = RGB(pixel_pin=None, pixels=pixels)
keyboard.extensions.append(rgb)
```

207
docs/en/scanners.md Normal file
View File

@@ -0,0 +1,207 @@
# Scanners
The default key scanner in KMK assumes a garden variety switch matrix, with
one diode per switch to prevent ghosting.
This doesn't cover all hardware designs though. With macro pads, for example, it
is very common to not have a matrix topology at all.
Boards like this aren't compatible with the default matrix scanner, so you will
need to swap it out with an alternative scanner.
## Keypad Scanners
The scanners in `kmk.scanners.keypad` wrap the `keypad` module that ships with
CircuitPython and support the same configuration and tuning options as their
upstream. You can find out more in the [CircuitPython
documentation](https://docs.circuitpython.org/en/latest/shared-bindings/keypad/index.html).
### keypad MatrixScanner
This is the default scanner used by KMK.
It uses the CircuitPython builtin `keypad.KeyMatrix`.
```python
from kmk.scanners.keypad import MatrixScanner
class MyKeyboard(KMKKeyboard):
def __init__(self):
# create and register the scanner
self.matrix = MatrixScanner(
# required arguments:
column_pins=self.col_pins,
row_pins=self.row_pins,
# optional arguments with defaults:
columns_to_anodes=DiodeOrientation.COL2ROW,
interval=0.02,
max_events=64
)
```
### keypad KeysScanner
The `keypad.Keys` scanner treats individual GPIO pins as discrete keys. To use
this scanner, provide a sequence of pins that describes the layout of your
board then include it in the initialization sequence of your keyboard class.
```python
import board
from kmk.kmk_keyboard import KMKKeyboard
from kmk.scanners.keypad import KeysScanner
# GPIO to key mapping - each line is a new row.
_KEY_CFG = [
board.SW3, board.SW7, board.SW11, board.SW15,
board.SW2, board.SW6, board.SW10, board.SW14,
board.SW1, board.SW5, board.SW9, board.SW13,
board.SW0, board.SW4, board.SW8, board.SW12,
]
# Keyboard implementation class
class MyKeyboard(KMKKeyboard):
def __init__(self):
# create and register the scanner
self.matrix = KeysScanner(
# require argument:
pins=_KEY_CFG,
# optional arguments with defaults:
value_when_pressed=False,
pull=True,
interval=0.02,
max_events=64
)
```
### keypad ShiftRegisterKeys
This scanner can read keys attached to a parallel-in serial-out shift register
like the 74HC165 or CD4021. Note that you may chain shift registers to load in
as many values as you need.
```python
from kmk.scanners.keypad import ShiftRegisterKeys
class MyKeyboard(KMKKeyboard):
def __init__(self):
# create and register the scanner
self.matrix = ShiftRegisterKeys(
# require arguments:
clock=board.GP0,
data=board.GP1,
latch=board.GP2,
key_count=8,
# optional arguments with defaults:
value_to_latch=True, # 74HC165: True, CD4021: False
value_when_pressed=False,
interval=0.02,
max_events=64
)
```
## Digitalio Scanners
### digitalio MatrixScanner
The digitalio Matrix can scan over, as the name implies, `digitalio.DigitalInOut`
objects. That is especially useful if a matrix is build with IO-expanders.
```python
from kmk.scanners.digitalio import MatrixScanner
class MyKeyboard(KMKKeyboard):
def __init__(self):
# create and register the scanner
self.matrix = MatrixScanner(
cols=self.col_pins,
rows=self.row_pins,
diode_orientation=self.diode_orientation,
rollover_cols_every_rows=None, # optional
)
```
## Rotary Encoder Scanners
### RotaryioEncoder
Matrix events from a quadrature ("rotary") encoder?
```python
from kmk.scanners.encoder import RotaryioEncoder
class MyKeyboard(KMKKeyboard):
def __init__(self):
# create and register the scanner
self.matrix = RotaryioEncoder(
pin_a=board.GP0,
pin_b=board.GP1,
# optional
divisor=4,
)
```
## `Scanner` base class
If you require a different type of scanner, you can create your own by
providing a subclass of `Scanner`. This is a very simple interface, it only
contains a single method, `scan_for_changes(self)` which returns a key report
if one exists, or `None` otherwise.
## Advanced Configuration
### Multiple Scanners
Sometimes a single scanner doesn't cover all hardware configurations. For
example: The bulk of the keyboard may be scanned with a matrix scanner, but a
couple of additional keys are directly connected to GPIOs.
In that case KMK allows you to define multiple scanners. The `KMKKeyboard.matrix` attribute can either be assigned a single scanner, or a list of scanners.
KMK assumes that successive scanner keys are consecutive, and populates
`KMKKeyboard.coord_mapping` accordingly; for convenience you may have to supply a `coord_mapping` that resembles your physical layout more closely (expanded below).
Example:
```python
class MyKeyboard(KMKKeyboard):
self.matrix = [
MatrixScanner(...),
KeysScanner(...),
# etc...
]
```
#### Multiple Scanners coord_mapping and keymap changes
To add more scanners you need to add onto your `coord_mapping`.
Example:
`coord_mapping` with just one `MatrixScanner` on a 58 key split keyboard:
```python
coord_mapping = [
0, 1, 2, 3, 4, 5, 35, 34, 33, 32, 31, 30,
6, 7, 8, 9, 10, 11, 41, 40, 39, 38, 37, 36,
12, 13, 14, 15, 16, 17, 47, 46, 45, 44, 43, 42,
18, 19, 20, 21, 22, 23, 29, 59, 53, 52, 51, 50, 49, 48,
25, 26, 27, 28, 58, 57, 56, 55,
]
```
`coord_mapping` using `MatrixScanner` and `RotaryioEncoder` on the same 58 key split keyboard with an encoder on each half:
```python
coord_mapping = [
0, 1, 2, 3, 4, 5, 37, 36, 35, 34, 33, 32,
6, 7, 8, 9, 10, 11, 43, 42, 41, 40, 39, 38,
12, 13, 14, 15, 16, 17, 49, 48, 47, 46, 45, 44,
18, 19, 20, 21, 22, 23, 29, 61, 55, 54, 53, 52, 51, 50,
25, 26, 27, 28, 60, 59, 58, 57,
30, 31, 62, 63
]
```
On the top left side of a standard split keyboard `coord_mapping`, right below that you see a split keyboard where `RotaryioEncoder` and `MatrixScanner` (the default scanner) are used.
In the single scanner example, we used to count from 0 to 29 while the top right side starts at 30.
With the addition of the encoder scanner, the left side has 2 additional keys making it count up to 31 and the right side would then start at 32 and count to 63.
This means that keys 30, 31, 62, and 63 are for encoders.
Notice that all of the encoders are at the end of the array, because we put the encoder scanner after the matrix scanner in `keyboard.matrix`.
Therefore, we need to add 4 more key codes in the corresponding places of our `keyboard.keymap`, they will be used for the encoders.

185
docs/en/sequences.md Normal file
View File

@@ -0,0 +1,185 @@
# Sequences
Sequences are used for sending multiple keystrokes in a single action, and can
be used for things like Unicode characters (even emojis! 🇨🇦), _Lorem ipsum_
generators, triggering side effects (think lighting, speakers,
microcontroller-optimized cryptocurrency miners, whatever). If you are still
unsure of what this is, most other vendors call these "Macros", but can do much
more if you wish.
## Sending strings
The most basic sequence is `send_string`. It can be used to send any standard
English alphabet character, and an assortment of other "standard" keyboard keys
(return, space, exclamation points, etc.)
```python
from kmk.handlers.sequences import send_string
WOW = send_string("Wow, KMK is awesome!")
keyboard.keymap = [<other keycodes>, WOW, <other keycodes>]
```
## Key sequences
If you need to add modifier keys to your sequence, instead of `send_string` use
`simple_key_sequence`. While it's not as visually clean as `send_string`, you can
use it to add things like copying/pasting, tabbing between fields, etc.
```python
from kmk.handlers.sequences import simple_key_sequence
PASTE_WITH_COMMENTARY = simple_key_sequence(
(
KC.L,
KC.O,
KC.O,
KC.K,
KC.SPC,
KC.A,
KC.T,
KC.SPC,
KC.T,
KC.H,
KC.I,
KC.S,
KC.COLN,
KC.SPC,
KC.LCTL(KC.V),
)
)
keyboard.keymap = [<other keycodes>, PASTE_WITH_COMMENTARY, <other keycodes>]
```
The above example will type out "look at this: " and then paste the contents of your
clipboard.
### Sleeping within a sequence
If you need to wait during a sequence, you can use `KC.MACRO_SLEEP_MS(ms)` to wait a
length of time, in milliseconds.
```python
from kmk.handlers.sequences import simple_key_sequence
COUNTDOWN_TO_PASTE = simple_key_sequence(
(
KC.N3,
KC.ENTER,
KC.MACRO_SLEEP_MS(1000),
KC.N2,
KC.ENTER,
KC.MACRO_SLEEP_MS(1000),
KC.N1,
KC.ENTER,
KC.MACRO_SLEEP(1000),
KC.LCTL(KC.V),
)
)
keyboard.keymap = [<other keycodes>, COUNTDOWN_TO_PASTE, <other keycodes>]
```
from kmk.handlers.sequences import simple_key_sequence
NEXT = simple_key_sequence(
(
KC.LALT(no_release=True),
KC.MACRO_SLEEP_MS(30),
KC.TAB,
KC.MACRO_SLEEP_MS(30),
KC.LALT(no_press=True),
)
)
This example will type out the following, waiting one second (1000 ms) between numbers:
3
2
1
and then paste the contents of your clipboard.
### Alt Tab with delay
If alt tab isn't working because it requires a delay, adding a delay and triggering
down and up on ALT manually may fix the issue.
``` python
from kmk.handlers.sequences import simple_key_sequence
NEXT = simple_key_sequence(
(
KC.LALT(no_release=True),
KC.MACRO_SLEEP_MS(30),
KC.TAB,
KC.MACRO_SLEEP_MS(30),
KC.LALT(no_press=True),
)
)
```
## Unicode
Before trying to send Unicode sequences, make sure you set your `UnicodeMode`.
You can set an initial value in your keymap by setting `keyboard.unicode_mode`.
Keys are provided to change this mode at runtime - for example, `KC.UC_MODE_LINUX`.
### Unicode Modes:
On Linux, Unicode uses `Ctrl-Shift-U`, which is supported by `ibus` and GTK+3.
`ibus` users will need to add `IBUS_ENABLE_CTRL_SHIFT_U=1` to their environment
(`~/profile`, `~/.bashrc`, `~/.zshrc`, or through your desktop environment's
configurator).
On Windows, [WinCompose](https://github.com/samhocevar/wincompose) is required.
- Linux : `UnicodeMode.LINUX` or `UnicodeMode.IBUS`
- Mac: `UnicodeMode.MACOS` or `UnicodeMode.OSX` or `UnicodeMode.RALT`
- Windows: `UnicodeMode.WINC`
### Unicode Examples
To send a simple Unicode symbol
```python
from kmk.handlers.sequences import unicode_string_sequence
FLIP = unicode_string_sequence('(ノಠ痊ಠ)ノ彡┻━┻')
keyboard.keymap = [<other keycodes>, FLIP, <other keycodes>]
```
If you'd rather keep a lookup table of your sequences (perhaps to bind emojis to
keys), that's supported too, through an obnoxiously long-winded method:
```python
from kmk.handlers.sequences import compile_unicode_string_sequences as cuss
emoticons = cuss({
'BEER': r'🍺',
'HAND_WAVE': r'👋',
})
keymap = [<other keycodes>, emoticons.BEER, emoticons.HAND_WAVE, <other keycodes>]
```
> The observant will notice dot-notation is supported here despite feeding in a
> dictionary - the return of `compile_unicode_string_sequences` is a
> `kmk.types.AttrDict`, which you can think of as a read-only view over a
> dictionary adding attribute-based (dot-notation) access.
Finally, if you need to send arbitrary Unicode codepoints in raw form, that's
supported too, through `unicode_codepoint_sequence`.
```python
from kmk.handlers.sequences import unicode_codepoint_sequence
TABLE_FLIP = unicode_codepoint_sequence([
"28", "30ce", "ca0", "75ca","ca0", "29",
"30ce", "5f61", "253b", "2501", "253b",
])
keyboard.keymap = [<other keycodes>, TABLE_FLIP, <other keycodes>]
```

51
docs/en/serialace.md Normal file
View File

@@ -0,0 +1,51 @@
# Serial ACE (Arbitrary Code Execution over serial interface)
**Caution: This module allows unrestricted, arbitrary code execution on your KMK
device. That includes potential exploits, such as keyloggers, and unvetted
user code that may result in undesired behaviour and/or crashes.
This feature is purely experimental in the sense that you probably neither
want nor should use it in production.
Advanced knowledge of python and the serial console is required, and we will
not provide help or support in any way.**
This module provides an API to run any valid python code on your keyboard and
return the result of that code via an additional serial consol (not the one you
use for the circuitpython debugger).
## Prerequisite
Enable the data serial in `boot.py`:
```python
import usb_cdc
usb_cdc.enable(data=True)
```
## Example
Enable the module, just as any other module else:
```
from kmk.modules.serialace import SerialACE
keyboard.modules.append(SerialACE())
```
Assume the data serial is on `/dev/ttyACM1`.
Depending on your OS settings, it bay be necessary to explicitly set the serial
device to raw transmission, no echo:
```bash
stty -F /dev/ttyACM1 raw -echo
```
### Get the List of Active Layers
```bash
$ echo "keyboard.active_layers" > /dev/ttyACM1
$ cat /dev/ttyACM1
[0]
```
### "Tap" a Key
```bash
$ echo "exec('from kmk.keys import KC; keyboard.tap_key(KC.Y)')" > /dev/ttyACM1
$ y
```

126
docs/en/split_keyboards.md Normal file
View File

@@ -0,0 +1,126 @@
# Split Keyboards
Split keyboards are mostly the same as unsplit. Wired UART is fully supported,
and testing of Bluetooth splits, though we don't currently offer support for this.
Notice that this Split module must be added after the ModTap module to the keyboard.modules.
## Drive names
As you will have two circuitpython drives to update regularly, it is adviced to rename them to make
your life easier. Follow the instructions on how to [rename circuitpydrives](https://learn.adafruit.com/welcome-to-circuitpython/renaming-circuitpy) while making sure that:
- The left side ends in "L",
- the right side ends in "R",
- the entire drive name is 11 characters or less! This is a limitation of the filesystem and you will receive an error if you choose a name longer than that.
For example: `NYQUISTL` for the left and `NYQUISTR` for the right half.
## Wired UART
Wired connections can use UART over 1 or 2 wires. With 2 wires, you will be able
to synchronize the halves allowing additional features in some extensions.
```python
from kb import data_pin
from kmk.modules.split import Split, SplitSide
split = Split(split_side=SplitSide.LEFT)
keyboard.modules.append(split)
```
## Bluetooth split (aka no TRRS) [Currently in testing]
Wireless splits are fully featured with 2 way communication allowing all extensions to work 100%.
```python
from kb import data_pin
from kmk.modules.split import Split, SplitType, SplitSide
split = Split(split_type=SplitType.BLE, split_side=SplitSide.LEFT)
OR
split = Split(split_type=SplitType.BLE, split_side=SplitSide.RIGHT)
keyboard.modules.append(split)
```
## Config
Useful config options:
```python
split = Split(
split_flip=True, # If both halves are the same, but flipped, set this True
split_side=None, # Sets if this is to SplitSide.LEFT or SplitSide.RIGHT, or use EE hands
split_type=SplitType.UART, # Defaults to UART
split_target_left=True, # Assumes that left will be the one on USB. Set to False if it will be the right
uart_interval=20, # Sets the uarts delay. Lower numbers draw more power
data_pin=None, # The primary data pin to talk to the secondary device with
data_pin2=None, # Second uart pin to allow 2 way communication
uart_flip=True, # Reverses the RX and TX pins if both are provided
use_pio=False, # Use RP2040 PIO implementation of UART. Required if you want to use other pins than RX/TX
)
```
### `split_side`
This tells your microcontroller wich side it handles. It's usually not necessary -- defaulting to `split_side = None` it results in:
- Auto dectection of the side from the drive name (ending with 'R'/'L').
- The `split_target` will be overriden. Each side will act as a `split_target` if connected to a usb host.
The default will cover most cases, but you can still choose to set all that manually, if for example:
- You want to debug and/or upload to both sides at the same time over USB. Explicitly setting `split_side` and `split_target` prevents that both halfs consider themselves as `split_target` when a USB connection is detected.
- There are different peripherals on both sides, others than just mirrored the columns (see [`split_flip` section](#split_flip)). That means that the most boards with "flippable" PCBs do **not** need this. The following code is **not** a guideline, but an extraordinary example showing the flexibility of KMK (and would realistically be applicable only in messy handwired keyboards):
```python
from storage import getmount
side = SplitSide.RIGHT if str(getmount('/').label)[-1] == 'R' else SplitSide.LEFT
if side == SplitSide.RIGHT:
keyboard.col_pins = ...
keyboard.row_pins = ...
keyboard.diode_orientation = ...
else:
keyboard.col_pins = ...
keyboard.row_pins = ...
keyboard.diode_orientation = ...
split = Split(
split_side=side,
target_left=True,
...
)
```
Note: It is best to stay as consistent as possible, but thanks to the `coord_mapping` feature, none of the `col_pins`, `row_pins` and `diode_orientation` **need** to be the same for both side.
It is however necessary for `len(col_pins) * len(row_pins)` to be the same to calculate the offset of the key number on the left side correctly.
### `split_flip`
If your split keyboard uses the **same PCB for both sides**, but vertically flipped, set this to `True`, and `False` otherwise. `True` means the wiring is the same for both side except that the `col_pins` are reversed.
### `split_target_left`
The "split_target" refers to the side that acts as the USB HID.
Setting `split_side = None` (similar to EE HANDS in QMK) this parameter will be overriden.
### `uart_flip`
If your boards are connected through the **same** pins (like gpio**4** of board A to gpio**4** of board B): use `uart_flip = True`.
If your boards are connected through **different** pins (like gpio**4** of board A to gpio**10** of board B): use `uart_flip = False`.
### `use_pio`
If you're using an RP2040 based board and want the split communication to use other pins than the ones with hardware UART support, you can use the PIO implementation. Typical use cases for this are premade boards, made with QMK's bitbanging protocols in mind.
In order to enable it, you must:
- Install Circuitpython version > 7.2,
- pass `use_pio=True` into the `Split()` constructor.
### `data_pin`/`data_pin2`
For UART `SplitType`: on the `split_target` side, `data_pin` is the one use for RX, `data_pin2` the one for TX.
## EE HANDS / AUTO HANDEDNESS
If you want to plug USB in on either side, or are using Bluetooth, this is for you. For this feature to work your circuitpython drive must be renamed following the guidelines at the beginning of this doc.
For wired connections you don't need to pass anything. For Bluetooth, remove the `split_side` like this
```python
# Wired
split = Split()
# Wireless
split = Split(split_type=SplitType.BLE)
```

22
docs/en/sticky_mod.md Normal file
View File

@@ -0,0 +1,22 @@
# Sticky Mod
This module allows to hold a modifier while a key is being tapped repeatedly; the modifier will be released when any other key is pressed or released.
This is for example useful if you want to switch between open windows with ALT+TAB or CMD+TAB, using only a single key.
## Enabling the module
```python
from kmk.modules.sticky_mod import StickyMod
sticky_mod = StickyMod()
keyboard.modules.append(sticky_mod)
keyboard.keymap = [
[
KC.SM(kc=KC.TAB, mod=KC.LALT),
KC.SM(KC.TAB, KC.LSFT(KC.LALT)),
],
]
```
## Keycodes
|Key |Description |
|-------------------------|-----------------------------------------------|
|`KC.SM(KC.key, KC.mod)` |sticky mod |

View File

@@ -0,0 +1,37 @@
# String Substitution
The String Substitution module lets a user replace one typed sequence of characters with another. If a string of characters you type matches an entry in your dictionary, it gets deleted and replaced with the corresponding replacement string.
Potential uses:
- Rudimentary auto-correct: replace `yuo` with `you`
- Text expansion, à la [espanso](https://github.com/federico-terzi/espanso): when `:sig` is typed, replace it with `John Doe`, or turn `idk` into `I don't know`
## Usage
The String Substitution module takes a single argument to be passed during initialization: a user-defined dictionary where the keys are the text to be replaced and the values are the replacement text.
Example is as follows:
```python
from kmk.modules.string_substitution import StringSubstitution
my_dictionary = {
'yuo': 'you',
':sig': 'John Doe',
'idk': "I don't know"
}
string_substitution = StringSubstitution(dictionary=my_dictionary)
keyboard.modules.append(string_substitution)
```
### Recommendations
1. Consider prefixing text expansion entries with a symbol to prevent accidental activations: `:sig`, `!email`, etc.
2. If you want multiple similar replacements, consider adding a number to prevent unreachable matches: `replaceme1`, `replaceme2`, etc.
### Limitations
1. Currently supports characters for which there is a corresponding keycode in KMK - support for international characters is not implemented.
2. Since this runs on your keyboard, it is not context-aware. It can't tell if you are typing in a valid text field or not.
3. In the interest of a responsive typing experience, the first valid match will be used as soon as it is found. If your dictionary contains "abc" and "abcd", "abcd" will not be matchable.

9
docs/en/support.md Normal file
View File

@@ -0,0 +1,9 @@
# Support
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 in chat or open a bug report, if possible
make sure your copy of KMK is up-to-date.

62
docs/en/tapdance.md Normal file
View File

@@ -0,0 +1,62 @@
# Tap Dance
Tap dance is a way to allow a single physical key to work as multiple logical
keys / actions without using layers. With basic tap dance, you can trigger these
"nested" keys or macros through a series of taps of the physical key within a
given timeout.
The resulting "logical" action works just like any other key - it can be pressed
and immediately released, or it can be held. For example, let's take a key
`KC.TD(KC.A, KC.B)`. If the tap dance key is tapped and released once quickly,
the letter "a" will be sent. If it is tapped and released twice quickly, the
letter "b" will be sent. If it is tapped once and held, the letter "a" will be
held down until the tap dance key is released. If it is tapped and released once
quickly, then tapped and held (both actions within the timeout window), the
letter "b" will be held down until the tap dance key is released.
To use this, you may want to define a `tap_time` value in your keyboard
configuration. This is an integer in milliseconds, and defaults to `300`.
The timeout is reset after each tap and every tapdance sequence can also define
an individual `tap_time`.
You'll then want to create a sequence of keys using `KC.TD(KC.SOMETHING,
KC.SOMETHING_ELSE, MAYBE_THIS_IS_A_MACRO, WHATEVER_YO)`, and place it in your
keymap somewhere. The only limits on how many keys can go in the sequence are,
theoretically, the amount of RAM your MCU/board has.
Tap dance supports all `HoldTap` based keys, like mod tap, layer tap, oneshot...
it will even honor every option set for those keys.
Individual timeouts and prefer hold behavior for every tap in the sequence?
Not a problem.
Here's an example of all this in action:
```python
from kmk.keycodes import KC
from kmk.handlers.sequences import send_string
from kmk.modules.tapdance import TapDance
keyboard = KMKKeyboard()
tapdance = TapDance()
tapdance.tap_time = 750
keyboard.modules.append(tapdance)
EXAMPLE_TD = KC.TD(
# Tap once for "a"
KC.A,
# Tap twice for "b", or tap and hold for "left control"
KC.MT(KC.B, KC.LCTL, prefer_hold=False),
# Tap three times to send a raw string via macro
send_string('macros in a tap dance? I think yes'),
# Tap four times to toggle layer index 1, tap 3 times and hold for 3s to
# momentary toggle layer index 1.
KC.TT(1, tap_time=3000),
)
# make the default tap time really short for this tap dance:
EXAMPLE_TD2 = KC.TD(KC.A, KC.B, tap_time=80)
keyboard.keymap = [[ ...., EXAMPLE_TD, ....], ....]
```