ホーム ざれごと ワシントン州 ツール NT豆知識 Win32プログラミングノート 私的用語 ジョーク いろいろ ゲーム雑記 Favorites 掲示板 Mail
Windows XP で加わった Raw Input API を使って、システムにつながっている入力デバイスを列挙してみる。
キーボードの場合は、タイプとサブタイプも出力。
とりあえずデバッグ出力に一覧を出してみます。
お手軽にでっちあげた AutoArray を使ってますが、本番に使うには弱いのでそのままでは使わないほうがいいかも。
蛇足ですが。
WINVER=0x500 とか _WIN32_WINNT=0x0501 をコンパイルオプションなどで定義しておく必要があります。
1: | template <class T> |
2: | class AutoArray { |
3: | public: |
4: | AutoArray(size_t n) |
5: | { |
6: | #ifdef _DEBUG |
7: | // バッファオーバーランのチェックのため、 余計にひとつアロ ケート |
8: | m_ptr = new T[n + 1]; |
9: | #else |
10: | m_ptr = new T[n]; |
11: | #endif |
12: | if (m_ptr) { |
13: | m_size = n; |
14: | #ifdef _DEBUG |
15: | // 番兵を置く |
16: | FillMemory(&m_ptr[n], sizeof m_ptr[n], SENTINEL); |
17: | #endif |
18: | } |
19: | else { |
20: | m_size = 0; |
21: | } |
22: | |
23: | } |
24: | ~AutoArray() |
25: | { |
26: | #ifdef _DEBUG |
27: | if (m_ptr) { |
28: | PBYTE pb = reinterpret_cast<PBYTE>(&m_ptr[m_size]); |
29: | ASSERT(pb); |
30: | // バッファオー バーランのチェック |
31: | for (int i = 0; i < sizeof m_ptr[m_size]; ++i) { |
32: | ASSERT(pb[i] == SENTINEL); |
33: | } |
34: | } |
35: | #endif |
36: | delete[] m_ptr; |
37: | } |
38: | |
39: | bool OK() |
40: | { |
41: | return m_ptr != NULL; |
42: | } |
43: | |
44: | operator T*() |
45: | { |
46: | return m_ptr; |
47: | } |
48: | |
49: | T& operator[](size_t n) |
50: | { |
51: | ASSERT(n < m_size); |
52: | return m_ptr[n]; |
53: | } |
54: | |
55: | protected: |
56: | // to prohibit copy operations |
57: | AutoArray(const AutoArray<T>&); |
58: | AutoArray<T> operator=(const AutoArray<T>&); |
59: | |
60: | enum { SENTINEL = 0xcc }; |
61: | |
62: | protected: |
63: | T* m_ptr; |
64: | size_t m_size; |
65: | }; |
66: | |
67: | bool KeyboardList() |
68: | { |
69: | // 現在接続されている入力デバイスの数を取得 |
70: | UINT nInputDevices; |
71: | if (GetRawInputDeviceList(NULL, &nInputDevices, sizeof(RAWINPUTDEVICELIST)) != 0) { |
72: | return false; |
73: | } |
74: | |
75: | // 入力デバイスの基礎的情報を取得 |
76: | AutoArray<RAWINPUTDEVICELIST> rawinputDeviceList(nInputDevices); |
77: | if (!rawinputDeviceList.OK()) { |
78: | return false; |
79: | } |
80: | UINT ntmp = nInputDevices; |
81: | if (GetRawInputDeviceList(rawinputDeviceList, &nInputDevices, sizeof(RAWINPUTDEVICELIST)) != ntmp) { |
82: | return false; |
83: | } |
84: | |
85: | int nKbd = 0; // つながっているキーボードの数 |
86: | |
87: | for (UINT i = 0; i < nInputDevices; ++i) { |
88: | // デバイス名の長さを取得 |
89: | UINT size; |
90: | if (GetRawInputDeviceInfo(rawinputDeviceList[i].hDevice, RIDI_DEVICENAME, NULL, &size) != 0) { |
91: | return false; |
92: | } |
93: | // デバイス名を取得 |
94: | AutoArray<TCHAR> name(size); |
95: | if (!name.OK()) { |
96: | return false; |
97: | } |
98: | if ((int)GetRawInputDeviceInfo(rawinputDeviceList[i].hDevice, RIDI_DEVICENAME, name, &size) < 0) { |
99: | return false; |
100: | } |
101: | // デバイスの情報を表示 |
102: | static const TCHAR* deviceTypeNames[] = { |
103: | _T("Mouse"), |
104: | _T("Keybd"), |
105: | _T("HID "), |
106: | }; |
107: | TRACE3("[%02d] %s hDevice=%p", i, deviceTypeNames[rawinputDeviceList[i]. dwType], rawinputDeviceList[i].hDevice); |
108: | TRACE1(" %s\n", name); |
109: | |
110: | if (rawinputDeviceList[i].dwType == RIM_TYPEKEYBOARD) { |
111: | // キーボードだったら、 タイプ・サブタイプを表示 |
112: | ++nKbd; |
113: | |
114: | RID_DEVICE_INFO devinfo = { sizeof devinfo, }; |
115: | UINT sz = sizeof devinfo; |
116: | if ((int)GetRawInputDeviceInfo(rawinputDeviceList[i]. hDevice, RIDI_DEVICEINFO, &devinfo, &sz) < 0) { |
117: | return false; |
118: | } |
119: | ASSERT(devinfo.dwType == RIM_TYPEKEYBOARD); |
120: | TRACE2(" ==> [0x%02x, 0x%02x]\n", devinfo.keyboard.dwType, devinfo.keyboard.dwSubType); |
121: | } |
122: | } |
123: | |
124: | TRACE1("Number of keyboards: %d\n", nKbd); |
125: | |
126: | return true; |
127: | } |
出力の例はこんな感じ:
[00] Keybd hDevice=00010063 \??\Root#RDP_KBD#0000#{884b96c3-56ef-11d1-bc8c-00a0c91405dd} ==> [0x51,0x00] [01] Keybd hDevice=00010061 \??\Root#*PNP030b#1_0_22_0_32_0#{884b96c3-56ef-11d1-bc8c-00a0c91405dd} ==> [0x04,0x00] [02] Mouse hDevice=0001004B \??\Root#RDP_MOU#0000#{378de44c-56ef-11d1-bc8c-00a0c91405dd} [03] Mouse hDevice=00010049 \??\HID#Vid_045e&Pid_0040#6&31accd24&0&0000#{378de44c-56ef-11d1-bc8c-00a0c91405dd} Number of keyboards: 2
Type=4, Subtype=0 というのは、いわゆる 101 キーボードです。
Type=0x51 は未定義のタイプ、という意味です。
本来あってはいけませんが、USB キーボードで INF が正しく設定されない場合、タイプが不明になってしまうため、仕方なく未定義のタイプを割り当てています。
余談ですが、メーカによっては 101 でも 106 でも同じプロダクト ID を使っているケースがあるようです。
デバイスはベンダ ID・プロダクト ID によって識別されるので、101 と 106 に別々のタイプを割り当てることができないことになります。
これは最悪のケースで、INF でもどうしようもありませんね。
案外多いようですが...
Microsoft をはじめとして
。
Windows XP からは、ダイナミックレイアウトスイッチングという機能が加わりました。
USB などによって複数のキーボードを接続することができますが、このとき 101 / 106 などのタイプ・サブタイプを認識してダイナミックにキーボードレイアウトを切り替えるという機能です。
なお、日本と韓国向けの特殊機能ですが、英語版にも機能は入っています。
in-box でサポートされているのは、101 / 106 / NEC の三種類です。
ダイナミックレイアウトスイッチングはきちんと機能すれば便利なのですが、タイプ・サブタイプによってキーボードレイアウトを決定するため、不明なタイプ= 0x51 の場合にはうまく動作しません。 キーボードの種類が判別できないので、仕方なく PS/2 キーボードの設定にあわせるようです。 こればかりは OS 側ではどうしようもないので、USB キーボードのベンダー各社に正しい INF を用意してもらうしかありません。 そのうち無理やりタイプを設定するユーティリティを書こうと思っていますが、いかんせん時間がない…。
ダイナミックレイアウトスイッチングを有効にするためには、日本語のキーボードレイアウト(xxxx0411なもの)をアクティブにしておく必要があります。 日本語のキーボードレイアウトに埋め込まれている機能なのです。 たとえば US のキーボードレイアウトにはない機能ですので、ダイナミックレイアウトスイッチングが効かない場合にはまずアクティブなインプットロケールとそのキーボードレイアウトを要ちぇきら。
なお、↑の出力例でタイプ= 0x51 となっているのは、リダイレクト用の仮想デバイスです。 特定のハードウェアと結びついていないため不明のタイプとなっているものと思われます。
RegisterRawInputDevicesに機能が追加されています。
RIDEV_APPKEYS
これは、NOLEGACYが指定されていてもWM_APPCOMMANDが配られるようにするというフラグです。
相変わらずSDK DOC(MSDN)はわかりにくい。
RIDEV_DEVNOTIFY
デバイスのアタッチとデタッチ時に、WM_INPUT_DEVICE_CHANGEが送られるようにするフラグです。
なぜかMSDNにこのフラグは載っていません。DOCバグですね。
ホーム ざれごと ワシントン州 ツール NT豆知識 Win32プログラミングノート 私的用語 ジョーク いろいろ ゲーム雑記 Favorites 掲示板 Mail