Also throttling repetitive events to focus and widgets.

This commit is contained in:
Jakub Sobon 2019-02-21 01:44:31 -05:00
parent 60aaa7d8bb
commit 006c021f63
No known key found for this signature in database
GPG Key ID: F2451A77FB05D3B7
3 changed files with 45 additions and 24 deletions

View File

@ -250,11 +250,15 @@ func (c *Container) Subscribe(eds *event.DistributionSystem) {
c.mu.Lock()
defer c.mu.Unlock()
// maxReps is the maximum number of repetitive events towards widgets
// before we throttle them.
const maxReps = 10
root := rootCont(c)
// Subscriber the container itself in order to track keyboard focus.
eds.Subscribe([]terminalapi.Event{&terminalapi.Mouse{}}, func(ev terminalapi.Event) {
root.updateFocus(ev.(*terminalapi.Mouse))
})
}, event.MaxRepetitive(0)) // One event is enough to change the focus.
// Subscribe any widgets that specify Keyboard or Mouse in their options.
var errStr string
@ -266,7 +270,7 @@ func (c *Container) Subscribe(eds *event.DistributionSystem) {
if err := c.keyboardToWidget(ev.(*terminalapi.Keyboard)); err != nil {
eds.Event(terminalapi.NewErrorf("failed to send keyboard event %v to widget %T: %v", ev, c.opts.widget, err))
}
})
}, event.MaxRepetitive(maxReps))
}
if wOpt.WantMouse {
@ -274,7 +278,7 @@ func (c *Container) Subscribe(eds *event.DistributionSystem) {
if err := c.mouseToWidget(ev.(*terminalapi.Mouse)); err != nil {
eds.Event(terminalapi.NewErrorf("failed to send mouse event %v to widget %T: %v", ev, c.opts.widget, err))
}
})
}, event.MaxRepetitive(maxReps))
}
}
return nil

View File

