USB keyboardのテスト

2008/08/28工作::USBimport

USB keyboardの話

HIDとして,キーボードとマウスは抑えておきたいところである.そこで,キーボードについて,仕様ではよくわからなかった動作について確認する.PCやOSに依存するかもしれないので,ここで記述する事項は実際に試したこと,推測(妄想)事項であることを明記しておく.
何らかの明確な動作に関する資料が開示されているのであれば,ポインタを教示いただきますと幸いです.

実験と確認

先日の疑問について,実装して確認する.
デバイス側のマイコンから,キーコード(usage ID)を送信し,PC側でどういう挙動を示すかを調べる.

(1)	{0x00, 0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 },
(2)	{0x01, 0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 },
(3)	{0x00, 0, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A },
(4)	{0x00, 0, 0x07, 0x08, 0x09, 0x0A, 0x05, 0x06 },
(5)	{0x00, 0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // nothing
(6)	{0x00, 0, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00 }, // space

	結果.
	"abcdefg "の繰り返しとなる.
	 456789a

	"押している"情報であることがわかる.
	(1)-(2)で 'a'を2回送っていることになるはず.(2回数はshift押下)
	(3),(4)で並びを変えてみたが, 反応ナシ.
	(5)で全部離したと認識して, "bcdefg"をinput.
	このとき,押下情報(3)の若い順に入力されたと考えられる.(並びを変えて確認要)

	また,別キーボードにてshiftを押下したところ,押下中は文字サイズが変わった.

# 教訓.スキップせずにコツコツと進みましょう:)

"abcdefg "....

(1)	{0x01, 0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 },
(2)	{0x00, 0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 },
(3)	{0x00, 0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // nothing
(4)	{0x00, 0, 0x07, 0x08, 0x09, 0x0A, 0x05, 0x06 },
(5)	{0x00, 0, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00 },
(6)	{0x00, 0, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00 },

	"adefgbc "で繰り返された.
	(1) 'a'を押下,
	(2) 'a'を押下しながら shift押下
	(3) 'a'とshiftを同時に離す. 
	 → (shiftはキーの前後でon状態を保つ必要がある? 少なくとも入力時に同時か一つ前?)
	(4) d,e,f,g,b,c を押下
	(5) 'g'だけ離す...
	(6) b-fを離して, spaceを押す.


(1)	{0x01, 0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 },
(2)	{0x01, 0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // shift入れてみる
(3)	{0x01, 0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 },
(4)	{0x00, 0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // shift入れてみる
(5)	{0x00, 0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // nothing
(6)	{0x00, 0, 0x07, 0x08, 0x09, 0x00, 0x00, 0x00 },
(7)	{0x00, 0, 0x05, 0xC6, 0xC4, 0x00, 0x00, 0x00 },
(8)	{0x00, 0, 0x05, 0xC6, 0x00, 0x00, 0x00, 0x00 },
(9)	{0x00, 0, 0x05, 0xC6, 0xC4, 0x00, 0x00, 0x00 },
(A)	{0x00, 0, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00 },

	^a
	^a
	def
	0xC4/0xC6は無視されたぽいな..
	b
	<space>


!ここでReport descriptorのUsage Maxが 0x65なのに気づく.
0xE7とすることで,定義値全て有効になるはず..

(1)	{0x02, 0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 },
(2)	{0x02, 0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // shift入れてみる
(3)	{0x02, 0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 },
(4)	{0x00, 0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // shift入れてみる
(5)	{0x00, 0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // nothing
(6)	{0x00, 0, 0x07, 0x08, 0x09, 0x00, 0x00, 0x00 },
(7)	{0x00, 0, 0x05, 0xC6, 0xC4, 0x00, 0x00, 0x00 },
(8)	{0x00, 0, 0x05, 0xC6, 0x00, 0x00, 0x00, 0x00 },
(9)	{0x00, 0, 0x05, 0xC6, 0xC4, 0x00, 0x00, 0x00 },
(A)	{0x00, 0, 0x2C, 0x00, 0x00, 0x00, 0x00, 0x00 },

	ならなかったなぁ.
	AAdefb "Shift"は同時に離しても,跡で開放でも良いみたい.

min.max.を 0x80 - 0x7Fにしてみた.
	→値全部無視された.SHIFTのみに反応して,"固定キー機能"ダイアログが出てくる.

0x00 - 0x00E7にしてみたが,駄目だな. 
keypadになると,usage sub-IDが変わってくるので,無視されるのだろう.
table中,keyboard/keypadと明記されていたのはコレによるものと思われる.
分けてくれよ...

utility関数の作成

usage IDとASCIIコードとはテーブル引きするしかなさそう.US keyboardをベースにしているらしく,日本語keyboardとは異なるマップと考えるしかない.また,SHIFT/CTRL等の情報は文字とは別です.
前述の結果より,本I/FでPCが受信するのはキーの押下情報であり,入力された文字情報ではないです.文字入力の肩代わりをさせる場合,ほかのキーボードとの干渉を考慮する必要がありそうです.
ゲームの入力装置として考える場合は,押下情報であったことは良いことでしょう.同時押し6つまで認識してくれそうです.(SHIFT/ALT/CTRLは別腹で同時押し可)

ASCII文字 - 0x20を index0として,下記のIDを送ると良い.
ただし,"SHIFT+"は,SHIFTを押下しながら文字を入力した場合であり,単純に1倍との送信では実現できない.

0x2C, SHIFT+0x1E, SHIFT+0x34, SHIFT+0x20, SHIFT+0x21, SHIFT+0x22, SHIFT+0x24, 0x34, SHIFT+0x26, SHIFT+0x27, SHIFT+0x25, SHIFT+0x2E, 0x36, 0x2D, 0x37, 0x38,
	// 0x20~0x2F, → <SPC>!"#$%&'()*+,-./
0x27, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, SHIFT+0x33, 0x33, SHIFT+0x36, 0x2E, SHIFT+0x37, SHIFT+0x38
	// 0x30~0x3F, → 0123456789:;<=>?
SHIFT+0x1F, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12,
	// 0x40~0x4F, → @ABCDEFGHIJKLMNO
	// 0x89 : Keyboard International3(17) => '\'キー
0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x2F, 0x31 ,0x30, SHIFT+0x23, SHIFT+0x2D,
	// 0x50~0x5F, → PQRSTUVWXYZ[\]^_
0x34, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
	// 0x60~0x6F, → `abcdefghijklmno
0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, SHIFT+0x2F, SHIFT+0x31, SHIFT+0x30, SHIFT+0x32, 0x2A
	// 0x70~0x7F, → pqrstuvwxyz{|}~<DEL>


複合デバイスの作成

作り方

PSoC環境を使う限り,自動的にInterface数を把握して,standard requestに応答してくれる模様.便利ですな.. *1

  1. Descriptorにinterfaceを追加する.
  2. EPを追加する.
  3. Report descriptorを追加する.

メモ
PSoCのEPは,入出力で同じIDが使えない?simple IOの実装でEPを1/1または3/3としたときに,IN応答が無かった.OUTを受けてからIN transactionを起こしていたので,先に処理したモン勝ちか?詳細はPSoCのTRMで確認する予定.
【宿題】の結果,下記の記述が見つかりました.

PSoC TRM, Document No. 001-14463 Rev. **
34. Full-Speed USB

The SIE supports five endpoints including a control endpoint (endpoint 0) and four data endpoints (endpoint 1, 2, 3, and4).
The control endpoint can be configured to support SETUP, IN, and OUT requests.
The data endpoints can be individually configured to respond to Interrupt, Bulk, or Isochronous IN or OUT requests.

ということで,EP1~4は,INかOUTのいずれか1つしか取れません.したがって,インタフェースIN/OUTを2つ用いるデバイスでは,EPも2つ消費します.入出力対応しているEPであれば,EP数を削減できたのですが.まぁ,物理的な制約であり,仮に入出力OKでも,IDが経るなら同じなので,こんなもんなんでしょう.
キーボード,マウス,+α(入出力)とするならば,キーボードのLED出力は受け取れないということですね.

デバッグ・お試し時のメモ

PID/VIDが同じだと,Windows Device ManagerがInterfaceを覚えているようだ.
複合→単純に変えたとき,2度目以降は複合として扱われた.
Device Manager → USBコントローラ の 該当するVID/PIDの複合デバイスを削除することで,再度認識してくれるみたいです.


*1 : 仕組みを理解する上では,手抜きになってしまうなぁ.

参考サイト



wiki機能でコンテンツにしているけれども,まとまってないな...
日々書き散らかしてまとめていないからかなぁ.使い方間違ってる?w