vb.net поддержка геймпада, частично работает

Я нашел следующий код класса на форуме. Он отлично работает для геймпада (вверх, вниз, влево, вправо), однако весь код для кнопок отсутствует. Кто-нибудь может заполнить пробелы?

Это работает:

Private Sub joystick1_Up() Handles joystick1.Up
    moveUp()
End Sub

Это не:

Private Sub joystick1_buttonPressed() Handles joystick1.buttonPressed
    MsgBox(joystick1.btnValue)
End Sub

потому что нет события "buttonPressed", и я понятия не имею, как его написать.

А вот и класс:

Imports System.ComponentModel
Imports System.Runtime.InteropServices


Public Class joystick
    Inherits NativeWindow

    Private parent As Form
    Private Const MM_JOY1MOVE As Integer = &H3A0

    ' Public Event Move(ByVal joystickPosition As Point)
    Public btnValue As String
    Public Event Up()
    Public Event Down()
    Public Event Left()
    Public Event Right()

    <StructLayout(LayoutKind.Explicit)> _
    Private Structure JoyPosition
        <FieldOffset(0)> _
        Public Raw As IntPtr
        <FieldOffset(0)> _
        Public XPos As UShort
        <FieldOffset(2)> _
        Public YPos As UShort
    End Structure

    Private Class NativeMethods

        Private Sub New()
        End Sub

        ' This is a "Stub" function - it has no code in its body.
        ' There is a similarly named function inside a dll that comes with windows called
        ' winmm.dll. 
        ' The .Net framework will route calls to this function, through to the dll file.
        <DllImport("winmm", CallingConvention:=CallingConvention.Winapi, EntryPoint:="joySetCapture", SetLastError:=True)> _
        Public Shared Function JoySetCapture(ByVal hwnd As IntPtr, ByVal uJoyID As Integer, ByVal uPeriod As Integer, <MarshalAs(UnmanagedType.Bool)> ByVal changed As Boolean) As Integer
        End Function

    End Class

    Public Sub New(ByVal parent As Form, ByVal joyId As Integer)
        AddHandler parent.HandleCreated, AddressOf Me.OnHandleCreated
        AddHandler parent.HandleDestroyed, AddressOf Me.OnHandleDestroyed
        AssignHandle(parent.Handle)
        Me.parent = parent
        Dim result As Integer = NativeMethods.JoySetCapture(Me.Handle, joyId, 100, True)
    End Sub

    Private Sub OnHandleCreated(ByVal sender As Object, ByVal e As EventArgs)
        AssignHandle(DirectCast(sender, Form).Handle)
    End Sub

    Private Sub OnHandleDestroyed(ByVal sender As Object, ByVal e As EventArgs)
        ReleaseHandle()
    End Sub

    Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
        If m.Msg = MM_JOY1MOVE Then
            ' Joystick co-ords.
            ' (0,0) (32768,0) (65535, 0) 
            '
            '
            '
            ' (0, 32768) (32768, 32768) (65535, 32768)
            '
            '
            '
            '
            ' (0, 65535) (32768, 65535) (65535, 65535)
            '

            Dim p As JoyPosition
            p.Raw = m.LParam
            ' RaiseEvent Move(New Point(p.XPos, p.YPos))
            If p.XPos > 16384 AndAlso p.XPos < 49152 Then
                ' X is near the centre line.
                If p.YPos < 6000 Then
                    ' Y is near the top.
                    RaiseEvent Up()
                ElseIf p.YPos > 59536 Then
                    ' Y is near the bottom.
                    RaiseEvent Down()
                End If
            Else
                If p.YPos > 16384 AndAlso p.YPos < 49152 Then
                    ' Y is near the centre line
                    If p.XPos < 6000 Then
                        ' X is near the left.
                        RaiseEvent Left()
                    ElseIf p.XPos > 59536 Then
                        ' X is near the right
                        RaiseEvent Right()
                    End If
                End If
            End If
        End If
        If btnValue <> m.WParam.ToString Then
            btnValue = m.WParam.ToString
        End If
        MyBase.WndProc(m)
    End Sub

End Class

1 ответ

Вместо того, чтобы использовать более старый winmm, я бы использовал XInput (или, если вы можете, используйте XNA).

Есть несколько способов сделать это. Один шаг вверх - использовать библиотеки XInput напрямую, как указано в этом вопросе на форумах MSDN. Это все еще довольно уродливо, хотя. Вероятно, "более простой" способ сделать это - использовать библиотеку-оболочку, существующую там, как SlimDX или SharpDX.

Одним из преимуществ использования XInput через SlimDX или SharpDX является то, что он также будет работать в приложении Магазина Windows для Windows 8:).

Вот фрагмент из примера GamePad в SharpDX:

C#

var controllers = new[] { new Controller(UserIndex.One), new Controller(UserIndex.Two), new Controller(UserIndex.Three), new Controller(UserIndex.Four) };

// Get 1st controller available 
Controller controller = null; 
foreach (var selectControler in controllers) 
{ 
    if (selectControler.IsConnected) 
    { 
        controller = selectControler; 
        break; 
    }
}

VB

Dim controllers As New List(Of Controller)
controllers.Add(New Controller(UserIndex.One))
controllers.Add(New Controller(UserIndex.Two))
controllers.Add(New Controller(UserIndex.Three))
controllers.Add(New Controller(UserIndex.Four))

Dim controller as Controller = Nothing; 
For Each selectController In controllers
    If selectController.IsConnected Then
        controller = selectController
        Exit For
    End If
Next

Тогда вы можете заставить государство работать с:

var state = controller.GetState();

Вы заметите, что XInput использует больше модели опроса, поэтому вам придется периодически проверять нажатие кнопки, чтобы обнаружить это. Если вам нужно проводить опрос постоянно, вы можете раскрутить новое задание, чтобы сделать это.

Другие вопросы по тегам