Ergodoxで親指同時打鍵を実装する


最近、日本語入力の配列を [蜂蜜小梅配列](http://8x3koume.na.coocan.jp/) に切り替えてみました。それなりに打てるようになるまで２週間くらいかかりましたが、慣れてくるとだんだん快適になってきました。

## 同時打鍵系の配列を使うときの問題 ##

蜂蜜小梅配列もそうですが、 [新下駄配列](http://kouy.exblog.jp/13627994/) などの **同時打鍵** を必要とする配列の場合、IMEのアルファベット切り替えだけでは実装できません。Windowsであれば [DvorakJ](http://blechmusik.xii.jp/dvorakj/) であったり、 Macであれば [Karabinar](https://pqrs.org/osx/karabiner/) などの外部ツールが必要となるケースがほとんどです。

実際、一時期新下駄配列を使ってみていたとき、Linuxでこういったツールがなかったため、 [こんなツール](https://github.com/derui/okeyfum) を作成したりしていました。もっとも、単純にアルファベットを出力しているだけだと、新下駄配列や蜂蜜小梅配列などで提供されている「」とかの入力が難しいか不可能なんですが、概ね利用する上で不便はなかったです。

ただ、現場では当然ながらWindows、部屋では当然ながら(?)Linux、という生活をしていると、どうしても設定の同期であったり、ツール間の細かい挙動の違いがじみーにストレスになってしまい、結局ローマ字入力に戻ってしまいました。

## Ergodox & qmk\_firmware ##
そんな折、話題になっていた [Ergodox EZ](https://ergodox-ez.com/) を買い、同時に [qmk\_firmware](https://github.com/qmk/qmk_firmware) の存在を知りました。

Ergodox自体、親指シフトよろしく両手にそれぞれキーがあり、かつqmk\_firmwareを使えば、キーボードだけで同時打鍵系の配列って実装できるんじゃ?といつからか思っていました。そんな酔狂なことをしている人自体いないのか、調べてみても似た事例はありませんでしたが。

## 実際にやってみる ##
実際にやってみたのが [こちら](https://github.com/derui/qmk_firmware/tree/master/layouts/community/ergodox/derui) です。

この同時打鍵を実現する上では、いくつか実装の方式があります。

- あるキーが押されて **押上られるまでに** 別のキーが押されたら、同時とみなす
  - 要は同時押し
- あるキーが押されてから一定時間が経過するまでに別のキーが押されたら、同時とみなす

この方式の詳しい Pros/Consは、 DvorakJの [こちらのページ](http://blechmusik.xii.jp/dvorakj/wiliki.cgi?DvorakJ%3A%E3%83%AC%E3%83%95%E3%82%A1%E3%83%AC%E3%83%B3%E3%82%B9%E3%83%9E%E3%83%8B%E3%83%A5%E3%82%A2%E3%83%AB%3A%E8%A9%B3%E8%AA%AC%3A%E5%90%8C%E6%99%82%E6%89%93%E9%8D%B5%E3%81%AE%E5%88%A4%E5%AE%9A%E5%87%A6%E7%90%86) がとっても詳しいです。

今回は同時押しパターンを利用しました。理由としては次のような感じです。

- 実装がqmk\_firmwareのやり方に沿いやすい
- 以前実装したことがある
- 自分の利用感に合う

それと、以前Windowsで新下駄配列を利用していたとき、時間経過形式だとやたらミスが目立ったというのがありました。この辺は人それぞれですね。

qmk\_firmwareでの実装自体は、quantumというフレームワークのソースを読んだり、最近充実してきたドキュメントを読めば、わりかし単純です。一番時間がかかったのは配列の定義かもしれません・・・。しかし、この配列のサイズがネックになりました。

### qmk\_firmwareのDocker file ###
以前はVagrantが提供されていたりしましたが、現在はDockerでビルドするのが個人的におすすめです。

こんな感じでビルドできます。私はやっていませんが、CircleCIなどでCIする際にも利用できるんではないかと。

```bash
docker run -e keymap=derui -e keyboard=ergobox_ez --rm -v `pwd`:/qmk:rw qmk_firmware
```

## qmk\_firmwareでのサイズとの戦い方 ##

qmk\_firmwareで、単純にキー配列をいじったり、いくつかのレイヤーを利用したり、いくつかのマクロを利用したりしているくらいでは問題にならないかと思いますが、今回実装した配列の実装で一番問題になったのは、 **生成したhexファイルのサイズ** です。

Ergodox EZが利用しているコントローラーで利用できるhexファイルのサイズは大体32KBくらいなんですが、Ergodoxのmakeファイルをそのまま流用すると、大体36KBくらいになります(teency loaderでロードしようとすると、 **100%オーバー** になる)。
恐怖なのが、限界サイズを超えてても書き込み自体は出来てしまいます。この状態で間違って書き込むと、Ergodoxがフリーズします。何回か書き込んでしまい、その度にHHK2の出動と相成りました。

### 動的メモリへの追い出し ###

今回の実装では、 ``2byte * 8 * 391 = 6256 ≒ 6.1KB`` という配列のキー定義が問題になりました。近年のプログラミングでは全く問題にならないサイズですが、32KBしか利用できないErgodox EZでは死活問題です。
しかも、実際にはコントローラー自体のファームウェアも同じメモリ上に展開されるため、32KB全部をstaticにすることは出来ません。やると無限に再起動したりします(やった)。

しかし、ファイルを読み込むとかは基本的に出来ないので、どうしてもhexファイル内に収める必要があります。そんな時は、 ``PROGMEM`` に置く必要があります。

```c
const der_hk_key_shifter_t PROGMEM der_hk_key_shifters[] = {...};
```

PROGMEMは、起動時にはロードされず、必要なときに随時読み出すことを可能とするための識別子です。みんな最初に設定するkeymapにもついていますね。

これを指定した変数から読み出す場合、普通に配列から読み出すような形では読むことが出来ません。面倒ですが、こんな感じでコピーしてくる必要があります。

```c
der_hk_key_shifter_t der_get_mapping(int index) {
  der_hk_key_shifter_t data;
  memcpy_P(&data, &der_hk_key_shifters[index], sizeof(der_hk_key_shifter_t));
  return data;
}
```

他にも種類があるようでしたが、今回の用途ではPROGMEMだけで十分でした。

### featureの無効化 ###
Ergodox EZのデフォルトキーマップには、 **キーボードでのマウス操作** ということが可能でした。これ以外にも、MIDIキーボードっぽく利用できたり、RGBを自由にしたりとできます。
これはそれぞれ **feature** という形で実装されており、 ``#define`` や ``#undef`` でスイッチができます。

しかし、機能を追加するということは、そのままサイズの上昇に繋がります。そのため、ドキュメントには、それぞれの機能を有効にしたときにどれくらいのサイズが増えるか、ということが記載してあります。してないのも多いですが・・・。

今回、デフォルトでONになっている中で、OFFにしたfeatureは以下です。

- マウス操作
- RGBLIGHT

RGBLIGHTは特に大きく、5KBくらい減りました。持っているErgodoxにはそもそも付いてないので、有効にする必要が無かったというのもありましたが。

他にも無効化にできそうなfeatureは特にないというか、無効にすると困るものばっかでした。


## 実際の使用感 ##
現場では Microsoft IME、部屋では Mozc をそれぞれ利用していますが、変換・無変換でそれぞれかな・英数を切り替えるように設定した以外、全部デフォルトの状態で利用できています。

狙い通り、OSの違いに左右されず、余計なツールを間に挟んでいない分、レスポンスも軽快です。そういう意味では、ファームウェアレベルで実装した苦労は報われたと思います。

実は、記事作成時点ではまだ完成ではなく、蜂蜜小梅配列で定義しているタイプアシストとかは実装出来ていません。
また、キーリピートに対応できていないため、日本語入力中のBS連打がたまに厳しいです。

それでも、こういったキーボードカスタマイズは楽しさと実用性を両立しやすいと思います。
キー配列をいじるためだけにqmk\_firmwareを利用するっていうのは結構もったいないです。ぜひカスタマイズしてみましょう。今回の記事が、他にこういったことをする人の助けになれば幸いです。

・・・ツール使えるんなら使った方が速いけどな!