Android Question Gamepad Support [SOLVED]

wonder

Expert
Licensed User
Longtime User
UPDATE: Done!
Download: https://www.b4x.com/android/forum/threads/generic-gamepad-support-source-code.53518/


Here's a question to the gaming gurus of the forum.

Is there any library that would allow me to use, for example, a Dualshock 3 (PS3) controller via bluetooth, to control my game?

gamekilp_ps3_dualshock_3_game_controller_adapter_for_android_phones_1.jpg
 
Last edited:

wonder

Expert
Licensed User
Longtime User
Upvote 0

wonder

Expert
Licensed User
Longtime User
(tl;dr: What's the proper and elegant way to get the X,Y values from the event object?)

Hi Erel!
I've followed your steps the best I could, despite having zero experience with Java / libs.


You can try to create a small library that handles the onGenericMotionEvent event:
http://www.b4x.com/android/forum/th...ss-wrapper-library-gdk-jar.40694/#post-243590
I managed to compile your Java code into a library in order to catch the Generic Motion Event, see the attached file.


You can handle the onGenericMotionEvent by following these steps:
1. Add the following class to your library:
B4X:
package anywheresoftware.b4a.objects;

import android.app.Activity;
import android.view.MotionEvent;
import anywheresoftware.b4a.BA;

public class ActivityEx extends Activity {

   @Override
   public boolean onGenericMotionEvent(MotionEvent event) {
     try {
       BA ba = (BA) this.getClass().getField("processBA").get(null);
       ba.raiseEvent(null, "activity_ongenericmotionevent", event);
       return true;
     } catch (Exception e) {
       throw new RuntimeException(e);
     }
   }
   @Override
   public void onUserInteraction() {
     super.onUserInteraction();
     try {
       BA ba = (BA) this.getClass().getField("processBA").get(null);
       ba.raiseEvent2(null,true,  "activity_onuserinteraction", false);
     } catch (Exception e) {
       throw new RuntimeException(e);
     }
   }
}

Add the following line to your activity:
B4X:
#Extends: anywheresoftware.b4a.objects.ActivityEx

And handle the events in your code:
B4X:
Sub Activity_OnUserInteraction
   Log("OnUserInteraction")
End Sub

Sub Activity_OnGenericMotionEvent(event As Object)
   Log(event)
End Sub

The OnUserInteraction is just an example. You can remove it.


As soon as I got the lib imported into B4A, in order to test my controller, I've created the following program:
B4X:
#Region  Project Attributes
    #ApplicationLabel: B4A Example
    #VersionCode: 1
    #VersionName:
    'SupportedOrientations possible values: unspecified, landscape or portrait.
    #SupportedOrientations: unspecified
    #CanInstallToExternalStorage: False
#End Region

#Region  Activity Attributes
    #FullScreen: False
    #IncludeTitle: True
    #Extends: anywheresoftware.b4a.objects.ActivityEx
#End Region

Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
    Dim Main_Cycle As Timer
 
End Sub

Sub Globals
    'These global variables will be redeclared each time the activity is created.
    'These variables can only be accessed from this module.
    Private Output As Label
    Dim Global_Key_Code As Int
    Dim GME As String
    Dim X As Float
    Dim Y As Float
End Sub

Sub Activity_Create(FirstTime As Boolean)
    'Do not forget to load the layout file created with the visual designer. For example:
    Activity.LoadLayout("Layout1")
    Output.Left   = 0%x
    Output.Top    = 0%y
    Output.Width  = 100%x
    Output.Height = 100%y
    Main_Cycle.Initialize("Main_Cycle", 1000/60)
    Main_Cycle.Enabled = True
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

Sub Main_Cycle_Tick
    Output.text = GME & CRLF & CRLF & _
                  "Last KeyCode: " & Global_Key_Code & CRLF & CRLF & _
                  "X: " & Round2(x, 2) & "  Y: " & Round2(y, 2)
End Sub

Sub Activity_KeyPress (KeyCode As Int) As Boolean 
    Global_Key_Code = KeyCode
    Return True
End Sub

Sub Activity_OnGenericMotionEvent(event As Object)
    GME = event
 
    For i = 0 To (GME.Length - 1)
        If GME.SubString2(i, i + 5) = "x[0]=" Then
            Dim tempX As String
            For j = i + 5 To (GME.Length - 1)
                If GME.CharAt(j) = "," Then
                    Exit
                Else
                    tempX = tempX & GME.CharAt(j)
                End If
            Next
            If tempX <> "" Then Exit
        End If
    Next
    x = tempX

    For i = 0 To (GME.Length - 1)
        If GME.SubString2(i, i + 5) = "y[0]=" Then
            Dim tempY As String
            For j = i + 5 To (GME.Length - 1)
                If GME.CharAt(j) = "," Then
                    Exit
                Else
                    tempY = tempY & GME.CharAt(j)
                End If
            Next
            If tempY <> "" Then Exit
        End If 
    Next
    y = tempY
 
End Sub

Now, as you can see by my rudimentary code, I'm converting the event object into a string and catching the X and Y values of the left analog stick.
My question is, what's the proper and elegant way to get the X,Y values from the event object?

Many thanks in advance! :)
 

