Ver código fonte

Allow to obtain virtual keyboard height

On mobile platforms virtual keyboards take up significant amount of
screen space and UI containing a text box may need to be adjusted
after the keyboard appears to keep the text box visible to user. This
commit adds a way to obtain virtual keyabord height so that controls
are aware of how much they need to move.
Ruslan Mustakov 8 anos atrás
pai
commit
275e537058

+ 5 - 0
core/bind/core_bind.cpp

@@ -858,6 +858,10 @@ void _OS::hide_virtual_keyboard() {
 	OS::get_singleton()->hide_virtual_keyboard();
 }
 
+int _OS::get_virtual_keyboard_height() {
+	return OS::get_singleton()->get_virtual_keyboard_height();
+}
+
 void _OS::print_all_resources(const String &p_to_file) {
 
 	OS::get_singleton()->print_all_resources(p_to_file);
@@ -1064,6 +1068,7 @@ void _OS::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("has_virtual_keyboard"), &_OS::has_virtual_keyboard);
 	ClassDB::bind_method(D_METHOD("show_virtual_keyboard", "existing_text"), &_OS::show_virtual_keyboard, DEFVAL(""));
 	ClassDB::bind_method(D_METHOD("hide_virtual_keyboard"), &_OS::hide_virtual_keyboard);
+	ClassDB::bind_method(D_METHOD("get_virtual_keyboard_height"), &_OS::get_virtual_keyboard_height);
 	ClassDB::bind_method(D_METHOD("print_resources_in_use", "short"), &_OS::print_resources_in_use, DEFVAL(false));
 	ClassDB::bind_method(D_METHOD("print_all_resources", "tofile"), &_OS::print_all_resources, DEFVAL(""));
 

+ 1 - 0
core/bind/core_bind.h

@@ -204,6 +204,7 @@ public:
 	bool has_virtual_keyboard() const;
 	void show_virtual_keyboard(const String &p_existing_text = "");
 	void hide_virtual_keyboard();
+	int get_virtual_keyboard_height();
 
 	void print_resources_in_use(bool p_short = false);
 	void print_all_resources(const String &p_to_file);

+ 4 - 0
core/os/os.cpp

@@ -193,6 +193,10 @@ void OS::show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_scr
 void OS::hide_virtual_keyboard() {
 }
 
+int OS::get_virtual_keyboard_height() const {
+	return 0;
+}
+
 void OS::print_all_resources(String p_to_file) {
 
 	ERR_FAIL_COND(p_to_file != "" && _OSPRF);

+ 3 - 0
core/os/os.h

@@ -313,6 +313,9 @@ public:
 	virtual void show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2());
 	virtual void hide_virtual_keyboard();
 
+	// returns height of the currently shown virtual keyboard (0 if keyboard is hidden)
+	virtual int get_virtual_keyboard_height() const;
+
 	virtual void set_cursor_shape(CursorShape p_shape) = 0;
 
 	virtual bool get_swap_ok_cancel() { return false; }

+ 15 - 0
platform/android/java/src/org/godotengine/godot/Godot.java

@@ -277,6 +277,21 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
 		edittext.setView(mView);
 		io.setEdit(edittext);
 
+		final Godot godot = this;
+		mView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
+				@Override
+				public void onGlobalLayout() {
+					Point fullSize = new Point();
+					godot.getWindowManager().getDefaultDisplay().getSize(fullSize);
+					Rect gameSize = new Rect();
+					godot.mView.getWindowVisibleDisplayFrame(gameSize);
+
+					final int keyboardHeight = fullSize.y - gameSize.bottom;
+					Log.d("GODOT", "setVirtualKeyboardHeight: " + keyboardHeight);
+					GodotLib.setVirtualKeyboardHeight(keyboardHeight);
+				}
+		});
+
 		// Ad layout
 		adLayout = new RelativeLayout(this);
 		adLayout.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT));

+ 2 - 0
platform/android/java/src/org/godotengine/godot/GodotLib.java

@@ -69,4 +69,6 @@ public class GodotLib {
 	public static native void callobject(int p_ID, String p_method, Object[] p_params);
 	public static native void calldeferred(int p_ID, String p_method, Object[] p_params);
 
+	public static native void setVirtualKeyboardHeight(int p_height);
+
 }

+ 13 - 1
platform/android/java_glue.cpp

@@ -754,6 +754,18 @@ static void _alert(const String &p_message, const String &p_title) {
 	env->CallVoidMethod(_godot_instance, _alertDialog, jStrMessage, jStrTitle);
 }
 
