まごころせいじつ堂

浜町庄金 研究開発  マイコンで遊んでばっかりで

キーボード

Arduinoで任意のUSBコードを送る 解決編

 Arduino Leonardo/MicroはUSBキーボードとして使えるが、Usageコードが101より大きいものは無視されるという問題があった。
PS/2キーボード変換器の製作(18) USBキーボードの無視されるキーについて
対策箇所はわかっていたが、当時はバイナリにパッチするという手段しか思いつかず強引にやっていた。
PS/2キーボード変換器の製作(19) HEXファイルにパッチを当てる
 この後、Arduino IDEのフォルダ内にあるソースをいじると反映されることを知った。Arduino IDEは毎回ソースから全部ビルドしてたのか!コアな部分はコンパイル済と勝手に思っていた。
Turning an Arduino Leonardo into a joystick.(Imarginary Industries)
 この記事ではUSBAPI.h、HID.cppを修正することによりジョイスティックのUSB-HIDを追加している。ということはArduino IDEにあるHID.cppのHID Report Descripterを修正することで日本語キーボードの機種で¥マークなどを入力できるようになるはずだ。
MacOSXだと修正対象のソースはContents/Resources/Java/hardware/arduino/cores/arduino/以下にある。
https://gist.github.com/houmei/2ad9f7a713f46149e72f

HID.cppを差し替え、ライブラリを組み込む。このライブラリはHID.cpp/USBAPI.hと一体化もできると思うが以前作ったのをそのまま流用しているのでこうなっている。

2014shot1
 これはDavinciにArduino Microのファームウェアを書き込んだもの。pin4にスイッチを付けてフリスクの大きめのケースに入れてみた。たったこれだけ。日本語キーボードがついてるものがWindowsXPの古いノートPCしかなかったのでそれに接続して¥マークが入力できることを確認した。

https://gist.github.com/houmei/0ac6873618caa02f22b4

 USBキーボードのUsageコードについては以下からどうぞ。注意点としてUSキーボードのレイアウトが基準。
USB HID to PS/2 Scan Code Translation Table

 ああ、これで数年悩んでた問題が解決だ。変なバイナリパッチ作った時点で誰も突っ込んでくれないのね。


 ついでにPrint ScreenのUsageコード(0x46)を設定して最近話題のエビデンス画面スクリーンショット用ボタンにしてみた。これでハードコピー取り放題よ。
2014shot2

 

ArduinoIDE1.0.3 USB-HID特に変わらず

やっと今日Arduino1.0.3のソースがダウンロードできたので、USB0-HIDのキーボード部分をチェックした。

// Keyboard
    0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)	// 47
    0x09, 0x06,                    // USAGE (Keyboard)
    0xa1, 0x01,                    // COLLECTION (Application)
    0x85, 0x02,                    //   REPORT_ID (2)
    0x05, 0x07,                    //   USAGE_PAGE (Keyboard)
   
	0x19, 0xe0,                    //   USAGE_MINIMUM (Keyboard LeftControl)
    0x29, 0xe7,                    //   USAGE_MAXIMUM (Keyboard Right GUI)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
    0x75, 0x01,                    //   REPORT_SIZE (1)
    
	0x95, 0x08,                    //   REPORT_COUNT (8)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x75, 0x08,                    //   REPORT_SIZE (8)
    0x81, 0x03,                    //   INPUT (Cnst,Var,Abs)
    
	0x95, 0x06,                    //   REPORT_COUNT (6)
    0x75, 0x08,                    //   REPORT_SIZE (8)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x25, 0x65,                    //   LOGICAL_MAXIMUM (101)
    0x05, 0x07,                    //   USAGE_PAGE (Keyboard)
    
	0x19, 0x00,                    //   USAGE_MINIMUM (Reserved (no event indicated))
    0x29, 0x65,                    //   USAGE_MAXIMUM (Keyboard Application)
    0x81, 0x00,                    //   INPUT (Data,Ary,Abs)
    0xc0,                          // END_COLLECTION

