diff --git a/gesture/gesture.go b/gesture/gesture.go index 3fc56c60..7d37e1a7 100644 --- a/gesture/gesture.go +++ b/gesture/gesture.go @@ -225,6 +225,9 @@ func (s *Scroll) Scroll(cfg unit.Converter, q event.Queue, t time.Time, axis Axi s.dragging = false s.grab = false case pointer.Scroll: + if e.Priority < pointer.Foremost { + continue + } switch s.axis { case Horizontal: s.scroll += e.Scroll.X diff --git a/io/pointer/pointer.go b/io/pointer/pointer.go index 7d4c74b1..3344d6ba 100644 --- a/io/pointer/pointer.go +++ b/io/pointer/pointer.go @@ -113,6 +113,9 @@ const ( // Shared priority is for handlers that // are part of a matching set larger than 1. Shared Priority = iota + // Foremost priority is like Shared, but the + // handler is the foremost of the matching set. + Foremost // Grabbed is used for matching sets of size 1. Grabbed ) @@ -199,6 +202,8 @@ func (p Priority) String() string { switch p { case Shared: return "Shared" + case Foremost: + return "Foremost" case Grabbed: return "Grabbed" default: diff --git a/io/router/pointer.go b/io/router/pointer.go index de64d512..9afdb22d 100644 --- a/io/router/pointer.go +++ b/io/router/pointer.go @@ -262,29 +262,34 @@ func (q *pointerQueue) Push(e pointer.Event, events *handlerEvents) { } func (q *pointerQueue) deliverEvent(p *pointerInfo, events *handlerEvents, e pointer.Event) { + foremost := true for _, k := range p.handlers { h := q.handlers[k] e := e if p.pressed && len(p.handlers) == 1 { e.Priority = pointer.Grabbed + } else if foremost { + e.Priority = pointer.Foremost } + e.Position = h.transform.Invert().Transform(e.Position) - addPointerEvent(events, k, e, h.types) - - // Only deliver scroll events to the foremost handler. - if e.Type == pointer.Scroll && e.Type&h.types != 0 { - return + if e.Type&h.types == e.Type { + foremost = false + events.Add(k, e) } } } func (q *pointerQueue) deliverEnterLeaveEvents(p *pointerInfo, events *handlerEvents, e pointer.Event) { + foremost := true for _, k := range p.handlers { h := q.handlers[k] e := e if p.pressed && len(p.handlers) == 1 { e.Priority = pointer.Grabbed + } else if foremost { + e.Priority = pointer.Foremost } // Hit-test to deliver Enter/Leave events. Consider non-mouse @@ -304,18 +309,16 @@ func (q *pointerQueue) deliverEnterLeaveEvents(p *pointerInfo, events *handlerEv case !hit && entered != -1: p.entered = append(p.entered[:entered], p.entered[entered+1:]...) e.Type = pointer.Leave - addPointerEvent(events, k, e, h.types) case hit && entered == -1: p.entered = append(p.entered, k) e.Type = pointer.Enter - addPointerEvent(events, k, e, h.types) + default: + continue + } + if e.Type&h.types == e.Type { + foremost = false + events.Add(k, e) } - } -} - -func addPointerEvent(events *handlerEvents, k event.Tag, e pointer.Event, types pointer.Type) { - if e.Type&types == e.Type { - events.Add(k, e) } } diff --git a/io/router/pointer_test.go b/io/router/pointer_test.go index 12e3c4c9..cf9fbc37 100644 --- a/io/router/pointer_test.go +++ b/io/router/pointer_test.go @@ -125,7 +125,7 @@ func TestPointerTypes(t *testing.T) { assertEventSequence(t, r.Events(handler), pointer.Cancel, pointer.Press, pointer.Release) } -func TestPointerScroll(t *testing.T) { +func TestPointerPriority(t *testing.T) { handler1 := new(int) handler2 := new(int) var ops op.Ops @@ -139,7 +139,7 @@ func TestPointerScroll(t *testing.T) { var r Router r.Frame(&ops) r.Add( - // Hit handler 2. + // Hit both handlers. pointer.Event{ Type: pointer.Scroll, Position: f32.Point{ @@ -164,8 +164,12 @@ func TestPointerScroll(t *testing.T) { }, }, ) - assertEventSequence(t, r.Events(handler1), pointer.Cancel, pointer.Scroll) - assertEventSequence(t, r.Events(handler2), pointer.Cancel, pointer.Scroll) + hev1 := r.Events(handler1) + hev2 := r.Events(handler2) + assertEventSequence(t, hev1, pointer.Cancel, pointer.Scroll, pointer.Scroll) + assertEventSequence(t, hev2, pointer.Cancel, pointer.Scroll) + assertEventPriorities(t, hev1, pointer.Shared, pointer.Shared, pointer.Foremost) + assertEventPriorities(t, hev2, pointer.Shared, pointer.Foremost) } func TestPointerEnterLeave(t *testing.T) { @@ -463,7 +467,7 @@ func pointerTypes(events []event.Event) []pointer.Type { return types } -// assertEventSequence ensures that the provided actualEvents match the expected event types +// assertEventSequence checks that the provided events match the expected pointer event types // in the provided order. func assertEventSequence(t *testing.T, events []event.Event, expected ...pointer.Type) { t.Helper() @@ -473,6 +477,20 @@ func assertEventSequence(t *testing.T, events []event.Event, expected ...pointer } } +// assertEventPriorities checks that the pointer.Event priorities of events match prios. +func assertEventPriorities(t *testing.T, events []event.Event, prios ...pointer.Priority) { + t.Helper() + var got []pointer.Priority + for _, e := range events { + if e, ok := e.(pointer.Event); ok { + got = append(got, e.Priority) + } + } + if !reflect.DeepEqual(got, prios) { + t.Errorf("expected priorities %v, got %v", prios, got) + } +} + func BenchmarkRouterAdd(b *testing.B) { // Set this to the number of overlapping handlers that you want to // evaluate performance for. Typical values for the example applications