io/router,widget: give every key.InputOp a chance to process events

If the currently focused handler don't want the key event, try every
other handler, from top to bottom. This change requires widgets to
only react when focused.

Fixes: https://todo.sr.ht/~eliasnaur/gio/406
Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2022-04-23 15:36:45 +02:00
parent 0273203743
commit 2381c5ad70
4 changed files with 6 additions and 35 deletions
+1 -17
View File
@@ -333,32 +333,16 @@ func TestKeyRouting(t *testing.T) {
key.InputOp{Tag: &handlers[2], Keys: "A"}.Add(ops) key.InputOp{Tag: &handlers[2], Keys: "A"}.Add(ops)
cl1.Pop() cl1.Pop()
key.FocusOp{Tag: &handlers[2]}.Add(ops)
r.Frame(ops) r.Frame(ops)
A, B := key.Event{Name: "A"}, key.Event{Name: "B"} A, B := key.Event{Name: "A"}, key.Event{Name: "B"}
r.Queue(A, B) r.Queue(A, B)
assertKeyEvent(t, r.Events(&handlers[2]), true, A) assertKeyEvent(t, r.Events(&handlers[2]), false, A)
assertKeyEvent(t, r.Events(&handlers[1]), false, B) assertKeyEvent(t, r.Events(&handlers[1]), false, B)
assertKeyEvent(t, r.Events(&handlers[0]), false) assertKeyEvent(t, r.Events(&handlers[0]), false)
} }
func TestTopLevelInputOp(t *testing.T) {
h := new(int)
ops := new(op.Ops)
r := new(Router)
key.InputOp{Tag: h, Keys: "A"}.Add(ops)
r.Frame(ops)
A := key.Event{Name: "A"}
r.Queue(A)
assertKeyEvent(t, r.Events(h), false, A)
}
func assertKeyEvent(t *testing.T, events []event.Event, expected bool, expectedInputs ...event.Event) { func assertKeyEvent(t *testing.T, events []event.Event, expected bool, expectedInputs ...event.Event) {
t.Helper() t.Helper()
var evtFocus int var evtFocus int
+3 -16
View File
@@ -182,25 +182,12 @@ func rangeNorm(r key.Range) key.Range {
func (q *Router) queueKeyEvent(e key.Event) { func (q *Router) queueKeyEvent(e key.Event) {
kq := &q.key.queue kq := &q.key.queue
f := q.key.queue.focus if f := q.key.queue.focus; f != nil && kq.Accepts(f, e) {
a := 0 // Root area q.handlers.Add(f, e)
if f != nil { return
if kq.Accepts(f, e) {
q.handlers.Add(f, e)
return
}
a = kq.AreaFor(f)
} }
pq := &q.pointer.queue pq := &q.pointer.queue
idx := len(pq.hitTree) - 1 idx := len(pq.hitTree) - 1
// Locate first potential receiver.
for idx != -1 {
n := &pq.hitTree[idx]
if n.area == a {
break
}
idx--
}
for idx != -1 { for idx != -1 {
n := &pq.hitTree[idx] n := &pq.hitTree[idx]
idx = n.next idx = n.next
+1 -1
View File
@@ -166,7 +166,7 @@ func (b *Clickable) update(gtx layout.Context) {
case key.FocusEvent: case key.FocusEvent:
b.focused = e.Focus b.focused = e.Focus
case key.Event: case key.Event:
if e.State != key.Release { if !b.focused || e.State != key.Release {
break break
} }
if e.Name != key.NameReturn && e.Name != key.NameSpace { if e.Name != key.NameReturn && e.Name != key.NameSpace {
+1 -1
View File
@@ -98,7 +98,7 @@ func (e *Enum) Layout(gtx layout.Context, k string, content layout.Widget) layou
e.focused = false e.focused = false
} }
case key.Event: case key.Event:
if ev.State != key.Release { if !e.focused || ev.State != key.Release {
break break
} }
if ev.Name != key.NameEnter && ev.Name != key.NameSpace { if ev.Name != key.NameEnter && ev.Name != key.NameSpace {