6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Arduino Leonardoでスキャンコードを指定してキー入力

Posted at

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つのファイルを見つけられたら下の画像みたいな感じでプロジェクトのディレクトリにコピーしてください。
スクリーンショット 2018-09-04 23.37.52.png

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:ってところに新しく定義した関数を追加しておきましょう。

Keyboard.h
// --省略--

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と同じです。

  1. 半角のアルファベット大文字・アルファベット小文字・数字・記号の"文字"に割り当てられたコード

  2. キーボード上にあるそれぞれの"キー"に割り当てられたコード。USBキーボードはこいつをパソコンに送っている

6
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?