USB手柄的控制

来源:互联网 发布:java多线程实现多任务 编辑:程序博客网 时间:2024/06/10 01:37

USB手柄的控制

                                                                                                                   Flyli

         USB手柄或游戏控制杆并不一定只在打游戏的时候才用得到,为了控制以PC机为核心的机器人能够在手动的控制下运动,略微研究了下USB手柄的控制方法。

         通过查阅相关资料,查到了2USB手柄的控制方法,一种是基于windows DDKUSB开发,由于没有搞到DDK所以暂且不谈这种方法

我们来说说第二种方法,就是以基于DirectX8.1以上的USB手柄控制方法,使用这种方法需要下载DirectSDK,运用到他的运行库。Dinput8.lib,DxErr.Lib,dxguid.lib另外还需要加载direct的一些头文件,至于头文件具体用到了那些我也没有测试,我把这些可能用到的程序都发到了我的资源中,地址是:http://download.csdn.net/source/402394

其中将所有的.h文件复制到vc的运行库下,把.lib文件加载到工程中就可以使用了。

其使用方法也是相当的简单:

1.       CDirectInput实例化

2.       调用InitDirectInput初始化USB手柄,通过其返回值判断手柄是否被识别

3.       声明一个DIJOYSTATE2 类型的值用于接收按键的状态

4.       GetState_Now()声明的DIJOYSTATE2的值进行赋值;

5.       DIJOYSTATE2 中部分键值的对应关系 lxly分别是对应上下左右的方向,rgbbutton[]的数组是分别用来对应其他的手柄按键。

遇到具体的问题可以再联系我哈

一下是我封装后的类

//********************************************************************

// DirectInput.h 文件

//********************************************************************************

#pragma once

#define DIRECTINPUT_VERSION 0x0800

#define _CRT_SECURE_NO_DEPRECATE

#ifndef _WIN32_DCOM

#define _WIN32_DCOM

#endif

 

#include <windows.h>

#include <commctrl.h>

#include <basetsd.h>

#include <dinput.h>

#include <dinputd.h>

#include <assert.h>

#include <oleauto.h>

#include <shellapi.h>

#include <wbemidl.h>

 

#pragma warning( disable : 4996 ) // disable deprecated warning

#include <strsafe.h>

#pragma warning( default : 4996 )

#include "resource.h"

//=============================================================

//宏定义

#define SAFE_DELETE(p)  { if(p) { delete (p);     (p)=NULL; } }

#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }

struct XINPUT_DEVICE_NODE

{

    DWORD dwVidPid;

    XINPUT_DEVICE_NODE* pNext;

};

 

struct DI_ENUM_CONTEXT

{

    DIJOYCONFIG* pPreferredJoyCfg;

    bool bPreferredJoyCfgValid;

};

 

 

class CDirectInput

{

public:

     CDirectInput(void);

public:

     ~CDirectInput(void);

public:

 

     static LPDIRECTINPUT8       g_pDI;        

     static LPDIRECTINPUTDEVICE8 g_pJoystick ;

     static bool    g_bFilterOutXinputDevices;

     static XINPUT_DEVICE_NODE* g_pXInputDeviceList;

    static DIJOYSTATE2 HandState;

public:

     static BOOL CALLBACK    EnumObjectsCallback( const DIDEVICEOBJECTINSTANCE* pdidoi, VOID* pContext );

     static BOOL CALLBACK    EnumJoysticksCallback( const DIDEVICEINSTANCE* pdidInstance, VOID* pContext );

     static HRESULT InitDirectInput(HWND hDlg);

     static VOID    FreeDirectInput();

     static DIJOYSTATE2 GetState_Now();

 

     // Stuff to filter out XInput devices

 

     static HRESULT SetupForIsXInputDevice();

     static bool    IsXInputDevice( const GUID* pGuidProductFromDirectInput );

     static void    CleanupForIsXInputDevice();

};

 

 

 

 

 

 

//********************************************************************

// DirectInput.h 文件

//********************************************************************************

 

 

#include "StdAfx.h"

#include "DirectInput.h"

 

 

LPDIRECTINPUT8       CDirectInput::g_pDI              = NULL;        

LPDIRECTINPUTDEVICE8 CDirectInput::g_pJoystick        = NULL;

bool    CDirectInput::g_bFilterOutXinputDevices = false;

XINPUT_DEVICE_NODE* CDirectInput::g_pXInputDeviceList = NULL;

DIJOYSTATE2 CDirectInput::HandState;

 

CDirectInput::CDirectInput(void)

{

}

 

CDirectInput::~CDirectInput(void)

