Virtual Keyboard Workaround in HTML5?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By AniMerrill

Hello!

So during the development of our jam game our team discovered an issue (luckily with 4 days to spare) in which it seems like, when you play an HTML export game on mobile, there is no way to have the virtual keyboard pop up when attempting to enter text into a text box. Likewise, there is no clipboard functionality. These both work perfectly fine in the desktop version of the same export, and apparently what we ran into is a known issue (Github Issue #32680).

However in that same issue, they mention some kind of workaround where you can directly edit the exported HTML base page for the game (presumably using this) to essentially pass normal HTML text input back and forth from the game. They do not mention or explain or link what this workaround is though, and none of the functions on that doc page seem directly relevant.

One obvious solution that immediately came to me is it should be pretty easy, using a click event or something, to just make a Control node based keyboard in Godot and have it only display on certain OSes (if that’s even possible, idk that was next step if I can’t figure this out). The only problem is that the game has a cooperative element where you continue the game state by sending relatively complicated hashes back and forth to each other, so even if I could DIY a keyboard solution then it wouldn’t really solve the UX problem of having to fat finger in a 20 character code like an old Nintendo game. Ideally it would be great to have some kind of access to the clipboard, as we imagine players probably sharing the code over discord or even a text app or something.

tl;dr

  1. Virtual keyboard does not work on mobile HTML gameplay
  2. We mostly need the ability to copy and paste, but typing would also be cool
  3. Are there any known workarounds?

Thank you.

:bust_in_silhouette: Reply From: wombatstampede

You could probably do an entry form in html+Javascript and let overlay the game.

You can communicate with the html page via Javascript.eval().
See:

An input in HTML should work like every other html page on that device and therefore allow copy & paste + virtual keyboard (if no physical kb is present).

Due to the asynchronuous nature of the form input (eval can/should not wait for an answer) you’d probably have to poll for a result. At least I don’t know of a method of directly calling back / signalling back to Godot from HTML.

Polling means that the html input form sets some (javascript global) variable which you repeatedly check from Godot (i.e. in a Timer each 50ms). Make sure to set the parameter for use_global_execution_context to true.

If a simple line entry is sufficient you might just directly use/eval the Javascript window.prompt().

Yeah somebody on reddit had told me about the JavaScript.eval() thing, so I just used it to call a prompt and a couple other things.

func _ready():
	connect("focus_entered", self, "js_text_entry")

func js_text_entry():
	text = JavaScript.eval(
			"prompt('%s', '%s');" % ["Please enter text:", text], 
			true
			)
	
	release_focus()

Here’s the full source for what I did over on Github, for any future Googlers who want a more comprehensive example. Basically just a script that can go on any LineEdit node.

I do hope that 4.0 possibly adds a more eloquent solution to being able to use UI on mobile HTML games. It’s frankly impressive that the desktop versions of all games come with copypaste menus so you don’t have to make that functionality yourself, it’s sort of disappointing that isn’t there on mobile.

AniMerrill | 2020-01-16 15:19

Thank you, I did this.
I did not overlayed the html input but instead hide it outside of the visible window (using css position=absolute and top=-500) and I give it the focus with JavaScript and jQuery.

socomajor | 2020-04-12 12:51

:bust_in_silhouette: Reply From: Cosmin Bacanu

If you only use a “line edit” (ex: user / password forms) here’s my workaround.

For the login LineEdit, add a “TextureButton” as a child and make it cover the entire LineEdit (i used layout → full rect). Now, connect the “pressed” event of the “Texture button” to the login script. Inside I have:

if OS.has_feature('JavaScript'):
	find_node("LoginLineEdit").text = JavaScript.eval("""
		window.prompt('Username')
	""")

In web export it will show a prompt and the prompt will set the text of the initial LineEdit.
Now you can use the value of the LineEdit as intended without needing to modify it for web (in case you are also exporting for windows, mobile, etc)

One issue with this method (using prompt) is that when prompting for a password, there is no way to hide it, so it will be in plain text while the prompt is prompted.

:bust_in_silhouette: Reply From: MurphysDad

I think that Godot Web progress report #7: Virtual keyboard on the Web, better HTTPClient might help with this

It’s a true way, it’s better than a js eval crutch. Thanks!

InterVi | 2022-07-27 21:01