2016-08-23 2 views
0

J'essaie de lire à partir de mon contrôleur XBox 360 sans interroger. (Pour être précis, j'utilise actuellement un Logitech F310, mais mon PC Windows 10 le voit comme un contrôleur XBox 360.) J'ai écrit un code HID plutôt méchant qui utilise des E/S qui se chevauchent pour bloquer dans un thread sur deux événements, un qui indique qu'il existe un rapport prêt à lire à partir du périphérique HID, l'autre indiquant que le thread d'interface utilisateur a demandé le thread HID pour quitter. Cela fonctionne bien, mais le pilote HID se comporte un peu différemment de XInput. En particulier, il consolide les deux déclencheurs en une seule valeur, ne faisant que passer leur différence (sur la curieuse revendication que les jeux attendent des valeurs HID à 0x80 lorsque le doigt du joueur est hors contrôle). XInput les traite comme deux valeurs distinctes, ce qui est une grande amélioration. En outre, XInput signale que les commutateurs de chapeau sont en quatre bits, ce qui signifie que vous pouvez en extraire dix états: non compressé, N, NE, E, SE, S, SW, W, NW et tout-en-bas (ce dernier peut être difficile à utiliser avec succès, mais au moins c'est là si vous le voulez, je l'ai utilisé pour quitter ma boucle d'interrogation). L'inconvénient, pour moi, de XInput est qu'il semble y avoir aucun moyen de bloquer sur une demande de lecture jusqu'à ce que le contrôleur modifie l'une de ses valeurs ou boutons. En tant que périphérique HID, l'appel ReadFile se bloque (plus exactement, les blocs WaitForMultipleEvents jusqu'à ce que des données soient disponibles). XInput semble anticiper les sondages. Pour un jeu qui serait naturellement écrit pour interroger le contrôleur aussi souvent qu'il a mis à jour l'état du jeu (peut-être une fois pour chaque nouvelle image vidéo affichée, par exemple), cela a du sens. Mais si vous voulez utiliser le contrôleur à d'autres fins (je travaille sur une application théâtrale), vous voudrez peut-être un système purement asynchrone comme les fournitures de l'API HID. Mais, encore une fois, l'API HID combine les deux déclencheurs de valeur. Maintenant, lorsque vous lisez l'appareil avec XInput, vous obtenez non seulement l'état de tous les contrôles, mais aussi un numéro de paquet. MSDN indique que le numéro de paquet change seulement quand l'état d'un contrôle change. De cette façon, si les numéros de paquets consécutifs sont identiques, vous n'avez pas à vous préoccuper de tout traitement après le premier, car vous savez que l'état du contrôleur n'a pas changé. Mais vous êtes encore en train d'interroger ce qui, pour moi, est un peu vulgaire. Ce qui m'intrigue, cependant, c'est que quand je mets un grand retard entre mes sondages (100ms), je peux voir que les numéros de paquets augmentent de plus d'un quand les contrôles de valeur (les triggers ou les sticks) sont déplacé. Cela, je pense, suggère que le périphérique envoie des paquets sans attendre d'être interrogé, et que je reçois seulement le paquet le plus récent chaque fois que je sondage. Si tel est le cas, il semble que je devrais être capable de bloquer jusqu'à ce qu'un paquet soit envoyé, et de réagir seulement quand cela se produit, plutôt que d'avoir à interroger du tout. Mais je ne trouve aucune indication que c'est une option. Parce que je peux bloquer avec l'API HID, je ne veux pas abandonner sans essayer (y compris demander des conseils ici). À moins d'écrire mon propre pilote pour le contrôleur (dont je ne suis pas sûr est même une option sans documentation propriétaire), quelqu'un sait comment je peux utiliser des E/S chevauchantes (ou toute autre méthode de blocage) pour lire le Contrôleur XBox 360 comme XInput, avec les déclencheurs comme valeurs séparées, et le chapeau comme quatre boutons?Un moyen de bloquer tout en lisant un contrôleur XBox 360 autre que l'API HID?

Ci-dessous est un code que j'ai écrit qui lit le contrôleur et montre que le nombre de paquets peuvent sauter par plus d'un entre les lectures:

#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; 
} 

S'il vous plaît noter que DirectInput ne nous aide pas, car il combine aussi les déclencheurs en une seule valeur.

Merci!

Répondre

1

Je ne suis pas sûr qu'il y ait un avantage à cela, mais pourriez-vous écrire un fil qui interroge sur un intervalle régulier, puis définit un sémaphore (ou un autre signal) lorsque l'état a changé. Ensuite, votre thread principal pourrait bloquer l'attente du signal du thread d'interrogation.Mais potentiellement, il n'y a peut-être aucun avantage à ce système, car sur certains contrôleurs, les valeurs des vignettes changent légèrement, que vous les déplaciez ou non. (Bruit) Vous pouvez bien sûr ignorer les petits changements et ne signaler votre sémaphore que lorsqu'un gros changement s'est produit.

+0

Merci, Puce. C'est là que je m'attends à finir. Microsoft suggère fortement que nous codions ce qu'ils appellent une "zone morte" autour de la valeur "mains libres" idéale pour les contrôles de valeur, précisément à cause du problème de bruit (mes expériences confirment que les bâtons ne retournent pas exactement au même valeur chaque fois que je les lâche bien que, ironiquement, les déclencheurs font). Un thread qui émule un appel asynch à ReadFile fonctionnerait correctement et un appel à XInputGetState prend seulement 20us sur ma machine. Frais généraux très légers. Juste vulgaire;). –