使用DirectInput进行交互(2)

设置数据格式

每种设备都有一种用于读取数据的特定数据格式,需要考虑的东西也很多,包括键、鼠标按键、轴等。因此要使程序从设备读取数据,首先必须告诉DirectInput读取这种数据所采用的格式。通过 IDirectInputDevice8::SetDataFormat函数即可满足上述要求。

Sets the data format for the Microsoft DirectInput device.

Syntax

HRESULT SetDataFormat(LPCDIDATAFORMAT lpdf);

Parameters

lpdf
Address of a structure that describes the format of the data that the DirectInputDevice should return. An application can define its own DIDATAFORMAT structure or use one of the following predefined global variables:
 
c_dfDIKeyboard
c_dfDIMouse
c_dfDIMouse2
c_dfDIJoystick
c_dfDIJoystick2

Return Value

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_ACQUIRED The operation cannot be performed while the device is acquired.
DIERR_INVALIDPARAM An invalid parameter was passed to the returning function, or the object was not in a state that permitted the function to be called. This value is equal to the E_INVALIDARG standard Component Object Model (COM) return value.
DIERR_NOTINITIALIZED The object has not been initialized.

Remarks

The data format must be set before the device can be acquired by using the IDirectInputDevice8::Acquire method. It is necessary to set the data format only once. The data format cannot be changed while the device is acquired.

If the application is using action mapping, the data format is set instead by the call to IDirectInputDevice8::SetActionMap.

SetDataFormat函数只有一个参数,这个参数是一个指向DIDATAFORMAT结构体的指针,此结构体的定义如下:

Describes a device's data format. This structure is used with the IDirectInputDevice8::SetDataFormat method.

Syntax

typedef struct DIDATAFORMAT {
    DWORD dwSize;
    DWORD dwObjSize;
    DWORD dwFlags;
    DWORD dwDataSize;
    DWORD dwNumObjs;
    LPDIOBJECTDATAFORMAT rgodf;
} DIDATAFORMAT, *LPDIDATAFORMAT;
 
typedef const DIDATAFORMAT *LPCDIDATAFORMAT;

Members

dwSize
Size of this structure, in bytes.

dwObjSize
Size of the DIOBJECTDATAFORMAT structure, in bytes.

dwFlags
Flags describing other attributes of the data format. This value can be one of the following:

DIDF_ABSAXIS
The axes are in absolute mode. Setting this flag in the data format is equivalent to manually setting the axis mode property, using the IDirectInputDevice8::SetProperty method. This cannot be combined with DIDF_RELAXIS flag.

DIDF_RELAXIS
The axes are in relative mode. Setting this flag in the data format is equivalent to manually setting the axis mode property using the IDirectInputDevice8::SetProperty method. This cannot be combined with the DIDF_ABSAXIS flag.

dwDataSize
Size of a data packet returned by the device, in bytes. This value must be a multiple of 4 and must exceed the largest offset value for an object's data within the data packet.

dwNumObjs
Number of objects in the rgodf array.

rgodf
Address to an array of DIOBJECTDATAFORMAT structures. Each structure describes how one object's data should be reported in the device data. Typical errors include placing two pieces of information in the same location and placing one piece of information in more than one location.

Remarks

Applications do not typically need to create a DIDATAFORMAT structure. An application can use one of the predefined global data format variables, c_dfDIMouse, c_dfDIMouse2, c_dfDIKeyboard, c_dfDIJoystick, or c_dfDIJoystick2.

Applications that need to create a DIDATAFORMAT structure must first call IDirectInputDevice8::EnumObjects to determine the available objects for the current device. This is because the IDirectInputDevice8::SetDataFormat method will return DIERR_INVALIDPARAM if an an object is described in the DIDATAFORMAT structure but does not exist on the current device.

设置协作级别

首先必须面对一个事实,那就是每个程序都会使用许多输入设备。几乎每个程序都会使用键盘和鼠标,同时某些程序还会使用游戏杆。在处理的时候,必须同其他可能仍在运行的应用程序共享对这些设备的访问,或者应用程序独占对设备的所有访问,这样除非该应用程序结束了对设备的访问,否则就不允许其他应用程序控制这些设备。

设置协作级别的函数是IDirectInputDevice8::SetCooperativeLevel。

Establishes the cooperative level for this instance of the device. The cooperative level determines how this instance of the device interacts with other instances of the device and the rest of the system.

Syntax

HRESULT SetCooperativeLevel(HWND hwnd,
    DWORD dwFlags
);

Parameters

hwnd
Window handle to be associated with the device. This parameter must be a valid top-level window handle that belongs to the process. The window associated with the device must not be destroyed while it is still active in a Microsoft DirectInput device.

dwFlags
Flags that describe the cooperative level associated with the device. The following flags are defined:

DISCL_BACKGROUND
The application requires background access. If background access is granted, the device can be acquired at any time, even when the associated window is not the active window.

DISCL_EXCLUSIVE
The application requires exclusive access. If exclusive access is granted, no other instance of the device can obtain exclusive access to the device while it is acquired. However, nonexclusive access to the device is always permitted, even if another application has obtained exclusive access.

An application that acquires the mouse or keyboard device in exclusive mode should always unacquire the devices when it receives WM_ENTERSIZEMOVE and WM_ENTERMENULOOP messages. Otherwise, the user cannot manipulate the menu or move and resize the window.

DISCL_FOREGROUND
The application requires foreground access. If foreground access is granted, the device is automatically unacquired when the associated window moves to the background.

DISCL_NONEXCLUSIVE
The application requires nonexclusive access. Access to the device does not interfere with other applications that are accessing the same device.

DISCL_NOWINKEY
Disable the Microsoft Windows logo key. Setting this flag ensures that the user cannot inadvertently break out of the application. Note, however, that DISCL_NOWINKEY has no effect when the default action mapping user interface (UI) is displayed, and the Windows logo key will operate normally as long as that UI is present.

Return Value

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 An invalid parameter was passed to the returning function, or the object was not in a state that permitted the function to be called. This value is equal to the E_INVALIDARG standard Component Object Model (COM) return value.
DIERR_NOTINITIALIZED The object has not been initialized.
E_HANDLE The HWND parameter is not a valid top-level window that belongs to the process.

Remarks

Applications must specify either DISCL_FOREGROUND or DISCL_BACKGROUND; it is an error to specify both or neither. Similarly, applications must specify either DISCL_EXCLUSIVE or DISCL_NONEXCLUSIVE.

If the system mouse is acquired in exclusive mode, the pointer is removed from the screen until the device is unacquired. This applies only to a mouse created by passing GUID_SysMouse to IDirectInput8::CreateDevice.

Applications that select the background exclusive mode cooperative level are not guaranteed to retain access to the device if another application requests exclusive access. When a background exclusive mode application loses access, calls to DirectInput device methods will fail and return DIERR_NOTACQUIRED. The application can regain access to the device by manually unacquiring the device and reaquiring it.

Applications must call this method before acquiring the device by using the IDirectInputDevice8::Acquire method.

设置特殊属性

设置设备的特殊属性,包括轴模式(axis mode),缓冲区(buffering)以及最大最小范围。对于轴模式,有两个选择:相对和绝对。绝对模式基于一个中心坐标来报告坐标。位于这个点左边或上面的值都报告成负值,同时位于这个点右边或下面的值都报告成正值。相对坐标就是当前位置同上一个位置之间的距离差。

最后一个特殊性属性是设备的最小和最大范围设置。举例来说,将游戏杆推动到最左边就会产生最小值,而推动到最右边就会产生最大值。这两边产生何种值取决于具体的设置,只有游戏杆才会涉及到最小和最大范围设置。

用于设置特殊属性的函数是 IDirectInputDevice8::SetProperty。

Sets properties that define the device behavior. These properties include input buffer size and axis mode.

Syntax

HRESULT SetProperty(REFGUID rguidProp,
    LPCDIPROPHEADER pdiph
);

Parameters

rguidProp
Reference to (C++) or address of (C) the globally unique identifier (GUID) identifying the property to be set. This can be one of the predefined values, or a pointer to a GUID that identifies the property. The following property values are predefined for an input device:

DIPROP_APPDATA
Sets the application-defined value associated with an in-game action, as a DIPROPPOINTER.

DIPROP_AUTOCENTER
Specifies whether device objects are self centering. This setting applies to the entire device, rather than to any particular object, so the dwHow member of the associated DIPROPDWORD structure must be DIPH_DEVICE.
The dwData member can be one of the following values.

DIPROPAUTOCENTER_OFF: The device should not automatically center when the user releases the device. An application that uses force feedback should disable autocentering before playing effects.

DIPROPAUTOCENTER_ON: The device should automatically center when the user releases the device.

