~eliasnaur/gio#415: 
WASM key.InputOp behaves inconsistently

The following Gio program registers to be notified when the "a" key is pressed:

https://go.dev/play/p/rTAlmwwHYvh

On Linux, running this program and pressing the "a" key will display keypresses in the log output.

If you build this program for WASM with gogio and run it in the browser, the browser console will not register any presses of the key "a". You can press tab once and this will sometimes generate a key.FocusEvent after which the input handler will receive keypresses until you press tab again. After pressing tab again, I have found no way to make keypresses register again.

The only workaround I've been able to find is to lay out an editor. If there is an editor within the UI, this global key handling works reliably as expected.

This inconsistency makes it difficult to build keyboard shortcuts that work reliably when your app is built for WASM unless you always have an editor on-screen.

Tested in Firefox 100 and Chrome 101.0.4951.41-1 on Gio version v0.0.0-20220425071242-aa14056350d6 with Go 1.18.

Status
REPORTED
Submitter
~whereswaldon
Assigned to
No-one
Submitted
6 months ago
Updated
3 months ago
Labels
No labels applied.

~theclapp 6 months ago

After pressing tab again, I have found no way to make keypresses register again

Just to check: You've tried shift-tab, yes?

~whereswaldon 6 months ago

~theclapp You're right that I can get focus back with shift-tab. I indeed had not tried that, expecting focus to cycle back with enough presses of tab. :D

However, the core issue is that using a naked key.InputOp for shortcut handling doesn't work in WASM unless you either tab to focus it or create an editor. I think this is either a bug or a really unfortunate behavior difference.

~eliasnaur 6 months ago

On WASM we create and use an <input> element for both IME and key events. Perhaps there's a more direct way to receive key events.

~whereswaldon 5 months ago

Yeah, this just bit me as I attempted to better document how key event propagation works in the Architecture document. Here is my branch of the website with the changes. My example works well on desktop, but I can't seem to get key events to work properly when it's embedded in the architecture page. I ran out of time to investigate this for now though.

~atomgardner 3 months ago

Hi ~whereswaldon—I've since found a better workaround than the press-tab-and-pray: add a key.FocusOp and a key.SoftKeyboardOp after the key.InputOp.

This seems to give the desired behaviour on desktop FF and Chrome, but mobile browsers still have some problems.

~whereswaldon 3 months ago

Thanks for the tip! I'm afraid it doesn't solve my use-case though. Adding the soft keyboard op does help me gain key focus, but seems to break other things. Branch for the curious. It's a bummer though, because until we figure this out I can't publish a good example for key input in the architecture doc.

~atomgardner 3 months ago

~whereswaldon, what breaks?

The workaround below was suggested by ~inkeliz, but I don't think I could get it working properly.

diff --git a/app/os_js.go b/app/os_js.go
index 7eb64d56..dd92224f 100644
--- a/app/os_js.go
+++ b/app/os_js.go
@@ -172,12 +172,9 @@ func (w *window) addEventListeners() {
                return nil
        })
        w.addEventListener(w.window, "popstate", func(this js.Value, args []js.Value) interface{} {
-               ev := &system.CommandEvent{Type: system.CommandBack}
-               w.w.Event(ev)
-               if ev.Cancel {
+               if w.w.Event(&key.Event{Name: key.NameBack}) {
                        return w.browserHistory.Call("forward")
                }
-
                return w.browserHistory.Call("back")
        })
        w.addEventListener(w.document, "visibilitychange", func(this js.Value, args []js.Value) interface{} {
@@ -259,11 +256,11 @@ func (w *window) addEventListeners() {
                w.blur()
                return nil
        })
-       w.addEventListener(w.tarea, "keydown", func(this js.Value, args []js.Value) interface{} {
+       w.addEventListener(w.window, "keydown", func(this js.Value, args []js.Value) interface{} {
                w.keyEvent(args[0], key.Press)
                return nil
        })
-       w.addEventListener(w.tarea, "keyup", func(this js.Value, args []js.Value) interface{} {
+       w.addEventListener(w.window, "keyup", func(this js.Value, args []js.Value) interface{} {
                w.keyEvent(args[0], key.Release)
                return nil
        })
@@ -276,7 +273,7 @@ func (w *window) addEventListeners() {
                w.flushInput()
                return nil
        })
-       w.addEventListener(w.tarea, "input", func(this js.Value, args []js.Value) interface{} {
+       w.addEventListener(w.window, "input", func(this js.Value, args []js.Value) interface{} {
                if w.composing {
                        return nil
                }

~whereswaldon 3 months ago

Try

go run ./include/files/architecture/ key-input-tree

On this code: https://git.sr.ht/~eliasnaur/giouiorg/log/key-input

Should work fine, and let you interact with certain areas using certain keys.

Then run:

go generate ./...
go run ./cmd/giouiorg

Open localhost:8080 in your browser and navigate to the input section of the architecture document. At the bottom you can find that same example, but now it doesn't get keyboard input properly. It's not a useful example of key event management because the key events don't get handled correctly. I suspect something to do with the iframe, but I don't know.

Register here or Log in to comment, or comment via email.