天行健 君子当自强而不息

DirectInput8初探 - 键盘篇

DirectInput是Directx的一个组件接口,提供了大量的接口函数处理用户在键盘,鼠标,游戏杆以及力反馈等游戏装置上的输入,而且 DirectInput是直接与硬件驱动程序打交道,因此DirectInput可较快的处理用户的输入。另一方面,正是由于DirectInput直接与驱动程序进行通信,所以在控制面板上所作的任何键盘和鼠标的属性设置(如键盘按键的延迟重复率和鼠标的左右手习惯等),都不会对应用 DirectInput的程序起作用,除非是修改由驱动程序提供的属性设置。

创建DirectInput接口对象

在创建具体的输入设备对象之前,首先要利用Win32 API函数DirectInput8Create建立1个DirectInput接口对象。

Creates a Microsoft DirectInput object and returns an IDirectInput8 or later interface.

Syntax

HRESULT WINAPI DirectInput8Create(HINSTANCE hinst,
    DWORD dwVersion,
    REFIID riidltf,
    LPVOID *ppvOut,
    LPUNKNOWN punkOuter
);

Parameters

hinst
Instance handle to the application or dynamic-link library (DLL) that is creating the DirectInput object. DirectInput uses this value to determine whether the application or DLL has been certified and to establish any special behaviors that might be necessary for backward compatibility. 
It is an error for a DLL to pass the handle to the parent application. For example, an Microsoft ActiveX control embedded in a Web page
 that uses DirectInput must pass its own instance handle, and not the handle to the browser. This ensures that DirectInput recognizes the
control and can enable any special behaviors that might be necessary.

dwVersion
Version number of DirectInput for which the application is designed. This value is normally DIRECTINPUT_VERSION. If the application
defines DIRECTINPUT_VERSION before including Dinput.h, the value must be greater than 0x0800. For earlier versions, use DirectInputCreateEx,
which is in Dinput.lib.

riidltf
Unique identifier of the desired interface. This value is IID_IDirectInput8A or IID_IDirectInput8W. Passing the IID_IDirectInput8 define selects the
ANSI or Unicode version of the interface, depending on whether UNICODE is defined during compilation.

ppvOut
Address of a pointer to a variable to receive the interface pointer if the call succeeds.

punkOuter
Pointer to the address of the controlling object's IUnknown interface for Component Object Model (COM) aggregation, or NULL if the interface
is not aggregated. Most calling applications pass NULL. If aggregation is requested, the object returned in ppvOut is a pointer to IUnknown,
as required by COM aggregation.

Return Value

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 The application was written for an unsupported prerelease version of DirectInput.
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 COM return value.
DIERR_OLDDIRECTINPUTVERSION The application requires a newer version of DirectInput.
DIERR_OUTOFMEMORY The DirectInput subsystem couldn't allocate sufficient memory to complete the call. This value is equal to the
E_OUTOFMEMORY standard COM return value.

使用DirectInput接口函数

建立 DirectInput接口对象之后,就可以利用IDirectInput接口所提供的CreateDevice函数为键盘,鼠标和游戏杆等输入装置建立 1个对应的DirectInput设备对象,此后就可用设备对象来读取用户的输入。

Creates and initializes an instance of a device based on a given globally unique identifier (GUID), and obtains an IDirectInputDevice8 interface. 

Syntax

HRESULT CreateDevice(          REFGUID rguid,
    LPDIRECTINPUTDEVICE *lplpDirectInputDevice,
    LPUNKNOWN pUnkOuter
);

Parameters

rguid
Reference to (C++) or address of (C) the instance GUID for the desired input device (see Remarks). The GUID is retrieved through the
IDirectInput8::EnumDevices method, or it can be one of the predefined GUIDs listed below. For the following GUID values to be valid,
your application must define INITGUID before all other preprocessor directives at the beginning of the source file, or link to Dxguid.lib.

