简单介绍一下用DirectInput获取鼠标输入的方法。
源程序是DirectX SDK sample文件夹里面的示例工程。
//----------------------------------------------------------------------------- // File: CustomFormat.cpp // // Desc: demonstrates the use of a custom data format for input retrieval from // a device which doesn't correspond to one of the predefined mouse, keyboard, // or joystick types. // // Copyright (c) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- #define STRICT #define DIRECTINPUT_VERSION 0x0800 #include <windows.h> #include <commctrl.h> #include <basetsd.h> #include <dinput.h> #pragma warning( disable : 4996 ) // disable deprecated warning #include <strsafe.h> #pragma warning( default : 4996 ) #include "resource.h" // Here we define a custom data format to store input from a mouse. In a // real program you would almost certainly use either the predefined // DIMOUSESTATE or DIMOUSESTATE2 structure to store mouse input, but some // input devices such as the Sidewinder GameVoice controller are not well // described by the provided types and may require custom formats. struct MouseState { LONG lAxisX; LONG lAxisY; BYTE abButtons[3]; BYTE bPadding; // Structure must be DWORD multiple in size. }; // Each device object for which you want to receive input must have an entry // in this DIOBJECTDATAFORMAT array which is stored in the custom DIDATAFORMAT. // The DIOBJECTDATAFORMAT maps detected device object to a particular offset // within MouseState structure declared above. Inside the input routine, a // MouseState structure is provided to the GetDeviceState method, and // DirectInput uses this offset to store the input data in the provided // structure. // // Any of the elements which are not flagged as DIDFT_OPTIONAL, and // which describe a device object which is not found on the actual device will // cause the SetDeviceFormat call to fail. For the format defined below, the // system mouse must have an x-axis, y-axis, and at least one button. DIOBJECTDATAFORMAT g_aObjectFormats[] = { { &GUID_XAxis, FIELD_OFFSET( MouseState, lAxisX ), // X axis DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, { &GUID_YAxis, FIELD_OFFSET( MouseState, lAxisY ), // Y axis DIDFT_AXIS | DIDFT_ANYINSTANCE, 0 }, { 0, FIELD_OFFSET( MouseState, abButtons[0] ), // Button 0 DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0 }, { 0, FIELD_OFFSET( MouseState, abButtons[1] ), // Button 1 (optional) DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 }, { 0, FIELD_OFFSET( MouseState, abButtons[2] ), // Button 2 (optional) DIDFT_BUTTON | DIDFT_ANYINSTANCE | DIDFT_OPTIONAL, 0 } }; #define numMouseObjects (sizeof(g_aObjectFormats) / sizeof(DIOBJECTDATAFORMAT)) // Finally, the DIDATAFORMAT is filled with the information defined above for // our custom data format. The format also defines whether the returned axis // data is absolute or relative. Usually mouse movement is reported in relative // coordinates, but our custom format will use absolute coordinates. DIDATAFORMAT g_dfMouse = { sizeof( DIDATAFORMAT ), sizeof( DIOBJECTDATAFORMAT ), DIDF_ABSAXIS, sizeof( MouseState ), numMouseObjects, g_aObjectFormats }; //----------------------------------------------------------------------------- // Defines, constants, and global variables //----------------------------------------------------------------------------- #define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } } #define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } } LPDIRECTINPUT8 g_pDI = NULL; // DirectInput interface LPDIRECTINPUTDEVICE8 g_pMouse = NULL; // Device interface //----------------------------------------------------------------------------- // Function-prototypes //----------------------------------------------------------------------------- INT_PTR CALLBACK MainDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam ); HRESULT InitDirectInput( HWND hDlg ); VOID FreeDirectInput(); HRESULT UpdateInputState( HWND hDlg ); //----------------------------------------------------------------------------- // Name: WinMain() // Desc: Entry point for the application. Since we use a simple dialog for // user interaction we don't need to pump messages. //----------------------------------------------------------------------------- int APIENTRY WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, int ) { InitCommonControls(); // Display the main dialog box. DialogBox( hInst, MAKEINTRESOURCE( IDD_MOUSE_IMM ), NULL, MainDlgProc ); return 0; } //----------------------------------------------------------------------------- // Name: MainDialogProc // Desc: Handles dialog messages //----------------------------------------------------------------------------- INT_PTR CALLBACK MainDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam ) { switch( msg ) { case WM_INITDIALOG: if( FAILED( InitDirectInput( hDlg ) ) ) { MessageBox( NULL, TEXT( "Error Initializing DirectInput" ), TEXT( "DirectInput Sample" ), MB_ICONERROR | MB_OK ); EndDialog( hDlg, 0 ); } // Set a timer to go off 30 times a second. At every timer message // the input device will be read SetTimer( hDlg, 0, 1000 / 30, NULL ); return TRUE; case WM_TIMER: // Update the input device every timer message if( FAILED( UpdateInputState( hDlg ) ) ) { KillTimer( hDlg, 0 ); MessageBox( NULL, TEXT( "Error Reading Input State. " ) / TEXT( "The sample will now exit." ), TEXT( "DirectInput Sample" ), MB_ICONERROR | MB_OK ); EndDialog( hDlg, TRUE ); } return TRUE; case WM_COMMAND: switch( LOWORD( wParam ) ) { case IDCANCEL: EndDialog( hDlg, 0 ); return TRUE; } break; case WM_DESTROY: // Cleanup everything KillTimer( hDlg, 0 ); FreeDirectInput(); return TRUE; } return FALSE; // Message not handled } //----------------------------------------------------------------------------- // Name: InitDirectInput() // Desc: Initialize the DirectInput variables. //----------------------------------------------------------------------------- HRESULT InitDirectInput( HWND hDlg ) { HRESULT hr; // Register with the DirectInput subsystem and get a pointer // to a IDirectInput interface we can use. if( FAILED( hr = DirectInput8Create( GetModuleHandle( NULL ), DIRECTINPUT_VERSION, IID_IDirectInput8, ( VOID** )&g_pDI, NULL ) ) ) return hr; // Retrieve the system mouse if( FAILED( g_pDI->CreateDevice( GUID_SysMouse, &g_pMouse, NULL ) ) ) { MessageBox( NULL, TEXT( "Mouse not found. The sample will now exit." ), TEXT( "DirectInput Sample" ), MB_ICONERROR | MB_OK ); EndDialog( hDlg, 0 ); return S_OK; } // A data format specifies which controls on a device we are interested in, // and how they should be reported. This tells DInput that we will be // passing a MouseState structure to IDirectInputDevice::GetDeviceState(). if( FAILED( hr = g_pMouse->SetDataFormat( &g_dfMouse ) ) ) return hr; // Set the cooperative level to let DInput know how this device should // interact with the system and with other DInput applications. if( FAILED( hr = g_pMouse->SetCooperativeLevel( hDlg, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND ) ) ) return hr; return S_OK; } //----------------------------------------------------------------------------- // Name: UpdateInputState() // Desc: Get the input device's state and display it. //----------------------------------------------------------------------------- HRESULT UpdateInputState( HWND hDlg ) { HRESULT hr; TCHAR strText[128] = {0}; // Device state text MouseState ms; // Custom mouse state static POINT pOrigin = {0}; // Initial position static BOOL bInitialized = FALSE; // Indicates offsets are valid if( NULL == g_pMouse ) return S_OK; // Poll the device to read the current state hr = g_pMouse->Poll(); if( FAILED( hr ) ) { // DInput is telling us that the input stream has been // interrupted. We aren't tracking any state between polls, so // we don't have any special reset that needs to be done. We // just re-acquire and try again. hr = g_pMouse->Acquire(); while( hr == DIERR_INPUTLOST ) hr = g_pMouse->Acquire(); // hr may be DIERR_OTHERAPPHASPRIO or other errors. This // may occur when the app is minimized or in the process of // switching, so just try again later return S_OK; } // Get the input's device state if( FAILED( hr = g_pMouse->GetDeviceState( sizeof( MouseState ), &ms ) ) ) return hr; // The device should have been acquired during the Poll() // The initial mouse position should be subracted from the current point. if( !bInitialized ) { bInitialized = TRUE; pOrigin.x = ms.lAxisX; pOrigin.y = ms.lAxisY; } // Display state to dialog StringCchPrintf( strText, 128, TEXT( "%ld" ), ms.lAxisX - pOrigin.x ); SetWindowText( GetDlgItem( hDlg, IDC_X_AXIS ), strText ); StringCchPrintf( strText, 128, TEXT( "%ld" ), ms.lAxisY - pOrigin.y ); SetWindowText( GetDlgItem( hDlg, IDC_Y_AXIS ), strText ); // Fill up text with which buttons are pressed strText[0] = 0; for( int i = 0; i < 3; i++ ) { if( ms.abButtons[i] & 0x80 ) { TCHAR sz[128]; StringCchPrintf( sz, 128, TEXT( "%02d " ), i ); StringCchCat( strText, 128, sz ); } } SetWindowText( GetDlgItem( hDlg, IDC_BUTTONS ), strText ); return S_OK; } //----------------------------------------------------------------------------- // Name: FreeDirectInput() // Desc: Initialize the DirectInput variables. //----------------------------------------------------------------------------- VOID FreeDirectInput() { // Unacquire the device one last time just in case // the app tried to exit while the device is still acquired. if( g_pMouse ) g_pMouse->Unacquire(); // Release any DirectInput objects. SAFE_RELEASE( g_pMouse ); SAFE_RELEASE( g_pDI ); }
基本思路(我用伪代码表达):
//自定义一个数据格式来存储鼠标输入
//虽然在真正的程序里一般用DIMOUSESTATE用或DIMOUSESTATE2就够了
//但是一些特殊的鼠标设备可能没办法得到很好的描述,所以自定义一个
struct MouseState
{
LONG lAxisX;
LONG lAxisY;
BYTE abButtons[3];//具体内容看自己的需要了
BYTE bPadding;//这个只是为了补齐结构使得结构为DWORD的整数倍
};
//每个需要接收输入的设备对象应该有个DIOBJECTDATAFORMAT数组来存放DIDATAFORMAT
//DIOBJECTDATAFORMAT检测设备对象映射到MouseState的值上。
//MouseState结构可以提供给GetDeviceState方法,DirectInput在把数据存到这个结构中
//不用DIDFT_OPTIONAL标记的元素,还有设备对象没有关联实际设备的,都会是SetDeviceFormat调用失败
//自定义的格式至少要有 x轴,Y轴,还有至少一个按钮
DIOBJECTDATAFORMAT g_aObjectFormats[]=()
//最后,DIDATAFORMAT填充了我们的自定义数据格式。
//这种格式还定义了返回轴的移动是否相对,否则使用绝对坐标
DIDATAFORMAT g_dfMouse =
{
sizeof( DIDATAFORMAT ),
sizeof( DIOBJECTDATAFORMAT ),
DIDF_ABSAXIS,
sizeof( MouseState ),
numMouseObjects,
g_aObjectFormats
};
INT APIENTRY WinMain(HINSTANCE hInst, HINSTANCE , LPSTR, int);//程序入口
INT _PTR CALLBACK MainDlgProc(HWND hDlg, UINT msg; WPARAM wParam, LPARAM lParam)//处理对话框消息
//初始化DirectInput
HRESULT InitDirectInput(HWND hwnd)
{ //产生DirectInput8Create对象,
//产生设备
//设定数据格式
//设定协作级别
}
//更新输入状态
HRESULT UpdateInputState(HWND hDlg)
{
MouseState ms;//当前鼠标状态
g_pMouse->Poll()//测试设备是否读取数据
//数据如果失败说明没有输入流,只要在申请重试一遍,调用g_pMouse->Acquire()
g_pMouse->GetDeviceState(sizeof(MouseState),&ms)//获取输入状态给鼠标状态ms
//用ms进行相关操作
}
//释放对象
VOID FreeDirectInput()
{
//如果没有鼠标设备,重申请,不然待会释放空会出问题:)
//释放鼠标设备对象
//释放设备对象
}