Not all devices support the autocenter property.

DIPROP_AXISMODE
Sets the axis mode. The value being set (DIPROPAXISMODE_ABS or DIPROPAXISMODE_REL) must be specified in the dwData member of the associated DIPROPDWORD structure. See the description of the pdiph parameter for more information.

This setting applies to the entire device, so the dwHow member of the associated DIPROPDWORD structure must be set to DIPH_DEVICE.

DIPROP_BUFFERSIZE
Sets the input buffer size. The value being set must be specified in the dwData member of the associated DIPROPDWORD structure. See Remarks. This setting applies to the entire device, so the dwHow member of the associated DIPROPDWORD structure must be set to DIPH_DEVICE.

DIPROP_CALIBRATION
Predefined property that allows the application to access the information that Microsoft DirectInput uses to manipulate axes that require calibration. This property exists primarily for applications of the control panel type. Normal applications should not need to deal with calibration information.
You can access the calibration mode property for an axis by setting the dwHow member of the DIPROPHEADER structure to DIPH_BYID or to DIPH_BYOFFSET and setting the dwObj member to the object identifier (ID) or offset, respectively.

Control panel applications that set new calibration data must also invoke the IDirectInputJoyConfig::SendNotify method to notify other applications of the change in calibration. For more information about IDirectInputJoyConfig::SendNotify, see the Microsoft DirectX Driver Development Kit (DDK).

DIPROP_CALIBRATIONMODE
Enables the application to specify whether DirectInput should retrieve calibrated or uncalibrated data from an axis. By default, DirectInput retrieves calibrated data.
Setting the calibration mode for the entire device is equivalent to setting it for each axis individually.

The dwData member of the DIPROPDWORD structure can be one of the following values:

DIPROPCALIBRATIONMODE_COOKED: DirectInput should return data after applying calibration information. This is the default mode.
DIPROPCALIBRATIONMODE_RAW: DirectInput should return raw, uncalibrated data. This mode is typically used only by applications of the control panel type. Note that raw data might include negative values.

Setting a device into raw mode causes the dead zone, saturation, and range settings to be ignored.

DIPROP_CPOINTS
Sets calibration points used for the adjustment of incoming raw data. The values being set must be specified as CPOINT types in the cp array of the associated DIPROPCPOINTS structure. This setting applies to individual device objects, so the dwHow member of the associated DIPROPHEADER structure must be set to either DIPH_BYID or DIPH_BYOFFSET.

DIPROP_DEADZONE
Sets the value for the dead zone of a joystick, in the range from 0 through 10,000, where 0 indicates that there is no dead zone, 5,000 indicates that the dead zone extends over 50 percent of the physical range of the axis on both sides of center, and 10,000 indicates that the entire physical range of the axis is dead. When the axis is within the dead zone, it is reported as being at the center of its range. This setting can be applied to either the entire device or to a specific axis.

DIPROP_FFGAIN
Sets the gain for the device. This setting applies to the entire device, rather than to any particular object, so the dwHow member of the associated DIPROPDWORD structure must be DIPH_DEVICE.
The dwData member contains a gain value that is applied to all effects created on the device. The value is an integer in the range from 0 through 10,000, specifying the amount by which effect magnitudes should be scaled for the device. For example, a value of 10,000 indicates that all effect magnitudes are to be taken at face value. A value of 9,000 indicates that all effect magnitudes are to be reduced to 90 percent of their nominal magnitudes.

DirectInput always checks the gain value before setting the gain property. If the gain is outside of the range (less than zero or greater than 10,000), IDirectInputDevice8::SetProperty will return DIERR_INVALIDPARAM. Otherwise, if successful, it will return DI_OK, even if the device does not support force feedback.

Setting a gain value is useful when an application wants to scale down the strength of all force-feedback effects uniformly, based on user preferences.

Unlike other properties, the gain can be set when the device is in an acquired state.

DIPROP_INSTANCENAME
This property exists for advanced applications that want to change the friendly instance name of a device (as returned in the tszInstanceName member of the DIDEVICEINSTANCE structure) to distinguish it from similar devices that are plugged in simultaneously. Most applications should have no need to change the friendly name.
This setting applies to the entire device, so the dwHow member of the associated DIPROPDWORD structure must be set to DIPH_DEVICE.

The pdiph parameter must be a pointer to the diph member of a DIPROPSTRING structure.

