manvaのエンジニアリング魂

エンジニアリング・ものづくり・DIYをもっと身近にするためのブログ。インスピレーションを刺激します。

Arduino IDEで日本語キーボードを使う方法

Arduino IDEで日本語キーボードを作ろうとしていたら,キーボードの仕様がいろいろわかりにくかったので、まとめておく。

Arduinoの仕様 ASCIIコード

まず,古く(1963年)からある仕様で,ASCIIコードというのがある。

ASCII - Wikipedia

128個(7ビット)の基本的なキーの番号が振られている。

Arduino IDEのKeyboard.press() などの関数で引数で渡すのはこの番号である。

ただ,今どきのキーボードでは、128個では足りないので、Ctrl,Shift,Alt,Windowsキー,カーソルキー,ファンクションキーなどが128番以降に追加されている。Arduino IDEでは、ASCII以外は↓のように定義されている。www.arduino.cc

 

 日本語キーボード対応方法

上記ページを見てみるとわかるが,Arduino IDEの標準機能では,日本語キーボードには対応しておらず,「¥」「全角/半角」など日本語特有のキーは使えなかったり,配置が違ったりする。

が,すでに解決してくれている人がいる。↓の記事にあるコードをコピーしてKeyboard_jp.hとKeyboard_jp.cppを作成し,Keybord.hの代わりにincludeするだけで,日本語キーボードとして使えるようになる。

mgt.blog.ss-blog.jp

 

 Windows側の設定

普段,英語キーボードを使っていた人は,上記でも,全角/半角キーで日本語に切替えられず,「`」になるなどの問題が起こるかもしれない。これはキーボード側のソフトの問題ではなく,Windows側で英語キーボードとして認識されているためだ。

↓に従ってレジストリをいじったら日本語キーボードとして使える。

Windows 8 でキーボードが英語配列キーボードとして認識されるsupport.microsoft.com

ただし,Windowsでは,複数のキーボードを接続した場合,日本語と英語の切換えは基本的にキーボードごとの設定ではなく,全てのキーボードで同じ設定になるようだ。下記記事↓によると、最近まではキーボードごとに設定できたようだが,追記として書かれているように,Windowsのアップデート後,できなくなっているっぽい。やってみたができなかった。

tyheeeee.hateblo.jp

 

ここまでで問題なければ終わりだが,何かうまくいかない場合やキーコードを追加したい場合などのために,もう少し踏み込んで整理しておく。

USBキーボードの仕様 Usage IDとModifier

最近のキーボードはUSBで繋ぐものが多く、USBの仕様の中にキーボードの仕様が含まれている。Pro MicroもUSBキーボードとして扱われる。USBキーボードでASCIIなどのコードに対応する値は、Usage IDという。

HID Usage Tables for Universal Serial Bus ↓ 10章の表にUsage IDがある。

https://usb.org/sites/default/files/hut1_22.pdf

Arduino IDE の Keyboard.press() などの関数も、結局はUsage IDに変換して送っている。

 Ctrl,Shift,Alt,Windowsキー(左右計8個)は,普通のキーとは別扱いになっており、Modifierと呼ばれる8ビット変数のビットがそれぞれに割り当てられている。

ASCIIコードは文字に対してコードが割り当てられていたが,Usage IDではキーボードのキーに対してコードが割り当てられている。例えばアルファベットのAは、ASCIIコードでは大文字と小文字に別のコードが割り当てられているが、USBキーボードではaのUsage ID+シフトキーのModifierビットとして送られる。

Keyboard.cppを読み解く ASCIIコードとUsage IDの対応

ASCIIコード(基本128個)とUsage IDの変換のマップが,標準のArduino IDEでは,

C:\Program Files (x86)\Arduino\libraries\Keyboard\src フォルダにある Keyboard.cpp の
const uint8_t _asciimap[128]
という配列で定義されている。例えば小文字のaのASCIIコードは97(0x61)なので、配列の98個目の値がaのUsage IDである0x04となっている。引数0から127は,この配列でUsage IDに書き換えて送信している。

引数128から135は、Arduino IDEのASCIIコード拡張でModifier(Ctrl,Shift,Alt,Windowsキー)と定義されており,Modifierのビットを立てて送信している。
引数136以上は単純に136差し引いてUsage IDとして送信している。つまり,ASCIIコードの136番以降にUSBキーボードのUsage IDをそのままの順で全部足したような仕様になっている。上記のKeyboard Modifiers - Arduino Referenceの表を確認すると,136以上のものは対応するUsage IDに136を足した値になっている。ということは,表にないものも,Usage IDに136を足した値を引数で渡せば使えるはずだ! ・・残念,引数がuint8_t型(8ビット)なので,255までしか渡せない。Usage IDで255-136=119 (0x77)までだと,バックスラッシュ(ひらがなの「ろ」のキー) など,日本語特有のキーKeyboard International1 (0x87-)に届かない。

 

Keyboard_jp.cppを読み解く 

上記記事の Keyboard_jp.cpp では,日本語キーボードに対応するために,以下の点を修正している。

  • 配列asciimapを日本語キーボードの配置に置き換え

前述のように,ASCIIコードは文字に対してコードが割り当てられるのに対し,Usage IDではキーに対してコードが割り当てられるため,この配列asciimapで対応関係を修正している。例えば 「&」の文字(ASCIIコード=38(0x26))は,USキーボードでは「7」のキー(Usage ID=0x24)のシフトで入力するが,日本語キーボードでは「6」のキー(Usage ID=0x23)のシフトで入力するので配列の39番目を0x23|SHIFTに変更している。

  • Modifierキーを248-255に移動
  • 引数128-247は0x58=88を引いてUsage IDとして送信

Keyboard_jp.hで定義されているキーコードは,Usage ID + 0x58(=88)になっている。足りないキーがあれば,Usage IDに88を足してここに定義しておけば良い。

Keyboard.cppで 136引いていたところを88に減らしている。これにより,128-88=40 (0x28)番 より前のUsage IDは使えなくなるが,Usage IDの始めの方は,ASCIIコードにもあるので問題ない。その分,後ろのUsage IDまで(247-88=159(0x9F)まで)使えるようになっている。それにより、日本語特有のキーもカバーできている。

 

ここまで理解すると,

  最初からUsage IDを引数にしたらよくね?

ということに気づく。

なぜArduino標準ではASCIIコードを引数にしたのだろう。ASCIIコードを丸暗記していてすぐに脳内変換できる,という人以外はメリットないと思われる。

Keyboard_jp.cpp では,抜かりなくKeyboard.pressRaw()等という関数を用意してくれていて,Usage IDを引数にしてKeyboard.press()等と同じことができるので,そちらを使うべきだろう。