androidinputgamepadinput-devices

Filter real input devices


I'm trying to get list of connected gamepads following way:

InputDevice.getDeviceIds()
        .map { InputDevice.getDevice(it) }
        .filter { it.sources and InputDeviceCompat.SOURCE_GAMEPAD == InputDeviceCompat.SOURCE_GAMEPAD }
        .forEach {
            Log.i("gamepads", "$it")
        }

In general, it should return only gamepads, but for my Nexus TV this block finds 2 more devices, both of the same kind:

Input Device 4: virtual-search
Descriptor: 38c59f5a8771de8bd485da05030eb001094d7936
Generation: 10
Location: built-in
Keyboard Type: non-alphabetic
Has Vibrator: false
Has mic: false
Sources: 0x701 ( keyboard dpad gamepad )

Fun fact: while these devices are obviously virtual, call InputDevice.isVirtual() returns false for both of it.

So, easiest solution will be to filter devices based on mLocation field of InputDevice. Fortunately, InputDevice have public method to check it. Unfortunately, this method InputDevice.isExternal() is marked as hidden, thus unavailable.

Is there any other way to filter out these virtual devices without accessing hidden methods/fields via reflection?


Solution

  • It looks like possible solution is to filter devices based on vendorId. For these virtual-search ones InputDevice.getVendorId() returns 0, while it's non-zero for real external devices.

    Of course, I'm barring myself from using some noname devices with empty vendor id, but it's still better than access hidden methods that are effectively not guaranteed to work.