そんなわけで LOGICAL_MAXIMUM(101) 、USAGE_MAXIMUM(101) →0x65 で変わらず。
なんで毎回制限してんだろ?日本語キーボードなど国際化無視?
 

PS/2キーボード変換器の製作(18) USBキーボードの無視されるキーについて

正確にはArduino Leonardoで送信するキーのコードの一部が無視される現象について。

 WindowsXPで日本語キーボードが使える状態にして[¥]、[ろ]キーに対応するUsageコード0x89,0x87を送信する。普通の日本語キーボードでは期待通りの表示。だがArduino Leonardoから対応するコード0x89,0x87を送信しても無視される。この動作はUbuntu12.04をインストールした日本語キーボード接続のPCでも同様。
 USBlyzer というのを使ってパケットを監視してみた。これは有料だがお試し期間がある。
すると、日本語キーボードを接続したときは0x89を含むパケットにInternational3、0x87を含むパケットにInternational1の注釈がはいる。 しかしArduino Leonardoの場合は0x89、0x87とも注釈がApplicationとなっている。おなじキーボードデバイスなのに違う扱いを受けているようだ。どこかに違いがあるはずだが、ディスクリプタをよく理解していないので時間がかかりそう。キーボードに種別があるような記述は見つけていないし、ディスクリプタ中に現れるbCountrycodeは日本語キーボードでも0だったため、使われる地域の指定は無関係だった。他にあるのか。

 なお、調査中にわかったのだが、日本語キーボードの全角/半角キーはUsage 0x94にコードが割り当てられているが、実際に全角/半角の動作に切り替わるのは0x35[`]だった。

追記:なんとなくわかってきた。

https://gist.github.com/3854088

普通の日本語キーボードのHID Report Descriptorでは

Logical Minimum 0
Logical Maxmum 255
Usage Minimum (Undefined)
Usage Maximum 255

だけど、Arduino Leonardoは

Logical Minimum 0
Logical Maxmum 101
Usage Minimum (Undefined)
Usage Maximum 101 (アプリケーションキーまで)

となっている。0x89や0x87のコードを送っても無視されるのは多分このせい。

これらの記述はHID.cppの最初の方にある。これは……パッチを当てるしかないのか?


以下、資料: 
USB Descriptor
マウス付きUSBキーボードのディスクリプタ構成を調べる
HIDクラス
http://linux.die.net/Mobile-Guide/mobile-guide-p2c1s6-keyboard.html
USBキーボードのキーコード
アーカイブ: HID デバイスのハードウェア ID
Device Class Definition for Human Interface Devices (HID) [pdf]
HID Usage Tables[pdf]HID Usage Tables

PS/2キーボード変換器の製作(17) USBキーボードの任意コードの送出

Arduino Leonardo+IDE1.0.1ではKeyboard.press() / release()でUSB HIDキーボードのキーを押したような動作ができるが、引数としてアルファベットはASCIIコードを受け付け、HID Usage IDに変換してから送出しているので送れないキーがある。できれば余計な変換なしでHID Usage IDをそのまま送りたい。
 キーボードのコードを送信している部分 HID.cpp内のKeyboard_::sendReport(KeyReport* keys)はUSBAPI.hではprivateで宣言されている。USBAPI.hをコピーしてここだけpublic宣言にすればダマせるかなとやってみたがそんなのは通用しなかった。ここはコンパイル済で提供されているのでいじると大げさだしそんな実力はない。ということで、sendReport()内で呼び出してるHID_SendReport()は隠されてないのでこれを呼び出すArduinoライブラリを作ってみた。

https://gist.github.com/2ad9f7a713f46149e72f

ほぼHID.cppからのコピペですよ。

PS/2キーボード変換器の製作(16) ArduinoIDE1.0.1

Bootloaderメモ:
ArduinoのブートローダをいじってHIDのみホストに認識させることはできないだろうか?
dfu-programmer

ATmega 32u4 bootloader without ISP connection

USBメモ:
Arduino Leonardoを使ってUSBキーボード相当を実現しようとすると日本語キーボードの一部(¥、_)に対応するコードが送信できない。keyboard.press()を実現している部分をArduinoIDE1.0.1のソースから持ってきてそのままのコードを送れるように書き換えた。
ただしコンパイルが通った程度&汚いのでとりあえず置いとく。今週ちゃんと書きなおす。

https://gist.github.com/3827425

PS/2キーボード変換器の製作(15) US配列→JP配列の問題点

US配列から日本語配列に変換する部分を作成した。
Arduino用のスケッチは以下のとおり。これはUSB HIDキーボードに文字を出力すると共にシリアルポートにデバッグ情報を流す。
https://gist.github.com/3464019
ライブラリ(ps2kybd.h、ps2kybd.cpp)は前回から修正なし。
https://gist.github.com/ab100bfb33a78ddf067d



記号の置き換えは、以下のパターンで行う。
(1)SHIFTを押していない状態でSHIFTを押したような入力……右シフトキーpress、置き換えコード、右シフトキーrelease
(2)SHIFTを押していない状態で記号の置き換え……置き換えコード
(3)SHIFTを押した状態でSHIFTを押したような入力……置き換えコード
(4)SHIFTを押した状態でSHIFTを押さないような入力……左右のシフトキーをrelease、置き換えコード、元のシフトキーをpress

ALTキーを押した状態では、[`~]キーは変換せずにそのまま出力することで[ALT]+[漢字]と同じ操作になる。

 これで記号の置き換え、漢字入力のON/OFFができた。

 残った問題点。