{

}

//-----------------------------------------------------------------------------

// Name: InitDirectInput()

// Desc: Initialize the DirectInput variables.

//-----------------------------------------------------------------------------

HRESULT CDirectInput::InitDirectInput( HWND hDlg )

{

    HRESULT hr;

     //创建主com接口

    if( FAILED( hr = DirectInput8Create( GetModuleHandle(NULL), /

         DIRECTINPUT_VERSION,IID_IDirectInput8,/

         (VOID**)&g_pDI, NULL ) ) )

     {   

         return hr;

     }

     //hr->

    if( g_bFilterOutXinputDevices )

        SetupForIsXInputDevice();

 

    DIJOYCONFIG PreferredJoyCfg = {0};

    DI_ENUM_CONTEXT enumContext;

    enumContext.pPreferredJoyCfg = &PreferredJoyCfg;

    enumContext.bPreferredJoyCfgValid = false;

 

    IDirectInputJoyConfig8* pJoyConfig = NULL; 

    if( FAILED( hr = g_pDI->QueryInterface( IID_IDirectInputJoyConfig8, (void **) &pJoyConfig ) ) )

        return hr;

 

    PreferredJoyCfg.dwSize = sizeof(PreferredJoyCfg);

    if( SUCCEEDED( pJoyConfig->GetConfig(0, &PreferredJoyCfg, DIJC_GUIDINSTANCE ) ) ) // This function is expected to fail if no Joystick is attached

        enumContext.bPreferredJoyCfgValid = true;

    SAFE_RELEASE( pJoyConfig );

    if( FAILED( hr = g_pDI->EnumDevices( DI8DEVCLASS_GAMECTRL,

                                         EnumJoysticksCallback,

                                         &enumContext, DIEDFL_ATTACHEDONLY ) ) )

        return hr;

 

    if( g_bFilterOutXinputDevices )

        CleanupForIsXInputDevice();

    if( NULL == g_pJoystick )

    {

         /*::MessageBox( NULL, TEXT("Joystick not found. The sample will now exit."), 

                    TEXT("DirectInput Sample"),

                    MB_ICONERROR | MB_OK );*/

       // EndDialog( hDlg, 0 );

        return 0-1;

    }

    if( FAILED( hr = g_pJoystick->SetDataFormat( &c_dfDIJoystick2 ) ) )

        return hr;

    if( FAILED( hr = g_pJoystick->SetCooperativeLevel( hDlg, DISCL_EXCLUSIVE |

                                                             DISCL_FOREGROUND ) ) )

        return hr;

    if( FAILED( hr = g_pJoystick->EnumObjects( EnumObjectsCallback,

                                                (VOID*)hDlg, DIDFT_ALL ) ) )

        return hr;

     CDirectInput::GetState_Now();

    return S_OK;

}

 

 

//-----------------------------------------------------------------------------

// Enum each PNP device using WMI and check each device ID to see if it contains

// "IG_" (ex. "VID_045E&PID_028E&IG_00").  If it does, then itan XInput device

// Unfortunately this information can not be found by just using DirectInput.

// Checking against a VID/PID of 0x028E/0x045E won't find 3rd party or future

// XInput devices.

//

// This function stores the list of xinput devices in a linked list

// at g_pXInputDeviceList, and IsXInputDevice() searchs that linked list

//-----------------------------------------------------------------------------

HRESULT CDirectInput::SetupForIsXInputDevice()