GUID_SysKeyboard   The default system keyboard. 
GUID_SysMouse       The default system mouse.

lplpDirectInputDevice
Address of a variable to receive the IDirectInputDevice8 interface pointer if successful.

pUnkOuter
Address of the controlling object's IUnknown interface for Component Object Model (COM) aggregation,
or NULL if the interface is not aggregated. Most calling applications pass NULL.

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:

DIERR_DEVICENOTREG The device or device instance is not registered with Microsoft DirectInput.
This value is equal to the REGDB_E_CLASSNOTREG standard COM return value.

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 COM return value.

DIERR_NOINTERFACE The specified interface is not supported by the object. This value is equal to the E_NOINTERFACE
standard COM return value.

DIERR_NOTINITIALIZED The object has not been initialized.

DIERR_OUTOFMEMORY The DirectInput subsystem couldn't allocate sufficient memory to complete the call. This value is equal to
the E_OUTOFMEMORY standard COM return value. 

设置DirectInput设备的数据格式

DirectInput设备创建出来后,必须为它设置设备的属性和数据的读取格式。

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.

设置DirectInput设备的协调级别

如果同一个物理输入设备建立了多个DirectInput设备实例,必须处理这些实例相互间的协调级别。此外,还需要设定设备实例与系统的其他对象的协调级别。

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.

获取输入设备的访问权

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 I
DirectInputDevice8::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.



读取键盘输入

首先建立1个256B的缓冲区以接收键盘的输入数据,然后不断调用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.

代码示例:

需要在工程中设置链接dxguid.lib和 dinput8.lib。
由于只是起演示作用,所以代码组织的可能不是很严谨,如果其中有错误,敬请指出。

下载源码

HandleKey.h
/////////////////////////////////////////////////////////////////////////////////////////
//
// PURPOSE:
//  Header file for key input function defines.
//
/////////////////////////////////////////////////////////////////////////////////////////

#ifndef HANDLE_KEY_H
#define HANDLE_KEY_H

#include 
<dinput.h>

extern HINSTANCE g_instance;
extern HWND g_wnd;

#define Safe_Release(object)    if(object != NULL)  { object->Release(); object = NULL; }

extern LPDIRECTINPUT8 g_directinput;
extern LPDIRECTINPUTDEVICE8 g_directinput_device;

extern char g_key_buffer[256];

BOOL Init_Keyboard();
BOOL Is_Key_Pressed(
int key);
void Release_COM_Object();

#endif

HandleKey.cpp
/////////////////////////////////////////////////////////////////////////////////////////
//
// PURPOSE:
//  Define functions for key input.
//
/////////////////////////////////////////////////////////////////////////////////////////

#define DIRECTINPUT_VERSION 0x0800  // let compile shut up

#include 
"HandleKey.h"

LPDIRECTINPUT8 g_directinput 
= NULL;
LPDIRECTINPUTDEVICE8 g_directinput_device 
= NULL;

