diff options
| author | crueter <crueter@eden-emu.dev> | 2026-07-25 15:09:16 +0200 |
|---|---|---|
| committer | crueter <crueter@eden-emu.dev> | 2026-07-25 15:09:16 +0200 |
| commit | 9d60030af5535052b8365a5316c8d9e563bcb4e1 (patch) | |
| tree | d8c8133859bee7f266b85ed4e5890df85ea3cdb2 /src/android | |
| parent | f5d1a78846673020bab29c5327362a1f8e46ccf8 (diff) | |
[android] Support Joy-Con D-pad buttons (#4225)
Closes eden-emulator/Issue-Reports#8
Closes eden-emulator/Issue-Reports#428
Currently, [Android's input layer](https://android.googlesource.com/platform/frameworks/base.git/+/refs/heads/android16-release/data/keyboards/Vendor_057e_Product_2009.kl#54) doesn't return `KEYCODE_DPAD_*` for the left Joy-Con, we fall back to the scan code in this case, this will also fix most third party Joy-Con controllers.
- The scan codes are not reliable and may vary from device to another. I searched for (0x220-0x223) values in the [android repo](https://android.googlesource.com/platform/frameworks/base.git/+/refs/heads/android16-release/data/keyboards) and they all have the same DPAD_* key mapping, so not a big issue just might cause future issues if Google change the mapping in another vendor. I could simply limit the fix to the [left Joy-Con](https://github.com/torvalds/linux/blob/master/drivers/hid/hid-ids.h#L1096-L1105) `if (event.keyCode == 0 && event.device.vendorId == 0x057e && event.device.productId == 0x2006)`.
- Auto mapping doesn't work, I'm not very familiar with the JNI Specification, I managed to implement the below workaround, it basically checks if it's the left Joy-Con and add the first four DPAD_* keycodes
```cpp
// ./src/input_common/drivers/android.cpp
ButtonMapping Android::GetButtonMappingForDevice(const Common::ParamPackage& params) {
// ...
const char *yuzu_device_name = env->GetStringUTFChars((jstring) env->CallObjectMethod(j_device, Common::Android::GetYuzuDeviceGetName()), &isCopy);
const char *switch_left_string_name = "Nintendo Switch Left Joy-Con";
bool is_switch_left = strncmp(yuzu_device_name, switch_left_string_name, strlen(switch_left_string_name)) == 0;
std::set<s32> available_keys;
for (size_t i = 0; i < keycode_ids.size(); ++i) {
if (j_has_keys[i] || (is_switch_left && i <= 3)) {
available_keys.insert(keycode_ids[i]);
}
}
// ...
}
```
Signed-off-by: crueter <crueter@eden-emu.dev>
Authored-by: Anas Bouzid <bouzid.anas.1@gmail.com>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4225
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Diffstat (limited to 'src/android')
| -rw-r--r-- | src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/InputDialogFragment.kt | 4 | ||||
| -rw-r--r-- | src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/InputHandler.kt | 21 |
2 files changed, 22 insertions, 3 deletions
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/InputDialogFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/InputDialogFragment.kt index d07a6e6aea..0e2f78c49f 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/InputDialogFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/InputDialogFragment.kt @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: 2024 yuzu Emulator Project @@ -169,7 +169,7 @@ class InputDialogFragment : DialogFragment() { NativeInput.onGamePadButtonEvent( controllerData.getGUID(), controllerData.getPort(), - event.keyCode, + InputHandler.getButtonIdFromEvent(event), action ) onInputReceived(event.device) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/InputHandler.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/InputHandler.kt index 1909a73319..cde084c68f 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/InputHandler.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/InputHandler.kt @@ -49,6 +49,12 @@ object InputHandler { MotionEvent.AXIS_RTRIGGER ) + // Currently, Android doesn't support Joy-Con D-pad buttons. We fall back to the scan code + private const val LINUX_BUTTON_DPAD_UP = 0x220 + private const val LINUX_BUTTON_DPAD_DOWN = 0x221 + private const val LINUX_BUTTON_DPAD_LEFT = 0x222 + private const val LINUX_BUTTON_DPAD_RIGHT = 0x223 + fun isPhysicalGameController(device: InputDevice?): Boolean { device ?: return false @@ -87,12 +93,25 @@ object InputHandler { NativeInput.onGamePadButtonEvent( controllerData.getGUID(), controllerData.getPort(), - event.keyCode, + getButtonIdFromEvent(event), action ) return true } + fun getButtonIdFromEvent(event: KeyEvent): Int { + if (event.keyCode == 0) { + return when (event.scanCode) { + LINUX_BUTTON_DPAD_UP -> KeyEvent.KEYCODE_DPAD_UP + LINUX_BUTTON_DPAD_DOWN -> KeyEvent.KEYCODE_DPAD_DOWN + LINUX_BUTTON_DPAD_LEFT -> KeyEvent.KEYCODE_DPAD_LEFT + LINUX_BUTTON_DPAD_RIGHT -> KeyEvent.KEYCODE_DPAD_RIGHT + else -> return 0 + } + } + return event.keyCode + } + fun dispatchGenericMotionEvent(event: MotionEvent): Boolean { val controllerData = androidControllers[event.device.controllerNumber] ?: return false |
