DirectInput - Joystick  

Die Verwaltung eines Joysticks über DirectInput ist im Grunde recht einfach. Da ein Joystick kein Systemeingabegerät ist, kann nicht davon ausgegangen werden, dass an jedem Computer ein Joystick angeschlossen ist. Daher ist eine Auflistung der vorhandenen Eingabegeräte notwendig. Es ist ja nicht sinnvoll dem Anwender die Möglichkeit anzubieten ein Spiel mit einem Joystick zu spielen, wenn gar kein Joystick am Computer angeschlossen ist. Des weiteren sollten auch die Eigenschaften eines ggf. vorhandenen Joysticks abgefragt werden.

Es ist zwar toll wenn ein Spiel 10 Joystick-Tasten unterstützt, aber nicht sinnvoll für einen Spieler der einen Joystick mit nur 5 Tasten besitzt. In diesem Teil unseres DirectInput-Tutorials wird immer die Bezeichnung Joystick verwendet. Diese Bezeichnung steht für alle Arten von Joysticks, Flightsticks, GamePads und Steuerräder ausgenommen der Force-Feedback-Geräte.

Es gibt zwei Möglichkeiten um Eingabedaten eines Joysticks abzufragen:

  • in der Spielschleife die Eingabeinformationen abfragen

  • auf ein DirectXEvent warten und dann erst die Eingabeinformationen verarbeiten

Doch zunächst muss festgestellt werden, ob und wie viele Joysticks am Computer angeschlossen sind. Hierfür benötigt man ein DirectInputEnumDevices-Objekt und die Funktion GetDIEnumDevices vom DirectInput-Objekt (siehe Grundlagen), wobei nicht alle Eingabegeräte, sondern nur die angeschlossenen Joysticks abgefragt werden.

Dies erfolgt mit dem Typ-Filter DIDEVTYPE_JOYSTICK und dem Flag DIEDFL_ATTACHEDONLY. So erhalten wir eine Liste der z.Zt. am Computer angeschlossenen Joysticks. Ist die Liste leer (GetCount = 0), dann ist kein Joystick vorhanden.

Dim diJoystick As DirectInputDevice
Dim enumDevice As DirectInputEnumDevices
  'Auflistung aller angeschlossenen Joysticks einlesen
Set enumDevice = DI.GetDIEnumDevices(DIDEVTYPE_JOYSTICK, _
  DIEDFL_ATTACHEDONLY)

If enumDevice.GetCount = 0 Then
  MsgBox "Es sind keine Joysticks am PC angeschlossen.", _
    vbInformation
End If

Gehen wir davon aus es ist ein Joystick angeschlossen. Nun möchten wir aber auch wissen welche Eigenschaften dieser Joystick besitzt, wie z.B. wie viel Achsen, Tasten, Schieberegler usw. Nicht jeder Joystick hat z.B. die gleiche Anzahl an Tasten. Um die Eigenschaften zu erhalten, muss ein DirectInputDevice-Objekt erstellt, und über ein DirectInputEnumDeviceObjects-Objekt können diese dann abgefragt werden.

Im folgenden Beispiel wird nur die Anzahl der Tasten ermittelt. Zu beachten ist, das es für Joysticks keine SystemGUID gibt. Wir müssen daher die GUID des Joysticks aus der Auflistung nehmen.

Dim Caps As DIDEVCAPS
Dim diEnumObjects As DirectInputEnumDeviceObjects

  'erstelle Input-Objekt mit GUID aus der Liste
Set diJoystick = _
  DI.CreateDevice(enumDevice.GetItem(1).GetGuidInstance)
  'setze DirectInput DatenFormat auf Joystick
diJoystick.SetCommonDataFormat DIFORMAT_JOYSTICK
  'setze Cooperative Level
diJoystick.SetCooperativeLevel Me.hWnd, _
  DISCL_BACKGROUND Or DISCL_EXCLUSIVE
  'hole Fähigkeiten des Joysticks
diJoystick.GetCapabilities Caps
  'irgendwelche Fähigkeiten hat der Joystick hoffentlich
If Caps.lFlags Then
   'hole Tasten-Auflistung vom Joystick
  Set diEnumObjects = diJoystick.GetDeviceObjectsEnum(DIDFT_BUTTON)
   'wieviele Tasten hat der Joystick
  JSButton = diEnumObjects.GetCount
End If

Das richtige Setzen des Cooperative Level ist wichtig, da sonst Windows bzw. andere Anwendungen nicht wissen wie sie das Eingabegerät mit ihrem Programm teilen sollen. Wie dies genau geht, ist in unserem Abschnitt CooperativeLevel und Datenformat genau beschrieben.

