• 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;       
    }
    作者:常想一二
    出处:http://www.cnblogs.com/wolfmvp/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
    如果文中有什么错误,欢迎指出。以免更多的人被误导。
  • 相关阅读:
    作业 20181204-1 每周例行报告
    对团队成员公开感谢
    附加作业 软件工程原则的应用实例分析
    作业 20181127-2 每周例行报告
    作业 20181120-1 每周例行报告
    作业 20181113-2 每周例行报告
    作业 20181030-4 每周例行报告
    作业 20181023-3 每周例行报告
    SDWebImage的实现原理与底层结构拆解
    计算文件或者文件夹的大小用于计算下载速度或者是显示清除缓存大小
  • 原文地址:https://www.cnblogs.com/wolfmvp/p/6902589.html
Copyright © 2020-2023  润新知