DirectInput键盘输入(1)

来源

对于DirectInput来说,键盘是作为一个高效的游戏控制器来处理的。如果你要输入文本,那么你可以使用Windows提供的标准服务。在独占模式中,我们是不能获取键盘数据的,我们所能获得的是WM_KEYDOWN、 WM_KEYUP和WM_CHAR消息以及由GetDeviceState和GetDeviceData所返回的输入值。在DInput例子程序中,应用 程序通过对Ctrl-F的响应就说明了这一点。
1、一个有101个按钮的游戏板
就像DirectX SDK文档中所说的一样,在DirectInput情况下,键盘并不是文本输入设备,而是一块带有很多按钮的游戏板。虽然在键盘中并没有轴(游戏板中有),但它们还是具有很大的相似性的。在消息传递系统中,Windows在把一个按钮消息发送到消息队列之前要对它做很多处理。它要判断一个键是否被按下,如果是这样的话,那么就检查所按下的时间并与控制面板中设置好的重复延时和重复速率相比较。在生成消息的时候,Windows还要处理物理键所代表的虚拟键(VirtualKey)以及组合键的使用等。对于GetAsyncKeyState这类函数,它所返回的也是Windows处理过的数据。
在DirectInput中,情况却完全不是这样的,它所关心的仅是两件事情:某个键是否被按下和这个键的代码是什么。为了实现事件通知和基于缓冲区的数据,DirectInput把键状态的改变翻译成一次按键事件和一次释放事件。但在一个键被按下时,不管按下多长时间,它所触发的仅是一个单一的事件。
用一对一的方法,DirectInput把扫描码转换成一个从0到255之间的数值,并且这些数值都用DIK_*的方式来定义(参见附表)。与 Windows的键盘服务不一样,DirectInput要区分两个具有相同名字的键,如主键盘和数字键盘上的Enter键。另外与Windows服务不 一样的是,DirectInput以相同的方式处理每一个键,而不管这个键是字母、数字还是Alt、Scroll Lock等键。
当 然,DirectInput在某些特殊的情况下还是会执行一些转换操作。例如,NEC键盘所生成的并不是标准的扫描码,这时DirectInput就会自 动把它转换成标准的PC键盘扫描码。如果你们所开发的应用程序是面对国际市场的,那么还要注意日本的键盘上有些键是不存在的,而在美国式的键盘上,则有一些非标准的附加键。关于这些信息,请参考DirectInput SDK的文档。
2、直接的键盘数据
读取键盘的状态再也没有这么简单了,你只需申明一个256字节的数组然后再调用 IDirectInputDevice::GetDeviceState。注意,你并不需要在调用 IDirectInputDevice::GetDeviceState之前调用Poll,这是因为键盘数据总是由中断产生的。

char keys[256];
HRESULT hr = g_lpdid2->GetDeviceState( sizeof( keys ), keys );

现在你可以访问这个数组并用DIK_*数值来判断任何键的状态。与以前一样,如果字节的高位被置成1,则说明键是被按下;如果是0说明键没有被按下。

If ( keys[DIK_LMENU] & 0 ×80 ) {;} // Ieft Alt is down.

3、基于缓冲区的键盘数据
DirectInput是用基于缓冲区数据的方法来处理键盘输入的,对于这一点我们不必感到奇怪。从键盘中读取基于缓冲区的输入就像读取游戏杆和鼠标的按键输入一样。

#define BUFFERSIZE 32 /* Remember to set the device’s
DIPROP_BUFFERSIZE property to this value */
DIDEVICEOBJECTDATA rgdod[BUFFERSIZE];
DWORD dwItmes = BUFFERSIZE; // Could be fewer.
HRESULT = g_lpdid2->GetDeviceData(
sizeof( DIDEVICEOBJECTDATA ),
rgdod, // Where to put data?
&dwItems, // How many items?
0); // Flags.
与以前一样,每一个基于缓冲区的事件都与DIDEVICEOBJECTDATA结构的dwOfs成员变量中的设备物相联系。在这种情况 下,......。如果事件被按下,那么dwData成员变量的0×80位被置成1;如果事件被释放,那么dwData成员变量的0×80位被置成0。

3.1 处理数据的丢失
到目前为止,我们还没有谈到这样的一个问题:对于基于缓冲区的数据,怎样处理数据流被打断的情况。这种情况不仅仅会出现在键盘设备上,在其他的任何设备上它都可能会出现。数据流的打断会以如下两种方式出现:
1)设备被强制性地失去获取状态——例如,当原来具有前端协作级别的应用程序被移到后端时,GetDeviceData函数失败并且返回 DIERR_INPUTLOST。如果应用程序在重新获取设备时失败,那么下一次调用GetDeviceData将返回 DIERR_NOTACQUIRED。
2)缓冲区溢出。GetDeviceData函数执行成功,但返回DI_BUFFEROVERFLOW。这表明某些数据没有被返回而且这些数据永远地丢失了。
假设应用程序在GetDeviceData函数获取空格键被按下事件时开始进行射击,而在空格键被释放时停止射击。如果用户在按下空格键和释放空格键中间碰巧用鼠标单击了另一个窗口程序,那么应用程序是不会停止射击的,这是因为应用程序将丢失键盘的信息,从而导致它不能获取空格键的释放事件。为了从上述 情形下恢复正常,我们将不得不立即调用GetDeviceState函数以重新获取设备。对于出现DI_BUFFEROVERFLOW结果的情况也一样。

 

