sago35/tinygo-keyboard を用いて自作キーボードを作ろう

この記事では TinyGo + Wio Terminal を用いて sago35/tinygo-keyboard を使った自作キーボードを作るための情報をまとめます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63649/a22afd85-8f64-5e91-5f1d-55006087addd.png)

sago35/tinygo-keyboard は TinyGo で自作キーボードを作るための package です。レイヤー対応や各種スイッチ読み取り方式への対応、 Vial 対応等が含まれます。

https://github.com/sago35/tinygo-keyboard

## 前提知識

以下の書籍 「基礎から学ぶ TinyGoの組込み開発」を読んでおくとスムーズです。
※[電子書籍は 2024/01/22 まで 40% オフで購入](https://book.mynavi.jp/manatee/books/detail/id=134168)することができます

https://sago35.hatenablog.com/entry/2022/11/04/230919

最低限の情報は以下にも記載していますので、適宜参照してください。

https://qiita.com/sago35/items/92b22e8cbbf99d0cd3ef

あるいは Go Conference mini 2023 Winter IN KYOTO でも自作キーボードについてトークしています。sago35/tinygo-keyboard にはほとんど触れていませんが、ライブコーディングもしているので基礎知識として見ておくと良いかもしれません。

https://sago35.hatenablog.com/entry/2023/12/05/095108

## Go / TinyGo のプロジェクトを作成する

まずは `go mod init` を実行して、 `go.mod` というファイルを作成します。これは Go でも TinyGo でも共通のプロジェクト開始のための手順です。

```shell
$ mkdir mykeyboard

$ cd mykeyboard

$ go mod init main
go: creating new go.mod: module main

$ ls
go.mod
```

`go.mod` を作ったあとは、このあと必要となる sago35/tinygo-keyboard を go get しておきましょう。なお、Version 指定なしで go get するとその時点の最新版が取り込まれるため、 Version 表記などは異なる場合があります。

```
$ go get github.com/sago35/tinygo-keyboard
go: added github.com/bgould/tinygo-rotary-encoder v0.0.0-20231106003644-94bb14d88946
go: added github.com/sago35/tinygo-keyboard v0.0.0-20231226123717-7246a4ef8c39
go: added tinygo.org/x/drivers v0.25.0
```

## ソースコードの作成

次に sago35/tinygo-keyboard を import してキーボードを作り始めます。

以下のあたりのコードをコピーして雛形にするのも良いでしょう。

* https://github.com/sago35/tinygo-keyboard/tree/main/tutorial
* https://github.com/sago35/tinygo-keyboard/tree/main/targets

ここでは以下のソースコードを作成します。完全なソースコードは以下のリポジトリの basic branch にあります。

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

```go:main.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

Wio Terminal に書き込みます。

```shell
$ tinygo flash --target wioterminal --size short .
   code    data     bss |   flash     ram
  39076     684    9316 |   39760   10000
```

## 動作確認

書き込みが終わると、 Wio Terminal の上部のボタンがそれぞれ `a`、`b`、`レイヤー 1` として動作します。`レイヤー 1` を押している間は `1`、 `BackSpace` として動作します。


## ソースコードの解説

sago35/tinygo-keyboard の基本的な使い方は `keyboard.New()` して、 `AddXXXXKeyboard()` して `Loop()` をコール、という流れです。Wio Terminal のボタンはすべて GPIO ピンに直接つながっているので `AddGpioKeyboard()` を使います。

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

上記で `jp.XXX` と書かれている部分は、キー設定になります。

`jp.KeyMod1` は特殊なキーでレイヤーを使うためのものです。レイヤー関連のキーは以下の通りです。なお、 `KeyModX` については、レイヤー移動先にも同じキーを設定する必要があります。

sago35/tinygo-keyboard では、現時点でレイヤー 0 から 5 までの合計 6 レイヤーを使うことができます。

 | キー名 | 動作 |
 | --- | --- |
 | KeyMod0 〜 KeyMod5 | 押してる間だけレイヤー 0 〜 5 に切り替える |
 | KeyTo0 〜 KeyTo5 | レイヤー 0 〜 5 に切り替える (離しても戻らない) |

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

 ## sago35/tinygo-keyboard が対応している入力方式

sago35/tinygo-keyboard では、以下の入力方式に対応しています。対応形式は必要に応じて追加することができます。一般的な呼び名と異なっている可能性がありますので、詳細は回路図を参考にしてください。

### DuplexMatrixKeyboard

倍マトリクスとか Duplex Matrix とか Japanese Duplex Matrix とか言われるものです。普通のマトリクスに対して、 2 倍の入力を扱うことができます。

```go
AddDuplexMatrixKeyboard(colPins, rowPins []machine.Pin, keys [][]Keycode)
```

以下の回路が対象です。 targets/sgkb/left-0.3.0 などで使用されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63649/56570f08-255c-edf1-e9bf-5dbb4c31ad0a.png)


以下の 「倍マトリクス」 の説明を読むと良いです。

https://blog.ikejima.org/make/keyboard/2022/12/07/atypical-matrix-design.html

### GpioKeyboard

GPIO に直接接続されたピンを用いたキーボードです。opt によりボタン押下時の極性を設定することができます。

```go
AddGpioKeyboard(pins []machine.Pin, keys [][]Keycode, opt ...Option)
```

### MatrixKeyboard

おそらく自作キーボードで一番使われている方式だと思います。行と列のピンを作ることにより、少ないピン数で多くの入力を扱うことができます。opt によりダイオードの向きを設定することができます。

```go
AddMatrixKeyboard(colPins, rowPins []machine.Pin, keys [][]Keycode, opt ...Option)
```

以下の回路が対象です。 targets/sgkey などで使用されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63649/16f448e7-5a4f-21ef-1068-b9ba3f511ec3.png)

以下の 「通常のマトリクス」 の説明を読むと良いです。

https://blog.ikejima.org/make/keyboard/2022/12/07/atypical-matrix-design.html

### RotaryKeyboard

ロータリーエンコーダーを扱うことができます。

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

以下の回路が対象です。 targets/xiao-kb01 や macropad-rp2040 で使用されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63649/202fd4b2-7af6-e025-8cca-77d8bef5a4f7.png)


### ShifterKeyboard

シフトレジスターを扱うことができます。 pybadge / gobadge に使われている 74165TSSOP (74HC165 互換？) のために作成されました。 opt によりボタン押下時の極性を設定することができます。

```go
AddShifterKeyboard(shifterDevice shifter.Device, keys [][]Keycode, opt ...Option)
```

### SquaredMatrixKeyboard

改良二乗マトリクスを扱うことができます。非常にピン効率が良く、例えば 5 ピンで 5 x 4 = 20 ピンの入力を扱うことができます。

```go
AddSquaredMatrixKeyboard(pins []machine.Pin, keys [][]Keycode)
```

以下の回路が対象です。 targets/sgh60 や targets/xiao-kb01 などで使用されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63649/f291b41c-29ab-0383-4c9d-1c482f0de65c.png)

以下の 「改良二乗マトリクス」 の説明を読むと良いです。

https://blog.ikejima.org/make/keyboard/2022/12/07/atypical-matrix-design.html


### UartKeyboard

UART 経由で送られてきたキー情報を扱うことができます。主に分割キーボードのために作成されました。

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

targets/sgkb などで使用されています。


## Vial 対応を行う

Vial は Web ブラウザ等からキーマップを設定するためのプロジェクトです。 sago35/tinygo-keyboard から使うためには `keyboard.KeyboardDef []byte` を設定する必要があります。自分でマニュアル作成することもできますが、基本的には `vial.json` を用意して、 `gen-def` により `def.go` を作成すると良いです。この辺りは後述します。

正しく設定できていると以下の画面のように Web ブラウザから設定を行うことができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63649/51634c84-ebf0-86e5-eba9-40ae836cfd5c.png)

Vial は以下です。

https://vial.rocks/


### vial.json を作成する

vial.json の作り方の詳細は以下を参照してください。とはいえ、 sago35/tinygo-keyboard で使用する項目はごく一部であるため、既存の vial.json を参考にすると良いです。

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

既存の vial.json は targets/ 以下にあります。

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

layouts.keymap については KLE / Keyboard Layout Editor の `</>Raw data` から JSON をコピーすることで作成できます。

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

今回は Wio Terminal の上部の 3 ボタンのみを使用するため、以下のようになります。 sago35/tinygo-keyboard に必要な最低限の設定は以下の通りです。なお、 name / vendorId / productId は何を設定しても良いです。

```json:vial.json
{
    "name": "tinygo-wioterminal",
    "vendorId": "0x2886",
    "productId": "0x802D",
    "matrix": {"rows": 1, "cols": 3},
    "layouts": {
        "keymap": [
            ["0,2","0,1","0,0"]
        ]
    }
}
```

上記を `vial.json` という名前で保存したら `gen-def` を実行します。

```shell
$ ls
go.mod  go.sum  main.go  vial.json

# gen-def をインストール
# `go env GOPATH` で表示される場所にインストールされます
$ go install github.com/sago35/tinygo-keyboard/cmd/gen-def@latest

# vial.json から def.go を生成する
$ gen-def vial.json

$ ls
def.go  go.mod  go.sum  main.go  vial.json
```

自動生成された `def.go` は以下のようになっています。ここで定義される `loadKeyboardDef()` をコールすることで Vial 対応が完了します。

```go
package main

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

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

以下のように `d.Loop()` をコールするまでに実行してください。

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

ソースコードの完全な例は、以下の `main.go` にあります。

https://github.com/sago35/tinygo-keyboard-examples

うまくソースコードを作ることが出来たら、 Vial にアクセスしてみてください。
※ブラウザは Chrome もしくは Edge を使用してください

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63649/affd70c4-0df7-f6eb-fdae-86f52b599bd4.png)

## まとめ

TinyGo + Wio Terminal を用いて sago35/tinygo-keyboard を使った自作キーボードを作るための情報をまとめました。不明点がある場合などは、以下のリポジトリの Issue に書いていただくか、 Twitter/X からメンションしてください。サポートしますのでお気軽にどうぞ。

https://github.com/sago35/tinygo-keyboard

https://twitter.com/sago35tk