This article compiles information on creating a custom keyboard using TinyGo + Wio Terminal with sago35/tinygo-keyboard.
sago35/tinygo-keyboard is a package for building custom keyboards with TinyGo. It includes features such as layer support, various switch reading methods, and Vial compatibility.
sago35 / tinygo-keyboard
USB HID keyboard firmware for tinygo
USB HID Keyboard firmware for TinyGo
The API is not yet fixed.
The following are supported.
- key input
- squared matrix scan
- matrix scan
- duplex-matrix scan
- rotary encoder
- GPIO
- UART
- Shifter (tinygo.org/x/drivers/shifter)
- layer feature by mod key
- mouse click / mouse wheel
- support TRRS (UART)
- support Vial
Microcontrollers
The following microcontrollers are supported.
- rp2040
- nrf52840
- samd51
- samd21
Tutorial
Additional Resources
sgkb-0.4.0
# sgkb-0.4.0
$ tinygo flash --target xiao-rp2040 --size short ./targets/sgkb/left/
$ tinygo flash --target xiao-rp2040 --size short ./targets/sgkb/right/
# sgkb-0.3.0 or before
$ tinygo flash --target xiao-rp2040 --size short ./targets/sgkb/left-0.3.0/
$ tinygo flash --target xiao-rp2040 --size short ./targets/sgkb/right/
- files
-
./kicad/sgkb for KiCad 7.0
- KiCanvas : sgkb-0.4.0 left
- KiCanvas : sgkb-0.4.0 right
- KiCanvas : sgkb-0.3.0 left
- KiCanvas : sgkb-0.3.0 right
-
./kicad/sgkb for KiCad 7.0
name | amount |
---|---|
Cherry MX / Kailh Choc V1 | 72 |
key cap (1u) | 68 |
Creating a Go / TinyGo Project
First, run go mod init to create a file called go.mod. This is a common procedure for starting a project in both Go and TinyGo.
$ mkdir mykeyboard
$ cd mykeyboard
$ go mod init main
go: creating new go.mod: module main
$ ls
go.mod
After creating go.mod, you'll need to go get the necessary sago35/tinygo-keyboard. Note that if you go get without specifying a version, it will fetch the latest version at that time, so the version may differ.
$ go get github.com/sago35/tinygo-keyboard
go: downloading github.com/sago35/tinygo-keyboard v0.0.0-20240229115423-a1702f57f94c
go: added github.com/sago35/tinygo-keyboard v0.0.0-20240229115423-a1702f57f94c
go: added golang.org/x/exp v0.0.0-20231226003508-02704c960a9b
go: added tinygo.org/x/drivers v0.27.0
Creating the Source Code
Next, import sago35/tinygo-keyboard
and start building your keyboard.
It's a good idea to copy the code around here to use as a template:
- https://github.com/sago35/tinygo-keyboard/tree/main/tutorial
- https://github.com/sago35/tinygo-keyboard/tree/main/targets
Here, we'll create the following source code. The complete source code is available in the basic branch of the following repository:
package main
import (
"context"
"machine"
keyboard "github.com/sago35/tinygo-keyboard"
"github.com/sago35/tinygo-keyboard/keycodes/jp"
)
func main() {
d := keyboard.New()
gpioPins := []machine.Pin{
machine.WIO_KEY_A,
machine.WIO_KEY_B,
machine.WIO_KEY_C,
}
for c := range gpioPins {
gpioPins[c].Configure(machine.PinConfig{Mode: machine.PinInput})
}
d.AddGpioKeyboard(gpioPins, [][]keyboard.Keycode{
{
// layer 0
jp.KeyA,
jp.KeyB,
jp.KeyMod1,
},
{
// layer 1
jp.Key1,
jp.KeyBackspace,
jp.KeyMod1,
},
})
d.Loop(context.Background())
}
Flash
We'll write to the Wio Terminal.
$ tinygo flash --target wioterminal --size short .
code data bss | flash ram
39076 684 9316 | 39760 10000
Operation Check
After flashing, the buttons at the top of the Wio Terminal will function as follows: respectively, as a
, b
, and Layer 1
. While holding down Layer 1
, it will function as 1
and BackSpace
.
Explanation of the Source Code
The basic usage of sago35/tinygo-keyboard involves calling keyboard.New()
, adding the desired keyboard type with AddXXXXKeyboard()
, and then calling Loop()
. Since all buttons on the Wio Terminal are directly connected to GPIO pins, we use AddGpioKeyboard()
.
d := keyboard.New()
d.AddGpioKeyboard(gpioPins, [][]keyboard.Keycode{
{
// layer 0
jp.KeyA,
jp.KeyB,
jp.KeyMod1,
},
{
// layer 1
jp.Key1,
jp.KeyBackspace,
jp.KeyMod1,
},
})
d.Loop(context.Background())
The values labeled jp.XXX
above represent key settings.
Note: Instead of jp.XXX
, you can also use the code from machine/usb/hid/keyboard/keycode.go.
jp.KeyMod1
is a special key used to switch layers. The keys related to layer switching are as follows. Note that for KeyModX
, the same key needs to be assigned to the destination layer.
In sago35/tinygo-keyboard, you can currently use a total of 6 layers, from layer 0 to 5.
Key name | Action |
---|---|
KeyMod0 to KeyMod5
|
Temporarily switch to layers 0 to 5 while pressed |
KeyTo0 to KeyTo5
|
Switch to layers 0 to 5 (sticky) |
Supported Key Inputs by sago35/tinygo-keyboard
sago35/tinygo-keyboard supports the following input methods. Additional formats can be added as needed. Please refer to the circuit diagram for details, as they may differ from common naming conventions.
DuplexMatrixKeyboard
This refers to a Duplex Matrix, also known as a Japanese Duplex Matrix, which allows handling twice the input compared to a regular matrix.
AddDuplexMatrixKeyboard(colPins, rowPins []machine.Pin, keys [][]Keycode)
The following circuit is targeted. It is used in targets/sgkb/left-0.3.0 and similar configurations.
GpioKeyboard
This is a keyboard that uses pins directly connected to GPIO. The polarity of button presses can be set using opt.
AddGpioKeyboard(pins []machine.Pin, keys [][]Keycode, opt ...Option)
MatrixKeyboard
This is probably the most commonly used method in DIY keyboards. By creating rows and columns of pins, you can handle many inputs with few pins. The polarity of diodes can be set using opt.
AddMatrixKeyboard(colPins, rowPins []machine.Pin, keys [][]Keycode, opt ...Option)
The following circuit is targeted. It is used in targets/sgkey and similar configurations.
RotaryKeyboard
This can handle rotary encoders.
AddRotaryKeyboard(rotA, rotB machine.Pin, keys [][]Keycode)
The following circuit is targeted. It is used in targets/xiao-kb01 and macropad-rp2040.
ShifterKeyboard
This can handle shift registers. It was created for the 74165TSSOP (74HC165 compatible?) used in pybadge/gobadge. The polarity of button presses can be set using opt.
AddShifterKeyboard(shifterDevice shifter.Device, keys [][]Keycode, opt ...Option)
SquaredMatrixKeyboard
This can handle improved squared matrices. It is very pin-efficient, allowing you to handle 20 input pins with just 5 pins, for example.
AddSquaredMatrixKeyboard(pins []machine.Pin, keys [][]Keycode)
The following circuit is targeted. It is used in targets/sgh60 and targets/xiao-kb01, among others.
UartKeyboard
This can handle key information sent via UART. It was primarily created for split keyboards.
AddUartKeyboard(size int, uart *machine.UART, keys [][]Keycode)
It is used in targets/sgkb, among others.
Configuring Vial Support
Vial is a project for setting keymaps from web browsers and the like. To use it with sago35/tinygo-keyboard, you need to set keyboard.KeyboardDef []byte
. You can create a manual yourself, but basically, it's a good idea to prepare vial.json
and create def.go
with gen-def
. We'll discuss this later.
When configured correctly, you can make settings from a web browser as shown in the screenshot below.
Creating vial.json
For detailed instructions on how to create vial.json
, please refer to the following. However, since only a few items are used in sago35/tinygo-keyboard, it's a good idea to refer to existing vial.json files.
Existing vial.json
files can be found under targets/.
For the layouts.keymap
, you can create it by copying JSON from KLE / Keyboard Layout Editor's </> Raw data
.
Since only the top 3 buttons of the Wio Terminal are used this time, the vial.json looks like this. The minimum required settings for sago35/tinygo-keyboard are as follows. Note that name / vendorId / productId can be set to anything.
{
"name": "tinygo-wioterminal",
"vendorId": "0x2886",
"productId": "0x802D",
"matrix": {"rows": 1, "cols": 3},
"layouts": {
"keymap": [
["0,2","0,1","0,0"]
]
}
}
After saving the above as vial.json
, run gen-def
.
$ ls
go.mod go.sum main.go vial.json
# Install gen-def
# It will be installed in the location displayed by `go env GOPATH`
$ go install github.com/sago35/tinygo-keyboard/cmd/gen-def@latest
# Generate def.go from vial.json
$ gen-def vial.json
$ ls
def.go go.mod go.sum main.go vial.json
The automatically generated def.go looks like this. Vial support is completed by calling loadKeyboardDef()
defined here.
package main
import keyboard "github.com/sago35/tinygo-keyboard"
func loadKeyboardDef() {
keyboard.KeyboardDef = []byte{
// ...
}
}
Please execute before calling d.Loop()
as follows.
loadKeyboardDef()
d.Loop(context.Background())
The complete example source code is in main.go below.
sago35 / tinygo-keyboard-examples
examples of sago35/tinygo-keyboard
tinygo-keyboard-examples
This repository is an example of a project using sago35/tinygo-keyboard.
You can write to the Wio Terminal using the following command.
$ tinygo flash --target wioterminal --size short .
how to start your keyboard project
You can use the "gonew" command to copy the project template. Alternatively, you can also clone the GitHub project or download it as a zip file.
$ gonew github.com/sago35/tinygo-keyboard-examples example.com/your/keyboard
gonew: initialized example.com/your/keyboard in .\keyboard
$ cd ./keyboard
$ tinygo flash --target wioterminal --size short .
Update def.go
Use gen-def
.
# install gen-def
$ go install github.com/sago35/tinygo-keyboard/cmd/gen-def@latest
# generage def.go from vial.json
$ gen-def vial.json
Once you've successfully created the source code, try accessing Vial.
Note: Please use Chrome or Edge browser
Conclusion
We've covered the information for creating a custom keyboard using TinyGo + Wio Terminal with sago35/tinygo-keyboard. If you have any questions or concerns, feel free to reach out by posting on the Issues section of the following repository or mention me on Twitter/X or mention me on Mastodon. We're here to help, so don't hesitate to ask.
Top comments (0)