Memulai XInput di aplikasi Windows

XInput memungkinkan aplikasi Windows memproses interaksi pengontrol (termasuk efek rumble pengontrol dan input dan output suara).

Topik ini memberikan gambaran singkat tentang kemampuan XInput dan cara menyiapkannya dalam aplikasi. Ini termasuk berikut ini:

Pengantar XInput

Aplikasi dapat menggunakan API XInput untuk berkomunikasi dengan pengontrol game ketika dicolokkan ke PC Windows (hingga empat pengontrol unik dapat dicolokkan pada satu waktu).

Dengan menggunakan API ini, pengontrol yang terhubung yang kompatibel dapat dikueri untuk statusnya, dan efek getaran dapat diatur. Pengontrol yang memiliki headset terpasang juga dapat dikueri untuk perangkat input dan output suara yang dapat digunakan dengan headset untuk pemrosesan suara.

Tata Letak Pengontrol

Pengontrol yang kompatibel memiliki dua tongkat arah analog, masing-masing dengan tombol digital, dua pemicu analog, pad arah digital dengan empat arah, dan delapan tombol digital. Status masing-masing input ini dikembalikan dalam struktur XINPUT_GAMEPAD saat fungsi XInputGetState dipanggil.

Pengontrol juga memiliki dua motor getaran untuk menyediakan efek umpan balik paksa kepada pengguna. Kecepatan motor ini ditentukan dalam struktur XINPUT_VIBRATION yang diteruskan ke fungsi XInputSetState untuk mengatur efek getaran.

Secara opsional, headset dapat disambungkan ke pengontrol. Headset memiliki mikrofon untuk input suara, dan headphone untuk output suara. Anda dapat memanggil fungsi XInputGetAudioDeviceIds atau XInputGetDSoundAudioDeviceGuids warisan untuk mendapatkan pengidentifikasi perangkat yang sesuai dengan perangkat untuk mikrofon dan headphone. Anda kemudian dapat menggunakan API Core Audio untuk menerima input suara dan mengirim output suara.

Menggunakan XInput

Menggunakan XInput sama sederhananya dengan memanggil fungsi XInput sesuai kebutuhan. Dengan menggunakan fungsi XInput, Anda dapat mengambil status pengontrol, mendapatkan ID audio headset, dan mengatur efek rumble pengontrol.

Beberapa Pengontrol

XInput API mendukung hingga empat pengontrol yang terhubung kapan saja. Semua fungsi XInput memerlukan parameter dwUserIndex yang diteruskan untuk mengidentifikasi pengontrol yang diatur atau dikueri. ID ini akan berada dalam rentang 0-3 dan diatur secara otomatis oleh XInput. Angka sesuai dengan port yang dicolokkan pengontrol, dan tidak dapat dimodifikasi.

Setiap pengontrol menampilkan ID mana yang digunakannya dengan menerangi kuadrian pada "cincin cahaya" di tengah pengontrol. Nilai dwUserIndex 0 sesuai dengan kuadran kiri atas; penomoran berlanjut di sekitar cincin dalam urutan searah jarang.

Aplikasi harus mendukung beberapa pengontrol.

Mendapatkan Status Pengontrol

Selama durasi aplikasi, mendapatkan status dari pengontrol mungkin akan paling sering dilakukan. Dari bingkai ke bingkai dalam aplikasi game, status harus diambil dan informasi game diperbarui untuk mencerminkan perubahan pengontrol.

Untuk mengambil status, gunakan fungsi XInputGetState:

DWORD dwResult;    
for (DWORD i=0; i< XUSER_MAX_COUNT; i++ )
{
    XINPUT_STATE state;
    ZeroMemory( &state, sizeof(XINPUT_STATE) );

    // Simply get the state of the controller from XInput.
    dwResult = XInputGetState( i, &state );

    if( dwResult == ERROR_SUCCESS )
    {
        // Controller is connected
    }
    else
    {
        // Controller is not connected
    }
}

Perhatikan bahwa nilai pengembalian XInputGetState dapat digunakan untuk menentukan apakah pengontrol tersambung. Aplikasi harus menentukan struktur untuk menyimpan informasi pengontrol internal; informasi ini harus dibandingkan dengan hasil XInputGetState untuk menentukan perubahan apa, seperti penekanan tombol atau delta pengontrol analog, dibuat bingkai tersebut. Dalam contoh di atas, g_Controllers mewakili struktur seperti itu.

Setelah status diambil dalam struktur XINPUT_STATE , Anda dapat memeriksa perubahan dan mendapatkan informasi spesifik tentang status pengontrol.