char g_key_buffer[256= {0};


//--------------------------------------------------------------------------
// Initialize keyboard.
//--------------------------------------------------------------------------
BOOL Init_Keyboard()
{
    
// Creates a Microsoft DirectInput object and returns an IDirectInput8 interface
    if(FAILED(DirectInput8Create(g_instance, DIRECTINPUT_VERSION, IID_IDirectInput8, (LPVOID *)&g_directinput, NULL)))
    {
        MessageBox(NULL, 
"DirectInput interface create failed.""ERROR", MB_OK | MB_ICONINFORMATION);
        
return FALSE;
    }

    
// create keyboard device
    if(FAILED(g_directinput->CreateDevice(GUID_SysKeyboard, &g_directinput_device, NULL)))
    {
        MessageBox(NULL, 
"DirectInput interface create failed.""ERROR", MB_OK | MB_ICONINFORMATION);
        
return FALSE;
    }

    
// Sets the data format for the Microsoft DirectInput device.
    if(FAILED(g_directinput_device->SetDataFormat(&c_dfDIKeyboard)))
    {
        MessageBox(NULL, 
"Set data format with keyboard read mode failed.""ERROR", MB_OK | MB_ICONINFORMATION);
        
return FALSE;
    }
    
    
// 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.
    if(FAILED(g_directinput_device->SetCooperativeLevel(g_wnd, DISCL_FOREGROUND | DISCL_EXCLUSIVE)))
    {
        MessageBox(NULL, 
"Set cooperative Leve failed.""ERROR", MB_OK | MB_ICONINFORMATION);
        
return FALSE;
    }

    
// Obtains access to the keyboard device
    if(FAILED(g_directinput_device->Acquire()))
    {
        MessageBox(NULL, 
"Acquire keyboard access failed.""ERROR", MB_OK | MB_ICONINFORMATION);
        
return FALSE;
    }

    
return TRUE;    
}

//--------------------------------------------------------------------------
// Judge if a key is pressed down.
//--------------------------------------------------------------------------
BOOL Is_Key_Pressed(int key)
{
    
// Retrieves immediate key data state
    HRESULT hr = g_directinput_device->GetDeviceState(sizeof(g_key_buffer), g_key_buffer);

    
if(hr == DIERR_INPUTLOST)
    {
        
// re-acquire keyboard access
        g_directinput_device->Acquire();

        
if(FAILED(g_directinput_device->GetDeviceState(sizeof(g_key_buffer), g_key_buffer)))
        {
            MessageBox(NULL, 
"Get keyboard state failed.""ERROR", MB_OK | MB_ICONINFORMATION);
            
return FALSE;
        }
    }

    
return (g_key_buffer[key] & 0x80);        
}

//--------------------------------------------------------------------------
// Release all COM object.
//--------------------------------------------------------------------------
void Release_COM_Object()
{
    
if(g_directinput_device)
    {
        
// Releases access to the device
        g_directinput_device->Unacquire();

        Safe_Release(g_directinput_device);
    }

    Safe_Release(g_directinput);
}

main.cpp
/////////////////////////////////////////////////////////////////////////////////////////
//
// PURPOSE:
//  key input test.
//
/////////////////////////////////////////////////////////////////////////////////////////

#define DIRECTINPUT_VERSION 0x0800

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

//////////////////////////////////////// GLOBAL ////////////////////////////////////////

HINSTANCE g_instance;
HWND g_wnd;

const TCHAR g_wnd_class_name[] = "Game";
const TCHAR g_wnd_title[] = "DirectInput key input";

WNDCLASSEX g_wnd_class;

//////////////////////////////////////// PROTOTYPE ////////////////////////////////////////
ATOM Reg_Wnd_Class(HINSTANCE instance);
LRESULT CALLBACK Wnd_Proc(HWND wnd, UINT msg, WPARAM w_param, LPARAM l_param);
BOOL Create_Wnd(HINSTANCE instance, 
int cmd_show);


//////////////////////////////////////// FUNCTION ////////////////////////////////////////

//--------------------------------------------------------------------------
// Entry function.
//--------------------------------------------------------------------------
int WINAPI WinMain(HINSTANCE instance, HINSTANCE, LPSTR cmd_line, int cmd_show)
{
    MSG msg 
= {0};
    g_instance 
= instance;

    
// register window class
    Reg_Wnd_Class(instance);
    
    
// create main window
    if(! Create_Wnd(instance, cmd_show))
    {
        MessageBox(NULL, 
"Create Windows failed!""ERROR", MB_OK);
        
return FALSE;
    }
    
    
// initialize keyboard
    if(! Init_Keyboard())
        
return FALSE;

    
// message loop, break out only receive WM_QUIT message.
    while(msg.message != WM_QUIT)
    {
        
// get message
        if(PeekMessage(&msg, NULL, 00, PM_REMOVE))
        {
            
// there are messages from window, handle it.
            TranslateMessage(&msg);
            DispatchMessage(
&msg);
        }
        
else
        {            
            
// there is no messages, do anything we want.

            
if(Is_Key_Pressed(DIK_RIGHT))
                MessageBox(NULL, 
"Right Arrow is pressed.""Key State", MB_OK | MB_ICONINFORMATION);
            
            
if(Is_Key_Pressed(DIK_LEFT))
                MessageBox(NULL, 
"Left Arrow is pressed.""Key State", MB_OK | MB_ICONINFORMATION);

            
if(Is_Key_Pressed(DIK_D) & Is_Key_Pressed(DIK_LCONTROL))
                MessageBox(NULL, 
"Ctrl + D is pressed.""Key State", MB_OK | MB_ICONINFORMATION);

            
if(Is_Key_Pressed(DIK_ESCAPE))
                PostQuitMessage(
0);
        }
    }

    Release_COM_Object();
    UnregisterClass(g_wnd_class_name, g_wnd_class.hInstance);

    
return (int) msg.wParam;
}

//--------------------------------------------------------------------------
// Registers a window class for subsequent use in calls to the CreateWindow 
// or CreateWindowEx function. 
//
// If the function succeeds, the return value is a class atom that uniquely 
// identifies the class being registered.
// If the function fails, the return value is zero. 
//--------------------------------------------------------------------------
ATOM Reg_Wnd_Class(HINSTANCE instance)
{
    g_wnd_class.cbSize          
= sizeof(WNDCLASSEX);
    g_wnd_class.style           
= CS_HREDRAW | CS_VREDRAW;
    g_wnd_class.lpfnWndProc     
= (WNDPROC) Wnd_Proc;
    g_wnd_class.cbClsExtra      
= 0;
    g_wnd_class.cbWndExtra      
= 0;
    g_wnd_class.hInstance       
= g_instance;
    g_wnd_class.hIcon           
= 0;
    g_wnd_class.hCursor         
= LoadCursor(NULL, IDC_ARROW);
    g_wnd_class.hbrBackground   
= (HBRUSH) GetStockObject(BLACK_BRUSH);
    g_wnd_class.lpszMenuName    
= 0;
    g_wnd_class.lpszClassName   
= g_wnd_class_name;
    g_wnd_class.hIconSm         
= NULL;

    
return RegisterClassEx(&g_wnd_class);    
}

//--------------------------------------------------------------------------
// Create a window.
//--------------------------------------------------------------------------
BOOL Create_Wnd(HINSTANCE instance, int cmd_show)
{
    
// create a window
    g_wnd = CreateWindow(g_wnd_class_name, g_wnd_title, WS_OVERLAPPEDWINDOW, 
                         CW_USEDEFAULT, 
0, CW_USEDEFAULT, 0, NULL, NULL, instance, NULL);
    
    
if(g_wnd == NULL)
        
// create failed
        return FALSE;

    
// sets the specified window's show state 
    ShowWindow(g_wnd, cmd_show);
    
// updates the client area of the specified window
    UpdateWindow(g_wnd);

    
return TRUE;
}

//--------------------------------------------------------------------------
// Callback function, handle message return by windows.
//--------------------------------------------------------------------------
LRESULT CALLBACK Wnd_Proc(HWND wnd, UINT msg, WPARAM w_param, LPARAM l_param)
{
    
switch(msg)
    {
    
case WM_DESTROY:
        PostQuitMessage(
0);
        
break;
    }

    
return DefWindowProc(wnd, msg, w_param, l_param);
}

仅当按下左右箭头和Ctrl + D时程序会相应。


posted on 2007-05-05 01:33 lovedday 阅读(5699) 评论(0)  编辑 收藏 引用 所属分类: ■ DirectX 9 Program


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


公告

导航

统计

常用链接

随笔分类(178)

3D游戏编程相关链接

搜索

最新评论