DEV Community

Cover image for Create Your Own Keyboard with sago35/tinygo-keyboard
sago35
sago35

Posted on

Create Your Own Keyboard with sago35/tinygo-keyboard

This article compiles information on creating a custom keyboard using TinyGo + Wio Terminal with sago35/tinygo-keyboard.

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.

GitHub logo 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/
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
Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

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:

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())
}

Enter fullscreen mode Exit fullscreen mode

Flash

We'll write to the Wio Terminal.

$ tinygo flash --target wioterminal --size short .
   code    data     bss |   flash     ram
  39076     684    9316 |   39760   10000
Enter fullscreen mode Exit fullscreen mode

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())

Enter fullscreen mode Exit fullscreen mode

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)

Enter fullscreen mode Exit fullscreen mode

The following circuit is targeted. It is used in targets/sgkb/left-0.3.0 and similar configurations.

circuit of duplex-matrix

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)

Enter fullscreen mode Exit fullscreen mode

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)

Enter fullscreen mode Exit fullscreen mode

The following circuit is targeted. It is used in targets/sgkey and similar configurations.

circuit of matrix

RotaryKeyboard

This can handle rotary encoders.

AddRotaryKeyboard(rotA, rotB machine.Pin, keys [][]Keycode)

Enter fullscreen mode Exit fullscreen mode

The following circuit is targeted. It is used in targets/xiao-kb01 and macropad-rp2040.

circuit of rotary-encoder

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)

Enter fullscreen mode Exit fullscreen mode

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)

Enter fullscreen mode Exit fullscreen mode

The following circuit is targeted. It is used in targets/sgh60 and targets/xiao-kb01, among others.

circuit of squared-matrix

UartKeyboard

This can handle key information sent via UART. It was primarily created for split keyboards.

AddUartKeyboard(size int, uart *machine.UART, keys [][]Keycode)

Enter fullscreen mode Exit fullscreen mode

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.

vial

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"]
        ]
    }
}

Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

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{
        // ...
    }
}

Enter fullscreen mode Exit fullscreen mode

Please execute before calling d.Loop() as follows.

    loadKeyboardDef()
    d.Loop(context.Background())

Enter fullscreen mode Exit fullscreen mode

The complete example source code is in main.go below.

GitHub logo 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

vial

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)