Anggota dwPacketNumber dari struktur XINPUT_STATE dapat digunakan untuk memeriksa apakah status pengontrol telah berubah sejak panggilan terakhir ke XInputGetState. Jika dwPacketNumber tidak berubah antara dua panggilan berurutan ke XInputGetState, maka belum ada perubahan status. Jika berbeda, maka aplikasi harus memeriksa anggota Gamepad dari struktur XINPUT_STATE untuk mendapatkan informasi status yang lebih rinci.

Untuk alasan performa, jangan panggil XInputGetState untuk slot pengguna 'kosong' setiap bingkai. Kami menyarankan agar Anda melakukan pemeriksaan ruang untuk pengontrol baru setiap beberapa detik sebagai gantinya.

Zona Mati

Agar pengguna memiliki pengalaman gameplay yang konsisten, game Anda harus menerapkan zona mati dengan benar. Zona mati adalah nilai "gerakan" yang dilaporkan oleh pengontrol bahkan ketika thumbstick analog tidak tersentuh dan berpusat. Ada juga zona mati untuk 2 pemicu analog.

Catatan

Game yang menggunakan XInput yang tidak memfilter zona mati sama sekali akan mengalami gameplay yang buruk. Harap dicatat bahwa beberapa pengontrol lebih sensitif daripada yang lain, sehingga zona mati dapat bervariasi dari unit ke unit. Disarankan agar Anda menguji game dengan beberapa pengontrol yang berbeda pada sistem yang berbeda.

Aplikasi harus menggunakan "zona mati" pada input analog (pemicu, tongkat) untuk menunjukkan kapan gerakan telah dibuat dengan cukup pada tongkat atau pemicu agar dianggap valid.

Aplikasi Anda harus memeriksa zona mati dan merespons dengan mudah, seperti dalam contoh ini:

XINPUT_STATE state = g_Controllers[i].state;

float LX = state.Gamepad.sThumbLX;
float LY = state.Gamepad.sThumbLY;

//determine how far the controller is pushed
float magnitude = sqrt(LX*LX + LY*LY);

//determine the direction the controller is pushed
float normalizedLX = LX / magnitude;
float normalizedLY = LY / magnitude;

float normalizedMagnitude = 0;

//check if the controller is outside a circular dead zone
if (magnitude > INPUT_DEADZONE)
{
    //clip the magnitude at its expected maximum value
    if (magnitude > 32767) magnitude = 32767;

    //adjust magnitude relative to the end of the dead zone
    magnitude -= INPUT_DEADZONE;

    //optionally normalize the magnitude with respect to its expected range
    //giving a magnitude value of 0.0 to 1.0
    normalizedMagnitude = magnitude / (32767 - INPUT_DEADZONE);
}
else //if the controller is in the deadzone zero out the magnitude
{
    magnitude = 0.0;
    normalizedMagnitude = 0.0;
}

//repeat for right thumb stick

Contoh ini menghitung vektor arah pengontrol dan seberapa jauh di sepanjang vektor pengontrol telah didorong. Hal ini memungkinkan pemberlakuan deadzone melingkar hanya dengan memeriksa apakah besarnya pengontrol lebih besar dari nilai deadzone. Selain itu kode menormalkan besaran pengontrol yang kemudian dapat dikalikan dengan faktor khusus game untuk mengonversi posisi pengontrol ke unit yang relevan dengan permainan.

Perhatikan bahwa Anda dapat menentukan zona mati Anda sendiri untuk tongkat dan pemicu (di mana saja dari 0-65534), atau Anda dapat menggunakan deadzone yang disediakan yang didefinisikan sebagai XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE, dan XINPUT_GAMEPAD_TRIGGER_THRESHOLD di XInput.h:

#define XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE  7849
#define XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE 8689
#define XINPUT_GAMEPAD_TRIGGER_THRESHOLD    30

Setelah deadzone diberlakukan, Anda mungkin merasa berguna untuk menskalakan rentang yang dihasilkan [0.0..1.0] floating point (seperti pada contoh di atas), dan secara opsional menerapkan transformasi non-linier.

Misalnya, dengan permainan mengemudi, mungkin berguna untuk kubus hasilnya untuk memberikan nuansa yang lebih baik untuk mengendarai mobil menggunakan gamepad, karena cubing hasilnya memberi Anda lebih presisi di rentang bawah, yang diinginkan, karena gamer biasanya menerapkan gaya lunak untuk mendapatkan gerakan halang atau menerapkan kekuatan keras ke satu arah untuk mendapatkan respons rd.

Mengatur Efek Getaran

