Share My Creation Generic GamePad Support (Source Code)

wonder

Expert
Licensed User
GENERIC GAMEPAD SUPPORT
Latest update: 19-05-2015

Many thanks to thedesolatesoul for his help with the getDeviceName function.


Fellow gamers and game developers, please test this app with your game controllers.
It works flawlessly with my PS3 one (using the Sixaxis Controller app), but it should work with any other brand recognized by your android device.

If like me, you're planning to use a PlayStation controller, please follow this tutorial:
Using a PlayStation 3 controller with your Android Device

Note: The Sixaxis app with root access is required only for PS3 / PS4 controllers.

Download the apk or the full project below (please use the updated GamePad.bas class file), the additional library is included.

Capture.PNG


APK:
Usage:
As you can see in the source code, the analog sticks and triggers are handled by Activity_OnGenericMotionEvent and the regular buttons by Activity_KeyPress. I've tried the best I could to make the code easier to understand, so everything should be self-explanatory.

Libraries:

Class (2016-28-12):
GamePad.bas (attached)

Documentation:

Source:
B4X:
#Region  Project Attributes
    #ApplicationLabel: B4A Generic GamePad Support
    #VersionCode: 1
    #VersionName:
    'SupportedOrientations possible values: unspecified, landscape or portrait.
    #SupportedOrientations: unspecified
    #CanInstallToExternalStorage: False
#End Region

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

Sub Process_Globals
    'Define the Main Cycle timer
        Dim Main_Cycle As Timer
End Sub

Sub Globals
    'REQUIRED
        Dim Controller As GamePad

    'Used solely for this example
        Dim Mode = "NORMAL" As String

    'Designer Variables
        Private Background As ImageView
        Private Output As Label
End Sub

Sub Activity_Create(FirstTime As Boolean)
    'Load the Activity Layout
        Activity.LoadLayout("Layout1")

    'Setup the Text and Background
        Background.Width = 100%x
        Background.Height = (100%x) * 720 / 1280
        Background.Left = 50%x - Background.Width / 2
        Background.Top = 50%y - Background.Height / 2

        Output.Left   = Background.Left + (0.054 * Background.Width)
        Output.Top    = Background.Top  + (0.116 * Background.Height)
        Output.Width  = 0.289 * Background.Width
        Output.Height = 0.625 * Background.Height

    'Initialize the first GamePad with a dead zone of 10%
        Controller.Initialize(0, 0.1)

    'Initialize the Main Cycle timer
        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


'========================================================================================================================
' MAIN CYCLE
'========================================================================================================================
    Sub Main_Cycle_Tick
        If Controller.Plugged_In Then
            If Mode = "NORMAL" Then
                Output.Text = _
                Controller.Device_Name & CRLF & _
                CRLF & _
                "Analog LX: " & Round(Controller.L_Analog_X * 100) & "%" & CRLF & _
                "Analog LY: " & Round(Controller.L_Analog_Y * 100) & "%" & CRLF & _
                "Analog RX: " & Round(Controller.R_Analog_X * 100) & "%" & CRLF & _
                "Analog RY: " & Round(Controller.R_Analog_Y * 100) & "%" & CRLF & _
                "L Trigger: " & Round(Controller.L_Trigger  * 100) & "%" & CRLF & _
                "R Trigger: " & Round(Controller.R_Trigger  * 100) & "%" & CRLF & _
                CRLF & _
                "Last KeyCode: " & Controller.Btn_Press & CRLF & _
                CRLF & _
                "Press START for Device Info" & CRLF & _
                "or SELECT To exit."
            Else If Mode = "DEVICE_INFO" Then
                If Controller.Device_Info = "" Then
                    Output.Text = "Please move one of the Analog Sticks / Triggers."
                Else
                    Output.Text = Controller.Device_Info & CRLF & _
                    CRLF & _
                    "Press START to begin" & CRLF & _
                    "or SELECT To exit."
                End If
            End If
        Else
            Output.Text = Controller.Device_Name & CRLF & _
            CRLF & _
            "Please plug you controller via USB" & CRLF & _
            "or pair it via Bluetooth to begin." & CRLF & _
            CRLF & _
            "Once you have it connected," & CRLF & _
            "press START to begin."
        End If
    End Sub
'========================================================================================================================




'========================================================================================================================
' BUTTON PRESS (KEYCODE) AND ANALOG AXIS / TRIGGER (GENERIC MOTION EVENT) HANDLING
'========================================================================================================================
    Sub Activity_KeyPress (KeyCode As Int) As Boolean
        Controller.Btn_Press = KeyCode
        If KeyCode = Controller.KEYCODE_BUTTON_START Then
            If Controller.Plugged_In Then
                If Mode = "NORMAL" Then
                    Mode = "DEVICE_INFO"
                Else
                    Mode = "NORMAL"
                End If
            Else
                Controller.Initialize(0, 0.1)
            End If
        Else If KeyCode = Controller.KEYCODE_BUTTON_SELECT OR KeyCode = KeyCodes.KEYCODE_BACK Then
            ExitApplication
        End If
        Return True
    End Sub


    Sub Activity_OnGenericMotionEvent(Event As Object)
        Controller.Input = Event

        Controller.Motion_Detected = True

        Controller.L_Analog_X  = Controller.getAxisValue(Controller.AXIS_X)
        Controller.L_Analog_Y  = Controller.getAxisValue(Controller.AXIS_Y)

        Controller.R_Analog_X  = Controller.getAxisValue(Controller.AXIS_Z)
        Controller.R_Analog_Y  = Controller.getAxisValue(Controller.AXIS_RZ)

        Controller.L_Trigger   = Controller.getAxisValue(Controller.AXIS_LTRIGGER)
        Controller.R_Trigger   = Controller.getAxisValue(Controller.AXIS_RTRIGGER)

        If Controller.Device_Info = "" Then Controller.Device_Info = Controller.getDeviceInfo
    End Sub
'========================================================================================================================
 

Attachments

Last edited:

wonder

Expert
Licensed User
HOW CAN I IMPLEMENT THIS FRAMEWORK ON MY PROJECT?

I know the ideal solution is to have a lib which handles everything, but since my java/lib experience is virtually zero, the way to implement my solution is a little bit fragmented.

Step 1:
Add both Generic Motion Event and JavaObject libraries to your project.
Step 2:
Add the GamePad class to your project.
Step 3:
Add the following code to your project:
B4X:
#Region  Activity Attributes
     #Extends: anywheresoftware.b4a.objects.ActivityEx
#End Region

Sub Globals
   Dim Controller As GamePad
End Sub

Sub Activity_Create(FirstTime As Boolean)
   Controller.Initialize(0, 0.1) 'Initializes the first GamePad with a dead zone of 10%
End Sub
Step 4:
Handle the events with Activity_OnGenericMotionEvent for analog sticks and triggers and Activity_KeyPress for the controller buttons.
Example:
B4X:
Sub Activity_KeyPress (KeyCode As Int) As Boolean      
    Controller.Btn_Press = KeyCode
    If KeyCode = Controller.KEYCODE_BUTTON_START Then
        If Controller.Plugged_In Then
            If Mode = "NORMAL" Then
                Mode = "DEVICE_INFO"
            Else
                Mode = "NORMAL"
            End If
        Else
            Controller.Initialize(0, 0.1)
        End If
    Else If KeyCode = Controller.KEYCODE_BUTTON_SELECT OR KeyCode = KeyCodes.KEYCODE_BACK Then
        ExitApplication  
    End If      
    Return True
End Sub


Sub Activity_OnGenericMotionEvent(Event As Object)
    Controller.Input = Event
  
    Controller.Motion_Detected = True
  
    Controller.L_Analog_X  = Controller.getAxisValue(Controller.AXIS_X)
    Controller.L_Analog_Y  = Controller.getAxisValue(Controller.AXIS_Y)

    Controller.R_Analog_X  = Controller.getAxisValue(Controller.AXIS_Z)
    Controller.R_Analog_Y  = Controller.getAxisValue(Controller.AXIS_RZ)
  
    Controller.L_Trigger   = Controller.getAxisValue(Controller.AXIS_LTRIGGER)
    Controller.R_Trigger   = Controller.getAxisValue(Controller.AXIS_RTRIGGER)  

    If Controller.Device_Info = "" Then Controller.Device_Info = Controller.getDeviceInfo      
