安価なUSB HIDを作りたい
というわけでとりあえず、マクロパッドを入手した。
aliexpressで900円だった。https://ja.aliexpress.com/item/1005005419376722.html
Windowsにぶっ刺してみる。ポピン! cccccccccccccccccccccccc
どのキーを押しても、ノブを回しても、ノブを押し込んでも 「c」が入力される。なんじゃこりゃ。
→ そういう仕様らしい。アプリでキーアサインしてねということらしい
Windows-X M でデバイスマネージャを見てみる。「HIDキーボードデバイス」×2として認識している模様。
「接続別」で見てみると、Composite Device の下に5個もぶら下がっていた。
インタフェースが4つ。それぞれのエンドポイントが1つずつ (EP1IN/IF0、EP2OUT/IF1、EP3IN/IF2、EP2IN/IF3)。なんかへんだけど、まあそういうものなのかな。
商品ページを見ると、「https://drive.google.com/drive/folders/1xqFDp-l5TVA_6Ojsn0rt7GqvF5EvWDCi からアプリをダウンロードせよ」とある。いや、Firmwareが欲しいんだよな……ソースはなさそうだよな……。
安価なUSBデバイスといえば、おそらく中身はCH552だろう、と思いつつ、開腹してみた。
予想通り、CH552Gだった。
パターンを追いかけて回路図を起こしてみた。
USBコネクタのCC1とCC2がNot Connectedなので、USB-C/USB-Cケーブルだと使えない (規格上、給電されない)。試してみたらやっぱり使えなかった。5kΩの抵抗2本を加えてGNDにプルダウンしておくと給電されるので使えるようになるはず。
オープンになっているR12を短絡して、USBのD+に接続した状態でUSBケーブルを接続すれば、CH552GのDFUモードに入れるのだと思う。R10が実装されているのはなんでだろう……ここもオープンにしてコストを抑えてもよさそうなのに。回路を読み間違えているのだろうか。
正解。R12を短絡した状態でUSB接続したら、Burning Tool の Search Devices で一覧に出てきた。
CH552Gのメーカーページから、WCHISPTool_Setup_exe (Burning Tool) をダウンロードできる:
USB通信をのぞき見してみたい。 Wireshark + USBPcapをインストールする。Windows11Pro22H2を使っている。
USB HID キーコード一覧。例えば「Aち」は0x04。
WebHID で叩いてみる:
await navigator.hid.requestDevice({filters: [{vendorId: 0x1189, productId: 0x8890}]})
await navigator.hid.requestDevice({filters: [{vendorId: 0x1189}]})
アプリをダウンロードして、Wiresharkしつつ、アプリからキーアサインを設定してみた。
「HID準拠ベンダー定義デバイス」あてに Output Report 0x03 を何枚か連続して送るみたい。
Key1に「ab」を設定した場合:
03 a1 01 # これから送るよー
03 01 11 02 # 03 Key Device Qty
03 01 11 02 01 00 04 # 03 Key Device Qty Nth Mod Keycode
03 01 11 02 02 00 05 # 03 Key Device Qty Nth Mod Keycode
03 aa aa # おわり
3行目の説明
- Key: Key1~Key12=01~0c, ダイヤル1左/押/右=0d/0e/0f、ダイヤル2左/押/右=10/11/12、ダイヤル3左/押/右=13,14,15
- Device: 上位バイトがLayerで0x10~0x30、下位バイトがデバイスで Keyboard=01
- キーボードの場合(5アクションまで設定できる)
- Qty はそのキーに格納したキーコード配列の長さ
- Nth はキーコード配列の添え字
- Mod はモディファイヤ、なし=00、Ctrl=01、Alt=04、Shift=02、Win=08、右Ctrl=10、右Alt=40、右Shift=20、右Win=80
- Keycode は USB HID キーコード(Keyboard/Keypad Page (0x07))
Key1に「Play/Pause(マルチメディア操作)」を設定した場合
03 a1 01 # これから送るよー
03 01 12 cd # 03 Key Device Action
03 aa aa # おわり
- Device: 上位バイトがLayerで0x10~0x30、下位バイトがデバイスで multimedia=02
- Actionとして、Consumer Page (0x0C)
- Play/Pauseがcd、nextがb5、Prevがb6、Vol+がe9、Vol-がea、Muteがe2
Key1に「Mouse Left Button」を設定した場合
03 a1 01 # これから送るよー
03 01 13 01 # 03 Key Device Action
03 aa aa # おわり
- Device: 上位バイトがLayerで0x10~0x30、下位バイトがデバイスで Mouse=03
- Actionとして、Button Page (0x09)
- Leftが01、Rightが03、Centerが04
- Wheel Upを割り当てたときは、03 01 13 00 00 00 01
- Wheel Dnを割り当てたときは、03 01 13 00 00 00 ff
- Wheel Dn + Shiftを割り当てたときは、03 01 13 00 00 00 ff 02
- Actionの2バイト目以降の00 00 00 あたり、アプリでいろいろ設定しても変化しないのでよくわからない。
LED Mode01を設定した場合
03 a1 01 # これから送るよー
03 b0 18 01 # 03 Key Device Action
03 aa aa # おわり
- KeyとDeviceが b0 ?8 固定
- ActionがLED Modeで、オフ=0、固定Blink=01、流れる=02
WebHID経由で自由にOutput Report を送れるので試してみた。
手順
- https://nondebug.github.io/webhid-explorer/ を開く
- 念のため別タブで chrome://device-log/?refresh=1 を開いておく
- Connect を押して、1189:8890 (=今回使っているマクロパッド) を選択する
- Connect右側のドロップダウンに選択肢が4つ追加されるので、矢印キーで選び、Device Info で
Usage: FF00:0001 (Vendor-defined page 0xFF00 usage 0x0001)
となっているものを選ぶ - Output Report 欄に
03 b0 18 01
と入力して SEND を押す → LEDがMode1(Blink)になる - Output Report 欄に
03 b0 18 02
と入力して SEND を押す → LEDがMode2(NightRider)になる - Output Report 欄に
03 01 13 00 01
と入力して SEND を押す → Key1がマウス右移動になる
Mouse の謎パラメータが判明した:
03 01 13 Button dX dY Wheel Modifier
同じことをやっている人を発見した:
CH552Gを使ったマクロパッドのファームウエアを見つけた。参考になる。
Output Report 03 を受け取るロジックを見つけられていない。どこだろう。
https://github.com/wagiminator/CH552-MacroPad-plus/blob/main/software/src/usb_hid.c#L67-L68 ここかな? 未実装なのかな?
REMAP(VIAプロトコル)に対応しているCH552なキーボード、ただしマウスキーなどの対応がされていない模様。
ビルドしてみた。
CH552Gは Flash 16kb, RAMが1280(1k+256), DataFlashが128で、
USB Setting: USER CODE w/ 148B ram とのことなので、
最大14336バイトのフラッシュメモリのうち、スケッチが6569バイト(45%)を使っています。
最大876バイトのRAMのうち、グローバル変数が127バイト(14%)を使っていて、ローカル変数で749バイト使うことができます。
インタフェースが1つ、エンドポイントが2つ (EP1IN, EP1OUT)、レポートが一つに「キーボード+ベンダー定義+マウス」が収容されている。
USB Device Tree Viewer で見てみた。
String Descriptor #2 が返ってきてない……。なんでだ……。
間違いを発見。0x16じゃなくて0x1cにしたら動いた。あとで報告しておこう。
レポートを見ようと思ったけど、USB Device Tree Viewer見られなかった。
Wiresharkで見ようと思ったら、URB_FUNCTION_ABORT_PIPE が出ている。なんだろう。
とりあえず劣後してレポートを見てみる。ふむ。1枚のレポートにUsageが3つ入ってるのね。なるほど。
Macropadの方のレポートはこんな感じになってる。4枚返している。
1枚目:
2枚目:
3枚目:
4枚目:
https://github.com/yswallow/CH552duinoKeyboard に https://usevia.app/ でキー設定を流し込んでみようと、こんなjsonを書いてみた。
jsonの読み込みはできたんだけど、authorize Device で「Failed to write the report.」というエラーに阻まれる。
{
"name": "CH55xduinokbd",
"vendorId": "0x1209",
"productId": "0xC55D",
"lighting": "qmk_rgblight",
"matrix": { "rows": 1, "cols": 5 },
"layouts": { "keymap": [ ["0,0","0,1","0,2",{"x":0.5},"0,3","0,4"] ] }
}
F12でChromeのDeveloper Console を開いて sendReport(0,data)
にブレークポイントを置いて待ち構えたら、DOMException: Failed to write the report.
というのを捕まえた。
Console.dir(r) してみたら、こんな感じ:
DOMException: Failed to write the report.
code: 0
message: "Failed to write the report."
name: "NotAllowedError"
[[Prototype]]: DOMException
なんで?
MDN https://developer.mozilla.org/ja/docs/Web/API/HIDDevice/sendReport
仕様 https://wicg.github.io/webhid/#dom-hiddevice-sendreport
If this report is a blocked report, ...... reject promise with a "NotAllowedError"
ブロックリスト https://github.com/WICG/webhid/blob/main/blocklist.txt
送信先は vendor:0x1209, product:0xc55d, usagePage:0xff60, usage: 0x61, reportId:0x08 なので、これに引っかかってるわけではないんだけどなぁ……。
ん、なんだこれ。
WebHID blocks access to any input, output, or feature reports defined in a top-level HID collection with IDs that would allow the device to be treated as a mouse or keyboard input.
同じコレクション内に、ブロックリストに該当するレポートがあるとダメなのか?
https://nondebug.github.io/webhid-explorer/ で、同じように Output Report で 00 01
を送ってみたら、同じように阻まれた。
デバイスログ: chrome://device-log/ には Invalid output report ID
HID Transter Failed
が出てる。via-appで失敗したときと同じメッセージだ。
ということは……?
- オリジナルのFirmwareのときは webhid-explorer で送信できた。
- Firmwareを CH552duinoKeyboard にしたら、webhid-explorer で送信できなくなった。
Collectionの木構造が異なっているのが気になる。
CH552duinoKeyboardのHID Descriptorを、
いまの「ひとつのCollectionに、キーボード/マウス/ベンダ準拠デバイスがぶら下がる」から、「Collectionが3つあり、キーボード/マウス/ベンダ準拠デバイスがそれぞれにぶら下がる」形に変えてみてやってみよう。
ん? まてよ!? Output Report で 08 01 00{31}
を送ってみたら、送れた。
TypeError DOMException じゃないのか……。
まあでもVIAでエラーが出るのは将来的には回避しないといけないから、まずはCollectionの形を変えてみることにしよう。
レポートサイズが期待と異なる場合でも同様のエラーが出るっぽい記事も見つけたのでURLをメモっておく。
なんだこれ、いい商売だなぁ。900円⇒3980円。うらやましい。