附表 DirectInput键盘常数

键名 别名
DIK_ESCAPDIK_1 在主键盘上
DIK_2 在主键盘上
DIK_3 在主键盘上
DIK_4 在主键盘上
DIK_5 在主键盘上
DIK_6 在主键盘上
DIK_7 在主键盘上
DIK_8 在主键盘上
DIK_9 在主键盘上
DIK_0 在主键盘上
DIK_MINUS 在主键盘上
DIK_EQUALS 在主键盘上
DIK_BACK DIK_BACKSPACE Backspace键
DIK_TAB
DIK_Q
DIK_W
DIK_E
DIK_R
DIK_T
DIK_Y
DIK_U
DIK_I
DIK_O
DIK_P
DIK_LBRACKET [键
DIK_RBRACKET ]键
DIK_RETURN 键盘上的回车键
DIK_LCONTROL 左Ctrl键
DIK_A
DIK_S
DIK_D
DIK_F
DIK_G
DIK_H
DIK_J
DIK_K
DIK_L
DIK_SEMICOLON
DIK_APOSTROPHE
DIK_GRAVE ‘键
DIK_LSHIFT 左Shift键
DIK_BACKSLASH
DIK_Z
DIK_X
DIK_C
DIK_V
DIK_B
DIK_N
DIK_M
DIK_COMMA
DIK_PERIOD 在主键盘上
DIK_SLASH 在主键盘上
DIK_RSHIFT 右Shift键
DIK_MULTIPLY DIK_NUMPADSTAR 数字键盘上的*键
DIK_LMENU
DIK_LALT 左Alt键
DIK_SPACE 空格
DIK_CAPITAL DIK_CAPSLOCK
DIK_F1
DIK_F2
DIK_F3
DIK_F4
DIK_F5
DIK_F6
DIK_F7
DIK_F8
DIK_F9
DIK_F10
DIK_NUMLOCK
DIK_SCROLL Scroll Lock键
DIK_NUMPAD7
DIK_NUMPAD8
DIK_NUMPAD9
DIK_SUBTRACT DIK_NUMPADMINUS 数字键盘上的-键
DIK_NUMPAD4
DIK_NUMPAD5
DIK_NUMPAD6
DIK_ADD DIK_NUMPADPLUS 数字键盘上的+键
DIK_NUMPAD1
DIK_NUMPAD2
DIK_NUMPAD3
DIK_NUMPAD0
DIK_DECIMAL DIK_NUMPADPERIOD 数字键盘上的.键
DIK_F11
DIK_F12
DIK_F13
DIK_F14
DIK_F15
DIK_KANA 在日本键盘上
DIK_CONVERT 在日本键盘上
DIK_NOCONVERT 在日本键盘上
DIK_YEN 在日本键盘上
DIK_NUMPADEQUALS 在数字键盘上(NEC PC98)
DIK_CIRCUMFLEX 在日本键盘上
DIK_AT 在日本键盘上
DIK_COLON 在日本键盘上
DIK_UNDERLINE 在日本键盘上
DIK_KANJI 在日本键盘上
DIK_STOP 在日本键盘上
DIK_AX 在日本键盘上
DIK_UNLABELED 在日本键盘上
DIK_NUMPADENTER
DIK_RCONTROL 右Ctrl键
DIK_NUMPADCOMMANEC PC98数字键盘上的逗号
DIK_DIVIDE DIK_NUMPADSLASH 数字键盘上的/号
DIK_SYSRQ
DIK_RMENU DIK_RALT 右Alt键
DIK_HOME
DIK_UP DIK_UPARROW
DIK_PRIOR DIK_PGUP PageUp键
DIK_LEFT DIK_LEFTARROW
DIK_RIGHT DIK_RIGHTARROW
DIK_END
DIK_DOWN DIK_DOWNARROW 下向箭头键
DIK_NEXT DIK_PGDN PageDown键
DIK_INSERT
DIK_DELETE
DIK_LWIN 左边Windows徽标键
DIK_RWIN 右边Windows徽标键
DIK_APPS 应用程序键

发布者

adaier

奔四。 好骑车,拍照,背包旅行和各种折腾。 最近的爱好应该是宅。 正努力充电正能量。