From 1bcbaa8137f6128cc77b44d94c04d2c45e11afad Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Thu, 19 Oct 2023 17:32:55 -0500 Subject: [PATCH] io/input,io/pointer: [API] make pointer grab a command Signed-off-by: Elias Naur --- gesture/gesture.go | 10 ++------- internal/ops/ops.go | 2 +- io/input/pointer.go | 48 +++++++++++++++++++--------------------- io/input/pointer_test.go | 6 +++-- io/input/router.go | 13 ++++++----- io/pointer/pointer.go | 24 +++++++++++--------- 6 files changed, 50 insertions(+), 53 deletions(-) diff --git a/gesture/gesture.go b/gesture/gesture.go index e6770551..d95e0a38 100644 --- a/gesture/gesture.go +++ b/gesture/gesture.go @@ -107,7 +107,6 @@ type Drag struct { pressed bool pid pointer.ID start f32.Point - grab bool } // Scroll detects scroll gestures and reduces them to @@ -119,7 +118,6 @@ type Scroll struct { estimator fling.Extrapolation flinger fling.Animation pid pointer.ID - grab bool last int // Leftover scroll. scroll float32 @@ -253,7 +251,6 @@ func (ClickEvent) ImplementsEvent() {} func (s *Scroll) Add(ops *op.Ops, bounds image.Rectangle) { oph := pointer.InputOp{ Tag: s, - Grab: s.grab, Kinds: pointer.Press | pointer.Drag | pointer.Release | pointer.Scroll, ScrollBounds: bounds, } @@ -308,7 +305,6 @@ func (s *Scroll) Update(cfg unit.Metric, q input.Source, t time.Time, axis Axis) fallthrough case pointer.Cancel: s.dragging = false - s.grab = false case pointer.Scroll: switch s.axis { case Horizontal: @@ -330,7 +326,7 @@ func (s *Scroll) Update(cfg unit.Metric, q input.Source, t time.Time, axis Axis) if e.Priority < pointer.Grabbed { slop := cfg.Dp(touchSlop) if dist := dist; dist >= slop || -slop >= dist { - s.grab = true + q.Queue(pointer.GrabCmd{Tag: s, ID: e.PointerID}) } } else { s.last = v @@ -366,7 +362,6 @@ func (s *Scroll) State() ScrollState { func (d *Drag) Add(ops *op.Ops) { pointer.InputOp{ Tag: d, - Grab: d.grab, Kinds: pointer.Press | pointer.Drag | pointer.Release, }.Add(ops) } @@ -408,7 +403,7 @@ func (d *Drag) Update(cfg unit.Metric, q input.Source, axis Axis) []pointer.Even diff := e.Position.Sub(d.start) slop := cfg.Dp(touchSlop) if diff.X*diff.X+diff.Y*diff.Y > float32(slop*slop) { - d.grab = true + q.Queue(pointer.GrabCmd{Tag: d, ID: e.PointerID}) } } case pointer.Release, pointer.Cancel: @@ -417,7 +412,6 @@ func (d *Drag) Update(cfg unit.Metric, q input.Source, axis Axis) []pointer.Even continue } d.dragging = false - d.grab = false } events = append(events, e) diff --git a/internal/ops/ops.go b/internal/ops/ops.go index 20e559f0..c4f0cd80 100644 --- a/internal/ops/ops.go +++ b/internal/ops/ops.go @@ -140,7 +140,7 @@ const ( TypeLinearGradientLen = 1 + 8*2 + 4*2 TypePassLen = 1 TypePopPassLen = 1 - TypePointerInputLen = 1 + 1 + 1*2 + 2*4 + 2*4 + TypePointerInputLen = 1 + 1*2 + 2*4 + 2*4 TypeSourceLen = 1 TypeTargetLen = 1 TypeKeyInputLen = 1 + 1 diff --git a/io/input/pointer.go b/io/input/pointer.go index 770f938f..cb7156d6 100644 --- a/io/input/pointer.go +++ b/io/input/pointer.go @@ -63,10 +63,9 @@ type pointerInfo struct { } type pointerHandler struct { - area int - active bool - wantsGrab bool - types pointer.Kind + area int + active bool + types pointer.Kind // min and max horizontal/vertical scroll scrollRange image.Rectangle @@ -269,6 +268,26 @@ func (c *pointerCollector) actionInputOp(act system.Action) { area.action = act } +func (q *pointerQueue) grab(req pointer.GrabCmd, events *handlerEvents) { + for _, p := range q.pointers { + if !p.pressed || p.id != req.ID { + continue + } + for i, k2 := range p.handlers { + if k2 == req.Tag { + // Drop other handlers that lost their grab. + dropped := q.scratch[:0] + dropped = append(dropped, p.handlers[:i]...) + dropped = append(dropped, p.handlers[i+1:]...) + for _, tag := range dropped { + q.dropHandler(events, tag) + } + return + } + } + } +} + func (c *pointerCollector) inputOp(op pointer.InputOp, events *handlerEvents) { areaID := c.currentArea() area := &c.q.areas[areaID] @@ -281,7 +300,6 @@ func (c *pointerCollector) inputOp(op pointer.InputOp, events *handlerEvents) { } area.semantic.valid = area.semantic.content.gestures != 0 h := c.newHandler(op.Tag, events) - h.wantsGrab = h.wantsGrab || op.Grab h.types = h.types | op.Kinds h.scrollRange = op.ScrollBounds } @@ -560,7 +578,6 @@ func (q *pointerQueue) reset() { // Reset handler. h.active = false h.area = -1 - h.wantsGrab = false h.types = 0 h.sourceMimes = h.sourceMimes[:0] h.targetMimes = h.targetMimes[:0] @@ -596,25 +613,6 @@ func (q *pointerQueue) Frame(events *handlerEvents) { q.dropHandler(nil, k) delete(q.handlers, k) } - if h.wantsGrab { - for _, p := range q.pointers { - if !p.pressed { - continue - } - for i, k2 := range p.handlers { - if k2 == k { - // Drop other handlers that lost their grab. - dropped := q.scratch[:0] - dropped = append(dropped, p.handlers[:i]...) - dropped = append(dropped, p.handlers[i+1:]...) - for _, tag := range dropped { - q.dropHandler(events, tag) - } - break - } - } - } - } } for i := range q.pointers { p := &q.pointers[i] diff --git a/io/input/pointer_test.go b/io/input/pointer_test.go index 8f6ff6c3..fb9e8ae4 100644 --- a/io/input/pointer_test.go +++ b/io/input/pointer_test.go @@ -86,7 +86,7 @@ func TestPointerGrab(t *testing.T) { types := pointer.Press | pointer.Release - pointer.InputOp{Tag: handler1, Kinds: types, Grab: true}.Add(&ops) + pointer.InputOp{Tag: handler1, Kinds: types}.Add(&ops) pointer.InputOp{Tag: handler2, Kinds: types}.Add(&ops) pointer.InputOp{Tag: handler3, Kinds: types}.Add(&ops) @@ -98,6 +98,7 @@ func TestPointerGrab(t *testing.T) { Position: f32.Pt(50, 50), }, ) + r.Source().Queue(pointer.GrabCmd{Tag: handler1}) assertEventPointerTypeSequence(t, r.Events(handler1), pointer.Cancel, pointer.Press) assertEventPointerTypeSequence(t, r.Events(handler2), pointer.Cancel, pointer.Press) assertEventPointerTypeSequence(t, r.Events(handler3), pointer.Cancel, pointer.Press) @@ -120,7 +121,7 @@ func TestPointerGrabSameHandlerTwice(t *testing.T) { types := pointer.Press | pointer.Release - pointer.InputOp{Tag: handler1, Kinds: types, Grab: true}.Add(&ops) + pointer.InputOp{Tag: handler1, Kinds: types}.Add(&ops) pointer.InputOp{Tag: handler1, Kinds: types}.Add(&ops) pointer.InputOp{Tag: handler2, Kinds: types}.Add(&ops) @@ -132,6 +133,7 @@ func TestPointerGrabSameHandlerTwice(t *testing.T) { Position: f32.Pt(50, 50), }, ) + r.Source().Queue(pointer.GrabCmd{Tag: handler1}) assertEventPointerTypeSequence(t, r.Events(handler1), pointer.Cancel, pointer.Press) assertEventPointerTypeSequence(t, r.Events(handler2), pointer.Cancel, pointer.Press) r.Frame(&ops) diff --git a/io/input/router.go b/io/input/router.go index 7772ddad..39e531df 100644 --- a/io/input/router.go +++ b/io/input/router.go @@ -226,6 +226,8 @@ func (q *Router) executeCommands() { q.cqueue.ProcessWriteClipboard(req) case clipboard.ReadCmd: q.cqueue.ProcessReadClipboard(req.Tag) + case pointer.GrabCmd: + q.pointer.queue.grab(req, &q.handlers) } } q.commands = nil @@ -470,16 +472,15 @@ func (q *Router) collect() { case ops.TypePointerInput: op := pointer.InputOp{ Tag: encOp.Refs[0].(event.Tag), - Grab: encOp.Data[1] != 0, - Kinds: pointer.Kind(bo.Uint16(encOp.Data[2:])), + Kinds: pointer.Kind(bo.Uint16(encOp.Data[1:])), ScrollBounds: image.Rectangle{ Min: image.Point{ - X: int(int32(bo.Uint32(encOp.Data[4:]))), - Y: int(int32(bo.Uint32(encOp.Data[8:]))), + X: int(int32(bo.Uint32(encOp.Data[3:]))), + Y: int(int32(bo.Uint32(encOp.Data[7:]))), }, Max: image.Point{ - X: int(int32(bo.Uint32(encOp.Data[12:]))), - Y: int(int32(bo.Uint32(encOp.Data[16:]))), + X: int(int32(bo.Uint32(encOp.Data[11:]))), + Y: int(int32(bo.Uint32(encOp.Data[15:]))), }, }, } diff --git a/io/pointer/pointer.go b/io/pointer/pointer.go index 962960df..8c8ffecb 100644 --- a/io/pointer/pointer.go +++ b/io/pointer/pointer.go @@ -60,9 +60,6 @@ type PassStack struct { // events. type InputOp struct { Tag event.Tag - // Grab, if set, request that the handler get - // Grabbed priority. - Grab bool // Kinds is a bitwise-or of event types to receive. Kinds Kind // ScrollBounds describe the maximum scrollable distances in both @@ -73,6 +70,12 @@ type InputOp struct { ScrollBounds image.Rectangle } +// GrabCmd requests a pointer grab on the pointer identified by ID. +type GrabCmd struct { + Tag event.Tag + ID ID +} + type ID uint16 // Kind of an Event. @@ -250,15 +253,12 @@ func (op InputOp) Add(o *op.Ops) { } data := ops.Write1(&o.Internal, ops.TypePointerInputLen, op.Tag) data[0] = byte(ops.TypePointerInput) - if op.Grab { - data[1] = 1 - } bo := binary.LittleEndian - bo.PutUint16(data[2:], uint16(op.Kinds)) - bo.PutUint32(data[4:], uint32(op.ScrollBounds.Min.X)) - bo.PutUint32(data[8:], uint32(op.ScrollBounds.Min.Y)) - bo.PutUint32(data[12:], uint32(op.ScrollBounds.Max.X)) - bo.PutUint32(data[16:], uint32(op.ScrollBounds.Max.Y)) + bo.PutUint16(data[1:], uint16(op.Kinds)) + bo.PutUint32(data[3:], uint32(op.ScrollBounds.Min.X)) + bo.PutUint32(data[7:], uint32(op.ScrollBounds.Min.Y)) + bo.PutUint32(data[11:], uint32(op.ScrollBounds.Max.X)) + bo.PutUint32(data[15:], uint32(op.ScrollBounds.Max.Y)) } func (t Kind) String() string { @@ -404,3 +404,5 @@ func (c Cursor) String() string { } func (Event) ImplementsEvent() {} + +func (GrabCmd) ImplementsCommand() {}