DIPROP_PRODUCTNAME
This property exists for advanced applications that want to change the friendly product name of a device (as returned in the tszProductName member of the DIDEVICEINSTANCE structure) to distinguish it from similar devices which are plugged in simultaneously. Most applications should have no need to change the friendly name.
This setting applies to the entire device, so the dwHow member of the associated DIPROPDWORD structure must be set to DIPH_DEVICE.

The pdiph parameter must be a pointer to the diph member of a DIPROPSTRING structure.

Setting the product name is only useful for changing the user-defined name of an analog joystick on Microsoft Windows 98,Windows 2000, and Windows Millennium Edition (Windows Me) computers. In other cases, attempting to set this property will still return DI_OK. However, the name is not stored in a location used by IDirectInputDevice8::GetProperty.

DIPROP_RANGE
Sets the range of values an object can possibly report. The minimum and maximum values are taken from the lMin and lMax members of the associated DIPROPRANGE structure.
For some devices, this is a read-only property.

You cannot set a reverse range; lMax must be greater than lMin.

DIPROP_SATURATION
Sets the value for the saturation zones of a joystick, in the range from 0 through 10,000. The saturation level is the point at which the axis is considered to be at its most extreme position. For example, if the saturation level is set to 9,500, the axis reaches the extreme of its range when it has moved 95 percent of the physical distance from its center position (or from the dead zone). This setting can be applied to either the entire device or a specific axis.

pdiph
Address of the DIPROPHEADER structure contained within the type-specific property structure.

Return Value

If the method succeeds, the return value is DI_OK or DI_PROPNOEFFECT.

If the method fails, the return value can be one of the following error values.

DIERR_INVALIDPARAM An invalid parameter was passed to the returning function, or the object was not in a state that permitted the function to be called. This value is equal to the E_INVALIDARG standard Component Object Model (COM) return value.
DIERR_NOTINITIALIZED The object has not been initialized.
DIERR_OBJECTNOTFOUND The requested object does not exist.
DIERR_UNSUPPORTED The function called is not supported at this time. This value is equal to the E_NOTIMPL standard COM return value.

Remarks

The buffer size determines the amount of data that the buffer can hold between calls to the IDirectInputDevice8::GetDeviceData method before data is lost. This value may be set to 0 to indicate that the application does not read buffered data from the device. If the buffer size in the dwData member of the DIPROPDWORD structure is too large for the device to support it, then the largest possible buffer size is set.

在调用SetProperty函数时始终要使用的DIPROPHEADER结构体定义如下:

Serves as a header for all property structures.

Syntax

typedef struct DIPROPHEADER {
    DWORD    dwSize;
    DWORD    dwHeaderSize;
    DWORD    dwObj;
    DWORD    dwHow;
} DIPROPHEADER, *LPDIPROPHEADER;
 
typedef const DIPROPHEADER *LPCDIPROPHEADER;

Members

dwSize
Size of the enclosing structure. This member must be initialized before the structure is used.

dwHeaderSize
Size of the DIPROPHEADER structure.

dwObj
Object for which the property is to be accessed. The value set for this member depends on the value specified in the dwHow member.

dwHow
Value that specifies how the dwObj member should be interpreted. This value can be one of the following:

DIPH_DEVICE
The dwObj member must be 0.

DIPH_BYOFFSET
The dwObj member is the offset into the current data format of the object whose property is being accessed.

DIPH_BYUSAGE
The dwObj member is the HID usage page and usage values in packed form.

DIPH_BYID
The dwObj member is the object type/instance identifier. This identifier is returned in the dwType member of the DIDEVICEOBJECTINSTANCE structure returned from a previous call to the IDirectInputDevice8::EnumObjects member.

获得设备

在使用任何设备之前,首先必须获得设备。只有获得了设备才能确保程序能够访问设备,以及同其他程序共享访问还是完全控制设备。要注意的是其他程序可能会争夺并抢走对设备的控制权,要补救这种情况就必须重新获得设备。何时必须获得设备?第一种情况就是在创建接口的时候,原因在于使用设备之前必须首先获得它。另一种情况就是当另一个程序抢走了对设备的控制,同时 DirectInput通知了程序时。

调用IDirectInputDevice8::Acquire函数即可获得设备。

Obtains access to the input device.

Syntax

HRESULT Acquire(VOID);

Return Value

If the method succeeds, the return value is DI_OK, or S_FALSE if the device was already acquired.

If the method fails, the return value can be one of the following error values.

