HID情報を入手する - RAWINPUTを使う

Windowsで手軽にタッチパネルの情報にアクセスできないだろうか?
タッチパネルといえばWindows 8だが、実はWindows 7から正式に対応をしているのだ。
(それ以前は、デジタイザという扱い)
WindowsではUI入力は十把一絡げにHID(Human Interface Device)クラスとして取り扱われている。
キーボードもマウスも、タッチパネルも皆HIDだ。


まずはMFCでWM_INPUTメッセージを利用してRAWINPUTを取得してみる。
https://msdn.microsoft.com/en-us/library/windows/desktop/ms645590(v=vs.85).aspx

Visual StudioMFCのダイアログベースのスケルトンを作成する

名前は適当に付ける(ここでは"MFCAho")。

WM_INPUTで受けるデバイスを登録する

DialogクラスのOnInitDialogに以下を追加する。

RAWINPUTDEVICE ridTest[1];
// for touch
ridTest[0].usUsagePage = 0x0d;
ridTest[0].usUsage = 0x00;
ridTest[0].dwFlags = RIDEV_INPUTSINK | RIDEV_PAGEONLY;
ridTest[0].hwndTarget = m_hWnd;
//
RegisterRawInputDevices(ridTest, 1, sizeof(RAWINPUTDEVICE));

今回はタッチの入力を拾うことが目的なので、タッチデバイスのみを登録している。
マウスやキーボードもここで登録すれば、マウスやキーボード入力があったときに以下のイベントハンドラで拾ってくれる。
RegisterRawInputDevicesの詳細は以下。
https://msdn.microsoft.com/en-us/library/windows/desktop/ms645600(v=vs.85).aspx
ここで出てくるusUsagePageとusUsageはHIDの仕様に従っている。
http://www.usb.org/developers/hidpage/Hut1_12v2.pdf

Class Wizardを開き、ダイアログのクラスを選択し、"Messages"から"WM_INPUT"を選びそのイベントハンドラ(OnRawInput)を追加する

イベントハンドラの実装は以下の通り

void CMFCAhoDlg::OnRawInput(UINT nInputcode, HRAWINPUT hRawInput)
{
	// This feature requires Windows XP or greater.
	// The symbol _WIN32_WINNT must be >= 0x0501.
	// TODO: Add your message handler code here and/or call default
	UINT size;
	RAWINPUT* pRI = NULL;
	GetRawInputData(
		hRawInput,
		RID_INPUT,
		NULL,
		&size,
		sizeof(RAWINPUTHEADER)
		);
	if (size != 0)
	{
		unsigned char* buffer = new unsigned char[size];
		pRI = (RAWINPUT*)buffer;
		GetRawInputData(
			hRawInput,
			RID_INPUT,
			pRI,
			&size,
			sizeof(RAWINPUTHEADER)
			);
		printRAWINPUT(pRI);
		Invalidate();
		delete[] buffer;
	}
	//
	CDialogEx::OnRawInput(nInputcode, hRawInput);
}

GetRawInputDataの詳細は以下。
https://msdn.microsoft.com/en-us/library/windows/desktop/ms645596(v=vs.85).aspx
ここでのポイントは、GetRawInputDataを2回呼ぶ必要があることだ。
一度目でサイズを取得し、その後バッファーを準備して、二回目でRAWINPUT構造体を取得する。

取得したRAWINPUT構造体をパースする

RAWINPUT構造体の詳細は以下。
https://msdn.microsoft.com/ja-jp/library/windows/desktop/ms645562(v=vs.85).aspx

typedef struct tagRAWINPUT {
  RAWINPUTHEADER header;
  union {
    RAWMOUSE    mouse;
    RAWKEYBOARD keyboard;
    RAWHID      hid;
  } data;
} RAWINPUT, *PRAWINPUT, *LPRAWINPUT;

中にはRAWINPUTHEADER、RAWMOUSE、RAWKEYBOARD、RAWHIDが含まれる。
RAWINPUTHEADER.dwTypeでマウス、キーボード、もしくはそれ以外のHIDが入力されたかがわかる。
https://msdn.microsoft.com/ja-jp/library/windows/desktop/ms645571(v=vs.85).aspx
なので、こんな感じで受ける。

void CMFCAhoDlg::parseRAWINPUT(RAWINPUT* pRAWINPUT)
{
	RAWINPUTHEADER RawInputHeader = pRAWINPUT->header;
	RAWMOUSE RawMouse = pRAWINPUT->data.mouse;
	RAWKEYBOARD RawKeyboard = pRAWINPUT->data.keyboard;
	RAWHID RawHID = pRAWINPUT->data.hid;
        //
	if (RawInputHeader.dwType == RIM_TYPEHID)
	{
		for (int count = 0; count < RawHID.dwSizeHid * RawHID.dwCount; count++)
		{
			// ここでRawHIDの処理をする
		}
	}
}


しめしめ、これでまんまとタッチパネルの情報が入手できるぞ。
うんしょうんしょ・・・
あれ、なんかそれっぽいデータが出てこない。
どうもレイヤードライバがすでにいじくり倒した後のようだ。
ということで、To Be Continued