1
0
mirror of https://github.com/mum4k/termdash.git synced 2025-04-25 13:48:50 +08:00

Hooking up events from termbox.

This commit is contained in:
Jakub Sobon 2018-04-05 19:35:02 +02:00
parent fe222a489e
commit cec3153dc6
No known key found for this signature in database
GPG Key ID: F2451A77FB05D3B7
5 changed files with 103 additions and 18 deletions

View File

@ -1,14 +1,37 @@
// Binary boxes just creates containers with borders.
// Runs as long as there is at least one input (keyboard, mouse or terminal resize) event every 10 seconds.
package main
import (
"context"
"log"
"time"
"github.com/mum4k/termdash/container"
"github.com/mum4k/termdash/draw"
"github.com/mum4k/termdash/terminal/termbox"
"github.com/mum4k/termdash/terminalapi"
)
func events(t terminalapi.Terminal, ctx context.Context) <-chan terminalapi.Event {
ch := make(chan terminalapi.Event)
go func() {
for {
ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
ev := t.Event(ctx)
switch ev.(type) {
case *terminalapi.Error:
log.Print(ev)
default:
ch <- ev
}
cancel()
}
}()
return ch
}
func main() {
t, err := termbox.New()
if err != nil {
@ -49,5 +72,17 @@ func main() {
if err := t.Flush(); err != nil {
panic(err)
}
time.Sleep(3 * time.Second)
ev := events(t, context.Background())
for {
timer := time.NewTicker(10 * time.Second)
defer timer.Stop()
select {
case e := <-ev:
log.Printf("Event: %v", e)
case <-timer.C:
log.Printf("Exiting...")
return
}
}
}

View File

@ -192,8 +192,8 @@ func convResize(tbxEv tbx.Event) terminalapi.Event {
}
}
// toTermdashEvent converts a termbox event to the termdash event format.
func toTermdashEvent(tbxEv tbx.Event) []terminalapi.Event {
// toTermdashEvents converts a termbox event to the termdash event format.
func toTermdashEvents(tbxEv tbx.Event) []terminalapi.Event {
switch t := tbxEv.Type; t {
case tbx.EventInterrupt:
return []terminalapi.Event{

View File

@ -14,7 +14,7 @@ import (
tbx "github.com/nsf/termbox-go"
)
func TestToTermdashEvent(t *testing.T) {
func TestToTermdashEvents(t *testing.T) {
tests := []struct {
desc string
event tbx.Event
@ -121,9 +121,9 @@ func TestToTermdashEvent(t *testing.T) {
for _, tc := range tests {
t.Run(tc.desc, func(t *testing.T) {
got := toTermdashEvent(tc.event)
got := toTermdashEvents(tc.event)
if diff := pretty.Compare(tc.want, got); diff != "" {
t.Errorf("toTermdashEvent => unexpected diff (-want, +got):\n%s", diff)
t.Errorf("toTermdashEvents => unexpected diff (-want, +got):\n%s", diff)
}
})
}
@ -149,14 +149,14 @@ func TestMouseButtons(t *testing.T) {
for _, tc := range tests {
t.Run(fmt.Sprintf("key:%v want:%v", tc.key, tc.want), func(t *testing.T) {
evs := toTermdashEvent(tbx.Event{Type: tbx.EventMouse, Key: tc.key})
evs := toTermdashEvents(tbx.Event{Type: tbx.EventMouse, Key: tc.key})
if got, want := len(evs), 1; got != want {
t.Fatalf("toTermdashEvent => got %d events, want %d", got, want)
t.Fatalf("toTermdashEvents => got %d events, want %d", got, want)
}
ev := evs[0]
if err, ok := ev.(*terminalapi.Error); ok != tc.wantErr {
t.Fatalf("toTermdashEvent => unexpected error:%v, wantErr: %v", err, tc.wantErr)
t.Fatalf("toTermdashEvents => unexpected error:%v, wantErr: %v", err, tc.wantErr)
}
if _, ok := ev.(*terminalapi.Error); ok {
return
@ -165,11 +165,11 @@ func TestMouseButtons(t *testing.T) {
switch e := ev.(type) {
case *terminalapi.Mouse:
if got := e.Button; got != tc.want {
t.Errorf("toTermdashEvent => got %v, want %v", got, tc.want)
t.Errorf("toTermdashEvents => got %v, want %v", got, tc.want)
}
default:
t.Fatalf("toTermdashEvent => unexpected event type %T", e)
t.Fatalf("toTermdashEvents => unexpected event type %T", e)
}
})
}
@ -263,7 +263,7 @@ func TestKeyboardKeys(t *testing.T) {
for _, tc := range tests {
t.Run(fmt.Sprintf("key:%v and ch:%v want:%v", tc.key, tc.ch, tc.want), func(t *testing.T) {
evs := toTermdashEvent(tbx.Event{
evs := toTermdashEvents(tbx.Event{
Type: tbx.EventKey,
Key: tc.key,
Ch: tc.ch,
@ -278,12 +278,12 @@ func TestKeyboardKeys(t *testing.T) {
}
if gotCount != wantCount {
t.Fatalf("toTermdashEvent => got %d events, want %d, events were:\n%v", gotCount, wantCount, pretty.Sprint(evs))
t.Fatalf("toTermdashEvents => got %d events, want %d, events were:\n%v", gotCount, wantCount, pretty.Sprint(evs))
}
for i, ev := range evs {
if err, ok := ev.(*terminalapi.Error); ok != tc.wantErr {
t.Fatalf("toTermdashEvent => unexpected error:%v, wantErr: %v", err, tc.wantErr)
t.Fatalf("toTermdashEvents => unexpected error:%v, wantErr: %v", err, tc.wantErr)
}
if _, ok := ev.(*terminalapi.Error); ok {
return
@ -292,11 +292,11 @@ func TestKeyboardKeys(t *testing.T) {
switch e := ev.(type) {
case *terminalapi.Keyboard:
if got, want := e.Key, tc.want[i]; got != want {
t.Errorf("toTermdashEvent => got key[%d] %v, want %v", got, i, want)
t.Errorf("toTermdashEvents => got key[%d] %v, want %v", got, i, want)
}
default:
t.Fatalf("toTermdashEvent => unexpected event type %T", e)
t.Fatalf("toTermdashEvents => unexpected event type %T", e)
}
}
})

View File

@ -6,6 +6,7 @@ import (
"image"
"github.com/mum4k/termdash/cell"
"github.com/mum4k/termdash/eventqueue"
"github.com/mum4k/termdash/terminalapi"
tbx "github.com/nsf/termbox-go"
)
@ -37,6 +38,13 @@ func ColorMode(cm terminalapi.ColorMode) Option {
// supported, because termbox uses global state.
// Implements terminalapi.Terminal.
type Terminal struct {
// events is a queue of input events.
events *eventqueue.Unbound
// done gets closed when Close() is called.
done chan struct{}
// Options.
colorMode terminalapi.ColorMode
}
@ -46,8 +54,12 @@ func New(opts ...Option) (*Terminal, error) {
if err := tbx.Init(); err != nil {
return nil, err
}
tbx.SetInputMode(tbx.InputEsc | tbx.InputMouse)
t := &Terminal{}
t := &Terminal{
events: eventqueue.New(),
done: make(chan struct{}),
}
for _, opt := range opts {
opt.set(t)
}
@ -57,6 +69,8 @@ func New(opts ...Option) (*Terminal, error) {
return nil, err
}
tbx.SetOutputMode(om)
go t.pollEvents() // Stops when Close() is called.
return t, nil
}
@ -112,13 +126,34 @@ func (t *Terminal) SetCell(p image.Point, r rune, opts ...cell.Option) error {
return nil
}
// pollEvents polls and enqueues the input events.
func (t *Terminal) pollEvents() {
for {
select {
case <-t.done:
return
default:
}
events := toTermdashEvents(tbx.PollEvent())
for _, ev := range events {
t.events.Push(ev)
}
}
}
// Implements terminalapi.Terminal.Event.
func (t *Terminal) Event(ctx context.Context) terminalapi.Event {
return nil
ev, err := t.events.Pull(ctx)
if err != nil {
return terminalapi.NewErrorf("unable to pull the next event: %v", err)
}
return ev
}
// Closes the terminal, should be called when the terminal isn't required
// anymore to return the screen to a sane state.
func (t *Terminal) Close() {
close(t.done)
tbx.Close()
}

View File

@ -25,6 +25,11 @@ type Keyboard struct {
func (*Keyboard) isEvent() {}
// String implements fmt.Stringer.
func (k Keyboard) String() string {
return fmt.Sprintf("Keyboard{Key: %v}", k.Key)
}
// Resize is the event used when the terminal was resized.
// Implements terminalapi.Event.
type Resize struct {
@ -34,6 +39,11 @@ type Resize struct {
func (*Resize) isEvent() {}
// String implements fmt.Stringer.
func (r Resize) String() string {
return fmt.Sprintf("Resize{Size: %v}", r.Size)
}
// Mouse is the event used when the mouse is moved or a mouse button is
// pressed.
// Implements terminalapi.Event.
@ -46,6 +56,11 @@ type Mouse struct {
func (*Mouse) isEvent() {}
// String implements fmt.Stringer.
func (m Mouse) String() string {
return fmt.Sprintf("Mouse{Position: %v, Button: %v}", m.Position, m.Button)
}
// Error is an event indicating an error while processing input.
type Error string