Arduino Leonardoを使うと簡単に接続されたパソコンにキー入力を行うことができます。
たとえば、Keyboard.h
をincludeしたプロジェクトで
Keyboard.print("Hello!");
と書けば、パソコン側に"Hello!"と入力されます。
このように、"a"とプログラム上で書けばちゃんと"Aのキー"が押下されるのは、利用しているKeyboardプログラムが1ASCIIコードから2スキャンコードに変換してくれているからです。
この機能は大変便利なのですが問題があって、定義されていないキーは入力できない(Print Screenとか)のと、JIS環境では一部記号の入力がおかしいことです。(変換テーブルがUS配列用のため)
なので、時には直接スキャンコードを使って入力したいことがあるはずです。
ここで書くのはそんな方法。
Arduino IDEからKeyboardプログラムを取り出す
Arduino IDEに入っているKeyboardプログラムを書き換えるのですが、そのまま書き換えて他のプロジェクトとかに影響あったらダメなので、現在のプロジェクトにコピーしてからそいつを編集します。
Keyboardプログラムは"Keyboard.cpp"と"Keyboard.h"の2つのファイルです。
Macなら"Arduino.app"を右クリックして"パッケージの内容を表示"を選択、あとは"Contents"→"Java"→"libraries"→"Keyboard"→"src"と辿っていけば見つけられるはずです。
Windowsの場合、Arduino公式サイトからダウンロードできるインストール不要のZIPファイルであれば"arduino.exe"と同じ場所に"libraries"フォルダがあるので、その中を"Keyboard"→"src"と辿っていけばあります。
インストーラーとかストアからインストールした場合はパス調べてないのでわからないです。探せばあると思いますが、わからない人は公式からインストール不要版をダウンロードした方がいいと思います。
"Windows ZIP file for non admin install"ってやつです。
2つのファイルを見つけられたら下の画像みたいな感じでプロジェクトのディレクトリにコピーしてください。
Keyboardプログラムを書き換える
2つのファイルをコピーした状態でinoファイルを開くと、Keyboard.cppとKeyboard.hがタブで選べるようになってるはずです。なので、ここで書き換えて行きましょう。
Keyboard.cpp
まずはKeyboard.cppです。これを見ると、Keyboard_::press関数とKeyboard_::release関数にある
if (k >= 136) { // it's a non-printing key (not a modifier)
k = k - 136;
} else if (k >= 128) { // it's a modifier key
_keyReport.modifiers &= ~(1<<(k-128));
k = 0;
} else { // it's a printing key
k = pgm_read_byte(_asciimap + k);
if (!k) {
return 0;
}
if (k & 0x80) { // it's a capital letter or other character reached with shift
_keyReport.modifiers &= ~(0x02); // the left shift modifier
k &= 0x7F;
}
}
この部分でASCIIコードからスキャンコードに変換していることは一目瞭然ですね。なので、これを抜いたKeyboard_::pressRaw関数とKeyboard_::releaseRaw関数を書き加えましょう。
あと、それだけだと修飾キーが使えなくなるので、修飾キーを指定する引数mも追加しておきましょう。
size_t Keyboard_::pressRaw(uint8_t k, uint8_t m)
{
uint8_t i;
// Add k to the key report only if it's not already present
// and if there is an empty slot.
if (_keyReport.keys[0] != k && _keyReport.keys[1] != k &&
_keyReport.keys[2] != k && _keyReport.keys[3] != k &&
_keyReport.keys[4] != k && _keyReport.keys[5] != k) {
for (i=0; i<6; i++) {
if (_keyReport.keys[i] == 0x00) {
_keyReport.keys[i] = k;
break;
}
}
if (i == 6) {
setWriteError();
return 0;
}
}
_keyReport.modifiers |= m;
sendReport(&_keyReport);
return 1;
}
size_t Keyboard_::releaseRaw(uint8_t k, uint8_t m)
{
uint8_t i;
// Test the key report to see if k is present. Clear it if it exists.
// Check all positions in case the key is present more than once (which it shouldn't be)
for (i=0; i<6; i++) {
if (0 != k && _keyReport.keys[i] == k) {
_keyReport.keys[i] = 0x00;
}
}
_keyReport.modifiers &= ~m;
sendReport(&_keyReport);
return 1;
}
あとはKeyboard_::writeRaw関数もあったら便利ですね。付け加えておきましょう。
size_t Keyboard_::writeRaw(uint8_t c, uint8_t m)
{
uint8_t p = pressRaw(c, m); // Keydown
releaseRaw(c, m); // Keyup
return p; // just return the result of press() since release() almost always returns 1
}
Keyboard.h
スキャンコードでキー入力を行う関数は実装できましたが、ヘッダーファイルに追加した関数を記述してないのでまだ呼び出せません。なので、Keyboard.hの下の方のpublic:ってところに新しく定義した関数を追加しておきましょう。
// --省略--
class Keyboard_ : public Print
{
private:
KeyReport _keyReport;
void sendReport(KeyReport* keys);
public:
Keyboard_(void);
void begin(void);
void end(void);
size_t write(uint8_t k);
size_t writeRaw(uint8_t k, uint8_t m = 0);
size_t press(uint8_t k);
size_t pressRaw(uint8_t k, uint8_t m = 0);
size_t release(uint8_t k);
size_t releaseRaw(uint8_t k, uint8_t m = 0);
void releaseAll(void);
};
extern Keyboard_ Keyboard;
#endif
#endif
あと、そのままだと修飾キーの指定が面倒なので、#defineが並んでる一番下あたりに修飾キー用のマクロを定義しておきます。
#define MODIFIER_LEFT_CTRL 0b00000001
#define MODIFIER_LEFT_SHIFT 0b00000010
#define MODIFIER_LEFT_ALT 0b00000100
#define MODIFIER_LEFT_GUI 0b00001000
#define MODIFIER_RIGHT_CTRL 0b00010000
#define MODIFIER_RIGHT_SHIFT 0b00100000
#define MODIFIER_RIGHT_ALT 0b01000000
#define MODIFIER_RIGHT_GUI 0b10000000
使い方
includeは
#include "Keyboard.h"
で大丈夫です。
元々定義してある関数は変更してないので、アルファベット入力する際はそっち使えばいいです。
USBキーボードのキーコード
このサイトでスキャンコードが調べられるので、調べたスキャンコードをKeyboard.writeRaw関数、もしくはKeyboard.pressRaw関数とKeyboard.releaseRawに渡します。
例えば、Print Screenは0x46なので、
Keyboard.writeRaw(0x46);
で入力できます。
修飾キーは第2引数に指定するので、例えばAlt+Print Screenを入力したいときは
Keyboard.writeRaw(0x46, MODIFIER_LEFT_ALT);
とすればいいでしょう。
Ctrl+Alt+Deleteなら
Keyboard.writeRaw(0x4c, MODIFIER_LEFT_CTRL | MODIFIER_LEFT_ALT);
ですね。
Keyboard.write('\\');
ではJIS環境で入力できなかったバックスラッシュも、
Keyboard.writeRaw(0x89);
と書けば入力できます。
押しっぱなしにしたいときはKeyboard.pressRaw、それを解除したいときはKeyboard.releaseRawであり、キーの指定方法はKeyboard.writeRawと同じです。