同時押したくさんできるキーボード作ろうとした話

 3年前くらいに作ろうとしたときのおぼろげな知識を書いておく(あんま日本語の記事がないので)。

導入

 普通のUSB HIDキーボードは同時に6個までしか押せない。これを一般に6キーロールオーバーと呼び、制限がないものをNキーロールオーバー(NKRO)と言う。6個までしか押せない理由はBIOSの問題とかいろいろあるらしい。

Report Descriptorについて

 紹介する前にReport Descriptorについて話す必要がある。Report Descriptorとは、HIDデバイスがやりとりするデータのフォーマットを定義するもの。つまり、これを都合よく書き換えればNKROを実現できるというわけ。

普通のキーボードのReport Descriptor

 まずは6キーロールオーバーの一般のキーボードのReport Descriptorについて軽く解説する。コードはUSB.orgのHID1.11から。というか多分これ全部日本語訳したほうが理解しやすい気がする。

HID1.11 ---https://www.usb.org/sites/default/files/hid1_11.pdf

Usage Page (Generic Desktop),
Usage (Keyboard),
Collection (Application),
 Report Size (1),
 Report Count (8),
 Usage Page (Key Codes),
 Usage Minimum (224),
 Usage Maximum (231),
 Logical Minimum (0),
 Logical Maximum (1),
 Input (Data, Variable, Absolute), ;Modifier byte
 Report Count (1),
 Report Size (8),
 Input (Constant), ;Reserved byte
 Report Count (5),
 Report Size (1),
 Usage Page (LEDs),
 Usage Minimum (1),
 Usage Maximum (5),
 Output (Data, Variable, Absolute), ;LED report
 Report Count (1),
 Report Size (3),
 Output (Constant), ;LED report padding
 Report Count (6),
 Report Size (8),
 Logical Minimum (0),
 Logical Maximum(255),
 Usage Page (Key Codes),
 Usage Minimum (0),
 Usage Maximum (255),
 Input (Data, Array),
End Collection

 これだけ見てもよくわからんと思うので順番に。
最初はあまり話に関係ないので軽く説明付け足しただけで。

Usage Page (Generic Desktop), //最初に必要
Usage (Keyboard),        //デバイスを指定
Collection (Application),   //入力開始!

修飾(Modifier)キー

 その次にあるのは修飾キーの情報です。Inputと書かれているとこで情報が区切られています。

 Report Size (1),                  //データのサイズが1bit
 Report Count (8),                 //個数は8個
 Usage Page (Key Codes),           //キーコード送るよ
 Usage Minimum (224),              //使うキーはUsageID(224)=LeftControlから
 Usage Maximum (231),              //UsageID(231)=RightGUI(メニューキー)まで
 Logical Minimum (0),              //実際に送るデータは0から
 Logical Maximum (1),              //1まで
 Input (Data, Variable, Absolute), //変数の絶対値のデータを送信するよ

上から順番に出てきた名前を順番に説明。

  • Report Size/Count ・・・データのサイズ/個数を指定

  • Usage Page ・・・データの種類を指定

  • Usage Minimum/Maximum ・・・データが表すものの始点/終点を表す

  • Logical Minimum/Maximim ・・・実際にデータが報告する値の下限/上限

  • Input ・・・データを入力する(出力するならOutputになる)

以上のように4つの情報指定と入力/出力の組み合わせでできている。これを上のものに当てはめると、
 データのサイズは各1bit × 8個 = 合計8bitで、
 キーコードを扱って、
 そのキーコードはLeftControlからRightGUI(メニューキー)まで、
 データの値は0から1で
 変数の絶対値で入力する
という感じになる。Usage Minimum/Maximumについて一体どこからそうなったのって思うかもしれないが、下の画像のようにUsage IDに対して各キーが指定されていて、USB.orgにまとめた表があるので、これでいい感じに当てる。

HID Usage Table ---https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf

以上の修飾キーの情報を画像で表すとこうなる。各bitがキーの状態を示し、0のときは入力なしで、1のときは入力ありを意味する。

普通のキー

 LEDの部分は飛ばして、次にAとかBとか普通のキーの情報(書かれている順番がさっきと違うけど問題ない)。

 Report Count (6),       //6個
 Report Size (8),        //8bit
 Logical Minimum (0),    //キーコード全部
 Logical Maximum(255),   //
 Usage Page (Key Codes), //キーコード
 Usage Minimum (0),      //キーコード全部
 Usage Maximum (255),    //
 Input (Data, Array),    //配列でデータ送信

今回送るデータは配列で、さっきの絶対値とは異なっている。これは
各8bit x 6個の配列にUsage IDを入れて送信するようになっている。例として、"a"を入力したいなら{4, 0, 0, 0, 0, 0}を送信する、"abc"を入力したいなら{4, 5, 6, 0, 0, 0}を送信する。これが、同時に送ることのできるキーは6個までである原因である。それならば、この配列の長さを長くしてしまえばよい。

方法1:配列を長くする

 配列を長くするには、Report Countを増やせばいいので、例として10個にするなら該当箇所を10に変えればよい。

 Report Count (10),
 Report Size (8),
 Logical Minimum (0),
 Logical Maximum(255),
 Usage Page (Key Codes),
 Usage Minimum (0),
 Usage Maximum (255),
 Input (Data, Array),

この方法でもある程度の長さまでは同時入力できる数を増やせるが、長くすれば長くするほど、送信するデータが膨大になってしまう。なので、たくさん同時入力したい人は次の方法を勧める。

方法2:Bitmapにする

 Bitmapって何???って感じだが、修飾キーの情報を指定したときみたいに、各キーの状態を1bitごとに表した変数でデータを送信するものだと思う(これの説明が検索してもででこないから確信はない)。
 修飾キーのやつを改変していく。例の表によるとキーボードに最低限必要そうなキーはUsage ID 0~83でこと足りそうなので、

 Report Size (1),
 Report Count (84),
 Usage Page (Key Codes),
 Usage Minimum (0),
 Usage Maximum (83),
 Logical Minimum (0),
 Logical Maximum (1),
 Input (Data, Variable, Absolute),

方法1では80bitで10文字だったのに対して、Bitmapだと84bitでほぼ全部表すことができた。この後、8で割り切れるよう(8 bit = 1byte)に空の容器を追加したりしなかったりする記事を見るが、どうやら自動的に補完してくるらしい(?)のでしないでおく。以上!!!!

もっと知りたい人へのURL



うろ覚えで調べながら書いたから、全然間違っている可能性あるし、noteでやる必要性全然ないことに途中で気づいた。


いいなと思ったら応援しよう!