Surface Dialを2個以上接続していたとしても、正規のAPIからアクセスするといくつあっても1個にしか見えないのは周知の事実です。じゃぁどうにかして、2個認識できないのかなぁ…ということでやってみました。
2019/3/31: 今見返してみたら、3バイト目から2バイトが符号付で回転角やん…本文は修正済みです。
TL;DR
- 通常のAPIからは1個しかみえないが、HIDデバイスなので直接読めば読める
- VID:045E, PID: 091B, UsagePage: 0001, Usage: 000Eを読めば生データ見える
- 生データの2バイト目の下位1bitが押し下げフラグ、3バイト目から2バイトが回転量(signed)
デバイス構成
これを見ると、HID over GATTで5種類のデバイスが見えていて、UsagePage, Usageは次の通り
UsagePage | Usage |
---|---|
0001 | 0080 |
0001 | 000E |
0001 | 0072 |
FF07 | 0070 |
FF07 | 0071 |
一番上はWinRTでブロックされているUsageなので今回は省略。ほかの4つは特にWinRTでブロックされてない(!!)のでアクセスしてみたところ、返事が返ってきたのは2個目のやつでした。
とりあえずアクセス
public MainPage() { this.InitializeComponent(); Loaded += async (sender, args) => { var d2 = await GetAsync(0x0001, 0x000E); d2.InputReportReceived += D2_InputReportReceived; }; } private void D2_InputReportReceived(HidDevice sender, HidInputReportReceivedEventArgs args) { var dump = string.Join(" ", args.Report.Data.ToArray().Select(b => $"{b:X2}")); Debug.WriteLine($"D2: {dump}"); } async Task<HidDevice> GetAsync(ushort up, ushort uid) { var str = HidDevice.GetDeviceSelector(up, uid);//, 0x045E, 0x091B); var devices = (await DeviceInformation.FindAllAsync(str)).ToArray(); return await HidDevice.FromIdAsync(devices[0].Id, FileAccessMode.Read); }
こんなの書いて、ダイアルを回したり押したりするとこんなダンプがデバッグ出力で得られます。
D2: 01 02 02 00 0A 0B 0C 0D 3A D2: 01 02 03 00 0A 0B 0C 0D 3A D2: 01 02 02 00 0A 0B 0C 0D 3A D2: 01 02 FF FF 0A 0B 0C 0D 3A D2: 01 02 FF FF 0A 0B 0C 0D 3A D2: 01 02 FE FF 0A 0B 0C 0D 3A D2: 01 02 FF FF 0A 0B 0C 0D 3A D2: 01 02 FD FF 0A 0B 0C 0D 3A D2: 01 02 FD FF 0A 0B 0C 0D 3A D2: 01 02 FD FF 0A 0B 0C 0D 3A D2: 01 02 FC FF 0A 0B 0C 0D 3A D2: 01 02 FB FF 0A 0B 0C 0D 3A
解析結果
このバイナリの中身をよく見てるとだいたいこんな構造みたい。
struct Report{ byte One; byte Flags; short Degree; byte[5] Nazo; }
2バイト目のFlagsとして名前を付けてみたところは、ビットフィールドになっているようでそれぞれ次の意味っぽい。
ビット | 意味 |
---|---|
1ビット目 | 押し下げ状態。1で押してる状態 |
2ビット目 | 回転中? |
3バイト目から2バイトは符号付の値のようで、右回転で正の値、左回転で負の値になってる感じ。WinRTのデフォルトより元気で1度ごとにレポートがきます。
で、のこった5バイトはよくわからん。
まとめ
SOUND VOLTEXごっこできそうですね!