+// volatile because it can be changed from non-main thread and we need to
+// ensure the change is immediately visible to other threads.
+static volatile int virtual_keyboard_height;
+
+static int _get_vk_height() {
+	return virtual_keyboard_height;
+}
+
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setVirtualKeyboardHeight(JNIEnv *env, jobject obj, jint p_height) {
+	virtual_keyboard_height = p_height;
+}
+
 JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *env, jobject obj, jobject activity, jboolean p_need_reload_hook, jobject p_asset_manager, jboolean p_use_apk_expansion) {
 
 	__android_log_print(ANDROID_LOG_INFO, "godot", "**INIT EVENT! - %p\n", env);
@@ -824,7 +836,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv *en
 		AudioDriverAndroid::setup(gob);
 	}
 
-	os_android = new OS_Android(_gfx_init_func, env, _open_uri, _get_data_dir, _get_locale, _get_model, _get_screen_dpi, _show_vk, _hide_vk, _set_screen_orient, _get_unique_id, _get_system_dir, _play_video, _is_video_playing, _pause_video, _stop_video, _set_keep_screen_on, _alert, p_use_apk_expansion);
+	os_android = new OS_Android(_gfx_init_func, env, _open_uri, _get_data_dir, _get_locale, _get_model, _get_screen_dpi, _show_vk, _hide_vk, _get_vk_height, _set_screen_orient, _get_unique_id, _get_system_dir, _play_video, _is_video_playing, _pause_video, _stop_video, _set_keep_screen_on, _alert, p_use_apk_expansion);
 	os_android->set_need_reload_hooks(p_need_reload_hook);
 
 	char wd[500];

+ 1 - 0
platform/android/java_glue.h

@@ -59,6 +59,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_method(JNIEnv *env, j
 JNIEXPORT jstring JNICALL Java_org_godotengine_godot_GodotLib_getGlobal(JNIEnv *env, jobject obj, jstring path);
 JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_callobject(JNIEnv *env, jobject p_obj, jint ID, jstring method, jobjectArray params);
 JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_calldeferred(JNIEnv *env, jobject p_obj, jint ID, jstring method, jobjectArray params);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setVirtualKeyboardHeight(JNIEnv *env, jobject obj, jint p_height);
 }
 
 #endif

+ 11 - 1
platform/android/os_android.cpp

@@ -519,6 +519,15 @@ bool OS_Android::has_virtual_keyboard() const {
 	return true;
 }
 
