片手用Bluetoothキーボードを買ったのでカスタマイズツールを作ってみた

Amazonで、2つのノブの付いた片手用Bluetoothキーボードを買ってみました。Bluetooth付きのもの・USB専用のものや、6/9/12キー他、3ノブのものなど、色々種類があるようです。
いろんなブランド名で出品されており怪しげなのですが、念のためAmazon出荷のものを選んでみました。

片手キーボード (Bluetooth接続 3層レイヤー機能付き ノブ2個付き 9キー) 黒
片手キーボード (Bluetooth接続 3層レイヤー機能付き ノブ2個付き 9キー) 白


接続はUSB Type-Cです。Bluetooth対応版だとリチウムイオン電池を内蔵していて、USB接続中に充電されます(USB接続中はUSBキーボードとして振る舞います)。ノブ付きの片手キーボードデバイスは意外と高価なものが多いので、多少安価な部類に思います(それでもBluetooth版だと価格は上がりますが)。質感もアクリルパネルで悪くはないのですが、裏面がネジ露出でそのままだと置いた場所が傷だらけになるので、ゴム足なりビニールテープなりを貼る等の対策が必須です。
Bluetooth版だと3つのレイヤーに違うキーを割り当ててボタンで切り替えて使うこともできます。

しかし最大の欠点は設定ツールで、商品説明のGoogleDriveリンクで配布されている未署名のWindows用アプリしかなく、ちょっと怪しげな感じで作りも最低限のものです。商品名にはLinux/Macなどと書いてあるのですが、設定するにはWindowsが必須になってしまいます*1


そこでLinux/Mac、あるいはWinでもこのアプリを使わずに設定できるよう、どうやって設定されているのか調べてみました。
やり方は簡単(?)で、Windows(念のため環境が壊れてもいいように仮想環境でやりました)上でこのアプリを動かし、WiresharkでUSBキャプチャして設定時の通信内容からプロトコルを調べます。

このツールは1キー割り当てるごとにデータを送信する方式です。試しにレイヤー1の真ん中のキー(5番*2)に数字の5のキー(スキャンコード 0x22)を割り当ててみたところをキャプチャしてみました。
ちなみにデバイス名は CH57x という中国製マイコンの名前がそのまま見えています。適当ですね。。
送信先はInterface 1のInterrupt OUT Endpoint(エンドポイント番号 02) です。
計4個のパケットが送出されました(省略部分は全て 00 です)。0x1bバイト(2行目の右から5個目)の0x03がHIDのレボート番号、そこから64byteがレボートの内容です。

0000   1b 00 60 80 9d c6 03 d5 ff ff 00 00 00 00 09 00
0010   00 03 00 01 00 02 01 41 00 00 00 03 a1 01 00 00
...
0050   00 00 00 00 00 00 00 00 00 00 00 00

0000   1b 00 60 80 9d c6 03 d5 ff ff 00 00 00 00 09 00
0010   00 03 00 01 00 02 01 41 00 00 00 03 05 11 01 00
...
0050   00 00 00 00 00 00 00 00 00 00 00 00

0000   1b 00 60 80 9d c6 03 d5 ff ff 00 00 00 00 09 00
0010   00 03 00 01 00 02 01 41 00 00 00 03 05 11 01 01
0020   00 22 00 00 00 00 00 00 00 00 00 00 00 00 00 00
...
0050   00 00 00 00 00 00 00 00 00 00 00 00

0000   1b 00 00 cb 28 c2 03 d5 ff ff 00 00 00 00 09 00
0010   00 03 00 01 00 02 01 41 00 00 00 03 aa aa 00 00
...
0050   00 00 00 00 00 00 00 00 00 00 00 00

共通する 0x03 はHID Reportの番号です。続く部分は以下の通り。

最初に 0xa1 に続けてレイヤー番号 (ここでは0x01)を送り、次に割り当てたいキーの数+1個のパケットで「キー番号(1byte)・0x11・長さ(0x01)・インデックス(0〜1)・修飾キー(0x00)・スキャンコード(1byte・最初は必ず0x00)」を送り、最後に 0xaa 0xaa を送れば良いようです。


あとは、これを適当に libusb で実装するだけ。今回作ったソースコードこちらです。複数キーは用途を思いつかなかったので対応していません。
github.com

事前に libusb-1.0 をインストールしておく必要があります。(Macなら brew intall libusb、Linuxなら apt install libusb-1.0-0-dev とか dnf install libusb1-devel 等で1.0系のものが入るでしょう。0.1系と間違えないように注意)
使い方は、makeでビルドし、引数で設定内容を与えます。

sudo ./usb-12key-kbd-prog レイヤー番号(1-3) キー番号(キーは1〜12、ノブは左回転・押し込み・右回転の順で13〜15と16〜18) 送信したいキー名 修飾キー名

を指定します。例えば上記のようにレイヤー1の真ん中のキーに数字の5を割り当てるなら

sudo ./usb-12key-kbd-prog 1 5 5

です。レイヤー2の上のノブ右回転に左シフトキー + 音量upを割り当てるなら

sudo ./usb-12key-kbd-prog 2 15 volumeup lshift

という感じです。キーの一覧は scancode.c の中を見てください。なおスキャンコードの数値を #12 のように指定することもできます。

*1:一旦設定さえしてしまえばツールがなくてもキー割当はデバイスが記憶してくれるのですが

*2:Googleドライブのマニュアルに各キーに対応する番号が載っています。