Steuerung von Fußschalter oder Joystick

By , 16. Januar 2014

Um Ereignisse zu erfassen die von einem Fußschalter oder einem Joystick ausgelöst werden, kann man sich der Methoden von DirectX bedienen. Im vorliegenden Beispiel wird die Version DirectX8 verwendet, d.H. Sie benötigen einen gültigen Verweis auf die „DirectX 8 für Visual Basic Type Library“. Dazu benötigen Sie die registrierte Datei dx8vb.dll auf Ihrem Computer.
Nach dem nun der Verweis gesetzt wurde kann mit der Deklaration der Objekte begonnen werden. Dazu verwende ich die Early-Binding Variante um die DirectX-Konstanten verwenden zu können:
Im Deklarationsteil des Formulars:

Private Const BufferSize As Long = 10
Private DX As DirectX8
Private DI As DirectInput8
Private DIEnum As DirectInputEnumDevices8
Private DIDevice As DirectInputDevice8
Private hEvent As Long
Implements DirectXEvent8

Im Load-Ereignis werden die Objekte dann Instanziert:

    Set DX = New DirectX8
    Set DI = DX.DirectInputCreate
    Set DIEnum = DI.GetDIDevices(DI8DEVCLASS_GAMECTRL, DIEDFL_ATTACHEDONLY)
    ' kein Gerät gefunden dann Abbruch
    If DIEnum.GetCount = 0 Then Exit Sub

Die Verwendeten Konstanten beim Zugriff auf die Geräte können hier nachgelesen werden:
DirectInput8::EnumDevices

In einer For-Schleife können jetzt alle gefundenen Geräte ausgelesen werden. Dabei helfen uns die beiden Methoden der DirectInputDeviceInstance-Klasse GetProductName und GetDevType um das richtige Gerät zu identifizieren, denn hier werden z.B. auch Tastatur und Maus aufgelistet.

    For j = 1 To DIEnum.GetCount
        Debug.Print DIEnum.GetItem(j).GetProductName
        Debug.Print DIEnum.GetItem(j).GetDevType
        ' 66068 -> Fußschalter (Herga); 65812 -> Handschalter Gameport über Rockfire USB
        If DIEnum.GetItem(j).GetDevType = 66068 Or DIEnum.GetItem(j).GetDevType = 65812 Or DIEnum.GetItem(j).GetDevType = 66069 Then ' etc.
            Set DevInst = DIEnum.GetItem(j)
            Set DIDevice = DI.CreateDevice(DevInst.GetGuidInstance)
        End If
    Next j

Man muss also zuerst einmal das korrekte Gerät identifizieren, daher einmal durchlaufen lassen und im Direktfenster sich ansehen was die Debug.Print-Befehle geschrieben haben.
Nachdem man jetzt die richtige Geräteinstanz in DIDevice stehen hat, kann man nun das Top-Level verhalten der Access-Anwendung einstellen. Dazu benötigen wir als ersten Parameter das Handle der Access-Anwendung. Im 2. Parameter stehen verschiedene Flags die das Verhalten bestimmen.

    Call DIDevice.SetCooperativeLevel(Application.hWndAccessApp, _
                                      DISCL_BACKGROUND Or DISCL_NONEXCLUSIVE)

Die Flags im 2. Parameter sind hier nachzulesen: DirectInput8::SetCooperativeLevel

Jetzt fehlen noch Angaben zur Speichergröße, und vorallem es muss ein Event-Handler erstellt werden um auf JoyStick- oder Fußschalter-Ereignisse zu reagieren.
Für letzteres haben wir ja die Variable hEvent deklariert.

    diProp.lHow = DIPH_DEVICE
    diProp.lObj = 0
    diProp.lData = BufferSize
    Call DIDevice.SetProperty("DIPROP_BUFFERSIZE", diProp)

Und hier der Code für das Event:

    hEvent = DX.CreateEvent(Me)
    DIDevice.SetEventNotification hEvent

So, jetzt müssen wir nur noch mitteilen dass wir das Gerät benutzen wollen:

    DIDevice.Acquire

Und dann wars das im Form_Load Ereignis. Im Prinzip funktioniert es bereits, doch wir haben noch keinen Eventhandler implementiert. Das wollen wir jetzt nachholen.
Im Eventhandler erhalten wir als übergebenen Parameter den eventid. Diesen benötigen wir eigentlich nur um zu prüfen ob auch das richtige Gerät das Ereignis ausgelöst hat.
Das auszuwertende Ereignis erhalten wir über die Methode GetDeviceData des Geräteobjektes, dessen erster Parameter ein Array ist welches nach dem Aufruf die vorhandenen Events beinhaltet.
Doch jetzt erst mal Code:

Private Sub DirectXEvent8_DXCallback(ByVal eventid As Long)
    If Not (eventid = hEvent) Then Exit Sub

    Dim DevData(1 To BufferSize) As DIDEVICEOBJECTDATA
    Dim nEvents As Long
    Dim i As Long
    nEvents = DIDevice.GetDeviceData(DevData, DIGDD_DEFAULT)
    For i = 1 To nEvents
        If DevData(i).lData > 0 Then
            Select Case DevData(i).lOfs

Im Array DevData stehen also die gesuchten Events, und über die Eigenschaft DevData(i).lOfs werden diese als Zahlencode sichtbar.
Hier helfen auch wieder DirectX Konstanten. Mögliche Werte für „Select Case“ sind:
DIMOFS_X: Bewegung auf der X-Achse
DIMOFS_Y: Bewegung auf der Y-Achse
48: JoyStick Feuer Button 1
49: JoyStick Button 2
50: JoyStick Button 3
51: JoyStick Button 4
32: JoyStick kleiner x/y Steuerknopf

Um jetzt herauszubekommen ob ich mich auf der X-Achse nach links oder rechts bewege, liest man die lData Eigenschaft aus: DevData(i).lData
Das gleiche gilt auch für die Y-Achse. Der Eigenschaftswert lData hat ein Maximum von etwa 65000 in beiden Achsen. Um nun in einem Formular ein Steuerelement zu bewegen muss lData zuerst einmal auf die Formulargröße heruntergerechnet werden. Ich habe das so gelöst indem ich ein Rechteck (spielfeld) gezeichnet habe in dem sich das Objekt (ball) bewegen darf.
So ergibt sich der Faktor (jeweils in X und Y Achse):

faktorX = (Me.spielfeld.Width - Me.ball.Width) / 65000
faktorY = (Me.spielfeld.Height - Me.ball.Height) / 65000

Das Steuerelement (bei mir ein Fußball als Bild) lässt sich dann ganz einfach steuern:

Case DIMOFS_X
    Me.ball.Left = Me.spielfeld.Left + CLng(faktorX * DevData(i).lData)
Case DIMOFS_Y
    Me.ball.Top = Me.spielfeld.Top + CLng(faktorY * DevData(i).lData)

So das wars auch schon mit dem Ausflug in die DirectX Welt. Beachtet dass mit anderen, insbesondere mit neueren Versionen von DirectX der Code nicht funktioniert.
Schaut euch die Beispiel-Datenbank an, ich habe dort noch ein paar Gimmicks eingebaut wie Schießen, Links und Rechts angeschnitten schießen etc.
Die Beispieldatenbank findet ihr im Downloadbereich.
Es gibt dazu auch von mir ein kleines Video auf Youtube:

bis dahin
2014 Andreas Vogt

OfficeFolders theme by Themocracy