zoukankan      html  css  js  c++  java
  • 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/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
    如果文中有什么错误,欢迎指出。以免更多的人被误导。
  • 相关阅读:
    My97日期控件 My97 DatePicker 4.0 Prerelease 发布
    My97DatePicker提问需知,仔细阅读可以在最快的时间收到问题反馈
    My97日期控件3.0不支持IE8,4.2以上已经支持,强烈建议还在使用3.x的用户换成最新版
    My97日期控件 My97 DatePicker 4.0 Beta4 发布(候选版本)
    My97日期控件 My97 DatePicker 4.0 正式版
    坚持打造最好的日期控件,My97 DatePicker 4.7 Release
    [PYTHON] 格式化输出的几种方法 HONG
    数组反转函数 blog_zss小帅
    fastadmin 按钮状态 blog_zss小帅
    fastadmin 固定列表字段 blog_zss小帅
  • 原文地址:https://www.cnblogs.com/wolfmvp/p/6902589.html
Copyright © 2011-2022 走看看