Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Penting
Lihat API GameInput untuk detail tentang API input generasi berikutnya yang didukung pada PC dan Xbox melalui Microsoft Game Development Kit (GDK).
Dokumen ini membandingkan XInput dan DirectInput implementasi input pengontrol dan cara mendukung perangkat XInput dan perangkat DirectInput warisan.
aplikasi Windows Store tidak mendukung DirectInput.
Ikhtisar
XInput memungkinkan aplikasi menerima input dari pengontrol XUSB. API tersedia melalui DirectX SDK, dan driver tersedia melalui Windows Update.
Ada beberapa keuntungan menggunakan XInput daripada DirectInput:
- XInput lebih mudah digunakan dan membutuhkan lebih sedikit pengaturan daripada DirectInput
- Pemrograman Xbox dan Windows akan menggunakan set API inti yang sama, memungkinkan pemrograman untuk menerjemahkan lintas platform jauh lebih mudah
- Akan ada basis pengontrol besar yang dipasang
- Perangkat XInput hanya akan memiliki fungsionalitas getaran saat menggunakan API XInput
Menggunakan pengontrol XUSB dengan DirectInput
Pengontrol XUSB dijumlahkan dengan benar pada DirectInput, dan dapat digunakan dengan DirectInputAPIs. Namun, beberapa fungsionalitas yang disediakan oleh XInput akan hilang dari implementasi DirectInput:
- Tombol pemicu kiri dan kanan akan bertindak sebagai satu tombol, tidak secara independen
- Efek getaran tidak akan tersedia
- Kueri untuk perangkat headset tidak akan tersedia
Kombinasi pemicu kiri dan kanan di DirectInput dirancang. Game selalu mengasumsikan bahwa sumbu perangkat DirectInput berpusat ketika tidak ada interaksi pengguna dengan perangkat. Namun, pengontrol yang lebih baru dirancang untuk mendaftarkan nilai minimum, bukan pusat, ketika pemicu tidak ditahan. Oleh karena itu, game yang lebih lama akan mengasumsikan interaksi pengguna.
Solusinya adalah menggabungkan pemicu, mengatur satu pemicu ke arah positif dan yang lain ke arah negatif, sehingga tidak ada interaksi pengguna yang menunjukkan DirectInput "kontrol" berada di tengah.
Untuk menguji nilai pemicu secara terpisah, Anda harus menggunakan XInput.
XInput dan DirectInput Berdampingan
Hanya dengan mendukung XInput, game Anda tidak akan berfungsi dengan perangkat directInput warisan. XInput tidak akan mengenali perangkat ini.
Jika anda ingin game mendukung warisan DirectInput perangkat, anda dapat menggunakan DirectInput dan XInput secara berdampingan. Saat menghitung perangkat DirectInput Anda, semua perangkat DirectInput akan menghitung dengan benar. Semua perangkat XInput akan muncul sebagai perangkat XInput dan DirectInput, tetapi tidak boleh ditangani melalui DirectInput. Anda harus menentukan perangkat DirectInput mana yang merupakan perangkat warisan, dan yang merupakan perangkat XInput, dan menghapusnya dari enumerasi perangkat DirectInput.
Untuk melakukan ini, masukkan kode ini ke dalam panggilan balik enumerasi DirectInput Anda:
#include <wbemidl.h>
#include <oleauto.h>
#ifndef SAFE_RELEASE
#define SAFE_RELEASE(p) { if (p) { (p)->Release(); (p) = nullptr; } }
#endif
//-----------------------------------------------------------------------------
// Enum each PNP device using WMI and check each device ID to see if it contains
// "IG_" (ex. "VID_0000&PID_0000&IG_00"). If it does, then it's an XInput device
// Unfortunately this information cannot be found by just using DirectInput
//-----------------------------------------------------------------------------
BOOL IsXInputDevice( const GUID* pGuidProductFromDirectInput )
{
IWbemLocator* pIWbemLocator = nullptr;
IEnumWbemClassObject* pEnumDevices = nullptr;
IWbemClassObject* pDevices[20] = {};
IWbemServices* pIWbemServices = nullptr;
BSTR bstrNamespace = nullptr;
BSTR bstrDeviceID = nullptr;
BSTR bstrClassName = nullptr;
bool bIsXinputDevice = false;
// CoInit if needed
HRESULT hr = CoInitialize(nullptr);
bool bCleanupCOM = SUCCEEDED(hr);
// So we can call VariantClear() later, even if we never had a successful IWbemClassObject::Get().
VARIANT var = {};
VariantInit(&var);
// Create WMI
hr = CoCreateInstance(__uuidof(WbemLocator),
nullptr,
CLSCTX_INPROC_SERVER,
__uuidof(IWbemLocator),
(LPVOID*)&pIWbemLocator);
if (FAILED(hr) || pIWbemLocator == nullptr)
goto LCleanup;
bstrNamespace = SysAllocString(L"\\\\.\\root\\cimv2"); if (bstrNamespace == nullptr) goto LCleanup;
bstrClassName = SysAllocString(L"Win32_PNPEntity"); if (bstrClassName == nullptr) goto LCleanup;
bstrDeviceID = SysAllocString(L"DeviceID"); if (bstrDeviceID == nullptr) goto LCleanup;
// Connect to WMI
hr = pIWbemLocator->ConnectServer(bstrNamespace, nullptr, nullptr, 0L,
0L, nullptr, nullptr, &pIWbemServices);
if (FAILED(hr) || pIWbemServices == nullptr)
goto LCleanup;
// Switch security level to IMPERSONATE.
hr = CoSetProxyBlanket(pIWbemServices,
RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, nullptr,
RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE,
nullptr, EOAC_NONE);
if ( FAILED(hr) )
goto LCleanup;
hr = pIWbemServices->CreateInstanceEnum(bstrClassName, 0, nullptr, &pEnumDevices);
if (FAILED(hr) || pEnumDevices == nullptr)
goto LCleanup;
// Loop over all devices
for (;;)
{
ULONG uReturned = 0;
hr = pEnumDevices->Next(10000, _countof(pDevices), pDevices, &uReturned);
if (FAILED(hr))
goto LCleanup;
if (uReturned == 0)
break;
for (size_t iDevice = 0; iDevice < uReturned; ++iDevice)
{
// For each device, get its device ID
hr = pDevices[iDevice]->Get(bstrDeviceID, 0L, &var, nullptr, nullptr);
if (SUCCEEDED(hr) && var.vt == VT_BSTR && var.bstrVal != nullptr)
{
// Check if the device ID contains "IG_". If it does, then it's an XInput device
// This information cannot 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_s(strVid, L"VID_%4X", &dwVid) != 1)
dwVid = 0;
WCHAR* strPid = wcsstr(var.bstrVal, L"PID_");
if (strPid && swscanf_s(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;
}
}
}
VariantClear(&var);
SAFE_RELEASE(pDevices[iDevice]);
}
}
LCleanup:
VariantClear(&var);
if(bstrNamespace)
SysFreeString(bstrNamespace);
if(bstrDeviceID)
SysFreeString(bstrDeviceID);
if(bstrClassName)
SysFreeString(bstrClassName);
for (size_t iDevice = 0; iDevice < _countof(pDevices); ++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 )
{
if( IsXInputDevice( &pdidInstance->guidProduct ) )
return DIENUM_CONTINUE;
// Device is verified not XInput, so add it to the list of DInput devices
return DIENUM_CONTINUE;
}
Versi kode ini yang sedikit ditingkatkan ada dalam sampel DirectInput Joystick warisan.