Key events are being received by children, even when parent has focus

In the latest main (at least in v0.0.0-20230512135434-8571b25ff7cb), when a parent has focus, key.Events still arrive to children for some reason. This can be tested e.g. by modifying the key-input-tree example from giouiorg/include/files/architecture/main.go by making the second child respond only to "A" presses, like so:

func doKeyTree(ops *op.Ops, q event.Queue) {
	// Process events that arrived between the last frame and this one for every tag.
	for _, tag := range []*bool{&keyRoot, &keyChild1, &keyChild2} {
		for _, ev := range q.Events(tag) {
			switch ev := ev.(type) {
			case pointer.Event:
				switch ev.Type {
				case pointer.Release:
					// Request focus on this tag if the mouse click ended in our area.
					key.FocusOp{Tag: tag}.Add(ops)
			case key.FocusEvent:
				// If this tag is focused, update the focused variable.
				if ev.Focus {
					focused = tag
				} else if focused == tag {
					focused = nil
			case key.Event:
				// If we got a key.Event, it means that we are the foremost
				// handler for that key (based on the contents of our
				// key.InputOp's key.Set).
				*tag = ev.State == key.Press

	// If nothing is focused, focus the root:
	if focused == nil {
		key.FocusOp{Tag: &keyRoot}.Add(ops)
		key.SoftKeyboardOp{Show: true}.Add(ops)

	// Confine the rootArea of interest to a 200x200 rectangle.
	rootRect := clip.Rect(image.Rect(0, 0, 200, 200))
	rootArea := rootRect.Push(ops)
	keyDisplayForTag(ops, enterAndSpaceKeys, &keyRoot, rootRect)

	// Any clip areas we add before Pop-ing the root area
	// are considered its children.
	child1Rect := clip.Rect(image.Rect(25, 25, 175, 100))
	child1Area := child1Rect.Push(ops)
	keyDisplayForTag(ops, spaceKey, &keyChild1, child1Rect)

	child2Rect := clip.Rect(image.Rect(100, 25, 175, 175))
	child2Area := child2Rect.Push(ops)
	keyDisplayForTag(ops, "A", &keyChild2, child2Rect) // THIS IS THE ONLY LINE I MODIFIED

	// Now anything we add is _not_ a child of the rootArea.

If the large widget (parent widget) has focus, the child 2 still get the "A" presses. This cannot be right.

Assigned to
6 months ago
6 months ago
No labels applied.

~whereswaldon 6 months ago

I replicated the behavior and bisected it to this commit:

28c206fc78c76b1481fc3ed4c28ce3562ce424ba is the first bad commit
commit 28c206fc78c76b1481fc3ed4c28ce3562ce424ba
Author: Elias Naur <mail@eliasnaur.com>
Date:   Wed Jul 20 10:37:28 2022 +0200

    io/router: try all handlers if a key don't match the focus ancestor tree

    When a key.InputOp is focused, a key.Event is matched to it and its ancestors.
    If there is no focus, every handler is matched.
    This change always matches to every handler, after checking the focus and
    its ancestors.

    Signed-off-by: Elias Naur <mail@eliasnaur.com>

 io/router/key_test.go | 4 ++--
 io/router/router.go   | 6 ++++++
 2 files changed, 8 insertions(+), 2 deletions(-)

Reading the commit description, it seems that this behavior is deliberate, but I lack the context on why it was made. ~eliasnaur can you comment on this?

~eliasnaur 6 months ago

I don't remember the intention, but I suppose the offending change can be reverted now that topmost handlers act as backstops for key.Events which is a better behaviour.

FWIW, I can't seem to find this key-input-tree example in main.go. What did I miss?

~eliasnaur REPORTED FIXED 6 months ago

Elias Naur referenced this ticket in commit e3ef98d.

~whereswaldon 6 months ago

FWIW, I can't seem to find this key-input-tree example in main.go. What did I miss?

It's on the key-input branch. I can't publish it because the example doesn't work in the WASM environment. I think the use of an iframe messes up the way we do keyboard focus or something. There's some related discussion in #415.

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