Bagikan melalui


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 yang berikut:

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 ketika fungsiXInputGetState 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 fungsiXInputSetState 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 fungsi lama XInputGetDSoundAudioDeviceGuids untuk mendapatkan pengidentifikasi perangkat yang sesuai dengan 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 getaran 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 diperiksa. 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 menunjukkan ID yang digunakannya dengan menyalakan kuadran pada "cincin cahaya" di tengah pengontrol. Nilai dwUserIndex 0 sesuai dengan kuadran kiri atas; penomoran berlanjut di sekitar cincin dalam urutan searah jarum jam.

Aplikasi harus mendukung beberapa pengontrol.

Mendapatkan Status Pengontrol

Sepanjang penggunaan 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 fungsiXInputGetState:

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 pengembalianXInputGetState dapat digunakan untuk menentukan apakah pengontrol tersambung. Aplikasi harus mendefinisikan sebuah struktur untuk menyimpan informasi pengontrol internal; informasi ini harus dibandingkan dengan hasil XInputGetState untuk menentukan perubahan apa, seperti penekanan tombol atau delta pengontrol analog, yang dibuat pada frame tersebut. Dalam contoh di atas, g_Controllers mewakili struktur seperti itu.

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

Anggota dwPacketNumber dari struktur XINPUT_STATE digunakan untuk memeriksa apakah keadaan 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, aplikasi harus memeriksa elemen Gamepad dari struktur XINPUT_STATE untuk mendapatkan informasi status yang lebih rinci.

Demi alasan kinerja, jangan memanggil XInputGetState untuk slot pengguna 'kosong' setiap frame. Kami sarankan agar Anda memeriksa 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.

Nota

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 tepat, 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 dari pengontrol dan seberapa jauh pengontrol telah didorong sepanjang vektor tersebut. Hal ini memungkinkan penerapan deadzone melingkar dengan hanya memeriksa apakah besarnya input 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 stik dan pemicu (dari 0 hingga 65534), atau Anda dapat menggunakan zona mati yang telah disediakan yang didefinisikan sebagai XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE, XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE, dan XINPUT_GAMEPAD_TRIGGER_THRESHOLD dalam 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 menaikkan pangkat tiga hasilnya guna memberikan nuansa yang lebih baik saat mengendarai mobil menggunakan gamepad, karena menaikkan pangkat tiga hasilnya memberi Anda lebih presisi pada rentang bawah yang diinginkan, oleh karena gamer biasanya menerapkan gaya ringan untuk mendapatkan gerakan halus atau menerapkan kekuatan keras ke satu arah untuk mendapatkan respons cepat.

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 fungsiXInputSetState.

Kecepatan setiap motor dapat ditentukan menggunakan nilai WORD dalam struktur XINPUT_VIBRATION yang diteruskan ke fungsiXInputSetState 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 Cara Menangkap Sebuah Stream.

Mendapatkan GUID DirectSound (hanya untuk DirectX SDK versi lama)

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.

Nota

Penggunaan warisan DirectSound 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