(1)CapsLockの扱い。CapsLockはUSキーではSHIFT併用だが、日本語キーではそのまま。
→Capsフラグはライブラリ側にまかせているが、これをスケッチ側で対処
(2)[¥_]が入力できない →Arduino LeonardoはいったんASCIIコードで受けて内部で変換しUSB HIDコードを送っている。USキーのレイアウトを前提にしているため、日本語配列の[¥_]は対応するものがない。
(3)このアダプタをWindowsXPに接続するたびにデバイスドライバの確認ダイアログが登場する。

(2)、(3)は非常に大きな問題。

(2)はUSB HIDを直接送出する方法を調べなければならない。
(3)はArduinoのブートローダを置き換えなければならない。

うーん、これはけっこう難しいぞ……

POS端末用PS/2キーボード FTP-CKB11の解析

 昔ジャンク屋で入手したPOS用のPS/2接続キーボード。テンキー以外はラベルを入れることができる。鍵付き。
2011pos01

 裏面はツメで嵌めこまれているだけなので簡単に外れる。キーボードのくせに基板が複雑。16bitマイコンが載っていた。
F2MC-16L MB90610A Series[pdf]

2012pos02

 これは磁気カードリーダーにも対応しているためだろう。フラッシュメモリも搭載されていたのでログを取るのかもしれない。

2012pos03

解析結果

pos_scancode
 

富士通コンポーネントKB8811-251のスキャンコード

 また脱線。

 富士通コンポーネント(元 富士通高見澤)製のFKB8811-251。赤外線ワイヤレスのPS/2キーボード。10年くらい前に入手。赤外線受信機はマウス出力もある。赤外線を出すマウスもあったのだろうけど、私が買ったものにはついてなかった。

2012kybd251_1

 赤外線受信機側にCapsLock等のLEDがあるので、キーボード本体はキーに対応したコードを送るだけと思われる。

2012kybd251_2


 FKB8811で検索するとラック用のコンパクトキーボードとして出てくる。これをワイヤレスにしてマルチメディア関連のキーを追加したものらしい。この追加されたキーのスキャンコードが気になって調べた。

停止(■)	E0 3B / E0 F0 3B	なし
再生・一時停止(▶||)	E0 34 / E0 F0 34	なし
巻き戻し(|<<)	E0 15 / E0 F0 15	あり
早送り(>>|)	E0 4D / E0 F0 4D	あり
Vol-	E0 21 / E0 F0 21	あり
Mute	E0 23 / E0 F0 23	なし
Vol+	E0 32 / W0 F0 32	あり
App1	56 / F0 56	なし
App2	5E / F0 5E	なし
App3	8 / F0 8	なし
Email	18 / E0 18	なし
Internet	10 / E0 10	なし
ScreenSaver	65 / E0 65	なし
Sleep	E0 3F / E0 F0 3F	なし

