diff --git a/gesture/gesture.go b/gesture/gesture.go index c43b3210e..977658f32 100644 --- a/gesture/gesture.go +++ b/gesture/gesture.go @@ -37,6 +37,8 @@ type Click struct { clicks int // pressed tracks whether the pointer is pressed. pressed bool + // Buttons tracks which buttons are pressed. + Buttons pointer.Buttons // entered tracks whether the pointer is inside the gesture. entered bool // pid is the pointer.ID. @@ -53,6 +55,7 @@ type ClickEvent struct { Position f32.Point Source pointer.Source Modifiers key.Modifiers + Buttons pointer.Buttons // NumClicks records successive clicks occurring // within a short duration of each other. NumClicks int @@ -131,7 +134,7 @@ func (c *Click) Hovered() bool { return c.entered } -// Pressed returns whether a pointer is pressing. +// Pressed returns whether a pointer is pressing the left mouse button. func (c *Click) Pressed() bool { return c.pressed } @@ -146,10 +149,12 @@ func (c *Click) Events(q event.Queue) []ClickEvent { } switch e.Type { case pointer.Release: - if !c.pressed || c.pid != e.PointerID { + if c.pid != e.PointerID { break } - c.pressed = false + b := c.Buttons ^ e.Buttons // the released button + c.pressed = e.Buttons&pointer.ButtonPrimary > 0 + c.Buttons = e.Buttons if c.entered { if e.Time-c.clickedAt < doubleClickDuration { c.clicks++ @@ -157,22 +162,21 @@ func (c *Click) Events(q event.Queue) []ClickEvent { c.clicks = 1 } c.clickedAt = e.Time - events = append(events, ClickEvent{Type: TypeClick, Position: e.Position, Source: e.Source, Modifiers: e.Modifiers, NumClicks: c.clicks}) + events = append(events, ClickEvent{Type: TypeClick, Position: e.Position, Source: e.Source, Buttons: b, Modifiers: e.Modifiers, NumClicks: c.clicks}) } else { - events = append(events, ClickEvent{Type: TypeCancel}) + events = append(events, ClickEvent{Type: TypeCancel, Buttons: b}) } case pointer.Cancel: - wasPressed := c.pressed - c.pressed = false + b := e.Buttons ^ c.Buttons + wasPressed := c.Buttons.Contain(b) + c.pressed = e.Buttons&pointer.ButtonPrimary > 0 + c.Buttons = e.Buttons c.entered = false if wasPressed { - events = append(events, ClickEvent{Type: TypeCancel}) + events = append(events, ClickEvent{Type: TypeCancel, Buttons: b}) } case pointer.Press: - if c.pressed { - break - } - if e.Source == pointer.Mouse && e.Buttons != pointer.ButtonPrimary { + if e.Source == pointer.Mouse && e.Buttons == c.Buttons { break } if !c.entered { @@ -181,17 +185,17 @@ func (c *Click) Events(q event.Queue) []ClickEvent { if c.pid != e.PointerID { break } - c.pressed = true - events = append(events, ClickEvent{Type: TypePress, Position: e.Position, Source: e.Source, Modifiers: e.Modifiers}) + c.pressed = e.Buttons&pointer.ButtonPrimary > 0 + events = append(events, ClickEvent{Type: TypePress, Position: e.Position, Source: e.Source, Buttons: e.Buttons, Modifiers: e.Modifiers}) case pointer.Leave: - if !c.pressed { + if !c.Buttons.Contain(c.Buttons ^ e.Buttons) { c.pid = e.PointerID } if c.pid == e.PointerID { c.entered = false } case pointer.Enter: - if !c.pressed { + if !c.Buttons.Contain(c.Buttons ^ e.Buttons) { c.pid = e.PointerID } if c.pid == e.PointerID { diff --git a/gesture/gesture_test.go b/gesture/gesture_test.go index 3c9f03837..177d26526 100644 --- a/gesture/gesture_test.go +++ b/gesture/gesture_test.go @@ -35,6 +35,21 @@ func TestMouseClicks(t *testing.T) { 100*time.Millisecond+doubleClickDuration+1), clicks: []int{1, 1}, }, + { + label: "left and right clicks mixed", + events: mouseMultiButtonClickEvents( + 100*time.Millisecond, + 100*time.Millisecond+doubleClickDuration*1+1, + 100*time.Millisecond+doubleClickDuration*2+1, + 100*time.Millisecond+doubleClickDuration*3+1, + 100*time.Millisecond+doubleClickDuration*4+1, + 100*time.Millisecond+doubleClickDuration*5+1, + 100*time.Millisecond+doubleClickDuration*6+1, + 100*time.Millisecond+doubleClickDuration*7+1, + 100*time.Millisecond+doubleClickDuration*8+1, + ), + clicks: []int{1, 1, 1, 1, 1, 1, 1, 1, 1}, + }, } { t.Run(tc.label, func(t *testing.T) { var click Click @@ -85,3 +100,49 @@ func filterMouseClicks(events []ClickEvent) []ClickEvent { } return clicks } + +func mouseMultiButtonClickEvents(times ...time.Duration) []event.Event { + events := make([]event.Event, 0) + numSecondaryClick := 0 + numPrimaryClick := 0 + for i, _ := range times { + if i%2 == 0 { + press := pointer.Event{ + Type: pointer.Press, + Source: pointer.Mouse, + Buttons: pointer.ButtonPrimary, + } + numPrimaryClick++ + events = append(events, press) + } else { + press := pointer.Event{ + Type: pointer.Press, + Source: pointer.Mouse, + Buttons: pointer.ButtonSecondary, + } + numSecondaryClick++ + events = append(events, press) + } + } + i := 0 + for ; i < numPrimaryClick; i++ { + release := pointer.Event{ + Type: pointer.Release, + Source: pointer.Mouse, + Buttons: pointer.ButtonPrimary, + Time: times[i], + } + events = append(events, release) + } + for ; i < numSecondaryClick+numPrimaryClick; i++ { + release := pointer.Event{ + Type: pointer.Release, + Source: pointer.Mouse, + Buttons: pointer.ButtonSecondary, + Time: times[i], + } + + events = append(events, release) + } + return events +}