Die Funktion GetDeviceObjectsEnum bietet eine Fülle an Informationen über den Joystick, und folgende Eigenschaften können abgefragt werden:

  DIDFT_ABSAXIS

Absolute Achsen

DIDFT_ALIAS

Ist zu benutzen wie eine Steuerung, die durch ein HID (Human Interface Device = ein Gerät das es dem Mensch ermöglicht, mit dem Computer zu kommunizieren) identifiziert wurde. Diese Eigenschaft gilt nur für HID kompatiblen USB-Geräte.

DIDFT_ALL

Alle Eigenschaften

DIDFT_ANYINSTANCE

Für die erste  Instanz, auf die andere Kriterien wie auf DIDFT_AXIS oder DIDFT_BUTTON zutreffen.

DIDFT_AXIS

Anzahl der absoluten als auch relativen Achsen

DIDFT_BUTTON

Anzahl aller Tasten

DIDFT_COLLECTION

HID-Ausstattung. Die HID-Ausstattung generiert keine eigenen Daten.

DIDFT_FFACTUATOR

Objekt, das einen Force-Feedback Auslöser enthält. Forces (Kräfte) können auf dieses Objekt angewendet werden.

  DIDFT_FFEFFECTTRIGGER

Objekt, mit dem Force-Feedback Effekte ausgelöst werden können.

DIDFT_INSTANCEMASK 

das gleiche wie DIDFT_ANYINSTANCE

DIDFT_NOCOLLECTION

Objekt, das zu keiner HID-Ausstattung gehört, das heißt, ein Objekt zu dem DirectInputDeviceObjectInstance.GetCollectionNumber eine 0 zurückliefert.

DIDFT_NODATA

Objekt, das keine Daten generiert.

DIDFT_OUTPUT

Objekt, das Daten mit der DirectInputDevice8.SendDeviceData Methode senden kann.

DIDFT_POV

Point-of-view Controller

DIDFT_PSHBUTTON

PushButton - Eine Taste die bei Drücken ihren Zustand ändert und solange beibehält, bis sie losgelassen wird.

DIDFT_RELAXIS

Relative Achsen

DIDFT_TGLBUTTON

ToggleButton - Eine Taste die bei einmaligem Drücken ihren Zustand (gedrückt oder nicht-gedrückt) ändert und solange beibehält, bis sie nochmals gedrückt wird.

DIDFT_VENDORDEFINED

Ein vom Hersteller definierter Objekttyp.

 'z.B. Einlesen aller Eigenschaften
Set diEnumObjects = diJoystick.GetDeviceObjectsEnum(DIDFT_ALL)

Jetzt muss das Eingabegerät für die Anwendung reserviert werden. Hiefür wird die Funktion Acquire vom DirectInputDevice-Objekt verwendet. Anders als bei der Maus und der Tastatur braucht man auch noch die Funktion Poll. Die Poll Funktion stellt die Eingabeinformationen des Joysticks zur Verfügung.

diJoystick.Acquire
diJoystick.Poll
Nun steht die Verbindung und die Eingabeinformationen können verarbeitet werden. Zu beachten ist noch, dass bei den Achsen die Mittelstellung nicht den Wert 0 sondern den Wert 32768 liefert. Bei einem GamePad kann daher ruhig der Wert 32768 abgezogen werden um bei der Mittelstellung der Achse Null zu erhalten, da die Achsen eines GamePads sowieso einen statischen Wert liefern, egal ob Links/Rechts oder Rauf/Runter. 

Ein normaler Joystick hingegen liefert einen Wert zwischen 0 und dem maximalen äußeren Wert. Bei solchen Joysticks kommt noch hinzu das sich die Werte der Achsen bei Mittelstellung ein klein wenig verändern. Dieses "Zittern" kann über setzen von Joystickeigenschaften ausgeschaltet werden und wird weiter unten erklärt. Die Joystickdaten erhält man über den Typ DIJOYSTATE und der Funktion GetDeviceStateJoystick vom DirectInputDevice-Objekt.

Dim JoystickState As DIJOYSTATE
diJoystick.GetDeviceStateJoystick JoystickState

Soll die Steuerung bei einem Spiel hauptsächlich durch einen Joystick erfolgen, dann ist es sinnvoll, die Eingabeinformationen in der Hauptschleife des Spieles zu verarbeiten.

Dim JoystickState As DIJOYSTATE

  'stelle Verbindung her
diJoystick.Acquire
  'mache Daten verfügbar
