DirectX 2008-08-10 15:11:34 阅读169 评论0 字号:大 中 小 订阅
输入设备简介
计算机通常使用三种输入设备:键盘、鼠标和游戏杆。三种输入设备都是其他设备所无法替代的,同时每种设备都各有优缺点。键盘适用于输入,但无法取代 鼠标,而且和游戏杆相比,键盘也不如游戏杆那么灵巧。鼠标适用于定位和移动,但是和游戏杆相比,又缺少控制上的简易性。至于游戏杆,它适用于简单的移动 ----向上、向下、向左和向右移动,除此之外几乎无任何用途。
通过键盘进行交互
基本上,键盘是按照一定逻辑格式排列的按键矩阵。除开一些微小差别之外,大多数键盘都有一种标准布局。键盘上的每个键实际上都是一个开关,当按下或 者释放一个键的时候,就触发了这个开关。按下或者释放一个键就向键盘的微处理器发送了一个信号,这样就在计算机系统上产生了一个中段 (interrupt)。系统从键盘的微处理器接收数据,从而确定按下或者释放了哪个键,接收的数据被称为扫描码(scan code)。
中断是各种各样的信号,它通知系统一个设备或程序需要立即进行处理,使用中断确保了系统知道设备的状态已经发生了改变。扫描码是一些值,它们确定了 键盘上的哪个键被按下或释放了。这些扫描码都是一个字节(操作系统可以使用很多方法来表示扫描码),字节的一部分表示包含了哪个按键,一个位表示键是否被 按下或释放。扫描码只能识别单个按键,无法区分大写和小写字母。因此,大写字母A和小写字母a拥有相同的扫描码,通过跟踪是否按住了Shift键,操作系 统自动检测和区分大小写字母。
如下图所示,这是一个典型的101-102键盘,键盘的局部放大图显示了一些带有相应扫描码的键,扫描码是位编码数字。
注意扫描码是按照键盘上的顺序进行排列的,每行中位于右边的键通常是更高的扫描码。扫描码的最低7位(位0--6)表示了键值(被按下或者释放的那 个键),同时扫描码的最高位(位7)表示此键是否被按下(该位被设置)或者释放(该位被清除)。字节最高能够表示的数字是255,且最高位保留,这样就给 出了128个键的空间。
在windows中处理键盘
windows能够处理检索键盘输入的一般性任务,为了使工作变得更加容易,windows将从键盘接收到的扫描码转化成虚拟键码以及ASCII码的标准码。windows采用许多方法将这些值报告给程序员,不过通常使用消息过程函数。
虚拟键码是windows版本的扫描码,举例来说,字母A的扫描码为30,但是虚拟键码不使用这个值,而是使用虚拟键码宏VK_A来表示字母A,不管使用什么样的键盘(以及键盘报告的扫描码),VK_A总是表示字母A。
ASCII(美国信息交换标准码,American Standard Code for Information Interchange)是一个标准,它规定了哪个值被映射到哪个字符。使用ASCII能够为多达128个不同字符映射值,这些字符包括数字、字母表、一 般符号以及控制码。
windows实际使用的是扩展ASCII码以及unicode字符(或宽字节字符)。扩展ASCII码在规则ASCII上添加了信息的额外位,因 此将字母的最大数目提升到了256。这样做也带来了不利的方面----扩展字符可以是任何东西,因为没有实质标准来约束这些字符。当然,因为有些其他语言 需要更多的字符,因此Unicode就应运而生,它将字符的最大数目扩展到了16位,足够存储65536个字符。
使用DirectInput
DirectInput是一些COM对象的集合(和所有DirectX组件相同),这些COM对象描绘了输入系统和各个输入设备。最主要的对象是DirectInput8,它用于初始化系统以及创建输入设备接口。
DirectInput COM对象:
IDirectInput8:主要的DirectInput8 COM接口,其他所有接口都通过这个接口进行查询。
DirectInputDevice8:用于输入设备的COM接口,每个设备都有自己单独的接口可供使用。
DirectInputEffect:用于力反馈效果的 COM接口,比如某些游戏杆和某些鼠标上的力反馈效果。
各 种输入设备(比如键盘、鼠标和游戏杆)都使用相同的接口对象IDirectInputDevice8。某些设备,比如游戏杆和鼠标,能够通过查询各自的 IDirectInputDevice8对象以得到另外一个接口IDirectInputEffect,这个接口用于控制设备的力反馈效果。
IDirectInput8、IDirectInputDevice8、IDirectInputEffect接口之间的关系如下图所示:
IDirectInput8组件对象包含了很多用于初始化输入系统以及获得设备接口的函数,在这些函数中,常用的只有两个,它们是 IDirectInput8::EnumDevices和IDirectInput8::CreateDevice。
初始化DirectInput
要使用DirectInput,需要确保包含了DInput.h和在工程中链接了DInput8.lib,一个IDirectInput8对象就代表了主要DirectInput对象。
DirectInput提供了帮助函数 DirectInput8Create 用于初始化IDirectInput8接口。
Creates a DirectInput object and returns an IDirectInput8 Interface or later interface.
HRESULT DirectInput8Create (
HINSTANCE hinst ,
DWORD dwVersion ,
REFIID riidltf ,
LPVOID * ppvOut ,
LPUNKNOWN punkOuter
);
If the function succeeds, the return value is DI_OK. If the function fails, the return value can be one of the following error values: DIERR_BETADIRECTINPUTVERSION, DIERR_INVALIDPARAM, DIERR_OLDDIRECTINPUTVERSION, DIERR_OUTOFMEMORY.
The DirectInput object created by this function is implemented in Dinput8.dll. Versions of interfaces earlier than DirectX 8.0 cannot be obtained in this implementation.
To create a DirectX 8.x interface with the latest DirectX SDK without using CoCreateInstance:
To create a DirectX 8.x interface with the DirectX 8.x SDK without using CoCreateInstance:
To create a DirectX 7.0 interface from the DirectX 8.x or latest DirectX SDK without using CoCreateInstance:
To create a DirectX 7.0 interface from the DirectX 8.x or latest DirectX SDK using CoCreateInstance:
To create a DirectX 8.x or DirectX 9.0 interface from the DirectX 8.x or latest DirectX SDK using CoCreateInstance:
Calling the function with pUnkOuter = NULL is equivalent to creating the object through CoCreateInstance( &CLSID_DirectInput8, punkOuter, CLSCTX_INPROC_SERVER, &IID_IDirectInput8W, lplpDirectInput), then initializing it with IDirectInput8::Initialize .
Calling the function with pUnkOuter != NULL is equivalent to creating the object through CoCreateInstance( &CLSID_DirectInput8, punkOuter, CLSCTX_INPROC_SERVER, &IID_IUnknown, lplpDirectInput). The aggregated object must be initialized manually.
使用DirectInput设备的步骤
1、获取设备GUID,调用IDirectInput8::EnumDevice来实现。
2、创建设备COM对象,调用IDirectInput8::CreateDevice来实现。
3、设置数据格式,调用IDirectInputDevice8::SetDataFormat来实现。
4、设置协作级别,调用IDirectInputDevice8::SetCooperativeLevel来实现。
5、设置任何特殊属性,调用IDirectInputDevice8::SetProperty来实现。
6、获得设备,调用IDirectInputDevice8::Acquire来实现。
7、轮询设备,调用IDirectInputDevice8::Poll来实现。
8、读取数据,调用IDirectInputDevice8::GetDeviceState来实现。
在进行这些步骤前,要确保声明了一个IDirectInput设备对象,即IDirectInputDevice8对象。
获取设备GUID
每 个安装的设备都有一个系统分配的全局惟一标识符(global unique identification, GUID)数字。要使用一个设备,首先必须知道它的GUID。对于连接到系统上的鼠标和键盘,得到他们的GUID非常容易,DirectInput分别为 鼠标和键盘的GUID定义成GUID_SysKeyboard和GUID_SysMouse。要使用GUID_SysKeyboard或 GUID_SysMouse,必须在所有其他的预处理程序指令前定义INITGUID,或者将DXGuid.lib库链接到项目中。至于其他设备,必须枚 举出这些设备,才能得到需要的那些设备的GUID。枚举就是遍历一个含有数据项的列表的过程,数据项就是诸如游戏杆之类的输入设备。假设有5个游戏杆连接 到了系统上,那么在枚举的过程中,DirectInput就会传递各个游戏杆的相关信息,而且每次只传递一个游戏杆的信息,直到所有的游戏杆都已经被列出 来或者列举被强行终止。
用于枚举设备的函数是IDirectInput8::EnumDevice。
Enumerates available devices.
HRESULT EnumDevices(
DWORD dwDevType ,
LPDIENUMDEVICESCALLBACK lpCallback ,
LPVOID pvRef ,
DWORD dwFlags
);
Device type filter.
To enumerate a class of devices, use one of the following values.
If the method succeeds, the return value is DI_OK. If the method fails, the return value can be one of the following error values: DIERR_INVALIDPARAM, DIERR_NOTINITIALIZED.
All installed devices can be enumerated, even if they are not present. For example, a flight stick might be installed on the system but not currently plugged into the computer. Set the dwFlags parameter to indicate whether only attached or all installed devices should be enumerated. If the DIEDFL_ATTACHEDONLY flag is not present, all installed devices are enumerated.
A preferred device type can be passed as a dwDevType filter so that only the devices of that type are enumerated.
On Microsoft Windows XP, DirectInput enumerates only one mouse and one keyboard device, referred to as the system mouse and the system keyboard. These devices represent the combined output of all mice and keyboards respectively on a system. For information about how to read from multiple mice or keyboards individually on Windows XP, see the WM_INPUT documentation.
Note The order in which devices are enumerated by DirectInput is not guaranteed.
lpCallback是一个指向枚举函数的指针,在系统上每找到一个匹配的设备时,就会调用该函数。
Application-defined callback function that receives DirectInput devices as a result of a call to the IDirectInput8::EnumDevices method.
BOOL DIEnumDevicesCallback(
LPCDIDEVICEINSTANCE lpddi ,
LPVOID pvRef
);
Returns DIENUM_CONTINUE to continue the enumeration or DIENUM_STOP to stop the enumeration.
If a single hardware device can function as more than one DirectInput device type, it is enumerated as each device type that it supports. For example, a keyboard with a built-in mouse is enumerated twice: once as a keyboard and once as a mouse. The product globally unique identifier (GUID) is the same for each device, however.
lpddi是一个指向DIDEVICEINSTANCE结构体的指针,此结构体包含了此次调用时当前枚举设备上的信息。
Describes an instance of a DirectInput device. This structure is used with the IDirectInput8::EnumDevices, IDirectInput8::EnumDevicesBySemantics, and IDirectInputDevice8::GetDeviceInfo methods.
typedef struct DIDEVICEINSTANCE {
DWORD dwSize;
GUID guidInstance;
GUID guidProduct;
DWORD dwDevType;
TCHAR tszInstanceName[MAX_PATH];
TCHAR tszProductName[MAX_PATH];
GUID guidFFDriver;
WORD wUsagePage;
WORD wUsage;
} DIDEVICEINSTANCE, *LPDIDEVICEINSTANCE;
The following device types and subtypes are defined for use in the dwDevType member.
First-person action game device. The following subtypes are defined.
Device that does not provide the minimum number of device objects for action mapping.
Device designed for first-person shooter games.
Device with six degrees of freedom; that is, three lateral axes and three rotational axes.
Unknown subtype.
Device that does not fall into another category.
Input device used to control another type of device from within the context of the application. The following subtypes are defined.
Control used to make communications selections.
Device that must use its default configuration and cannot be remapped.
Unknown subtype.
Device for steering. The following subtypes are defined.
Steering device that reports acceleration and brake pedal values from a single axis.
Steering device that reports acceleration and brake pedal values from separate axes.
Hand-held steering device.
Steering device that does not provide the minimum number of device objects for action mapping.
Steering device that reports acceleration, brake, and clutch pedal values from separate axes.
Controller for flight simulation. The following subtypes are defined.
Flight controller that does not provide the minimum number of device objects for action mapping.
Flight device based on a remote control for model aircraft.
Joystick.
Yoke.
Gamepad. The following subtypes are defined.
Gamepad that does not provide the minimum number of device objects for action mapping.
Standard gamepad that provides the minimum number of device objects for action mapping.
Gamepad that can report x-axis and y-axis data based on the attitude of the controller.
Joystick. The following subtypes are defined.
Joystick that does not provide the minimum number of device objects for action mapping.
Standard joystick that provides the minimum number of device objects for action mapping.
Keyboard or keyboard-like device. The following subtypes are defined.
Subtype could not be determined.
IBM PC/XT 83-key keyboard.
Olivetti 102-key keyboard.
IBM PC/AT 84-key keyboard.
IBM PC Enhanced 101/102-key or Microsoft Natural keyboard.
Nokia 1050 keyboard.
Nokia 9140 keyboard.
Japanese NEC PC98 keyboard.
Japanese NEC PC98 laptop keyboard.
Japanese NEC PC98 106-key keyboard.
Japanese 106-key keyboard.
Japanese AX keyboard.
Japanese J3100 keyboard.
A mouse or mouse-like device (such as a trackball). The following subtypes are defined.
Mouse that returns absolute axis data.
Fingerstick.
Touchpad.
Trackball.
Traditional mouse.
Subtype could not be determined.
Remote-control device. The following subtype is defined.
Subtype could not be determined.
Screen pointer. The following subtypes are defined.
Unknown subtype.
Light gun.
Light pen.
Touch screen.
Specialized device with functionality unsuitable for the main control of an application, such as pedals used with a wheel. The following subtypes are defined.
Secondary handheld controller.
Device whose primary function is to report acceleration and brake pedal values from a single axis.
Device whose primary function is to report acceleration and brake pedal values from separate axes.
Device that tracks hand movement.
Device that tracks head movement.
Device with rudder pedals.
Device that reports gear selection from an axis.
Device that reports gear selection from button states.
Device whose primary function is to report at least two throttle values. It may have other controls.
Device whose primary function is to report acceleration, brake, and clutch pedal values from separate axes.
Device whose primary function is to report a single throttle value. It may have other controls.
Unknown subtype.
Versions of DirectInput earlier than DirectX 8.0 have a somewhat different scheme of device types and subtypes. See the DIDEVTYPExxx defines in Dinput.h.
创建设备COM对象
有了设备GUID,就能创建实际的IDirectInputDevice8 COM对象了,用于创建此COM对象的函数是IDirectInput8::CreateDevice。
Creates and initializes an instance of a device based on a given globally unique identifier (GUID), and obtains an IDirectInputDevice8 Interface interface.
HRESULT CreateDevice(
REFGUID rguid ,
LPDIRECTINPUTDEVICE * lplpDirectInputDevice ,
LPUNKNOWN pUnkOuter
);
If the method succeeds, the return value is DI_OK. If the method fails, the return value can be one of the following: DIERR_DEVICENOTREG, DIERR_INVALIDPARAM, DIERR_NOINTERFACE, DIERR_NOTINITIALIZED, DIERR_OUTOFMEMORY.
Calling this method with pUnkOuter = NULL is equivalent to creating the object by CoCreateInstance (&CLSID_DirectInputDevice, NULL, CLSCTX_INPROC_SERVER, riid, lplpDirectInputDevice) and then initializing it with Initialize.
Calling this method with pUnkOuter != NULL is equivalent to creating the object by CoCreateInstance (&CLSID_DirectInputDevice, punkOuter, CLSCTX_INPROC_SERVER, &IID_IUnknown, lplpDirectInputDevice). The aggregated object must be initialized manually.