{

    IWbemServices*          pIWbemServices = NULL;

    IEnumWbemClassObject*   pEnumDevices   = NULL;

    IWbemLocator*           pIWbemLocator  = NULL;

    IWbemClassObject*       pDevices[20]   = {0};

    BSTR                    bstrDeviceID   = NULL;

    BSTR                    bstrClassName  = NULL;

    BSTR                    bstrNamespace  = NULL;

    DWORD                   uReturned      = 0;

    bool                    bCleanupCOM    = false;

    UINT                    iDevice        = 0;

    VARIANT                 var;

    HRESULT                 hr;

 

    // CoInit if needed

    hr = CoInitialize(NULL);

    bCleanupCOM = SUCCEEDED(hr);

 

    // Create WMI

    hr = CoCreateInstance( __uuidof(WbemLocator),

                           NULL,

                           CLSCTX_INPROC_SERVER,

                           __uuidof(IWbemLocator),

                           (LPVOID*) &pIWbemLocator);

    if( FAILED(hr) || pIWbemLocator == NULL )

        goto LCleanup;

 

    // Create BSTRs for WMI

    bstrNamespace = SysAllocString( L"////.//root//cimv2" ); if( bstrNamespace == NULL ) goto LCleanup;

    bstrDeviceID  = SysAllocString( L"DeviceID" );           if( bstrDeviceID == NULL )  goto LCleanup;       

    bstrClassName = SysAllocString( L"Win32_PNPEntity" );    if( bstrClassName == NULL ) goto LCleanup;       

   

    // Connect to WMI

    hr = pIWbemLocator->ConnectServer( bstrNamespace, NULL, NULL, 0L,

                                       0L, NULL, NULL, &pIWbemServices );

    if( FAILED(hr) || pIWbemServices == NULL )

        goto LCleanup;

 

    // Switch security level to IMPERSONATE

    CoSetProxyBlanket( pIWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL,

                       RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, 0 );                   

 

    // Get list of Win32_PNPEntity devices

    hr = pIWbemServices->CreateInstanceEnum( bstrClassName, 0, NULL, &pEnumDevices );

    if( FAILED(hr) || pEnumDevices == NULL )

        goto LCleanup;

 

    // Loop over all devices

    for( ;; )

    {

        // Get 20 at a time

        hr = pEnumDevices->Next( 10000, 20, pDevices, &uReturned );

        if( FAILED(hr) )

            goto LCleanup;

        if( uReturned == 0 )

            break;

 

        for( iDevice=0; iDevice<uReturned; iDevice++ )

        {

            // For each device, get its device ID

            hr = pDevices[iDevice]->Get( bstrDeviceID, 0L, &var, NULL, NULL );

            if( SUCCEEDED( hr ) && var.vt == VT_BSTR && var.bstrVal != NULL )

            {

                // Check if the device ID contains "IG_".  If it does, then itan XInput device

                // Unfortunately this information can not be found by just using DirectInput

                if( wcsstr( var.bstrVal, L"IG_" ) )

                {

                    // If it does, then get the VID/PID from var.bstrVal

                    DWORD dwPid = 0, dwVid = 0;

                    WCHAR* strVid = wcsstr( var.bstrVal, L"VID_" );

                    if( strVid && swscanf( strVid, L"VID_%4X", &dwVid ) != 1 )

                        dwVid = 0;

                    WCHAR* strPid = wcsstr( var.bstrVal, L"PID_" );

                    if( strPid && swscanf( strPid, L"PID_%4X", &dwPid ) != 1 )

                        dwPid = 0;

 

                    DWORD dwVidPid = MAKELONG( dwVid, dwPid );

 

                    // Add the VID/PID to a linked list

                    XINPUT_DEVICE_NODE* pNewNode = new XINPUT_DEVICE_NODE;

                    if( pNewNode )

                    {

                        pNewNode->dwVidPid = dwVidPid;

                        pNewNode->pNext = g_pXInputDeviceList;

                        g_pXInputDeviceList = pNewNode;

                    }

                }

            }  

            SAFE_RELEASE( pDevices[iDevice] );

        }

    }

 

LCleanup:

    if(bstrNamespace)

        SysFreeString(bstrNamespace);

    if(bstrDeviceID)

        SysFreeString(bstrDeviceID);

    if(bstrClassName)

        SysFreeString(bstrClassName);

    for( iDevice=0; iDevice<20; iDevice++ )

        SAFE_RELEASE( pDevices[iDevice] );

    SAFE_RELEASE( pEnumDevices );

    SAFE_RELEASE( pIWbemLocator );

    SAFE_RELEASE( pIWbemServices );

 

    return hr;

}

 

 

//-----------------------------------------------------------------------------

// Returns true if the DirectInput device is also an XInput device.

// Call SetupForIsXInputDevice() before, and CleanupForIsXInputDevice() after

//-----------------------------------------------------------------------------

bool CDirectInput::IsXInputDevice( const GUID* pGuidProductFromDirectInput )

{

    // Check each xinput device to see if this device's vid/pid matches

    XINPUT_DEVICE_NODE* pNode = g_pXInputDeviceList;

    while( pNode )

    {

        if( pNode->dwVidPid == pGuidProductFromDirectInput->Data1 )

            return true;

        pNode = pNode->pNext;

    }

 

    return false;

}

//-----------------------------------------------------------------------------

// Cleanup needed for IsXInputDevice()

//-----------------------------------------------------------------------------

void CDirectInput::CleanupForIsXInputDevice()

{

    // Cleanup linked list

    XINPUT_DEVICE_NODE* pNode = g_pXInputDeviceList;

    while( pNode )

    {

        XINPUT_DEVICE_NODE* pDelete = pNode;

        pNode = pNode->pNext;

        SAFE_DELETE( pDelete );

    }

}

