XInput和DirectInput


原文鏈接:https://msdn.microsoft.com/en-us/library/windows/desktop/ee417014(v=vs.85).aspx

XInput是一個允許應用從Windows平台Xbox 360控制器中接收輸入的API。該文檔描述XInput和DirectInput關於Xbox 360控制器接口間的不同,並說明如何在同一時間同時支持XInput設備和傳統DirectInput設備。
 
注意:傳統DirectInput目前不推薦使用,並且在Windows Store里面的應用已經不支持DirectInput。
 
新的標准:XInput
XInput目前可以應用於游戲開發,這個新的輸入標准可以應用於Xbox 360、Windows XP SP1及以上版本以及Windows Vista。該APIs在DirectX SDK中包含,並且通過Windows Update可以更新驅動。
 
XInput相較於DirectInput有以下方面的優勢:
  • XInput比DirectInput更方便使用並且創建步驟更少
  • Xbox 360和Windows編程使用相同的核心APIs集,並且跨平台編程更方便
  • Xbox 360有一個非常大的用戶群
  • XInput設備(也就是指Xbox 360控制器)將在僅使用XInput APIs時具備震動功能
  • 未來發布關於Xbox 360操縱台的控制器(也就是方向盤)將同樣可以應用於Windows
 
將DirectInput應用於Xbox 360控制器
Xbox 360可以通過DirectInput進行枚舉,並且可以應用DirectInput APIs。然而,某些XInput提供的功能在DirectInput中不存在:
  • 左、右扳柄不作為獨立的單一按鈕
  • 震動效果不可用
  • 無法查詢頭戴式設備
在DirectInput中設計左右扳柄處於組合狀態,游戲常常假定當沒有用戶與設備交互時DirectInput設備軸處於中間。然而,Xbox 360控制器設計該位置為最小值,並不是中間,當觸發器沒有被控制時,老的游戲因此假定用戶處於交互狀態。
 
解決方案是配置扳柄,設置一個為負向和另一個為正向,所以當沒有用戶交互時表示DirectInput控制處於中間狀態。
 
為了分別測試扳柄的值,此時必須用XInput。
 
同時支持XInput和DirectInput
假如僅僅支持XInput,游戲將不能工作在傳統的DirectInput設備上。XInput將不會識別這些設備。
 
如何想讓游戲支持傳統DirectInput設備,需要同時使用DirectInput和XInput。當枚舉DirectInput設備時,所有DirectInput設備將枚舉成功。所有的XInput設備將同時顯示在XInput和DirectInput設備中,但是他們不應該通過DirectInput處理。你需要決定那些DirectInput設備是傳統設備,那些是XInput設備並且從DirectInput設備枚舉集里面將他們移除。
 
為實現這個目的,將下面這些代碼插入到DirectInput回調函數里面:
#include <wbemidl.h>
#include <oleauto.h>
#include <wmsstd.h>

//-----------------------------------------------------------------------------
// 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 it's an XInput device
// Unfortunately this information can not be found by just using DirectInput
//-----------------------------------------------------------------------------
BOOL IsXInputDevice( const GUID* pGuidProductFromDirectInput )
{
    IWbemLocator*          pIWbemLocator  = NULL;
    IEnumWbemClassObject*  pEnumDevices  = NULL;
    IWbemClassObject*      pDevices[20]  = {0};
    IWbemServices*          pIWbemServices = NULL;
    BSTR                    bstrNamespace  = NULL;
    BSTR                    bstrDeviceID  = NULL;
    BSTR                    bstrClassName  = NULL;
    DWORD                  uReturned      = 0;
    bool                    bIsXinputDevice= false;
    UINT                    iDevice        = 0;
    VARIANT                var;
    HRESULT                hr;

    // CoInit if needed
    hr = CoInitialize(NULL);
    bool bCleanupCOM = SUCCEEDED(hr);

    // Create WMI
    hr = CoCreateInstance( __uuidof(WbemLocator),
                          NULL,
                          CLSCTX_INPROC_SERVER,
                          __uuidof(IWbemLocator),
                          (LPVOID*) &pIWbemLocator);
    if( FAILED(hr) || pIWbemLocator == NULL )
        goto LCleanup;

    bstrNamespace = SysAllocString( L"\\\\.\\root\\cimv2" );if( bstrNamespace == NULL ) goto LCleanup;       
    bstrClassName = SysAllocString( L"Win32_PNPEntity" );  if( bstrClassName == NULL ) goto LCleanup;       
    bstrDeviceID  = SysAllocString( L"DeviceID" );          if( bstrDeviceID == 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, EOAC_NONE );                   

    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 it's an XInput device
                                    // This information can not be found from 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;

                    // Compare the VID/PID to the DInput device
                    DWORD dwVidPid = MAKELONG( dwVid, dwPid );
                    if( dwVidPid == pGuidProductFromDirectInput->Data1 )
                    {
                        bIsXinputDevice = true;
                        goto LCleanup;
                    }
                }
            } 
            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 );

    if( bCleanupCOM )
        CoUninitialize();

    return bIsXinputDevice;
}


//-----------------------------------------------------------------------------
// 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 EnumJoysticksCallback( const DIDEVICEINSTANCE* pdidInstance,
                                    VOID* pContext )
{
    HRESULT hr;

    if( IsXInputDevice( &pdidInstance->guidProduct ) )
        return DIENUM_CONTINUE;

        // Device is verified not XInput, so add it to the list of DInput devices

        return DIENUM_CONTINUE;       
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM