Search code examples
javaandroidcontroller

Controller events on Android


I'm working on a Android App that will use a controller (at this time I'm using a Gamesir G3s gamepad on Samsung Galaxy S8 connected trough Bluetooth). The application is using the standard Android API (level >= 19) for controller management. I'm facing two major problems at this time:

  1. how to discriminate events coming from DPAD pressure from analog stick movements;

  2. how to enumerate sources (i.e. axis, buttons, etc) of the controller before movement and pressure events arise.

In particular in this controller the event GenericMotionEvent is triggered for both analog stick motion and DPAD pressure:

@Override
public boolean onGenericMotionEvent(MotionEvent event)
{
    int source = event.getSource();

    if((source & InputDevice.SOURCE_JOYSTICK)== InputDevice.SOURCE_JOYSTICK && event.getAction() == MotionEvent.ACTION_MOVE)
    {
       .....
       return true;
    }

    return super.onGenericMotionEvent(event);
}

the source variable always contains 16777232 (i.e. SOURCE_JOYSTICK referring to Android Developer docs).

If I attach the same controller to a standard Windows PC (trough USB) DPAD events are depicted in different way (in a system dialog) from inputs of the analog stick. Of course this may depend on the controller electronics that may behave differently depending on the connected host but I'm wondering why anyway.

To scavenge into gamepad sources the only hint I found (in Android docs) is to use InputDevice.getSources() and so I did:

@Override
public void onInputDeviceAdded(int deviceId)
{
   InputDevice device = InputDevice.getDevice(deviceId);

   if(null!=device)
   {
      final int sources = device.getSources();
      Log.d("CONTROLLER", "Controller attached" + device.getDescriptor());
   }
}

The same check is also done at application startup (assuming the controller is already connected at this time). In this case sources variable contains 16786707 that correctly is SOURCE_JOYSTICK plus 0x2503 that should be the composed result of the following constants:

  • SOURCE_GAMEPAD,
  • SOURCE_CLASS_BUTTON,
  • SOURCE_KEYBOARD,
  • SOURCE_CLASS_JOYSTICK,
  • SOURCE_CLASS_POINTER,
  • SOURCE_MOUSE.

but adding single values sums a total of 0x2517 that's pretty strange.

My doubts about electronics behaviour are confirmed: attached to Android I found axis mapped in a different way than on Windows (on Windows analog sticks axis are mapped on X,Y,RX,RY while on Android X,Y,Z,RZ respectively).

Someone have hints?

Best regards.


Solution

  • I finally found the solution. Investigating the Android developer official sources I found a sample code that shows how to handle controller events (including DPAD ones) of course it wasn't working in my specific case. The global misunderstanding arise from the fact that my controller it's not depicting himself as a SOURCE_DPAD and then every source bound to such distinction is failing. In the specific case of the source example provided by Android Developer the problem is this function:

     public static boolean isDpadDevice(InputEvent event) {
        // Check that input comes from a device with directional pads.
        if ((event.getSource() & InputDevice.SOURCE_DPAD)
             != InputDevice.SOURCE_DPAD) {
             return true;
         } else {
             return false;
         }
     }
    

    That inhibits the caller method:

    public int getDirectionPressed(InputEvent event) ...
    

    That should handle the event. In my case the source responsible for DPAD events is SOURCE_JOYSTICK.