PS/2キーボードの Power,Sleep,Wakeキー

またもや脱線。

 ELECOM TK-FCM008BK、これ112キーとあり、普通のPS/2キーボードにはないPower、Sleep、Wakeキーが付いている。500円台だったので買って調べてみた。

2012ps2

スキャンコード
キー名称 make / release
Power	E0 37 / E0 F0 37
Sleep	E0 3F / E0 F0 3F
Wake	E0 5E / E0 F0 5E
Powerキーは押すと電源OFFすることができる。ONはできない。PC本体が電源OFFの時にはPS/2キーボードに給電されていないからだ。しかしPowerキーの位置、危険な香り。

ELECOM メンブレン式キーボード 112キー PS2 スタンダードサイズ ブラック TK-FCM008BKELECOM メンブレン式キーボード 112キー PS2 スタンダードサイズ ブラック TK-FCM008BK

エレコム 2009-08-21
売り上げランキング : 3869

Amazonで詳しく見る
by G-Tools

記事タイトルPS/2キーボード変換器の製作(14) US配列でPS/2→USB変換OK

PS/2のスキャンコードをUSB UserIDまで変換できた。次にArduino Leonardoで扱っているコードに変換する。変換方法はほぼ同じで、テーブルを別に用意する。

https://gist.github.com/ab100bfb33a78ddf067d

PrtScr / ScrLock / Break まわりが難航した。ここはスキャンコードが面倒。
USBのコードをKeyboard.press()やKeyboard.release()で操作する時には充分に注意しないとスケッチの修正ができなくなる。Arduino IDEからソースをコンパイルする時にスケッチ画面に文字がタイプされてしまうからだ。

・Windows7(64bit)(英語キーボード配列の設定)に本アダプタと英語キーボードを接続し確認
・WindowsXP(日本語キーボード配列の設定)に本アダプタと日本語キーボードを接続し確認

○(1)PrintScreen / ALT+PrintScreen 正常動作
○(2)ScrLock正常動作(Excelで確認)
○(3)[目](App)キー正常動作
○(4)日本語入力/英数入力切り換え確認OK
○(5)接続したままPC本体電源ONでも動作OK。Windows7のパスワード入力も確認
×(6)[\ろ] キーと[¥]キーを\に対応させたいのだがうまくいかない(日本語キーボード接続時)
→これは無視してもよいか?

Arduino Leonardoのライブラリの制限で、PC側の[無変換][変換][かな]キーに対応するコードを送ることができない。外付けキーボードの[無変換][変換][かな]キーを別のキーに割り当てることは可能。

その他の問題点:
(a)アダプタを接続するたびにデバイスマネージャがデバイスドライバを探す。(WindowsXP)
Windows7ではドライバがインストールできなかったことを通知。でも気持ち悪い。
→できればArduino用のドライバを入れずに動かしたい

(b)キーボードのステータスがわからない。
→PC本体からの指示を受け取る手段がない。PS/2キーボード側に送信するプログラムを書いていない。
※本体接続のキーボードのランプは点灯する。

しばらく英語キーボード配列のPCに接続して使ってみる。並行してUS→JP変換のテーブルを作成。

追記:
(6)は日本語キーボードのみの問題で、キーに対応するコードがArduino Leonardoから送れないため。
(a)はブートローダ差し替えでできそう。32U4はHWB端子を見てブートローダを起動するかどうかを判断するが、Arduinoのブートローダは関連するフューズビットを設定していないらしい。 

PS/2キーボード変換器の製作(13) ハードウェアはできたが……