diJoystick.Poll
  'hole aktuelle Daten
  'entweder mit der GetDeviceStateJoystick-Funktion
diJoystick.GetDeviceStateJoystick JoystickState
  'oder mit der GetDeviceState-Funktion
  'diJoystick.GetDeviceState Len(JoystickState), JoystickState

  'gib AchsenWerte in einer TextBox aus
txt_XY.Text = "X: " & (JoystickState.x - JOYSTICKCENTERED) & _
  vbCrLf & "Y: " & (JoystickState.y - JOYSTICKCENTERED) & _
    vbCrLf & "Z: " & (JoystickState.z - JOYSTICKCENTERED)

  'gibt Tasten-Status in einer TextBox aus
For i = 1 To JSButton
  strhilf = "Nein"
  If JoystickState.buttons(i - 1) > 0 Then _
    strhilf = "Ja"
  txt_Buttons.Text = txt_Buttons.Text & _
    "Button " & i & " : " & strhilf & vbCrLf
Next

Eine Möglichkeit, die die Ressourcen am Wenigsten beansprucht ist, auf ein DirectXEvent zu warten, um dann erst die Joystickdaten zu verarbeiten. Dazu muss ein DirectXEvent erstellt werden und die Prozedur DirectXEvent_DXCallback im Hauptfenster der Anwendung vorhanden sein.

Zu beachten ist hier, dass bei Verwendung von mehreren DXEvents (z.B. wenn Wave-Dateien gestreamt werden) die Event-ID abgefragt wird, da ansonsten die Joystickdaten verarbeitet werden obwohl gar kein Ereignis von DirectInput vorliegt.
 
Setzen der Joystickeigenschaften

Anders als bei einem GamePad liefern alle Joysticks nicht immer die gleichen Wertebereiche bei einer Achsenabfrage. Daher ist es sinnvoll diesen Wertebereich in der Anwendung zu setzen. Die definierten Grenzen werden dann von allen Joysticks beachtet und die Anwendung erhält von allen Joysticks einheitliche Daten. Im folgenden Beispiel wird ein Wertebereich von 0 bis 10.000 mit einen toten Bereich (DeadZone) auf allen Achsen gesetzt.

DirectInput liefert nur dann Werte wenn sich der Joystick außerhalb des toten Bereiches bewegt. Das bedeutet, dass kleinste Bewegungen (zittern) des Joysticks nicht registriert werden. Aber auch dann, wenn ein Wertebereich gesetzt wird, liefert die Mittelstellung der Achse nicht den Wert Null, sondern die Hälfte des Wertebereichs.

 'setzen der Eigenschaften für alle Joysticks
  'setzen eines neuen Wertebereiches
Dim DiProp_Range As DIPROPRANGE
With DiProp_Range
  .lHow = DIPH_DEVICE
  .lSize = Len(DiProp_Range)
  .lMin = 0
  .lMax = 10000
End With
diJoystick.SetProperty "DIPROP_RANGE", DiProp_Range

  'setzen einer toten Zone
Dim DiProp_Dead As DIPROPLONG
With DiProp_Dead
  .lData = 1000
  .lSize = Len(DiProp_Dead)
  .lHow = DIPH_BYOFFSET
  .lObj = DIJOFS_X
  diJoystick.SetProperty "DIPROP_DEADZONE", DiProp_Dead
  .lObj = DIJOFS_Y
  diJoystick.SetProperty "DIPROP_DEADZONE", DiProp_Dead
End With

Wird das Programm beendet, sollten die Objekte und das Eingabegerät mit der Funktion Unacquire vom DirectInputDevice-Objekt wieder freigegeben werden. Das DirectInput-Objekt wird danach einfach auf Nothing gesetzt.

diJoystick.Unacquire
Set diJoystick = Nothing

Ein Beispiel für die Verwaltung von Joystickdaten können Sie hier downloaden.

  Download BitmapBlt.zip Download
tip0196.zip
 (10,6 kB)
Downloadzeit: <1 Min. - 28.8k / <1 Min. - ISDN Downloads bisher: [ 3942 ]

Startseite | VB-/VBA-Tipps | Projekte | Tutorials | API-Referenz | Komponenten | Bücherecke | Gewinnspiele | VB-/VBA-Forum | DirectX-Forum | VB.Net | .Net-Forum | Foren-Archiv | Chat | Spielplatz | Links | Suchen | Stichwortverzeichnis | Feedback | Impressum

Seite empfehlen Bug-Report

Letzte Aktualisierung, Sonntag, 19. Mai 2002