+int OS_Android::get_virtual_keyboard_height() const {
+	if (get_virtual_keyboard_height_func) {
+		return get_virtual_keyboard_height_func();
+	}
+
+	ERR_PRINT("Cannot obtain virtual keyboard height.");
+	return 0;
+}
+
 void OS_Android::show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect) {
 
 	if (show_virtual_keyboard_func) {
@@ -704,7 +713,7 @@ bool OS_Android::_check_internal_feature_support(const String &p_feature) {
 	return p_feature == "mobile" || p_feature == "etc" || p_feature == "etc2"; //TODO support etc2 only if GLES3 driver is selected
 }
 
-OS_Android::OS_Android(GFXInitFunc p_gfx_init_func, void *p_gfx_init_ud, OpenURIFunc p_open_uri_func, GetDataDirFunc p_get_data_dir_func, GetLocaleFunc p_get_locale_func, GetModelFunc p_get_model_func, GetScreenDPIFunc p_get_screen_dpi_func, ShowVirtualKeyboardFunc p_show_vk, HideVirtualKeyboardFunc p_hide_vk, SetScreenOrientationFunc p_screen_orient, GetUniqueIDFunc p_get_unique_id, GetSystemDirFunc p_get_sdir_func, VideoPlayFunc p_video_play_func, VideoIsPlayingFunc p_video_is_playing_func, VideoPauseFunc p_video_pause_func, VideoStopFunc p_video_stop_func, SetKeepScreenOnFunc p_set_keep_screen_on_func, AlertFunc p_alert_func, bool p_use_apk_expansion) {
+OS_Android::OS_Android(GFXInitFunc p_gfx_init_func, void *p_gfx_init_ud, OpenURIFunc p_open_uri_func, GetDataDirFunc p_get_data_dir_func, GetLocaleFunc p_get_locale_func, GetModelFunc p_get_model_func, GetScreenDPIFunc p_get_screen_dpi_func, ShowVirtualKeyboardFunc p_show_vk, HideVirtualKeyboardFunc p_hide_vk, VirtualKeyboardHeightFunc p_vk_height_func, SetScreenOrientationFunc p_screen_orient, GetUniqueIDFunc p_get_unique_id, GetSystemDirFunc p_get_sdir_func, VideoPlayFunc p_video_play_func, VideoIsPlayingFunc p_video_is_playing_func, VideoPauseFunc p_video_pause_func, VideoStopFunc p_video_stop_func, SetKeepScreenOnFunc p_set_keep_screen_on_func, AlertFunc p_alert_func, bool p_use_apk_expansion) {
 
 	use_apk_expansion = p_use_apk_expansion;
 	default_videomode.width = 800;
@@ -734,6 +743,7 @@ OS_Android::OS_Android(GFXInitFunc p_gfx_init_func, void *p_gfx_init_ud, OpenURI
 
 	show_virtual_keyboard_func = p_show_vk;
 	hide_virtual_keyboard_func = p_hide_vk;
+	get_virtual_keyboard_height_func = p_vk_height_func;
 
 	set_screen_orientation_func = p_screen_orient;
 	set_keep_screen_on_func = p_set_keep_screen_on_func;

+ 4 - 1
platform/android/os_android.h

@@ -67,6 +67,7 @@ typedef void (*VideoPauseFunc)();
 typedef void (*VideoStopFunc)();
 typedef void (*SetKeepScreenOnFunc)(bool p_enabled);
 typedef void (*AlertFunc)(const String &, const String &);
+typedef int (*VirtualKeyboardHeightFunc)();
 
 class OS_Android : public OS_Unix {
 public:
@@ -126,6 +127,7 @@ private:
 	GetScreenDPIFunc get_screen_dpi_func;
 	ShowVirtualKeyboardFunc show_virtual_keyboard_func;
 	HideVirtualKeyboardFunc hide_virtual_keyboard_func;
+	VirtualKeyboardHeightFunc get_virtual_keyboard_height_func;
 	SetScreenOrientationFunc set_screen_orientation_func;
 	GetUniqueIDFunc get_unique_id_func;
 	GetSystemDirFunc get_system_dir_func;
@@ -201,6 +203,7 @@ public:
 	virtual bool has_virtual_keyboard() const;
 	virtual void show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2());
 	virtual void hide_virtual_keyboard();
+	virtual int get_virtual_keyboard_height() const;
 
 	void set_opengl_extensions(const char *p_gl_extensions);
 	void set_display_size(Size2 p_size);
@@ -240,7 +243,7 @@ public:
 	void joy_connection_changed(int p_device, bool p_connected, String p_name);
 
 	virtual bool _check_internal_feature_support(const String &p_feature);
-	OS_Android(GFXInitFunc p_gfx_init_func, void *p_gfx_init_ud, OpenURIFunc p_open_uri_func, GetDataDirFunc p_get_data_dir_func, GetLocaleFunc p_get_locale_func, GetModelFunc p_get_model_func, GetScreenDPIFunc p_get_screen_dpi_func, ShowVirtualKeyboardFunc p_show_vk, HideVirtualKeyboardFunc p_hide_vk, SetScreenOrientationFunc p_screen_orient, GetUniqueIDFunc p_get_unique_id, GetSystemDirFunc p_get_sdir_func, VideoPlayFunc p_video_play_func, VideoIsPlayingFunc p_video_is_playing_func, VideoPauseFunc p_video_pause_func, VideoStopFunc p_video_stop_func, SetKeepScreenOnFunc p_set_keep_screen_on_func, AlertFunc p_alert_func, bool p_use_apk_expansion);
+	OS_Android(GFXInitFunc p_gfx_init_func, void *p_gfx_init_ud, OpenURIFunc p_open_uri_func, GetDataDirFunc p_get_data_dir_func, GetLocaleFunc p_get_locale_func, GetModelFunc p_get_model_func, GetScreenDPIFunc p_get_screen_dpi_func, ShowVirtualKeyboardFunc p_show_vk, HideVirtualKeyboardFunc p_hide_vk, VirtualKeyboardHeightFunc p_vk_height_func, SetScreenOrientationFunc p_screen_orient, GetUniqueIDFunc p_get_unique_id, GetSystemDirFunc p_get_sdir_func, VideoPlayFunc p_video_play_func, VideoIsPlayingFunc p_video_is_playing_func, VideoPauseFunc p_video_pause_func, VideoStopFunc p_video_stop_func, SetKeepScreenOnFunc p_set_keep_screen_on_func, AlertFunc p_alert_func, bool p_use_apk_expansion);
 	~OS_Android();
 };
 

+ 2 - 0
platform/iphone/gl_view.h

@@ -100,6 +100,8 @@
 - (void)destroyFramebuffer;
 
 - (void)audioRouteChangeListenerCallback:(NSNotification *)notification;
+- (void)keyboardOnScreen:(NSNotification *)notification;
+- (void)keyboardHidden:(NSNotification *)notification;
 
 @property NSTimeInterval animationInterval;
 @property(nonatomic, assign) BOOL useCADisplayLink;

+ 40 - 0
platform/iphone/gl_view.mm

@@ -63,6 +63,7 @@ void _pause_video();
 void _focus_out_video();
 void _unpause_video();
 void _stop_video();
+CGFloat _points_to_pixels(CGFloat);
 
 void _show_keyboard(String p_existing) {
 	keyboard_text = p_existing;
@@ -174,6 +175,19 @@ void _stop_video() {
 	video_playing = false;
 }
 
+CGFloat _points_to_pixels(CGFloat points) {
+	float pixelPerInch;
+	if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
+		pixelPerInch = 132;
+	} else if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
+		pixelPerInch = 163;
+	} else {
+		pixelPerInch = 160;
+	}
+	CGFloat pointsPerInch = 72.0;
+	return (points / pointsPerInch * pixelPerInch);
+}
+
 @implementation GLView
 
 @synthesize animationInterval;
@@ -537,6 +551,20 @@ static void clear_touches() {
 	[self resignFirstResponder];
 };
 
+- (void)keyboardOnScreen:(NSNotification *)notification {
+	NSDictionary *info = notification.userInfo;
+	NSValue *value = info[UIKeyboardFrameEndUserInfoKey];
+
+	CGRect rawFrame = [value CGRectValue];
+	CGRect keyboardFrame = [self convertRect:rawFrame fromView:nil];
+
+	OSIPhone::get_singleton()->set_virtual_keyboard_height(_points_to_pixels(keyboardFrame.size.height));
+}
+
+- (void)keyboardHidden:(NSNotification *)notification {
+	OSIPhone::get_singleton()->set_virtual_keyboard_height(0);
+}
+
 - (void)deleteBackward {
 	if (keyboard_text.length())
 		keyboard_text.erase(keyboard_text.length() - 1, 1);
@@ -606,6 +634,18 @@ static void clear_touches() {
 				   name:AVAudioSessionRouteChangeNotification
 				 object:nil];
 
+	printf("******** adding observer for keyboard show/hide\n");
+	[[NSNotificationCenter defaultCenter]
+			addObserver:self
+			   selector:@selector(keyboardOnScreen:)
+				   name:UIKeyboardDidShowNotification
+				 object:nil];
+	[[NSNotificationCenter defaultCenter]
+			addObserver:self
+			   selector:@selector(keyboardHidden:)
+				   name:UIKeyboardDidHideNotification
+				 object:nil];
+
 	//self.autoresizesSubviews = YES;
 	//[self setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleWidth];
 

+ 9 - 0
platform/iphone/os_iphone.cpp

@@ -463,6 +463,14 @@ void OSIPhone::hide_virtual_keyboard() {
 	_hide_keyboard();
 };
 
+void OSIPhone::set_virtual_keyboard_height(int p_height) {
+	virtual_keyboard_height = p_height;
+}
+
+int OSIPhone::get_virtual_keyboard_height() const {
+	return virtual_keyboard_height;
+}
+
 Error OSIPhone::shell_open(String p_uri) {
 	return _shell_open(p_uri);
 };
@@ -576,6 +584,7 @@ OSIPhone::OSIPhone(int width, int height) {
 	vm.resizable = false;
 	set_video_mode(vm);
 	event_count = 0;
+	virtual_keyboard_height = 0;
 
 	_set_logger(memnew(SyslogLogger));
 };

+ 4 - 0
platform/iphone/os_iphone.h

@@ -124,6 +124,8 @@ private:
 
 	InputDefault *input;
 
+	int virtual_keyboard_height;
+
 public:
 	bool iterate();
 
@@ -133,6 +135,7 @@ public:
 	void mouse_move(int p_idx, int p_prev_x, int p_prev_y, int p_x, int p_y, bool p_use_as_mouse);
 	void touches_cancelled();
 	void key(uint32_t p_key, bool p_pressed);
+	void set_virtual_keyboard_height(int p_height);
 
 	int set_base_framebuffer(int p_fb);
 
@@ -168,6 +171,7 @@ public:
 	virtual bool has_virtual_keyboard() const;
 	virtual void show_virtual_keyboard(const String &p_existing_text, const Rect2 &p_screen_rect = Rect2());
 	virtual void hide_virtual_keyboard();
+	virtual int get_virtual_keyboard_height() const;
 
 	virtual void set_cursor_shape(CursorShape p_shape);