2016-08-23 68 views
0

我試圖從我的XBox 360控制器中讀取而不進行輪詢。 (準確地說,我實際上使用的是Logitech F310,但我的Windows 10 PC將它視爲XBox 360控制器。)我寫了一些相當討厭的HID代碼,它們使用重疊的I/O在兩個線程中阻塞事件,一個表明有一個報告準備從HID設備讀取,另一個表明UI線程已經請求HID線程退出。這很好,但HID驅動程序的行爲與XInput有所不同。特別是,它將兩個觸發器合併爲一個單一的值,只是傳遞他們的差異(當遊戲者的手指離開控制時,遊戲期望HID值爲0x80)。 XInput將它們視爲兩個不同的值,這是一個很大的改進。此外,XInput將帽子開關報告爲四位,這意味着您實際上可以獲得十個狀態:未壓縮,N,NE,E,SE,S,SW,W,NW和全下(最後可能是很難成功使用,但至少它在那裏,如果你想要它,我一直在使用它來退出我的輪詢循環)。讀取HID API以外的XBox 360控制器時,有什麼辦法阻止?

對我而言,XInput的缺點是在控制器改變它的一個值或按鈕之前似乎沒有辦法阻塞讀取請求。作爲HID設備,ReadFile調用將阻塞(更確切地說,WaitForMultipleEvents塊直到有數據可用)。 XInput似乎預測投票。對於一種自然會寫入的遊戲來更新遊戲狀態(例如,對於顯示的每個新視頻幀,可能會每次顯示一次)來輪詢控制器,這是有道理的。但是,如果您想將控制器用於其他目的(我正在製作戲劇應用程序),則可能需要純粹的異步系統,如HID API耗材。但是,HID API再次結合了兩個值觸發器。

現在,當您使用XInput讀取設備時,您不僅可以獲得所有控件的狀態,還可以獲得包號。 MSDN表示只有當控件的狀態發生變化時,數據包號碼纔會更改。這樣,如果連續的數據包編號相同,則不必在第一個數據包之後進行任何處理,因爲您知道控制器狀態沒有改變。但你仍在投票,對我而言,這有點粗俗。然而,當我在我的民意調查(100毫秒)之間放了一個很大的延遲時,我可以看到,當值控制(觸發器或棍棒)時,包數量增加了一個以上移動。我認爲,這表明設備在不等待輪詢的情況下發送數據包,並且每次輪詢時我只收到最近的數據包。如果是這樣,似乎我應該能夠阻止,直到發送一個數據包,並且只有在發生這種情況時才作出反應,而不是必須進行輪詢。但我找不到任何跡象表明這是一種選擇。因爲我可以阻止HID API,所以我不想放棄,而不嘗試(包括在此尋求建議)。我不知道如何使用重疊的I/O(或任何其他阻塞方法)來讀取控制器(我不知道甚至沒有專有文檔的選項),沒有人知道如何使用重疊的I/O XBox 360控制器與XInput一樣,觸發器是單獨的值,帽子是四個按鈕?

下面是一些代碼,我寫了讀取控制器和顯示包號可以由一個以上的跳讀之間:

#include <Windows.h> 
#include <Xinput.h> 
#include <stdio.h> 

#define MAX_CONTROLLERS 4 

int main() 
{ 
    DWORD userIndex; 

    XINPUT_STATE xs; 
    XINPUT_VIBRATION v; 

    XInputEnable(TRUE); 

    // Which one are we? 

    for (userIndex = 0; userIndex < XUSER_MAX_COUNT; ++userIndex) 
     if (XInputGetState(userIndex, &xs) == ERROR_SUCCESS) 
      break; 

    if (userIndex == XUSER_MAX_COUNT) 
    { 
     printf("Couldn't find an Xbox 360 controller.\n"); 
     getchar(); 
     return -1; 
    } 

    printf("Using controller #%1d.\n", userIndex); 

    while (TRUE) 
    { 
     DWORD res = XInputGetState(userIndex, &xs); 

     printf("%5d %6d: %3d %3d %3d %3d %3d %3d 0x%04X\n", 
       res, 
      xs.dwPacketNumber, 
      xs.Gamepad.bLeftTrigger & 0xFF, 
      xs.Gamepad.bRightTrigger & 0xFF, 
      xs.Gamepad.sThumbLX & 0xFF, 
      xs.Gamepad.sThumbLY & 0xFF, 
      xs.Gamepad.sThumbRX & 0xFF, 
      xs.Gamepad.sThumbRY & 0xFF, 
      xs.Gamepad.wButtons); 

     if (xs.Gamepad.wButtons == 0x000F) // mash down the hat 
      break; 

     Sleep(100); 
    } 

    getchar(); 
    return 0; 
} 

請注意,DirectInput的是沒有太大的幫助,因爲它也結合了將觸發器合併爲一個值。

謝謝!

回答

1

不確定這是否有任何優勢,但是您可以編寫一個線程輪詢定期間隔,然後在狀態發生變化時設置信號量(或其他信號)。然後,您的主線程可能會阻止等待來自輪詢線程的信號。但是,這個系統可能沒有任何優勢,因爲在某些控制器上,無論您是否移動,拇指指杆的值都會稍有變化。 (噪聲)你當然可以忽略小的變化,只在發生大的變化時發出信號。

+0

謝謝,芯片。那就是我期望我會最終結束的地方。微軟實際上強烈建議我們將代碼稱爲「死區」,因爲價值控制的理想「脫手」價值,正是由於噪音問題(我的實驗證實這些棒不總是回到完全相同價值每次我放開他們,但諷刺的是,觸發器)。模擬對ReadFile的異步調用的線程可以正常工作,而對XInputGetState的調用在我的機器上只需要20us。非常輕的開銷。只是粗俗的;)。 –

相關問題