ハードウェアはできた。Daviciマイコンボードに6Pのmini-DINコネクタを接続、CLKとDATAをプルアップしてケース収納。
2012key01
2012key02
2012key03

 あとはPS/2のスキャンコードをUSB-UIDに変換(済)、Arduino Leonardoのkeyboard.press()に変換、さらに日本語キーボードの配列に変換するだけなのだが、問題点発覚。

以前調査した、Arduino IDE1.0.1でのコード変換部分。
Arduino IDE1.0.1/Leonardで足らないUSBキーを追加する
[HID.cpp]
	uint8_t i;
	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) {
			setWriteError();
			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;
		}
	}
 上記ソースはkeybord.press()でコードを変換している箇所。与えられた数値が0x00〜0x7fを印字可能なキー、0x80〜0x87をモディファイアキー、0x88〜を表示不能な特殊キーとみなしている。0x00〜0x7fは const uint8_t _asciimap[128] で定義されてあるテーブルで変換される。0x88以上は、その値から0x88を引いた数値がUsageIDとしてUSB経由で送信される。つまり、ファンクションキーF7は #define KEY_F7 0xC8 と定義されているが、実際は0xC8ー0x88=0x40が送信される。
 ここで漏れてしまうキーは、UIDが0x78より大きいもので、日本語キーボード関連で影響がありそうなものは