DIERR_INVALIDPARAM An invalid parameter was passed to the returning function, or the object was not in a state that permitted the function to be called. This value is equal to the E_INVALIDARG standard Component Object Model (COM) return value.
DIERR_NOTINITIALIZED The object has not been initialized.
DIERR_OTHERAPPHASPRIO Another application has a higher priority level, preventing this call from succeeding. This value is equal to the E_ACCESSDENIED standard COM return value. This error can be returned when an application has only foreground access to a device but is attempting to acquire the device while in the background.

Remarks

Before a device can be acquired, a data format must be set by using the IDirectInputDevice8::SetDataFormat method or IDirectInputDevice8::SetActionMap method. If the data format has not been set, IDirectInputDevice8::Acquire returns DIERR_INVALIDPARAM.

Devices must be acquired before calling the IDirectInputDevice8::GetDeviceState or IDirectInputDevice8::GetDeviceData methods for that device.

Device acquisition does not use a reference count. Therefore, if an application calls the IDirectInputDevice8::Acquire method twice, then calls the IDirectInputDevice8::Unacquire method once, the device is unacquired.

If IDirectInputDevice8::BuildActionMap succeeds but no actions have been mapped, a subsequent call to IDirectInputDevice8::SetActionMap will return DI_OK but a call to IDirectInputDevice8::Acquire will fail with DIERR_INVALIDPARAM.

轮询设备

轮询可以准备设备并在合适的情况下读取设备数据,因为数据可能具有临界时间。游戏杆就是这样的设备,要从设备读取数据,计算机需要发送一个电子脉冲给它。虽然轮询对于游戏杆输入而言是必须的,但是对键盘或鼠标来说却并不需要轮询。

轮询设备需要使用IDirectInputDevice8::Poll函数。

Retrieves data from polled objects on a Microsoft DirectInput device. If the device does not require polling, calling this method has no effect. If a device that requires polling is not polled periodically, no new data is received from the device. Calling this method causes DirectInput to update the device state, generate input events (if buffered data is enabled), and set notification events (if notification is enabled).

Syntax

HRESULT Poll(VOID);

Return Value

If the method succeeds, the return value is DI_OK, or DI_NOEFFECT if the device does not require polling.

If the method fails, the return value can be one of the following error values:

DIERR_INPUTLOST Access to the input device has been lost. It must be reacquired.
DIERR_NOTACQUIRED The operation cannot be performed unless the device is acquired.
DIERR_NOTINITIALIZED The object has not been initialized.

Remarks

Before a device data can be polled, the data format must be set by using the IDirectInputDevice8::SetDataFormat or IDirectInputDevice8::SetActionMap method, and the device must be acquired by using the IDirectInputDevice8::Acquire method.

读取数据

经过以上的步骤,就剩下最后一步了,那就是使用 IDirectInputDevice8::GetDeviceState函数读取设备数据。为了存储设备的信息,必须传递一个数据缓冲区给此函数,这样程序才能使用设备的信息,每种设备的数据各不相同。

Retrieves immediate data from the device.

Syntax

HRESULT GetDeviceState(DWORD cbData,
    LPVOID lpvData
);

Parameters

cbData
Size of the buffer in the lpvData parameter, in bytes.

lpvData
Address of a structure that receives the current state of the device. The format of the data is established by a prior call to the IDirectInputDevice8::SetDataFormat method.

Return Value

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_INPUTLOST Access to the input device has been lost. It must be reacquired.

DIERR_INVALIDPARAM An invalid parameter was passed to the returning function, or the object was not in a state that permitted the function to be called. This value is equal to the E_INVALIDARG standard Component Object Model (COM) return value.

DIERR_NOTACQUIRED The operation cannot be performed unless the device is acquired.

DIERR_NOTINITIALIZED The object has not been initialized.

E_PENDING Data is not yet available.

Remarks

Before device data can be obtained, set the cooperative level by using the IDirectInputDevice8::SetCooperativeLevel method, then set the data format by using IDirectInputDevice8::SetDataFormat, and acquire the device by using the IDirectInputDevice8::Acquire method.

The five predefined data formats require corresponding device state structures according to the following table:

Data format State structure
c_dfDIMouse DIMOUSESTATE
c_dfDIMouse2 DIMOUSESTATE2
c_dfDIKeyboard array of 256 bytes
c_dfDIJoystick DIJOYSTATE
c_dfDIJoystick2 DIJOYSTATE2