End Sub
Feel free to improve my code! If so, don't forget to share your own solution. :)
 
Last edited:

wonder

Expert
Licensed User
Hey guys,

Check the first and second post again.
I've cleaned-up and updated the source code, class and apk file.
The internal functions are now tucked in the GamePad.bas class, including thedesolatesoul's getDeviceName (thanks!).

Please update your projects accordingly.
 
Last edited:

freedom2000

Well-Known Member
Licensed User
HI,

It's quite a long time since you posted this code...
I promized to try it and I did it this evening :)

It WORKs --> simply GREAT

I have slightly changed the code to discover the "hat buttons".
Here is the mod I did :

B4X:
    Controller.L_Trigger   = Controller.getAxisValue(Controller.AXIS_HAT_X)
        Controller.R_Trigger   = Controller.getAxisValue(Controller.AXIS_HAT_Y)
I am not sure to have modified the right thing (What are L_Trigger and R_Trigger ?) but at least it works !

Again thank you

I will for sure quote your lib in a few days if I take some time to implement a fully working RC radio with android, B4A, your lib and an ESP8266
 

wonder

Expert
Licensed User
HI,

It's quite a long time since you posted this code...
I promized to try it and I did it this evening :)

It WORKs --> simply GREAT

I have slightly changed the code to discover the "hat buttons".
Here is the mod I did :

B4X:
    Controller.L_Trigger   = Controller.getAxisValue(Controller.AXIS_HAT_X)
        Controller.R_Trigger   = Controller.getAxisValue(Controller.AXIS_HAT_Y)
I am not sure to have modified the right thing (What are L_Trigger and R_Trigger ?) but at least it works !

Again thank you

I will for sure quote your lib in a few days if I take some time to implement a fully working RC radio with android, B4A, your lib and an ESP8266
Hello hello!

I'm really glad to hear that it works fine for you! :)
Every controller is slightly different so it's only normal we always have to tweak the button assignments here and there.
The original source code was modeled based on a Playstation 3 controller.

If I had the time, I'd like to turn this project into a simple (and single) library, but as I said, I'm really glad it works this way!
 

freedom2000

Well-Known Member
Licensed User
I will for sure quote your lib in a few days if I take some time to implement a fully working RC radio with android, B4A, your lib and an ESP8266
--> Done for my "Joystick to PPM" solution

--> Still to be done for the full RC controller with ESP8266...
 

sorex

Expert
Licensed User
are many people using these gamepads?

and are some games limited to use one?
 

wonder

Expert
Licensed User
are many people using these gamepads?
Probably not, it a niche part of the market. Nonetheless, we are at least 100,000 around the world, jugging by the download number of the Sixaxis Controller paid app (https://play.google.com/store/apps/details?id=com.dancingpixelstudios.sixaxiscontroller&hl=en).

and are some games limited to use one?
Can Android handle more than one controller at the same time?
I've seen apps that support up to 4 controllers at the same time, so it's up to the developer to implement such feature.
Docs: https://developer.android.com/training/game-controllers/multiple-controllers.html

and are some games limited to use one?
Are there any games which explicitly require a physical controller?
Yes. Most of NVIDIA Lightspeed Studios games.
- Portal: https://play.google.com/store/apps/details?id=com.nvidia.valvesoftware.portal&hl=en
- Doom3: https://play.google.com/store/apps/details?id=com.id.doom3bfg&hl=en
- Parallax: https://play.google.com/store/apps/details?id=com.nvidia.toastygames.parallax&hl=en
 
Last edited:

sorex

Expert
Licensed User
yes, I meant the second one. if there are only games that are playable with such controller.

Doom3 makes sense, you already need half a keyboard to play such games these days.
 
Top