[ろ](0x87)、[かたかな/ひらがな](0x88)、[¥](0x89)、[変換](0x8a)、[無変換](0x8b)、[かたかな](0x92)、[ひらがな](0x93)、[全角/半角](0x94)。
特に最後の[全角/半角](0x94)は日本語キーボードと認識している場合どうしたものか。USB-HIDをそのまま送出する方法を探すしかないのか。

 ターゲットとなるPCがキーボードを日本語配列と認識している場合、ALT+[`]が[全角/半角]と同等か調査し、もし違っていればUSB-UIDを直接送出する方法を探す。

追記: 
    Keyboard.press(KEY_LEFT_ALT);
    Keyboard.press('`');
    delay(10);
    Keyboard.release('`');
    Keyboard.release(KEY_LEFT_ALT);
 
WindowsXPにてこれで日本語入力が切り替わることを確認。助かった。MacOSXではそのままALT+`扱い。 

PS/2テンキーボード FMV-NTKB1の調査

ちょっと脱線。昔、USBポートのなかった頃のノートPCのオプションでPS/2接続のテンキーボードがあったのだが、この挙動が謎だった。スキャンコードを観測できるようになって、コードの割り当てがまったく違うことがわかった。

2012tenkey

富士通 FMV-NTKB1 テンキーボード

キー名称 make/releaseコード

NumLock 01 / 81
7home 02 / 82
4← 03 / 83
1End 04 / 84
/ 06 / 86
8↑ 07 / 87
5 08 / 88
2↓ 09 / 89
0Ins 0A / 8A
* 0B / 8B
9PgUp 0C / 8C
6→ 0D / 8D
3PgDn 0E / 8E
.Del 0F / 8F
- 10 / 90
+ 11 / 91
Enter 13 / 93

キーリピートなし

 要は専用のオプションだったってことですね。

PS/2キーボード変換器の製作(12) Scancode→USB UID変換

作業メモ:
https://gist.github.com/3056964
 

 scancodeからUSB-UserIDへの変換ができた。256バイトのテーブルを使って通常と拡張モード(0xE0)付きのスキャンコードを変換。可変長で扱いが面倒なスキャンコードをUSB-UserIDの固定長にした。
USB-UserIDは0x70に続く2バイトで表現。先頭のbit15はキーを離した時に1、とした。
 また、CTRL,SHIFT,ALT,GUI(META)キーの状態取得、Caps/Num/Scrのロック状態を取得。

 残りは特殊なキー[PrtScn]と[Pause/break]の取り扱い。特に[PrtScn]はalt併用状態をどう扱うか。
ここまでやれば英語キーボードの変換は一応済となる。

 あとはUSB-UserIDから日本語キーボード配列向けのUSB-UserIDに変換するテーブルを作成、ケース組み込み。

PS/2キーボード 特殊なキーのスキャンコード

 スキャンコードが安定して取得できるようになったので、特殊なキーについて確認した。

拡張:E0 リリース:F0

[PrtScn]
E0 12 E0 7C / E0 F0 7C E0 F0 12

[Alt]+[PrtScn]
84 / F0 84

[PrtScn]とその他[Ctrl]、[Shift]、[Meta(Windows)]を組み合わせても[Alt]優先。

※Windowsでのハードコピーが[PrtScn]と[Alt]+[PrtScn]なのはこの組み合わせしか区別がないから

[Pause/Break]
E1 14 77 E1 F0 14 F0 77

[Ctrl]+[Pause/Break]
E0 7E E0 F0 7E

[Pause/Break]を押すとすべてのキーリピートが止まる。

[App](windowsキーと一緒に追加されたマウスの右クリック相当のやつ)
E0 2F / E0 F0 2F


調査はMicrosoft Keyboard Elite(US版)でやったのでリファレンス的には問題ないだろう。

PS/2キーボード変換器の製作(11) スキャンコード取得

ArduinoでPS/2キーボードのスキャンコード取得が安定してできるようになった。ライブラリはarduino.ccのplaygroundで公開されているps2keyboardExt2を基本にps2keyboardの割り込み部分を混ぜた。ps2keyboardの方は外部割り込みでスキャンコードを受け取ったあとFIFOに入れている。(ここを自前で作ったら取り出し時に重複してしまった)

作りかけのライブラリとテスト用のスケッチ

Arduino UNOとLeonardoで挙動が違う部分に引っかかったので注意。
Arduino Leonardoの外部割り込み番号とピンの割り当てが異なる 

PS/2キーボード変換器の製作(10) 整理

・PS/2キーボード→USB接続、US配列を日本語配列に変換する。工程整理。

■開発環境とマイコンは確定
・ArduinoIDE1.0.1とArduino Leonardo(互換品)で作成。オープンソース。再現性高い。
・送り返して書きなおしたりしなくても、先方でアップデート可能

☆印は優先、これらが出来れば最低限動作

□ハードウェア
□マイコン選定(AVR ATmega32U4搭載 Arduino Leonard互換ボード、複数の選択肢があることは重要)
 ※sparkfun ATmega32U4モジュール 今回は使わない http://www.switch-science.com/products/detail.php?product_id=982
☆PS/2ポートのPullUp抵抗無くせるか 設定確認
□ケース組み込み

□ソフトウェア
■構造
 ■PS/2キーボード入出力はArduinoのライブラリとして構成 → arduino.cc playgroundのps2keyboard/ps2keyboardext2を参考
 ■USB HIDキーボード出力はArduinoIDE1.0.1の機能を利用
 ■スキャンコード→USBのコードへの変換はスケッチで行う

・ライブラリ
□PS/2キーボード入力
 ■PS/2キーボードのスキャンコード Type2決め打ちでOK(Type1は古い機種、Type3は特殊で使われない)
 ☆スキャンコードを直接扱うrawread()を追加→作成済、未確認
 ☆スキャンコードをFIFOに入れる→キー取りこぼし対策
 ☆PrintScreen/Alt+PrintScreen
 □Pause(ただしPrintScreenができればたいしたことはない)
 □NumLock時挙動 キーパッド部分
□PS/2キーボード出力
 □コマンド送出 キーボード本体のLED制御
 □コマンド送出 キーボードリピート設定

・スケッチ
☆スキャンコード PS/2-US→USB-HID変換
□スキャンコード マルチメディア系の追加キー
☆make/release制御 USBは同時押し6個まで、PS/2は無制限 この調整

メモ PS/2キーボードのUSB変換に関して

これまで調べたPS/2のスキャンコード、キー番号などに関する資料。

マイクロソフトの資料:
Enhanced Keyboards and Windows
Archive: Key Support, Keyboard Scan Codes, and Windows

キー番号、スキャンコードの組み合わせに関する説明:
Sazanami Online PS/2 インターフェイスの研究

Arduinoでキーボードをエミュレートする方法:
Arduino PS/2 Keyboard Emulator Issues
Arduino Forum › Hardware › Interfacing › Arduino as Keyboard

ArduinoをUSBキーボードにする方法:(Leonardo,Atmega32U4以外を使った方法)
Project Log : Arduino USB
Virtual USB Keyboard
practicalarduino / VirtualUsbKeyboard
Arduino Uno DFU プログラミング

 Arduino Leonardoは keyboard.press()とkeyboard.release()を使えば簡単にUSBキーボードをエミュレートできる。ただしUSキー配列なので変換テーブルなどが必要。
 PS/2のスキャンコードは可変長なのでやや扱いにくい。OADGでPS/2キーボードのキートップに対してキー番号が割り当てられているので、これを使えばすっきりする。
 だが、組み込み用途ではスキャンコード→キー番号→USBと変換すると冗長になる。今まで調べた例だとPS/2のスキャンコードからUSBのコードやASCIIコードに変換テーブルなりswich~case文で変換しているが、特殊キーや日本語配列の対応が考慮されていないため難しそう。そこでPS/2のスキャンコードを2バイトで表現し固定長にして、ASCIIコードやUSBのコードに変換しようと考えている。
例:1バイト目のbit7…make/break、bit0…拡張コードかどうか、2バイト目…スキャンコード
これだとスキャンコードの変換はほぼ流用できる。バッファは倍になるが、PS/2キーのバッファは16バイトなのでこれが32バイトになるだけ。

できるだけ再利用しやすい方向で考えたい。 

Arduino IDE1.0.1/Leonardで足らないUSBキーを追加する

Arduino IDE1.0.1とDavinciのLeonardo化の続き。
HID USBキーボードでどのキーが押されたかは、UsageIDというので与えられる。
http://www.usb.org/developers/devclass_docs/Hut1_11.pdf[pdf] のp.53〜 10 Keyboard/Keypad Page (0x07) 

表示不能な特殊キーとモディファイア(SHIFT,CTRL,ALT等)の番号を見ると、どうも違うのでソースを追ってみた。
特殊キーとモディファイアの定義は以下。
hardware/arduino/cores/arduino/USBAPI.h

keyboard.press()は以下。
hardware/arduino/cores/arduino/HID.cpp

 keyboard.press()では、与えられた数値が0x00〜0x7fを印字可能なキー、0x80〜0x87をモディファイアキー、0x88〜を表示不能な特殊キーとみなしている。
0x00〜0x7fは const uint8_t _asciimap[128] で定義されてあるテーブルで変換される。これはUSキー配列相当となっているので、日本語キーボード相当にしたければここをいじればよい。
0x88以上は、その値から0x88を引いた数値がUsageIDとしてUSB経由で送信される。つまり、ファンクションキーF7は #define KEY_F7 0xC8 と定義されているが、実際は0xC8ー0x88=0x40が送信される。

  ということで未定義のPrintScreenキーなどを追加してみた。

#define KEY_PRINTSCREEN                         0xCE
#define KEY_SCROLLLOCK                         0xCF
#define KEY_PAUSE                         0xD0

 といってもいきなりソースを修正するのは恐れ多いので、スケッチで実験してみる。

/* Button for Keyboard (Arduino Leonardo only) */

/*
  Button
 
 Turns on and off a light emitting diode(LED) connected to digital  
 pin 13, when pressing a pushbutton attached to pin 2. 
 
 
 The circuit:
 * LED attached from pin 13 to ground 
 * pushbutton attached to pin 2 from +5V
 * 10K resistor attached to pin 2 from ground
 
 * Note: on most Arduinos there is already an LED on the board
 attached to pin 13.
 
 
 created 2005
 by DojoDave 
 modified 30 Aug 2011
 by Tom Igoe
 
 This example code is in the public domain.
 
 http://www.arduino.cc/en/Tutorial/Button
 */

// constants won't change. They're used here to 
// set pin numbers:
const int buttonPin = 2;     // the number of the pushbutton pin
const int keymacroPin = 3;
const int ledPin =  13;      // the number of the LED pin

// variables will change:
int buttonState = 0;         // variable for reading the pushbutton status

#define KEY_PRINTSCREEN                         0xCE
#define KEY_SCROLLLOCK                         0xCF
#define KEY_PAUSE                         0xD0


void setup() {
  // initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);      
  // initialize the pushbutton pin as an input:
  pinMode(buttonPin, INPUT);
  pinMode(keymacroPin, INPUT);
  digitalWrite(buttonPin, HIGH);
  digitalWrite(keymacroPin, HIGH);

  Keyboard.begin();
}

void loop(){
  if (digitalRead(keymacroPin)==LOW) {
    // not implemented
  }

  // read the state of the pushbutton value:
  buttonState = digitalRead(buttonPin);

  // check if the pushbutton is pressed.
  // if it is, the buttonState is HIGH:
  if (buttonState == LOW) {     
    // turn LED on:    
    digitalWrite(ledPin, HIGH); 
    delay(30);
    while(buttonState == LOW){
      buttonState = digitalRead(buttonPin);
      // Keyboard.press(ctrlKey);
      Keyboard.press(KEY_PRINTSCREEN);
    }
  } 
  else {
    // turn LED off:
    digitalWrite(ledPin, LOW); 
    Keyboard.release(KEY_PRINTSCREEN);
  }
  delay(100);
}

 これは、Windowsマシンに接続してボタンを押すと画面のスナップショットをクリップボードにコピーする。定義されていないキーもこれで使用できた。

PS/2キーボード変換器の製作(9)

これまでの実験から方針確認。

・キーボード入力について
(1)PS/2キーボード入力はArduinoのPS2Keyboardライブラリからスキャンコードを取得できるよう作りなおす
(2)USBキーボード入力はUSBホストシールドまたはAndroid ADKが使用できそうだが未確認
(3)キーボードへの出力(LED制御、キーリピート等)が必要

・キーボード出力について 
(1)Davinci(Arduino Leonardo)のKeyboard.write()で確認したが単発のキーしか認識しない。
(2)DavinciはUSB複合デバイスとして認識されるのでWindowsで毎回デバイスを問い合わされる。Disableにする方法はないか?
(3)Arduino Leonardoは正式サポートではないので今後変わる可能性がある。
(4)代替手段としてV-USBがある。未確認。部品は揃えてある。
(5)PS/2出力を実現するPS2devというのがあるらしい。

プランB
78K0の作例を元に作る。

PS2KeyboardExt2の確認

以前PS2Keyboardライブラリを試したが、PS2KeyboardExt2というのもあったので試した。

http://arduino.cc/playground/Main/PS2KeyboardExt2 目的としてはPS2Keyboardの代替としてCTRLやALTなどの修飾キーの取得とコードサイズの縮小を目的としたものらしい。ソースはそのまま貼り付けてあるだけなので以下の様にライブラリに置いた。
(1)librariesディレクトリ以下にPS2KeyboardExt2というディレクトリを作る。 
(2)PS2KeyboardExt2ディレクトリ以下にPS2Keyboard.cppとPS2Keyboard.hをコピペして置く。
(3)PS2Keboard.cppのソース中"Wprogram.h"を"Arduino.h"に修正。(Arduino IDE1.0用)

もしPS2Keyboardライブラリをインストール済みだったら競合するのでディレクトリごとどこかに退避しておく。

 配線はPS2CLK(pin5)がArduino UNOのpin3、PS2DATA(pin1)がArduino UNOのpin4に接続。
サンプルスケッチをコピペして開き、動作を確認。
サイズは以下のとおり。
 Binary sketch size: 5170 bytes (of a 32256 byte maximum)
 修飾キー(CTRL,ALT)が取得できなかったのは?だが、これを元に動作を追いかけてみる。

記事検索
プロフィール

hardyboy

カテゴリ別アーカイブ
月別アーカイブ
QRコード
QRコード
  • ライブドアブログ