For example, if you passed the c_dfDIMouse format to the IDirectInputDevice8::SetDataFormat method, you must pass a DIMOUSESTATE structure to the IDirectInputDevice8::GetDeviceState method.

无论是哪种设备,下面的代码都能读取其数据。它们考虑了丢失设备并在适当的时刻重新获得设备的情况,必须传递一个指向缓冲区的指针给下面这个函数,缓冲区的大小要能够保存设备信息以及读取的数据量。

BOOL Read_Device(IDirectInputDevice8 *  directinput_device,  void *  buffer,  long  buffer_size)
{
    HRESULT rv;

    
while ( 1 )
    {
        
//  poll device
        g_directinput_device -> Poll();

        
//  read in state
         if (SUCCEEDED(rv  =  g_directinput_device -> GetDeviceState(buffer_size, buffer)))
            
break ;

        
//  return when an unknown error
         if (rv  !=  DIERR_INPUTLOST  ||  rv  !=  DIERR_NOTACQUIRED)
            
return  FALSE;

        
//  re-acquire and try again
         if (FAILED(g_directinput_device -> Acquire()))
            
return  FALSE;
    }

    
return  TRUE;
}

使用DirectInput处理键盘

如果调用成功,下面的初始化函数则返回一个指向新创建的IDirectInputDevice8对象的指针;反之当函数调用失败时,返回NULL。只需给此函数传递父窗口的句柄和与定义的DirectInput对象即可。

// --------------------------------------------------------------------------------
//  Initialize keyboard interface, return a keyboad interface pointer.
// --------------------------------------------------------------------------------
IDirectInputDevice8 *  Init_Keyboard(HWND hwnd, IDirectInput8 *  directinput)
{
    IDirectInputDevice8
*  directinput_device;

    
//  create the device object
     if (FAILED(directinput -> CreateDevice(GUID_SysKeyboard,  & directinput_device, NULL)))
        
return  NULL;

    
//  set the data format
     if (FAILED(directinput_device -> SetDataFormat( & c_dfDIKeyboard)))
    {
        directinput_device
-> Release();
        
return  NULL;
    }

    
//  set the coooperative mode
     if (FAILED(directinput_device -> SetCooperativeLevel(hwnd, DISCL_FOREGROUND  |  DISCL_NONEXCLUSIVE)))
    {
        directinput_device
-> Release();
        
return  NULL;
    }

    
//  acquire the device for use
     if (FAILED(directinput_device -> Acquire()))
    {
        directinput_device
-> Release();
        
return  NULL;
    }

    
//  everything well, so return a vaild pointer.
     return  directinput_device;
}

要存储键盘数据,必须使用一个大小为256字节的数组,每个字节存储一个键的状态,这样就给出了保存256个键的空间。每个字节存储键当前的状态信息,即键是否被按下。要得到键的状态,就要检查高位(字节),如果置位,键就被按下;如果清零,键就未被按下。在DirectInput 中,每个键都有一个属于自己的宏,这些宏都以DIK_为前缀。A键定义为DIK_A,ESC为DIK_ESCAPE等。查阅DX SDK或DInput.h可以得到其他键的宏。

点击下载源码和工程

完整源码如下:

/* **************************************************************************************
PURPOSE:
    Keyboard device Demo
 **************************************************************************************
*/

#define  DIRECTINPUT_VERSION 0x0800

#include 
< windows.h >
#include 
< stdio.h >
#include 
< dinput.h >
#include 
" resource.h "

#pragma comment(lib, 
" dxguid.lib " )
#pragma comment(lib, 
" dinput8.lib " )

#define  Safe_Release(p) if((p)) (p)->Release();

//  window handles, class and caption text.
HWND g_hwnd;
static   char  g_class_name[]  =   " KeyboardClass " ;

IDirectInput8
*  g_directinput;                //  directinput component
IDirectInputDevice8 *  g_directinput_device;   //  keyboard device

// --------------------------------------------------------------------------------
//  Window procedure.
// --------------------------------------------------------------------------------
long  WINAPI Window_Proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    
switch (msg)
    {
    
case  WM_DESTROY:
        PostQuitMessage(
0 );
        
return   0 ;
    }

    
return  ( long ) DefWindowProc(hwnd, msg, wParam, lParam);
}

