Games GamePad support for B4j

ilan

Expert
Licensed User
Longtime User
Unfortunately, b4j does not have a USB Support lib and that is why it's not possible to use any GamePads with our b4j projects, right?? ;) (nahhhhhh....)


Ok it's not a real gamepad support buts a simple workaround until we have something.
so how does it works?

very simple, i create a project in vb 2010 that can listen to the joysticks msgs and then i just use the "sendkeys" function and walla i can now use my joystick with my b4j project.

vb code:

first, we create a class named "joystick.vb"

B4X:
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 yLevel As Integer
    Public xLevel As Integer
    'Public Event JoyStats()

    <StructLayout(LayoutKind.Explicit)> _
    Public 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

            yLevel = mapping(p.YPos, 0, 65535, 0, 10)
            xLevel = mapping(p.XPos, 0, 65535, 0, 10)
        End If

        If btnValue <> m.WParam.ToString Then
            btnValue = m.WParam.ToString
        End If
        MyBase.WndProc(m)
    End Sub

    Function mapping(var As Double, min_real As Double, max_real As Double, min_scaled As Double, max_scaled As Double) As Double
        Return (var * ((max_scaled - min_scaled) / (max_real - min_real))) + min_scaled
    End Function
End Class

then we handle all changes on our joystick with a timer in our main form:

B4X:
Public Class Form1

    Private WithEvents joystick1 As Joystick
    Public storedv As String
    Public middleOn As Boolean

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        joystick1 = New Joystick(Me, 0)
    End Sub

    Private Sub joystick_Stats()
        Dim midx, midy As Boolean
        midx = False
        midy = False

        Select Case joystick1.xLevel
            Case Is < 5
                My.Computer.Keyboard.SendKeys("{LEFT}", False)
                middleOn = False
            Case Is > 5
                My.Computer.Keyboard.SendKeys("{RIGHT}", False)
                middleOn = False
            Case Else
                midx = True
        End Select

        Select Case joystick1.yLevel
            Case Is > 5
                My.Computer.Keyboard.SendKeys("{DOWN}", False)
                middleOn = False
            Case Is < 5
                My.Computer.Keyboard.SendKeys("{UP}", False)
                middleOn = False
            Case Else
                midy = True
        End Select

        If midx = True And midy = True And middleOn = False Then
            'do nothing
            middleOn = True
            My.Computer.Keyboard.SendKeys("{M}", False)
        End If
    End Sub

    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
        joystick_Stats()
        'Me.Text = joystick1.btnValue
        If joystick1.btnValue <> storedv Then
            storedv = joystick1.btnValue
            If joystick1.btnValue = "256" Then
                My.Computer.Keyboard.SendKeys(" ", False)
            End If
        End If
    End Sub

End Class

and then in our b4j project we catch all keys pressed and do our actions:

B4X:
Sub AppStart (Form1 As Form, Args() As String)
'.....

    Dim Obj As Reflector
    Obj.Target = MainForm.RootPane
    Obj.AddEventHandler("RootPaneKeyEvent", "javafx.scene.input.KeyEvent.ANY")

'.....
End Sub

B4X:
Sub RootPaneKeyEvent_Event(e As Event)
    ' bit hackish to get the code
    Dim KE As Reflector
    KE.Target = e
     
    Dim KeyCode As String = KE.RunMethod("getCode")
    Dim EventType As String = KE.RunMethod("getEventType")
 
    Log(KeyCode)

    Select EventType
        Case "KEY_PRESSED"
            Select KeyCode
                Case "RIGHT"
                     GoForward = True
                     Gobackward = False
                Case "LEFT"
                     GoForward = False
                     Gobackward = True
                Case "UP"
                    KaneUp = True
                    KaneDown = False
                Case "DOWN"             
                    KaneUp = False
                    KaneDown = True
                Case "SPACE"                                                                                                                                                                                                                                                                                                                                             
                    If shotnow Then
                        shotnow = False
                        Dim bullet As jbBody = CircleBody.CreateBody(world,kanebody.Position.x+((vpW*0.05)/Scale),kanebody.Position.y+(kanebody.Angle*cPI),0.3,2,0.8,0.2,0.5,False,"bullet",False,Null)
                        BulletList.Add(bullet)
                        Dim impulse As jbVec2
                        impulse.set(10,kanebody.Angle*cPI*2)
                        bullet.applyLinearImpulse(impulse,bullet.WorldCenter)                     
                    End If
            End Select
        Case "KEY_RELEASED"
            Select KeyCode
                Case "M"
                    GoForward = False
                    Gobackward = False
                    KaneUp = False
                    KaneDown = False
                Case "SPACE"
                    shotnow = True 
            End Select         
    End Select
End Sub

we still need to change the code a little if we want to use our Keyboard and not our Joystick but thats should be very simple to solve via if statement.

have fun, ilan ;)

ps: i just noticed how dusty my laptop is. with the light and the cam angle it look really bad so dont worry i cleaned it :D
 
Top