@ -294,8 +294,9 @@ func TestFocusTrackerMouse(t *testing.T) {
tests := []struct {
desc string
// Can be either the mouse event or a time.Duration to pause for.
events []*terminalapi.Mouse
wantFocused contLoc
events []*terminalapi.Mouse
wantFocused contLoc
wantProcessed int
}{
{
desc: "initially the root is focused",
@ -307,7 +308,8 @@ func TestFocusTrackerMouse(t *testing.T) {
{Position: image.Point{0, 0}, Button: mouse.ButtonLeft},
{Position: image.Point{1, 1}, Button: mouse.ButtonRelease},
},
wantFocused: contLocLeft,
wantFocused: contLocLeft,
wantProcessed: 2,
},
{
desc: "click and release moves focus to the right",
@ -315,7 +317,8 @@ func TestFocusTrackerMouse(t *testing.T) {
{Position: image.Point{5, 5}, Button: mouse.ButtonLeft},
{Position: image.Point{6, 6}, Button: mouse.ButtonRelease},
},
wantFocused: contLocRight,
wantFocused: contLocRight,
wantProcessed: 2,
},
{
desc: "click in the same container is a no-op",
@ -325,7 +328,8 @@ func TestFocusTrackerMouse(t *testing.T) {
{Position: insideRight, Button: mouse.ButtonLeft},
{Position: insideRight, Button: mouse.ButtonRelease},
},
wantFocused: contLocRight,
wantFocused: contLocRight,
wantProcessed: 4,
},
{
desc: "click in the same container and release never happens",
@ -334,7 +338,8 @@ func TestFocusTrackerMouse(t *testing.T) {
{Position: insideLeft, Button: mouse.ButtonLeft},
{Position: insideLeft, Button: mouse.ButtonRelease},
},
wantFocused: contLocLeft,
wantFocused: contLocLeft,
wantProcessed: 3,
},
{
desc: "click in the same container, release elsewhere",
@ -342,7 +347,8 @@ func TestFocusTrackerMouse(t *testing.T) {
{Position: insideRight, Button: mouse.ButtonLeft},
{Position: insideLeft, Button: mouse.ButtonRelease},
},
wantFocused: contLocRoot,
wantFocused: contLocRoot,
wantProcessed: 2,
},
{
desc: "other buttons are ignored",
@ -354,7 +360,8 @@ func TestFocusTrackerMouse(t *testing.T) {
{Position: insideLeft, Button: mouse.ButtonWheelUp},
{Position: insideLeft, Button: mouse.ButtonWheelDown},
},
wantFocused: contLocRoot,
wantFocused: contLocRoot,
wantProcessed: 6,
},
{
desc: "moving mouse with pressed button and then releasing moves focus",
@ -363,7 +370,8 @@ func TestFocusTrackerMouse(t *testing.T) {
{Position: image.Point{1, 1}, Button: mouse.ButtonLeft},
{Position: image.Point{2, 2}, Button: mouse.ButtonRelease},
},
wantFocused: contLocLeft,
wantFocused: contLocLeft,
wantProcessed: 3,
},
{
desc: "click ignored if followed by another click of the same button elsewhere",
@ -371,9 +379,9 @@ func TestFocusTrackerMouse(t *testing.T) {
{Position: insideRight, Button: mouse.ButtonLeft},
{Position: insideLeft, Button: mouse.ButtonLeft},
{Position: insideRight, Button: mouse.ButtonRelease},
{Position: insideRight, Button: mouse.ButtonRelease},
},
wantFocused: contLocRoot,
wantFocused: contLocRoot,
wantProcessed: 3,
},
{
desc: "click ignored if followed by another click of a different button",
@ -381,9 +389,9 @@ func TestFocusTrackerMouse(t *testing.T) {
{Position: insideRight, Button: mouse.ButtonLeft},
{Position: insideRight, Button: mouse.ButtonMiddle},
{Position: insideRight, Button: mouse.ButtonRelease},
{Position: insideRight, Button: mouse.ButtonRelease},
},
wantFocused: contLocRoot,
wantFocused: contLocRoot,
wantProcessed: 3,
},
}
@ -406,7 +414,7 @@ func TestFocusTrackerMouse(t *testing.T) {
eds.Event(ev)
}
if err := testevent.WaitFor(5*time.Second, func() error {
if got, want := eds.Processed(), len(tc.events); got != want {
if got, want := eds.Processed(), tc.wantProcessed; got != want {
return fmt.Errorf("the event distribution system processed %d events, want %d", got, want)
}
return nil

View File

@ -37,6 +37,10 @@ const (
// receiverModeBlock tells the receiver to block on the call to receive.
receiverModeBlock
// receiverModePause tells the receiver to pause before starting to
// receive.
receiverModePause
)
// receiver receives events from the distribution system.
@ -48,6 +52,9 @@ type receiver struct {
// events are the received events.
events []terminalapi.Event
// resumed indicates if the receiver was resumed.
resumed bool
}
// newReceiver returns a new event receiver.
@ -64,12 +71,14 @@ func (r *receiver) receive(ev terminalapi.Event) {
for {
time.Sleep(1 * time.Minute)
}
default:
r.mu.Lock()
defer r.mu.Unlock()
r.events = append(r.events, ev)
case receiverModePause:
time.Sleep(3 * time.Second)
}
r.mu.Lock()
defer r.mu.Unlock()
r.events = append(r.events, ev)
}
// getEvents returns the received events.
@ -273,7 +282,7 @@ func TestDistributionSystem(t *testing.T) {
opts: []SubscribeOption{
MaxRepetitive(0),
},
rec: newReceiver(receiverModeReceive),
rec: newReceiver(receiverModePause),
want: map[terminalapi.Event]bool{
&terminalapi.Keyboard{Key: keyboard.KeyEsc}: true,
&terminalapi.Keyboard{Key: keyboard.KeyEnter}: true,
@ -301,7 +310,7 @@ func TestDistributionSystem(t *testing.T) {
for i, sc := range tc.subCase {
gotEv := map[terminalapi.Event]bool{}
err := testevent.WaitFor(5*time.Second, func() error {
err := testevent.WaitFor(10*time.Second, func() error {
ev := sc.rec.getEvents()
want := len(sc.want)
switch got := len(ev); {