// --------------------------------------------------------------------------------
//  Initialize keyboard interface, return a keyboad interface pointer.
// --------------------------------------------------------------------------------
IDirectInputDevice8 *  Init_Keyboard(HWND hwnd, IDirectInput8 *  directinput)
{
    IDirectInputDevice8
*  directinput_device;

    
//  create the device object
     if (FAILED(directinput -> CreateDevice(GUID_SysKeyboard,  & directinput_device, NULL)))
        
return  NULL;

    
//  set the data format
     if (FAILED(directinput_device -> SetDataFormat( & c_dfDIKeyboard)))
    {
        directinput_device
-> Release();
        
return  NULL;
    }

    
//  set the coooperative mode
     if (FAILED(directinput_device -> SetCooperativeLevel(hwnd, DISCL_FOREGROUND  |  DISCL_NONEXCLUSIVE)))
    {
        directinput_device
-> Release();
        
return  NULL;
    }

    
//  acquire the device for use
     if (FAILED(directinput_device -> Acquire()))
    {
        directinput_device
-> Release();
        
return  NULL;
    }

    
//  everything well, so return a vaild pointer.
     return  directinput_device;
}

// --------------------------------------------------------------------------------
//  Read keyboard buffer.
// --------------------------------------------------------------------------------
BOOL Read_Device(IDirectInputDevice8 *  directinput_device,  void *  buffer,  long  buffer_size)
{
    HRESULT rv;

    
while ( 1 )
    {
        
//  poll device
        g_directinput_device -> Poll();

        
//  read in state
         if (SUCCEEDED(rv  =  g_directinput_device -> GetDeviceState(buffer_size, buffer)))
            
break ;

        
//  return when an unknown error
         if (rv  !=  DIERR_INPUTLOST  ||  rv  !=  DIERR_NOTACQUIRED)
            
return  FALSE;

        
//  re-acquire and try again
         if (FAILED(g_directinput_device -> Acquire()))
            
return  FALSE;
    }

    
return  TRUE;
}

// --------------------------------------------------------------------------------
//  Main function, routine entry.
// --------------------------------------------------------------------------------
int  WINAPI WinMain(HINSTANCE inst, HINSTANCE, LPSTR cmd_line,  int  cmd_show)
{
    WNDCLASS    win_class;
    MSG         msg;
    
char         key_state_buffer[ 256 ];

    
//  create window class and register it
    win_class.style          =  CS_HREDRAW  |  CS_VREDRAW;
    win_class.lpfnWndProc   
=  Window_Proc;
    win_class.cbClsExtra    
=   0 ;
    win_class.cbWndExtra    
=  DLGWINDOWEXTRA;
    win_class.hInstance     
=  inst;
    win_class.hIcon         
=  LoadIcon(inst, IDI_APPLICATION);
    win_class.hCursor       
=  LoadCursor(NULL, IDC_ARROW);
    win_class.hbrBackground 
=  (HBRUSH) (COLOR_BTNFACE  +   1 );
    win_class.lpszMenuName  
=  NULL;
    win_class.lpszClassName 
=  g_class_name;    

    
if ( !  RegisterClass( & win_class))
        
return  FALSE;

    
//  create the main window
    g_hwnd  =  CreateDialog(inst, MAKEINTRESOURCE(IDD_KEYBOARD),  0 , NULL);

    ShowWindow(g_hwnd, cmd_show);
    UpdateWindow(g_hwnd);

    
//  initialize directinput and get keyboard device
    DirectInput8Create(inst, DIRECTINPUT_VERSION, IID_IDirectInput8, ( void   ** & g_directinput, NULL);

    
//  initialize keyboard
    g_directinput_device  =  Init_Keyboard(g_hwnd, g_directinput);

    
//  start message pump, waiting for signal to quit.
    ZeroMemory( & msg,  sizeof (MSG));

    
while (msg.message  !=  WM_QUIT)
    {
        
if (PeekMessage( & msg, NULL,  0 0 , PM_REMOVE))
        {
            TranslateMessage(
& msg);
            DispatchMessage(
& msg);
        }
        
        
//  read in keyboard and break if ESCAPE pressed
        Read_Device(g_directinput_device, key_state_buffer,  sizeof (key_state_buffer));

        
if (key_state_buffer[DIK_ESCAPE]  &   0x80 )
            
break ;
    }

    
//  release directinput objects
    g_directinput_device -> Unacquire();
    g_directinput_device
-> Release();
    g_directinput
-> Release();

    UnregisterClass(g_class_name, inst);
    
    
return  ( int ) msg.wParam;
}


运行效果:


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值