diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml
index 1ff4e1a5e7d..fafdf6e9426 100644
--- a/doc/classes/DisplayServer.xml
+++ b/doc/classes/DisplayServer.xml
@@ -1204,6 +1204,14 @@
[b]Note:[/b] On iOS, this method has no effect if [member ProjectSettings.display/window/handheld/orientation] is not set to [constant SCREEN_SENSOR].
+
+
+
+
+ Sets the [param callable] that should be called when hardware keyboard is connected/disconnected. [param callable] should accept a single [bool] parameter indicating whether the keyboard is connected (true) or disconnected (false).
+ [b]Note:[/b] This method is only implemented on Android.
+
+
diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp
index 5db5d85aa6b..b174b178553 100644
--- a/platform/android/display_server_android.cpp
+++ b/platform/android/display_server_android.cpp
@@ -145,6 +145,16 @@ void DisplayServerAndroid::emit_system_theme_changed() {
}
}
+void DisplayServerAndroid::set_hardware_keyboard_connection_change_callback(const Callable &p_callable) {
+ hardware_keyboard_connection_changed = p_callable;
+}
+
+void DisplayServerAndroid::emit_hardware_keyboard_connection_changed(bool p_connected) {
+ if (hardware_keyboard_connection_changed.is_valid()) {
+ hardware_keyboard_connection_changed.call_deferred(p_connected);
+ }
+}
+
void DisplayServerAndroid::clipboard_set(const String &p_text) {
GodotJavaWrapper *godot_java = OS_Android::get_singleton()->get_godot_java();
ERR_FAIL_NULL(godot_java);
diff --git a/platform/android/display_server_android.h b/platform/android/display_server_android.h
index 894ef311fa1..fb1212141cc 100644
--- a/platform/android/display_server_android.h
+++ b/platform/android/display_server_android.h
@@ -89,6 +89,7 @@ class DisplayServerAndroid : public DisplayServer {
Callable rect_changed_callback;
Callable system_theme_changed;
+ Callable hardware_keyboard_connection_changed;
Callable dialog_callback;
Callable input_dialog_callback;
@@ -114,11 +115,10 @@ public:
virtual void tts_resume() override;
virtual void tts_stop() override;
- void emit_system_theme_changed();
-
virtual bool is_dark_mode_supported() const override;
virtual bool is_dark_mode() const override;
virtual void set_system_theme_change_callback(const Callable &p_callable) override;
+ void emit_system_theme_changed();
virtual void clipboard_set(const String &p_text) override;
virtual String clipboard_get() const override;
@@ -159,6 +159,8 @@ public:
virtual void virtual_keyboard_hide() override;
virtual int virtual_keyboard_get_height() const override;
virtual bool has_hardware_keyboard() const override;
+ virtual void set_hardware_keyboard_connection_change_callback(const Callable &p_callable) override;
+ void emit_hardware_keyboard_connection_changed(bool p_connected);
virtual void window_set_window_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override;
virtual void window_set_input_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override;
diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.kt b/platform/android/java/lib/src/org/godotengine/godot/Godot.kt
index 9ab30e5f5b6..6a5c5eb260e 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/Godot.kt
+++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.kt
@@ -77,7 +77,6 @@ import org.godotengine.godot.xr.XRMode
import java.io.File
import java.io.FileInputStream
import java.io.InputStream
-import java.lang.Exception
import java.security.MessageDigest
import java.util.*
import java.util.concurrent.atomic.AtomicBoolean
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
index d70915a9b37..5e599432d91 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
@@ -268,6 +268,11 @@ public class GodotLib {
*/
public static native void onNightModeChanged();
+ /**
+ * Invoked on the hardware keyboard connected/disconnected.
+ */
+ public static native void hardwareKeyboardConnected(boolean connected);
+
/**
* Invoked on the file picker closed.
*/
diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java
index cacc1643e30..68f5ffd37cf 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java
@@ -265,13 +265,6 @@ public class GodotEditText extends EditText {
}
public boolean hasHardwareKeyboard() {
- Configuration config = getResources().getConfiguration();
- boolean hasHardwareKeyboardConfig = config.keyboard != Configuration.KEYBOARD_NOKEYS &&
- config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO;
- if (hasHardwareKeyboardConfig) {
- return true;
- }
-
return mRenderView.getInputHandler().hasHardwareKeyboard();
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
index 695d56c24f8..205aae3347a 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
@@ -90,6 +90,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener, Sens
private int cachedRotation = -1;
private boolean overrideVolumeButtons = false;
+ private boolean hasHardwareKeyboardConfig = false;
public GodotInputHandler(Context context, Godot godot) {
this.godot = godot;
@@ -105,6 +106,9 @@ public class GodotInputHandler implements InputManager.InputDeviceListener, Sens
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
this.scaleGestureDetector.setStylusScaleEnabled(true);
}
+ Configuration config = context.getResources().getConfiguration();
+ hasHardwareKeyboardConfig = config.keyboard != Configuration.KEYBOARD_NOKEYS &&
+ config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO;
}
/**
@@ -143,6 +147,9 @@ public class GodotInputHandler implements InputManager.InputDeviceListener, Sens
}
boolean hasHardwareKeyboard() {
+ if (hasHardwareKeyboardConfig) {
+ return true;
+ }
return !mHardwareKeyboardIds.isEmpty();
}
@@ -797,5 +804,12 @@ public class GodotInputHandler implements InputManager.InputDeviceListener, Sens
public void onConfigurationChanged(Configuration newConfig) {
updateCachedRotation();
+
+ boolean newHardwareKeyboardConfig = newConfig.keyboard != Configuration.KEYBOARD_NOKEYS &&
+ newConfig.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO;
+ if (hasHardwareKeyboardConfig != newHardwareKeyboardConfig) {
+ hasHardwareKeyboardConfig = newHardwareKeyboardConfig;
+ GodotLib.hardwareKeyboardConnected(hasHardwareKeyboard());
+ }
}
}
diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp
index 196dfd88f46..066cf86d1c2 100644
--- a/platform/android/java_godot_lib_jni.cpp
+++ b/platform/android/java_godot_lib_jni.cpp
@@ -548,6 +548,13 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_onNightModeChanged(JN
}
}
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_hardwareKeyboardConnected(JNIEnv *env, jclass clazz, jboolean p_connected) {
+ DisplayServerAndroid *ds = (DisplayServerAndroid *)DisplayServer::get_singleton();
+ if (ds) {
+ ds->emit_hardware_keyboard_connection_changed(p_connected);
+ }
+}
+
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_filePickerCallback(JNIEnv *env, jclass clazz, jboolean p_ok, jobjectArray p_selected_paths) {
DisplayServerAndroid *ds = (DisplayServerAndroid *)DisplayServer::get_singleton();
if (ds) {
diff --git a/platform/android/java_godot_lib_jni.h b/platform/android/java_godot_lib_jni.h
index 47a5a62fb93..7cdc22d7189 100644
--- a/platform/android/java_godot_lib_jni.h
+++ b/platform/android/java_godot_lib_jni.h
@@ -68,6 +68,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setEditorProjectMetad
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setVirtualKeyboardHeight(JNIEnv *env, jclass clazz, jint p_height);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_requestPermissionResult(JNIEnv *env, jclass clazz, jstring p_permission, jboolean p_result);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_onNightModeChanged(JNIEnv *env, jclass clazz);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_hardwareKeyboardConnected(JNIEnv *env, jclass clazz, jboolean p_connected);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_filePickerCallback(JNIEnv *env, jclass clazz, jboolean p_ok, jobjectArray p_selected_paths);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_onRendererResumed(JNIEnv *env, jclass clazz);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_onRendererPaused(JNIEnv *env, jclass clazz);
diff --git a/servers/display_server.cpp b/servers/display_server.cpp
index a8ae645d894..1ff679b4b69 100644
--- a/servers/display_server.cpp
+++ b/servers/display_server.cpp
@@ -1033,6 +1033,7 @@ void DisplayServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("virtual_keyboard_get_height"), &DisplayServer::virtual_keyboard_get_height);
ClassDB::bind_method(D_METHOD("has_hardware_keyboard"), &DisplayServer::has_hardware_keyboard);
+ ClassDB::bind_method(D_METHOD("set_hardware_keyboard_connection_change_callback", "callable"), &DisplayServer::set_hardware_keyboard_connection_change_callback);
ClassDB::bind_method(D_METHOD("cursor_set_shape", "shape"), &DisplayServer::cursor_set_shape);
ClassDB::bind_method(D_METHOD("cursor_get_shape"), &DisplayServer::cursor_get_shape);
diff --git a/servers/display_server.h b/servers/display_server.h
index e26d6833e0c..0cb87fcd73e 100644
--- a/servers/display_server.h
+++ b/servers/display_server.h
@@ -271,6 +271,7 @@ public:
virtual Color get_accent_color() const { return Color(0, 0, 0, 0); }
virtual Color get_base_color() const { return Color(0, 0, 0, 0); }
virtual void set_system_theme_change_callback(const Callable &p_callable) {}
+ virtual void set_hardware_keyboard_connection_change_callback(const Callable &p_callable) {}
private:
static bool window_early_clear_override_enabled;