DigisparkをUSBキーボードにして一発入力させてみた

あらかじめセットしておいた動作をボタン一つで**ブワァァアア**って実行してくれるキーボード(プログラマブルキーボードというそうですね)をDigisparkを用いて自作した際に多少ハマった点があったので，書き残しておきたいと思います．
#環境
 - Arduino IDE 1.8.4
 - 中華Digispark

キーボードの動作はUSB2.0ポートを搭載したWindows8.1マシンで確認しています．
#Digisparkとは
Digisparkはとっても小さくて安くて(性能が)カワイイ，Arduino互換ボードです．
開発環境の準備からLチカ，自動入力まではこちらの記事がとても参考になります．

[DigiSparkでボタン入力を受け付けてPCにキー入力するまで](https://qiita.com/mascii/items/569e8a28a0b12d4d530e)
#ハマった点
###使用するピンについて
Didisparkには0番から5番まで計6本のGPIOピンが用意されていますが，USB機器として使用する場合は通信のため3,4番ピンが使用できなくなります．またLEDが1番ピン(世代が古いと0番)につながっています．

じゃあ残った0,2,5にスイッチをつないで，押されたら1ピンのLED光らせちゃおうかな！！と思ったのですが，**モノによっては5番ピンもUSB接続で潰れる**ようです．

ですので**入出力に安定して使えるピンは0,1,2番だけ**となります(僕は3つキーがほしかったのでLEDはあきらめました)．
###sendKeyStroke()の引数について
Digisparkにキーを出力させる時に使う`sendKeyStroke()`関数ですが，引数は

 - 第一引数：押したいキー
 - 第二引数：同時押ししたいキー(省略可)

です．ハマりポイントですが，**実際にキーを操作するときの操作順は関係ありません．**

```c
//Enterキーを押したことにする
DigiKeyboard.sendKeyStroke(KEY_ENTER);

//Alt + Enter(プロパティを表示)
DigiKeyboard.sendKeyStroke(KEY_ENTER, MOD_ALT_LEFT);

//N + Ctrl + Shift(フォルダの新規作成)
DigiKeyboard.sendKeyStroke(KEY_N, MOD_CONTROL_LEFT | MOD_SHIFT_LEFT);
```
`sendKeyStroke()`関数は指定されたキーの「押して離す(短押し)」を出力します．
長押ししたい場合は`sendKeyPress()`を使い，思う存分押してから`sendKeyPress(0,0)`で離します．

###キーの指定について
先ほどキーを`KEY_ENTER`とか`MOD_SHIFT_LEFT`で指定しましたが，本来キーはIDで指定されるべきものです．これを使いやすいように，`DigiKeyboard.h`ファイルでIDごとに定義してあります．

ただしヘッダファイルで定義されていないキーもありますので，それらはスケッチの冒頭で，**自分で定義する必要があります．**

```c
#define KEY_ESCAPE 0x29    //EscキーのIDを定義しています
#define KEY_TAB 0x2B       //Tabキー
#define KEY_ZENHAN 0x35    //全角半角キー
```
[DigiKeyboard.h](https://github.com/digistump/DigisparkArduinoIntegration/blob/master/libraries/DigisparkKeyboard/DigiKeyboard.h) を見てみて，ご所望のキーが見当たらなければ未定義です．

キーのIDは，usb.orgの公式リファレンスの53ページから始まる表を参照してください．
[Universal Serial Bus HID Usage Tables](https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf)
**Usage ID(Hex)**がそれにあたりますので`0x`のあとにそのIDを続けてください．十進数がお好みであれば**Usage ID(Dec)**をそのまま記述しても構いません．

**2020/3/15追記**
USB.orgのサイトリニューアルにつきリンクが切れていたので修正しました

###利用可能な文字について
Hello!と自動入力させたい場合に，1キーづつ`sendKeyStroke()`はしないですよね．
この場合は`print()`関数や`println()`関数の方が便利なわけですが，ここで問題になるのが**USキーボードと日本語キーボードのレイアウトの差**です．以下のスケッチを書き込んだとします．

```c
#include "DigiKeyboard.h"
void setup() {
}
void loop() {
  DigiKeyboard.sendKeyStroke(0);
  DigiKeyboard.print("https://");
  DigiKeyboard.delay(5000);
}
```
日本語キーボードを搭載したPCでDigisparkがこれを実行すると，実行結果は
https+//
となってしまいます．あれっ！？コロンはどこに行ったんや！！

実はキーボードレイアウトの差(USキーボードで:がある位置に日本語キーボードでは+があるなど)により，一部の記号はそのままでは正しく入力できません．僕が考えた解決策としては**あらかじめ誤作動を見越して置換しておく**というのがお手軽かと思います．

記号を入力させたい場合は，必要に応じて以下のように置換してください．
置換の必要がないものや，エスケープシーケンスが必要なものもありますね．
![kigou_okikae_large.gif](https://qiita-image-store.s3.amazonaws.com/0/284083/dcbda77a-1df5-21b5-ab40-d8b66db6b869.gif)

これを用いてやり直すと，先ほどのスケッチはこうなります．

```c
DigiKeyboard.print("https\'//");
```
そして上の置換表を眺めているとあることに気が付きます．それは**￥もとい\と，_と，|は置換できない**という点です．「円マーク」「バックスラッシュ」「アンダーバー」「あとこのなんかよくわかんないけどよく使う縦棒」はUSキーボードでその位置にキーが存在しない=置換のしようがない~~=自動入力できないのです(これは痛い)~~．

**2018.8.29追記：ヘッダファイルをいじったら解決できました．**
解決法に関する記事を書きましたのでこちらを参照してください．
[DigiKeyboardが日本語キーボード搭載PCで記号を正しく出力しない問題を解決する](https://qiita.com/Toramin10/items/c1f63c51568ed00ed741)

#DigiKeyboardあれこれ
そのほか，ハマってないけどふぅーんと思った点もあったので参考までに書きます．
###sendKeyStroke(0);って何よ
入力の始めにいつもあるこいつは何かと思ったら
>this is generally not necessary but with some older systems it seems to
 prevent missing the first character after a delay
(スケッチ例Keyboard.inoより引用)

とのことで，文字の欠落を抑えるためにダミーのキー操作を出力させているようです．
###普通のdelayじゃダメなの
`DigiKeyboard.delay()`って長くて面倒だなと思ったのですが，

>It's better to use DigiKeyboard.delay() over the regular Arduino delay() 
  if doing keyboard stuff because it keeps talking to the computer to make
   sure the computer knows the keyboard is alive and connected
(スケッチ例Keyboard.inoより引用)

とのことで，PCにキーボード接続死んだ？と思わせないように必要みたいですね．

#まとめ
このように，新興ボードとあってまだまだ資料も少なくすこーし面倒なところもありますが，Digisparkは小さいながら遊べるヤツだと思います．

製造元のWikiも参考になるのでリンクを貼っておきます．
http://digistump.com/wiki/digispark