//-----------------------------------------------------------------------------

// Name: EnumJoysticksCallback()

// Desc: Called once for each enumerated Joystick. If we find one, create a

//       device interface on it so we can play with it.

//-----------------------------------------------------------------------------

BOOL CALLBACK CDirectInput::EnumJoysticksCallback( const DIDEVICEINSTANCE* pdidInstance,

                                     VOID* pContext )

{

    DI_ENUM_CONTEXT* pEnumContext = (DI_ENUM_CONTEXT*) pContext;

    HRESULT hr;

 

    if( g_bFilterOutXinputDevices && IsXInputDevice( &pdidInstance->guidProduct ) )

        return DIENUM_CONTINUE;

 

    // Skip anything other than the perferred Joystick device as defined by the control panel. 

    // Instead you could store all the enumerated Joysticks and let the user pick.

    if( pEnumContext->bPreferredJoyCfgValid &&

        !IsEqualGUID( pdidInstance->guidInstance, pEnumContext->pPreferredJoyCfg->guidInstance ) )

        return DIENUM_CONTINUE;

 

    // Obtain an interface to the enumerated Joystick.

    hr = g_pDI->CreateDevice( pdidInstance->guidInstance, &g_pJoystick, NULL );

 

    // If it failed, then we can't use this Joystick. (Maybe the user unplugged

    // it while we were in the middle of enumerating it.)

    if( FAILED(hr) )

        return DIENUM_CONTINUE;

 

    // Stop enumeration. Note: we're just taking the first Joystick we get. You

    // could store all the enumerated Joysticks and let the user pick.

    return DIENUM_STOP;

}

//-----------------------------------------------------------------------------

// Name: EnumObjectsCallback()

// Desc: Callback function for enumerating objects (axes, buttons, POVs) on a

//       Joystick. This function enables user interface elements for objects

//       that are found to exist, and scales axes min/max values.

//-----------------------------------------------------------------------------

BOOL CALLBACK CDirectInput::EnumObjectsCallback( const DIDEVICEOBJECTINSTANCE* pdidoi,

                                   VOID* pContext )

{

    HWND hDlg = (HWND)pContext;

 

    static int nSliderCount = 0;  // Number of returned slider controls

    static int nPOVCount = 0;     // Number of returned POV controls

 

    // For axes that are returned, set the DIPROP_RANGE property for the

    // enumerated axis in order to scale min/max values.

    if( pdidoi->dwType & DIDFT_AXIS )

    {

        DIPROPRANGE diprg;

        diprg.diph.dwSize       = sizeof(DIPROPRANGE);

        diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER);

        diprg.diph.dwHow        = DIPH_BYID;

        diprg.diph.dwObj        = pdidoi->dwType; // Specify the enumerated axis

        diprg.lMin              = -1000;

        diprg.lMax              = +1000;

   

        // Set the range for the axis

        if( FAILED( g_pJoystick->SetProperty( DIPROP_RANGE, &diprg.diph ) ) )

            return DIENUM_STOP;

        

    }

    return DIENUM_CONTINUE;

}

//-----------------------------------------------------------------------------

// Name: UpdateInputState()

// Desc: Get the input device's state and display it.

//-----------------------------------------------------------------------------

DIJOYSTATE2 CDirectInput::GetState_Now()

{

    HRESULT     hr;

    DIJOYSTATE2 js;           // DInput Joystick state

    hr = g_pJoystick->Poll();

    if( FAILED(hr) ) 

    {

        hr = g_pJoystick->Acquire();

        while( hr == DIERR_INPUTLOST )

            hr = g_pJoystick->Acquire();

        //return S_OK;

    }

    // Get the input's device state

    if( FAILED( hr = g_pJoystick->GetDeviceState( sizeof(DIJOYSTATE2), &js ) ) );

     // CString str;

     //str.Format("%d",js.lX);

     CDirectInput::HandState = js;

     return js;

     //AfxMessageBox(str);

 

}

//-----------------------------------------------------------------------------

// Name: FreeDirectInput()

// Desc: Initialize the DirectInput variables.

//-----------------------------------------------------------------------------

VOID CDirectInput::FreeDirectInput()

{

    // Unacquire the device one last time just in case

    // the app tried to exit while the device is still acquired.

    if( g_pJoystick )

        g_pJoystick->Unacquire();

   

    // Release any DirectInput objects.

    SAFE_RELEASE( g_pJoystick );

    SAFE_RELEASE( g_pDI );

}

 
原创粉丝点击