From 6e8688a4effda257291a811fdaad245777d69ef2 Mon Sep 17 00:00:00 2001 From: andreas Date: Wed, 26 Aug 2026 05:20:53 +1000 Subject: [PATCH 1/2] Prevent virtual keyboard events from hiding the virtual joystick --- .../input/android/AndroidInputHandler.java | 18 +++++++++++++++++- .../input/android/AndroidInputHandler14.java | 4 +++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler.java b/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler.java index 6db3c95c6b..ac8643d17f 100644 --- a/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler.java +++ b/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler.java @@ -238,7 +238,9 @@ public boolean onKey(View view, int keyCode, KeyEvent event) { // logger.log(Level.INFO, "onKey source: {0}, isTouch: {1}", // new Object[]{source, isTouch}); - if ((source & InputDevice.SOURCE_KEYBOARD) == InputDevice.SOURCE_KEYBOARD && joyInput != null) { + if ((source & InputDevice.SOURCE_KEYBOARD) == InputDevice.SOURCE_KEYBOARD + && joyInput != null + && isFromPhysicalKeyboard(event)) { joyInput.onKeyboardInput(); } @@ -250,4 +252,18 @@ public boolean onKey(View view, int keyCode, KeyEvent event) { } + /** + * Distinguishes a real hardware keyboard/keypad from synthetic + * SOURCE_KEYBOARD events injected by the IME, accessibility services, or + * instrumentation, all of which report a virtual (non-hardware-backed) + * InputDevice. Only a genuine hardware keyboard should be able to + * suppress the AUTO-mode on-screen virtual joystick. + */ + protected static boolean isFromPhysicalKeyboard(KeyEvent event) { + InputDevice device = event.getDevice(); + return device != null + && !device.isVirtual() + && device.getKeyboardType() == InputDevice.KEYBOARD_TYPE_ALPHABETIC; + } + } diff --git a/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler14.java b/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler14.java index 355d3c55fa..63fbe0eea4 100644 --- a/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler14.java +++ b/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler14.java @@ -179,7 +179,9 @@ public boolean onKey(View view, int keyCode, KeyEvent event) { boolean isUnknown = (source & android.view.InputDevice.SOURCE_UNKNOWN) == android.view.InputDevice.SOURCE_UNKNOWN; - if ((source & InputDevice.SOURCE_KEYBOARD) == InputDevice.SOURCE_KEYBOARD && joyInput != null) { + if ((source & InputDevice.SOURCE_KEYBOARD) == InputDevice.SOURCE_KEYBOARD + && joyInput != null + && isFromPhysicalKeyboard(event)) { joyInput.onKeyboardInput(); } From eb68b2f1f85169e649d122a331aaa441b87771b3 Mon Sep 17 00:00:00 2001 From: Riccardo Balbo Date: Mon, 31 Aug 2026 15:39:20 +0200 Subject: [PATCH 2/2] improve android virtual keyboard detection --- .../input/android/AndroidInputHandler.java | 21 ++++---- .../input/android/AndroidInputHandler14.java | 2 +- .../input/android/AndroidInputHandler16.java | 53 +++++++++++++++++++ .../input/android/AndroidInputHandler24.java | 4 +- .../com/jme3/system/android/OGLESContext.java | 3 ++ 5 files changed, 69 insertions(+), 14 deletions(-) create mode 100644 jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler16.java diff --git a/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler.java b/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler.java index ac8643d17f..a1b6766235 100644 --- a/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler.java +++ b/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler.java @@ -58,6 +58,8 @@ public class AndroidInputHandler implements View.OnTouchListener, View.OnKeyListener { private static final Logger logger = Logger.getLogger(AndroidInputHandler.class.getName()); + // in API level 11. + private static final int VIRTUAL_KEYBOARD_DEVICE_ID = -1; protected GLSurfaceView view; protected AndroidTouchInput touchInput; @@ -240,7 +242,7 @@ public boolean onKey(View view, int keyCode, KeyEvent event) { if ((source & InputDevice.SOURCE_KEYBOARD) == InputDevice.SOURCE_KEYBOARD && joyInput != null - && isFromPhysicalKeyboard(event)) { + && !isVirtualKeyboardEvent(event)) { joyInput.onKeyboardInput(); } @@ -253,17 +255,14 @@ && isFromPhysicalKeyboard(event)) { } /** - * Distinguishes a real hardware keyboard/keypad from synthetic - * SOURCE_KEYBOARD events injected by the IME, accessibility services, or - * instrumentation, all of which report a virtual (non-hardware-backed) - * InputDevice. Only a genuine hardware keyboard should be able to - * suppress the AUTO-mode on-screen virtual joystick. + * Tests whether a key event identifies a software or on-screen keyboard. + * + * @param event the key event to test + * @return true if the event came from a virtual keyboard */ - protected static boolean isFromPhysicalKeyboard(KeyEvent event) { - InputDevice device = event.getDevice(); - return device != null - && !device.isVirtual() - && device.getKeyboardType() == InputDevice.KEYBOARD_TYPE_ALPHABETIC; + protected boolean isVirtualKeyboardEvent(KeyEvent event) { + int virtualFlags = KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_VIRTUAL_HARD_KEY; + return (event.getFlags() & virtualFlags) != 0 || event.getDeviceId() == VIRTUAL_KEYBOARD_DEVICE_ID; } } diff --git a/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler14.java b/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler14.java index 63fbe0eea4..0b37a913ce 100644 --- a/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler14.java +++ b/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler14.java @@ -181,7 +181,7 @@ public boolean onKey(View view, int keyCode, KeyEvent event) { if ((source & InputDevice.SOURCE_KEYBOARD) == InputDevice.SOURCE_KEYBOARD && joyInput != null - && isFromPhysicalKeyboard(event)) { + && !isVirtualKeyboardEvent(event)) { joyInput.onKeyboardInput(); } diff --git a/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler16.java b/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler16.java new file mode 100644 index 0000000000..6798c853d7 --- /dev/null +++ b/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler16.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2009-2026 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.jme3.input.android; + +import android.view.InputDevice; +import android.view.KeyEvent; + +/** + * Extends {@link AndroidInputHandler14} with input-device APIs introduced in + * Android API level 16. + */ +public class AndroidInputHandler16 extends AndroidInputHandler14 { + + @Override + protected boolean isVirtualKeyboardEvent(KeyEvent event) { + if (super.isVirtualKeyboardEvent(event)) { + return true; + } + + InputDevice device = event.getDevice(); + return device != null && device.isVirtual(); + } +} diff --git a/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler24.java b/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler24.java index ce405ec3f4..511db34b07 100644 --- a/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler24.java +++ b/jme3-android/src/main/java/com/jme3/input/android/AndroidInputHandler24.java @@ -33,13 +33,13 @@ package com.jme3.input.android; /** - * AndroidInputHandler24 extends AndroidInputHandler14 to + * AndroidInputHandler24 extends AndroidInputHandler16 to * use AndroidMouseInput24 which adds usage of newer events and also enables cursor visibility * and cursor image change. * * @author joliver82 */ -public class AndroidInputHandler24 extends AndroidInputHandler14 { +public class AndroidInputHandler24 extends AndroidInputHandler16 { public AndroidInputHandler24() { super(); diff --git a/jme3-android/src/main/java/com/jme3/system/android/OGLESContext.java b/jme3-android/src/main/java/com/jme3/system/android/OGLESContext.java index 2dbb590926..6a0571c1b9 100644 --- a/jme3-android/src/main/java/com/jme3/system/android/OGLESContext.java +++ b/jme3-android/src/main/java/com/jme3/system/android/OGLESContext.java @@ -50,6 +50,7 @@ import com.jme3.input.*; import com.jme3.input.android.AndroidInputHandler; import com.jme3.input.android.AndroidInputHandler14; +import com.jme3.input.android.AndroidInputHandler16; import com.jme3.input.android.AndroidInputHandler24; import com.jme3.input.android.AndroidInputHandler26; import com.jme3.input.controls.SoftTextDialogInputListener; @@ -166,6 +167,8 @@ public GLSurfaceView createView(Context context) { androidInput = new AndroidInputHandler26(); } else if (Build.VERSION.SDK_INT >= 24) { androidInput = new AndroidInputHandler24(); + } else if (Build.VERSION.SDK_INT >= 16) { + androidInput = new AndroidInputHandler16(); } else if (Build.VERSION.SDK_INT >= 14) { androidInput = new AndroidInputHandler14(); } else if (Build.VERSION.SDK_INT >= 9) {