Create Your Own Keyboard with sago35/tinygo-keyboard
Tags: tutorial, tinygo, go, keyboard
Published: 2024-03-01 00:55:19

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


![keyboard](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pb4h2ppvlv0003uoo1cw.png)

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.

{% embed https://github.com/sago35/tinygo-keyboard %}


## 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:

* https://github.com/sago35/tinygo-keyboard-examples/tree/basic



```go
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()`.

```go
	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](https://github.com/tinygo-org/tinygo/blob/v0.31.1/src/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) |

* https://github.com/sago35/tinygo-keyboard/blob/main/keycodes/keycodes.go


## 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.

![circuit of duplex-matrix](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cnz42cvgdkwag6nljfoq.png)


### 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.


![circuit of matrix](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ko3bsze41q8jqadjqzkv.png)



### 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.


![circuit of rotary-encoder](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6piyx8wywjbzz2tjnmnw.png)



### 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.


![circuit of squared-matrix](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dosl86f4ah8xac2bl6yz.png)


### 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.

![vial](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w89xsizbinjd3vxmv47s.png)

* https://vial.rocks/


### 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.

* https://get.vial.today/docs/porting-to-via.html

Existing `vial.json` files can be found under targets/.

* https://github.com/sago35/tinygo-keyboard/tree/main/targets
  * https://github.com/sago35/tinygo-keyboard/blob/main/targets/wiokey/vial.json

For the `layouts.keymap`, you can create it by copying JSON from KLE / Keyboard Layout Editor's `</> Raw data`.

* http://www.keyboard-layout-editor.com/

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.

```json
{
    "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.

```go
package main

import keyboard "github.com/sago35/tinygo-keyboard"

func loadKeyboardDef() {
	keyboard.KeyboardDef = []byte{
		// ...
	}
}

```

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

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

```

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

{% embed https://github.com/sago35/tinygo-keyboard-examples %}


Once you've successfully created the source code, try accessing Vial.
Note: Please use Chrome or Edge browser


![vial](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t535wsgb1qrzs7to2ezi.png)

* https://vial.rocks/

## 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.

* https://github.com/sago35/tinygo-keyboard
* https://twitter.com/sago35tk
* https://social.tinygo.org/@sago35