From 3779bf3845e43150cf1a3897aeeaea5489e498b8 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Wed, 17 Jun 2015 00:00:53 -0700 Subject: [PATCH] Fixed bug 2948 - [Android] Arrow keys from external keyboard are not received Sylvain http://developer.android.com/reference/android/view/InputDevice.html int SOURCE_CLASS_JOYSTICK Constant Value: 16 (0x00000010) int SOURCE_JOYSTICK Constant Value: 16777232 (0x01000010) int SOURCE_KEYBOARD Constant Value: 257 (0x00000101) int SOURCE_GAMEPAD Constant Value: 1025 (0x00000401) int SOURCE_DPAD Constant Value: 513 (0x00000201) I have an a PC keyboard that I connect to an android device. The issue is that "arrow" keys gets lost. More explanation: This device gets detected twice by the java "pollInputDevices()" both as SOURCE_KEYBOARD and as a composite (0x1000311 == SOURCE_JOYSTICK | SOURCE_KEYBOARD | SOURCE_DPAD). Because of being a SOURCE_CLASS_JOYSTICK, only the second entry is registered, and I opened it. When I press one arrow key, the java method "onKey(...)" is called. The Source "event.getSource()" is "SOURCE_KEYBOARD", so it enters this conditions : if ( (event.getSource() & InputDevice.SOURCE_GAMEPAD) != 0 || (event.getSource() & InputDevice.SOURCE_DPAD) != 0 ) { And then, it enters : SDLActivity.onNativePadDown() (native code in "SDL_sysjoystick.c") Since the "arrows" are viewed as "D-PAD", it gets translated : int button = keycode_to_SDL(keycode); But the android-java "event.getDeviceId()" is wrong: this is the one from the Keyboard, and not the one from the Joystick that I have opened. So I don't get them through the Joystick interface. And since, the keycode has been translated, it returns 0 and assume it was consumed. So I lost the key in the function "Android_OnPadDown()" Notice, It won't happen with other normal "letters" keys because they does not get translated by "keycode_to_SDL", so "Android_OnPadDown()" returns -1. And then java code send the keys to "SDLActivity.onNativeKeyDown()". Possible patch on "Android_OnPadDown" and also "Android_OnPadUp" (and maybe other functons): 85 int 186 Android_OnPadDown(int device_id, int keycode) 187 { 188 SDL_joylist_item *item; 189 int button = keycode_to_SDL(keycode); 190 if (button >= 0) { 191 item = JoystickByDeviceId(device_id); 192 if (item && item->joystick) { 193 SDL_PrivateJoystickButton(item->joystick, button , SDL_PRESSED); 194 } + else return -1; 195 return 0; 196 } 197 198 return -1; 199 } It would allow the java caller function to send the key to "SDLActivity.onNativeKeyDown();" Another solution, would be to replace: if ( (event.getSource() & InputDevice.SOURCE_GAMEPAD) != 0 || (event.getSource() & InputDevice.SOURCE_DPAD) != 0 ) { by if ( (event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) Because only "SOURCE_CLASS_JOYSTICK" devices are registered/opened. --- src/joystick/android/SDL_sysjoystick.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/joystick/android/SDL_sysjoystick.c b/src/joystick/android/SDL_sysjoystick.c index 1872c9431..8ab682d45 100644 --- a/src/joystick/android/SDL_sysjoystick.c +++ b/src/joystick/android/SDL_sysjoystick.c @@ -191,8 +191,8 @@ Android_OnPadDown(int device_id, int keycode) item = JoystickByDeviceId(device_id); if (item && item->joystick) { SDL_PrivateJoystickButton(item->joystick, button , SDL_PRESSED); + return 0; } - return 0; } return -1; @@ -207,8 +207,8 @@ Android_OnPadUp(int device_id, int keycode) item = JoystickByDeviceId(device_id); if (item && item->joystick) { SDL_PrivateJoystickButton(item->joystick, button, SDL_RELEASED); + return 0; } - return 0; } return -1;