Attachments

  • Generic Motion Event.zip
    5.6 KB · Views: 275
  • Gamepad.zip
    7.5 KB · Views: 262
Upvote 0

wonder

Expert
Licensed User
Longtime User
I've trying the JavaObject method with GetField("x") but at the end, I had no idea what I was doing. I got an error saying there is no such field.

You can get the other values with JavaObject.

B4X:
Dim jo As JavaObject = Event
Log(jo.RunMethod("getDownTime", null))
The methods are listed here: http://developer.android.com/reference/android/view/MotionEvent.html

So, if I understood correctly the code would be something like:
B4X:
x = GME.RunMethod("getAxisValue(0)", null)
output.text = x

Am I on the right path?
 
Last edited:
Upvote 0

wonder

Expert
Licensed User
Longtime User
I got it to work, Erel! Thank you so much!!!!!!!!

Solution:
B4X:
x  = GamePad.RuNMethod("getAxisValue", Array(00))
y  = GamePad.RuNMethod("getAxisValue", Array(01))
rx = GamePad.RuNMethod("getAxisValue", Array(12))
ry = GamePad.RuNMethod("getAxisValue", Array(13))
z  = GamePad.RuNMethod("getAxisValue", Array(11))
rz = GamePad.RuNMethod("getAxisValue", Array(14))

These indexes should probably be specific for my game controller.
In order to support all controllers, I'm guessing I should create a search algorithm then:
B4X:
Dim X_Axis_Index = -1 as Int
Dim i = 0 as Int

Do While X_Axis_Index = -1
     If GamePad.RuNMethod("axisToString", Array(i)) = "AXIS_X" Then X_Axis_Index = i
     i = i + 1
Loop

(etc...)
 
Upvote 0

walterf25

Expert
Licensed User
Longtime User
I got it to work, Erel! Thank you so much!!!!!!!!

Solution:
B4X:
x  = GamePad.RuNMethod("getAxisValue", Array(00))
y  = GamePad.RuNMethod("getAxisValue", Array(01))
rx = GamePad.RuNMethod("getAxisValue", Array(12))
ry = GamePad.RuNMethod("getAxisValue", Array(13))
z  = GamePad.RuNMethod("getAxisValue", Array(11))
rz = GamePad.RuNMethod("getAxisValue", Array(14))

These indexes should probably be specific for my game controller.
In order to support all controllers, I'm guessing I should create a search algorithm then:
B4X:
Dim X_Axis_Index = -1 as Int
Dim i = 0 as Int

Do While X_Axis_Index = -1
     If GamePad.RuNMethod("axisToString", Array(i)) = "AXIS_X" Then X_Axis_Index = i
     i = i + 1
Loop

(etc...)
So, did you get this working, I'm curious!
So the PS3 controller connects via bluetooth to your device?
Can you post the whole code pertaining to the controller?

Thanks,
Walter
 
Upvote 0
Top