Skip to content

Commit 8041b8e

Browse files
committed
Refactor event polling code.
This centralizes much of the logic (hopefully reducing duplication) for polling events and the queue. This will make it easier to make further design changes to express a better, simpler, API to consumers. While here addressed missing logic to handle Fini correctly on Windows.
1 parent e3a99dd commit 8041b8e

File tree

5 files changed

+158
-222
lines changed

5 files changed

+158
-222
lines changed

console_win.go

Lines changed: 33 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ type cScreen struct {
3333
out syscall.Handle
3434
cancelflag syscall.Handle
3535
scandone chan struct{}
36-
evch chan Event
3736
quit chan struct{}
3837
curx int
3938
cury int
@@ -53,11 +52,11 @@ type cScreen struct {
5352
oomode uint32
5453
cells CellBuffer
5554

56-
finiOnce sync.Once
57-
5855
mouseEnabled bool
5956
wg sync.WaitGroup
57+
eventQ chan Event
6058
stopQ chan struct{}
59+
finiOnce sync.Once
6160

6261
sync.Mutex
6362
}
@@ -146,7 +145,7 @@ const (
146145
vtSgr0 = "\x1b[0m"
147146
vtBold = "\x1b[1m"
148147
vtUnderline = "\x1b[4m"
149-
vtBlink = "\x1b[5m" // Not sure this is processed
148+
vtBlink = "\x1b[5m" // Not sure if this is processed
150149
vtReverse = "\x1b[7m"
151150
vtSetFg = "\x1b[38;5;%dm"
152151
vtSetBg = "\x1b[48;5;%dm"
@@ -179,7 +178,7 @@ func NewConsoleScreen() (Screen, error) {
179178
}
180179

181180
func (s *cScreen) Init() error {
182-
s.evch = make(chan Event, 10)
181+
s.eventQ = make(chan Event, 10)
183182
s.quit = make(chan struct{})
184183
s.scandone = make(chan struct{})
185184

@@ -286,7 +285,10 @@ func (s *cScreen) EnableFocus() {}
286285
func (s *cScreen) DisableFocus() {}
287286

288287
func (s *cScreen) Fini() {
289-
s.disengage()
288+
s.finiOnce.Do(func() {
289+
close(s.quit)
290+
s.disengage()
291+
})
290292
}
291293

292294
func (s *cScreen) disengage() {
@@ -356,52 +358,6 @@ func (s *cScreen) engage() error {
356358
return nil
357359
}
358360

359-
func (s *cScreen) PostEventWait(ev Event) {
360-
s.evch <- ev
361-
}
362-
363-
func (s *cScreen) PostEvent(ev Event) error {
364-
select {
365-
case s.evch <- ev:
366-
return nil
367-
default:
368-
return ErrEventQFull
369-
}
370-
}
371-
372-
func (s *cScreen) ChannelEvents(ch chan<- Event, quit <-chan struct{}) {
373-
defer close(ch)
374-
for {
375-
select {
376-
case <-quit:
377-
return
378-
case <-s.stopQ:
379-
return
380-
case ev := <-s.evch:
381-
select {
382-
case <-quit:
383-
return
384-
case <-s.stopQ:
385-
return
386-
case ch <- ev:
387-
}
388-
}
389-
}
390-
}
391-
392-
func (s *cScreen) PollEvent() Event {
393-
select {
394-
case <-s.stopQ:
395-
return nil
396-
case ev := <-s.evch:
397-
return ev
398-
}
399-
}
400-
401-
func (s *cScreen) HasPendingEvent() bool {
402-
return len(s.evch) > 0
403-
}
404-
405361
type cursorInfo struct {
406362
size uint32
407363
visible uint32
@@ -701,6 +657,13 @@ func mrec2btns(mbtns, flags uint32) ButtonMask {
701657
return btns
702658
}
703659

660+
func (s *cScreen) postEvent(ev Event) {
661+
select {
662+
case s.eventQ <- ev:
663+
case <-s.quit:
664+
}
665+
}
666+
704667
func (s *cScreen) getConsoleInput() error {
705668
// cancelFlag comes first as WaitForMultipleObjects returns the lowest index
706669
// in the event that both events are signalled.
@@ -743,19 +706,17 @@ func (s *cScreen) getConsoleInput() error {
743706
krec.mod = getu32(rec.data[12:])
744707

745708
if krec.isdown == 0 || krec.repeat < 1 {
746-
// its a key release event, ignore it
709+
// it's a key release event, ignore it
747710
return nil
748711
}
749712
if krec.ch != 0 {
750713
// synthesized key code
751714
for krec.repeat > 0 {
752715
// convert shift+tab to backtab
753716
if mod2mask(krec.mod) == ModShift && krec.ch == vkTab {
754-
s.PostEventWait(NewEventKey(KeyBacktab, 0,
755-
ModNone))
717+
s.postEvent(NewEventKey(KeyBacktab, 0, ModNone))
756718
} else {
757-
s.PostEventWait(NewEventKey(KeyRune, rune(krec.ch),
758-
mod2mask(krec.mod)))
719+
s.postEvent(NewEventKey(KeyRune, rune(krec.ch), mod2mask(krec.mod)))
759720
}
760721
krec.repeat--
761722
}
@@ -767,8 +728,7 @@ func (s *cScreen) getConsoleInput() error {
767728
return nil
768729
}
769730
for krec.repeat > 0 {
770-
s.PostEventWait(NewEventKey(key, rune(krec.ch),
771-
mod2mask(krec.mod)))
731+
s.postEvent(NewEventKey(key, rune(krec.ch), mod2mask(krec.mod)))
772732
krec.repeat--
773733
}
774734

@@ -781,14 +741,13 @@ func (s *cScreen) getConsoleInput() error {
781741
mrec.flags = getu32(rec.data[12:])
782742
btns := mrec2btns(mrec.btns, mrec.flags)
783743
// we ignore double click, events are delivered normally
784-
s.PostEventWait(NewEventMouse(int(mrec.x), int(mrec.y), btns,
785-
mod2mask(mrec.mod)))
744+
s.postEvent(NewEventMouse(int(mrec.x), int(mrec.y), btns, mod2mask(mrec.mod)))
786745

787746
case resizeEvent:
788747
var rrec resizeRecord
789748
rrec.x = geti16(rec.data[0:])
790749
rrec.y = geti16(rec.data[2:])
791-
s.PostEventWait(NewEventResize(int(rrec.x), int(rrec.y)))
750+
s.postEvent(NewEventResize(int(rrec.x), int(rrec.y)))
792751

793752
default:
794753
}
@@ -1128,7 +1087,10 @@ func (s *cScreen) resize() {
11281087
uintptr(s.out),
11291088
uintptr(1),
11301089
uintptr(unsafe.Pointer(&r)))
1131-
_ = s.PostEvent(NewEventResize(w, h))
1090+
select {
1091+
case s.eventQ <- NewEventResize(w, h):
1092+
default:
1093+
}
11321094
}
11331095

11341096
func (s *cScreen) clearScreen(style Style, vtEnable bool) {
@@ -1298,3 +1260,11 @@ func (s *cScreen) Tty() (Tty, bool) {
12981260
func (s *cScreen) GetCells() *CellBuffer {
12991261
return &s.cells
13001262
}
1263+
1264+
func (s *cScreen) EventQ() chan Event {
1265+
return s.eventQ
1266+
}
1267+
1268+
func (s *cScreen) StopQ() <-chan struct{} {
1269+
return s.stopQ
1270+
}

screen.go

Lines changed: 59 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2022 The TCell Authors
1+
// Copyright 2023 The TCell Authors
22
//
33
// Licensed under the Apache License, Version 2.0 (the "License");
44
// you may not use file except in compliance with the License.
@@ -314,11 +314,6 @@ type screenImpl interface {
314314
HideCursor()
315315
SetCursorStyle(CursorStyle)
316316
Size() (width, height int)
317-
ChannelEvents(ch chan<- Event, quit <-chan struct{})
318-
PollEvent() Event
319-
HasPendingEvent() bool
320-
PostEvent(ev Event) error
321-
PostEventWait(ev Event)
322317
EnableMouse(...MouseFlags)
323318
DisableMouse()
324319
EnablePaste()
@@ -351,6 +346,15 @@ type screenImpl interface {
351346
// GetCells returns a pointer to the underlying CellBuffer that the implementation uses.
352347
// Various methods will write to these for performance, but will use the lock to do so.
353348
GetCells() *CellBuffer
349+
350+
// StopQ is closed when the screen is shut down via Fini. It remains open if the screen
351+
// is merely suspended.
352+
StopQ() <-chan struct{}
353+
354+
// EventQ delivers events. Events are posted to this by the screen in response to
355+
// key presses, resizes, etc. Application code receives events from this via the
356+
// Screen.PollEvent, Screen.ChannelEvents APIs.
357+
EventQ() chan Event
354358
}
355359

356360
type baseScreen struct {
@@ -417,3 +421,52 @@ func (b *baseScreen) LockRegion(x, y, width, height int, lock bool) {
417421
}
418422
b.Unlock()
419423
}
424+
425+
func (b *baseScreen) ChannelEvents(ch chan<- Event, quit <-chan struct{}) {
426+
defer close(ch)
427+
for {
428+
select {
429+
case <-quit:
430+
return
431+
case <-b.StopQ():
432+
return
433+
case ev := <-b.EventQ():
434+
select {
435+
case <-quit:
436+
return
437+
case <-b.StopQ():
438+
return
439+
case ch <- ev:
440+
}
441+
}
442+
}
443+
}
444+
445+
func (b *baseScreen) PollEvent() Event {
446+
select {
447+
case <-b.StopQ():
448+
return nil
449+
case ev := <-b.EventQ():
450+
return ev
451+
}
452+
}
453+
454+
func (b *baseScreen) HasPendingEvent() bool {
455+
return len(b.EventQ()) > 0
456+
}
457+
458+
func (b *baseScreen) PostEventWait(ev Event) {
459+
select {
460+
case b.EventQ() <- ev:
461+
case <-b.StopQ():
462+
}
463+
}
464+
465+
func (b *baseScreen) PostEvent(ev Event) error {
466+
select {
467+
case b.EventQ() <- ev:
468+
return nil
469+
default:
470+
return ErrEventQFull
471+
}
472+
}

simulation.go

Lines changed: 16 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -309,68 +309,29 @@ func (s *simscreen) resize() {
309309
if w != ow || h != oh {
310310
s.back.Resize(w, h)
311311
ev := NewEventResize(w, h)
312-
s.PostEvent(ev)
312+
s.postEvent(ev)
313313
}
314314
}
315315

316316
func (s *simscreen) Colors() int {
317317
return 256
318318
}
319319

320-
func (s *simscreen) ChannelEvents(ch chan<- Event, quit <-chan struct{}) {
321-
defer close(ch)
322-
for {
323-
select {
324-
case <-quit:
325-
return
326-
case <-s.quit:
327-
return
328-
case ev := <-s.evch:
329-
select {
330-
case <-quit:
331-
return
332-
case <-s.quit:
333-
return
334-
case ch <- ev:
335-
}
336-
}
337-
}
338-
}
339-
340-
func (s *simscreen) PollEvent() Event {
341-
select {
342-
case <-s.quit:
343-
return nil
344-
case ev := <-s.evch:
345-
return ev
346-
}
347-
}
348-
349-
func (s *simscreen) HasPendingEvent() bool {
350-
return len(s.evch) > 0
351-
}
352-
353-
func (s *simscreen) PostEventWait(ev Event) {
354-
s.evch <- ev
355-
}
356-
357-
func (s *simscreen) PostEvent(ev Event) error {
320+
func (s *simscreen) postEvent(ev Event) {
358321
select {
359322
case s.evch <- ev:
360-
return nil
361-
default:
362-
return ErrEventQFull
323+
case <-s.quit:
363324
}
364325
}
365326

366327
func (s *simscreen) InjectMouse(x, y int, buttons ButtonMask, mod ModMask) {
367328
ev := NewEventMouse(x, y, buttons, mod)
368-
s.PostEvent(ev)
329+
s.postEvent(ev)
369330
}
370331

371332
func (s *simscreen) InjectKey(key Key, r rune, mod ModMask) {
372333
ev := NewEventKey(key, r, mod)
373-
s.PostEvent(ev)
334+
s.postEvent(ev)
374335
}
375336

376337
func (s *simscreen) InjectKeyBytes(b []byte) bool {
@@ -381,7 +342,7 @@ outer:
381342
if b[0] >= ' ' && b[0] <= 0x7F {
382343
// printable ASCII easy to deal with -- no encodings
383344
ev := NewEventKey(KeyRune, rune(b[0]), ModNone)
384-
s.PostEvent(ev)
345+
s.postEvent(ev)
385346
b = b[1:]
386347
continue
387348
}
@@ -393,7 +354,7 @@ outer:
393354
mod = ModCtrl
394355
}
395356
ev := NewEventKey(Key(b[0]), 0, mod)
396-
s.PostEvent(ev)
357+
s.postEvent(ev)
397358
b = b[1:]
398359
continue
399360
}
@@ -407,7 +368,7 @@ outer:
407368
r, _ := utf8.DecodeRune(utfb[:nout])
408369
if r != utf8.RuneError {
409370
ev := NewEventKey(KeyRune, r, ModNone)
410-
s.PostEvent(ev)
371+
s.postEvent(ev)
411372
}
412373
b = b[nin:]
413374
continue outer
@@ -526,3 +487,11 @@ func (s *simscreen) Tty() (Tty, bool) {
526487
func (s *simscreen) GetCells() *CellBuffer {
527488
return &s.back
528489
}
490+
491+
func (s *simscreen) EventQ() chan Event {
492+
return s.evch
493+
}
494+
495+
func (s *simscreen) StopQ() <-chan struct{} {
496+
return s.quit
497+
}

0 commit comments

Comments
 (0)