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:
parent
fe222a489e
commit
cec3153dc6
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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{
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user