Selain mendapatkan status pengontrol, Anda juga dapat mengirim data getaran ke pengontrol untuk mengubah umpan balik yang diberikan kepada pengguna pengontrol. Pengontrol berisi dua motor bergemuruh yang dapat dikontrol secara independen dengan meneruskan nilai ke fungsi XInputSetState.

Kecepatan setiap motor dapat ditentukan menggunakan nilai WORD dalam struktur XINPUT_VIBRATION yang diteruskan ke fungsi XInputSetState sebagai berikut:

XINPUT_VIBRATION vibration;
ZeroMemory( &vibration, sizeof(XINPUT_VIBRATION) );
vibration.wLeftMotorSpeed = 32000; // use any value between 0-65535 here
vibration.wRightMotorSpeed = 16000; // use any value between 0-65535 here
XInputSetState( i, &vibration );

Perhatikan bahwa motor kanan adalah motor frekuensi tinggi, motor kiri adalah motor frekuensi rendah. Mereka tidak selalu perlu diatur ke jumlah yang sama, karena memberikan efek yang berbeda.

Mendapatkan Pengidentifikasi Perangkat Audio

Headset untuk pengontrol memiliki fungsi-fungsi ini:

  • Merekam suara menggunakan mikrofon
  • Memutar kembali suara menggunakan headphone

Gunakan kode ini untuk mendapatkan pengidentifikasi perangkat untuk headset:

WCHAR renderId[ 256 ] = {0};
WCHAR captureId[ 256 ] = {0};
UINT rcount = 256;
UINT ccount = 256;

XInputGetAudioDeviceIds( i, renderId, &rcount, captureId, &ccount );

Setelah mendapatkan pengidentifikasi perangkat, Anda dapat membuat antarmuka yang sesuai. Misalnya, jika Anda menggunakan XAudio 2.8, gunakan kode ini untuk membuat suara mastering untuk perangkat ini:

IXAudio2* pXAudio2 = NULL;
HRESULT hr;
if ( FAILED(hr = XAudio2Create( &pXAudio2, 0, XAUDIO2_DEFAULT_PROCESSOR ) ) )
    return hr;

IXAudio2MasteringVoice* pMasterVoice = NULL;
if ( FAILED(hr = pXAudio2->CreateMasteringVoice( &pMasterVoice, XAUDIO2_DEFAULT_CHANNELS, XAUDIO2_DEFAULT_SAMPLERATE, 0, renderId, NULL, AudioCategory_Communications ) ) )
    return hr;

Untuk informasi tentang cara menggunakan pengidentifikasi perangkat captureId, lihat Menangkap Stream.

Mendapatkan GUID DirectSound (hanya DirectX SDK warisan)

Headset yang dapat dihubungkan ke pengontrol memiliki dua fungsi: dapat merekam suara menggunakan mikrofon, dan dapat memutar kembali suara menggunakan headphone. Dalam API XInput, fungsi-fungsi ini dicapai melalui DirectSound, menggunakan antarmuka IDirectSound8 dan IDirectSoundCapture8 .

Untuk mengaitkan mikrofon headset dan headphone dengan antarmuka DirectSound yang sesuai, Anda harus mendapatkan DirectSoundGUIDs untuk perangkat pengambilan dan render dengan memanggil XInputGetDSoundAudioDeviceGuids.

Catatan

Penggunaan DirectSound warisan tidak disarankan, dan tidak tersedia di aplikasi Windows Store. Info di bagian ini hanya berlaku untuk versi DirectX SDK XInput (XInput 1.3). Versi Windows 8 XInput (XInput 1.4) secara eksklusif menggunakan pengidentifikasi perangkat Windows Audio Session API (WASAPI) yang diperoleh melalui XInputGetAudioDeviceIds.

XInputGetDSoundAudioDeviceGuids( i, &dsRenderGuid, &dsCaptureGuid );

Setelah mengambil GUID, Anda dapat membuat antarmuka yang sesuai dengan memanggil DirectSoundCreate8 dan DirectSoundCaptureCreate8 seperti ini:

// Create IDirectSound8 using the controller's render device
if( FAILED( hr = DirectSoundCreate8( &dsRenderGuid, &pDS, NULL ) ) )
   return hr;

// Set coop level to DSSCL_PRIORITY
if( FAILED( hr = pDS->SetCooperativeLevel( hWnd, DSSCL_NORMAL ) ) )
   return hr;

// Create IDirectSoundCapture using the controller's capture device
if( FAILED( hr = DirectSoundCaptureCreate8( &dsCaptureGuid, &pDSCapture, NULL ) ) )
   return hr;

Referensi Pemrograman