mirror of
https://github.com/mum4k/termdash.git
synced 2025-04-25 13:48:50 +08:00
Fix mouse events
This commit is contained in:
parent
b23d99cd8d
commit
4fcdf48ecb
@ -12,9 +12,6 @@ import (
|
||||
// tcell representation of the space key
|
||||
var tcellSpaceKey = tcell.Key(' ')
|
||||
|
||||
// tcell representation of the tilde key
|
||||
var tcellTildeKey = tcell.Key('~')
|
||||
|
||||
// tcellToTd maps tcell key values to the termdash format.
|
||||
var tcellToTd = map[tcell.Key]keyboard.Key{
|
||||
tcellSpaceKey: keyboard.KeySpace,
|
||||
@ -41,7 +38,6 @@ var tcellToTd = map[tcell.Key]keyboard.Key{
|
||||
tcell.KeyLeft: keyboard.KeyArrowLeft,
|
||||
tcell.KeyRight: keyboard.KeyArrowRight,
|
||||
tcell.KeyEnter: keyboard.KeyEnter,
|
||||
tcellTildeKey: keyboard.KeyCtrlTilde,
|
||||
tcell.KeyCtrlA: keyboard.KeyCtrlA,
|
||||
tcell.KeyCtrlB: keyboard.KeyCtrlB,
|
||||
tcell.KeyCtrlC: keyboard.KeyCtrlC,
|
||||
@ -72,6 +68,7 @@ var tcellToTd = map[tcell.Key]keyboard.Key{
|
||||
tcell.KeyCtrlRightSq: keyboard.KeyCtrlRsqBracket,
|
||||
tcell.KeyCtrlUnderscore: keyboard.KeyCtrlUnderscore,
|
||||
tcell.KeyBackspace2: keyboard.KeyBackspace2,
|
||||
tcell.KeyCtrlSpace: keyboard.KeyCtrlSpace,
|
||||
}
|
||||
|
||||
// convKey converts a tcell keyboard event to the termdash format.
|
||||
@ -97,19 +94,33 @@ func convKey(event *tcell.EventKey) terminalapi.Event {
|
||||
|
||||
// convMouse converts a tcell mouse event to the termdash format.
|
||||
func convMouse(event *tcell.EventMouse) terminalapi.Event {
|
||||
//var button mouse.Button
|
||||
var button mouse.Button
|
||||
x, y := event.Position()
|
||||
|
||||
// Get wheel events
|
||||
tcellBtn := event.Buttons()
|
||||
|
||||
// tcell uses signed int16 for button masks, and negative values are invalid
|
||||
if tcellBtn < 0 {
|
||||
return terminalapi.NewErrorf("unknown mouse key %v in a mouse event", tcellBtn)
|
||||
}
|
||||
|
||||
// Get wheel events
|
||||
if tcellBtn&tcell.WheelUp != 0 {
|
||||
button = mouse.ButtonWheelUp
|
||||
} else if tcellBtn&tcell.WheelDown != 0 {
|
||||
button = mouse.ButtonWheelDown
|
||||
}
|
||||
|
||||
// Get button events
|
||||
// Return wheel event if found
|
||||
if button > 0 {
|
||||
return &terminalapi.Mouse{
|
||||
Position: image.Point{X: x, Y: y},
|
||||
Button: button,
|
||||
}
|
||||
}
|
||||
|
||||
// Get only button events, not wheel events
|
||||
tcellBtn &= tcell.ButtonMask(0xff)
|
||||
switch tcellBtn = event.Buttons(); tcellBtn {
|
||||
case tcell.ButtonNone:
|
||||
button = mouse.ButtonRelease
|
||||
@ -120,7 +131,8 @@ func convMouse(event *tcell.EventMouse) terminalapi.Event {
|
||||
case tcell.Button3:
|
||||
button = mouse.ButtonMiddle
|
||||
default:
|
||||
return terminalapi.NewErrorf("unknown mouse key %v in a mouse event", tcellBtn)
|
||||
// Do nothing, since tcell allows multiple buttons to be pressed at the same time
|
||||
// Maybe refactor terminalapi to handle multiple mouse buttons being pressed at the same time (e.g. M1 + M2)
|
||||
}
|
||||
|
||||
return &terminalapi.Mouse{
|
||||
|
253
terminal/tcell/event_test.go
Normal file
253
terminal/tcell/event_test.go
Normal file
@ -0,0 +1,253 @@
|
||||
package tcell
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"image"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gdamore/tcell"
|
||||
"github.com/kylelemons/godebug/pretty"
|
||||
"github.com/mum4k/termdash/keyboard"
|
||||
"github.com/mum4k/termdash/mouse"
|
||||
"github.com/mum4k/termdash/terminal/terminalapi"
|
||||
)
|
||||
|
||||
type mockUnknownEvent struct {
|
||||
}
|
||||
|
||||
func (m *mockUnknownEvent) When() time.Time {
|
||||
return time.Now()
|
||||
}
|
||||
|
||||
func TestToTermdashEvents(t *testing.T) {
|
||||
tests := []struct {
|
||||
desc string
|
||||
event tcell.Event
|
||||
want []terminalapi.Event
|
||||
}{
|
||||
{
|
||||
desc: "unknown event type",
|
||||
event: &mockUnknownEvent{},
|
||||
want: []terminalapi.Event{
|
||||
terminalapi.NewError("unknown tcell event type: &{}"),
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "interrupts aren't supported",
|
||||
event: tcell.NewEventInterrupt(nil),
|
||||
want: []terminalapi.Event{
|
||||
terminalapi.NewError("event type EventInterrupt isn't supported"),
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "error event",
|
||||
event: tcell.NewEventError(errors.New("error event")),
|
||||
want: []terminalapi.Event{
|
||||
terminalapi.NewError("encountered tcell error event: error event"),
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "resize event",
|
||||
event: tcell.NewEventResize(640, 480),
|
||||
want: []terminalapi.Event{
|
||||
&terminalapi.Resize{
|
||||
Size: image.Point{X: 640, Y: 480},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "resize event to a negative size",
|
||||
event: tcell.NewEventResize(-1, -1),
|
||||
want: []terminalapi.Event{
|
||||
terminalapi.NewError("terminal resized to negative size: (-1,-1)"),
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "mouse event",
|
||||
event: tcell.NewEventMouse(100, 200, tcell.Button1, tcell.ModNone),
|
||||
want: []terminalapi.Event{
|
||||
&terminalapi.Mouse{
|
||||
Position: image.Point{X: 100, Y: 200},
|
||||
Button: mouse.ButtonLeft,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "keyboard event",
|
||||
event: tcell.NewEventKey(tcell.KeyF1, 0, tcell.ModNone),
|
||||
want: []terminalapi.Event{
|
||||
&terminalapi.Keyboard{
|
||||
Key: keyboard.KeyF1,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
got := toTermdashEvents(tc.event)
|
||||
if diff := pretty.Compare(tc.want, got); diff != "" {
|
||||
t.Errorf("toTermdashEvents => unexpected diff (-want, +got):\n%s", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestMouseButtons(t *testing.T) {
|
||||
tests := []struct {
|
||||
btnMask tcell.ButtonMask
|
||||
want mouse.Button
|
||||
wantErr bool
|
||||
}{
|
||||
{btnMask: -1, wantErr: true},
|
||||
{btnMask: tcell.Button1, want: mouse.ButtonLeft},
|
||||
{btnMask: tcell.Button3, want: mouse.ButtonMiddle},
|
||||
{btnMask: tcell.Button2, want: mouse.ButtonRight},
|
||||
{btnMask: tcell.ButtonNone, want: mouse.ButtonRelease},
|
||||
{btnMask: tcell.WheelUp, want: mouse.ButtonWheelUp},
|
||||
{btnMask: tcell.WheelDown, want: mouse.ButtonWheelDown},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(fmt.Sprintf("key:%v want:%v", tc.btnMask, tc.want), func(t *testing.T) {
|
||||
|
||||
evs := toTermdashEvents(tcell.NewEventMouse(0, 0, tc.btnMask, tcell.ModNone))
|
||||
if got, want := len(evs), 1; 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("toTermdashEvents => unexpected error:%v, wantErr: %v", err, tc.wantErr)
|
||||
}
|
||||
if _, ok := ev.(*terminalapi.Error); ok {
|
||||
return
|
||||
}
|
||||
|
||||
switch e := ev.(type) {
|
||||
case *terminalapi.Mouse:
|
||||
if got := e.Button; got != tc.want {
|
||||
t.Errorf("toTermdashEvents => got %v, want %v", got, tc.want)
|
||||
}
|
||||
|
||||
default:
|
||||
t.Fatalf("toTermdashEvents => unexpected event type %T", e)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestKeyboardKeys(t *testing.T) {
|
||||
tests := []struct {
|
||||
key tcell.Key
|
||||
ch rune
|
||||
want keyboard.Key
|
||||
wantErr bool
|
||||
}{
|
||||
{key: 2000, wantErr: true},
|
||||
{key: tcell.KeyRune, ch: 'a', want: 'a'},
|
||||
{key: tcell.KeyRune, ch: 'A', want: 'A'},
|
||||
{key: tcell.KeyRune, ch: 'z', want: 'z'},
|
||||
{key: tcell.KeyRune, ch: 'Z', want: 'Z'},
|
||||
{key: tcell.KeyRune, ch: '0', want: '0'},
|
||||
{key: tcell.KeyRune, ch: '9', want: '9'},
|
||||
{key: tcell.KeyRune, ch: '!', want: '!'},
|
||||
{key: tcell.KeyRune, ch: ')', want: ')'},
|
||||
{key: tcellSpaceKey, want: keyboard.KeySpace},
|
||||
{key: tcell.KeyF1, want: keyboard.KeyF1},
|
||||
{key: tcell.KeyF2, want: keyboard.KeyF2},
|
||||
{key: tcell.KeyF3, want: keyboard.KeyF3},
|
||||
{key: tcell.KeyF4, want: keyboard.KeyF4},
|
||||
{key: tcell.KeyF5, want: keyboard.KeyF5},
|
||||
{key: tcell.KeyF6, want: keyboard.KeyF6},
|
||||
{key: tcell.KeyF7, want: keyboard.KeyF7},
|
||||
{key: tcell.KeyF8, want: keyboard.KeyF8},
|
||||
{key: tcell.KeyF9, want: keyboard.KeyF9},
|
||||
{key: tcell.KeyF10, want: keyboard.KeyF10},
|
||||
{key: tcell.KeyF11, want: keyboard.KeyF11},
|
||||
{key: tcell.KeyF12, want: keyboard.KeyF12},
|
||||
{key: tcell.KeyInsert, want: keyboard.KeyInsert},
|
||||
{key: tcell.KeyDelete, want: keyboard.KeyDelete},
|
||||
{key: tcell.KeyHome, want: keyboard.KeyHome},
|
||||
{key: tcell.KeyEnd, want: keyboard.KeyEnd},
|
||||
{key: tcell.KeyPgUp, want: keyboard.KeyPgUp},
|
||||
{key: tcell.KeyPgDn, want: keyboard.KeyPgDn},
|
||||
{key: tcell.KeyUp, want: keyboard.KeyArrowUp},
|
||||
{key: tcell.KeyDown, want: keyboard.KeyArrowDown},
|
||||
{key: tcell.KeyLeft, want: keyboard.KeyArrowLeft},
|
||||
{key: tcell.KeyRight, want: keyboard.KeyArrowRight},
|
||||
{key: tcell.KeyCtrlSpace, want: keyboard.KeyCtrlTilde},
|
||||
{key: tcell.KeyCtrlA, want: keyboard.KeyCtrlA},
|
||||
{key: tcell.KeyCtrlB, want: keyboard.KeyCtrlB},
|
||||
{key: tcell.KeyCtrlC, want: keyboard.KeyCtrlC},
|
||||
{key: tcell.KeyCtrlD, want: keyboard.KeyCtrlD},
|
||||
{key: tcell.KeyCtrlE, want: keyboard.KeyCtrlE},
|
||||
{key: tcell.KeyCtrlF, want: keyboard.KeyCtrlF},
|
||||
{key: tcell.KeyCtrlG, want: keyboard.KeyCtrlG},
|
||||
{key: tcell.KeyBackspace, want: keyboard.KeyBackspace},
|
||||
{key: tcell.KeyBackspace, want: keyboard.KeyCtrlH},
|
||||
{key: tcell.KeyCtrlH, want: keyboard.KeyBackspace},
|
||||
{key: tcell.KeyTab, want: keyboard.KeyTab},
|
||||
{key: tcell.KeyTab, want: keyboard.KeyCtrlI},
|
||||
{key: tcell.KeyCtrlI, want: keyboard.KeyTab},
|
||||
{key: tcell.KeyCtrlJ, want: keyboard.KeyCtrlJ},
|
||||
{key: tcell.KeyCtrlK, want: keyboard.KeyCtrlK},
|
||||
{key: tcell.KeyCtrlL, want: keyboard.KeyCtrlL},
|
||||
{key: tcell.KeyEnter, want: keyboard.KeyEnter},
|
||||
{key: tcell.KeyEnter, want: keyboard.KeyCtrlM},
|
||||
{key: tcell.KeyCtrlM, want: keyboard.KeyEnter},
|
||||
{key: tcell.KeyCtrlN, want: keyboard.KeyCtrlN},
|
||||
{key: tcell.KeyCtrlO, want: keyboard.KeyCtrlO},
|
||||
{key: tcell.KeyCtrlP, want: keyboard.KeyCtrlP},
|
||||
{key: tcell.KeyCtrlQ, want: keyboard.KeyCtrlQ},
|
||||
{key: tcell.KeyCtrlR, want: keyboard.KeyCtrlR},
|
||||
{key: tcell.KeyCtrlS, want: keyboard.KeyCtrlS},
|
||||
{key: tcell.KeyCtrlT, want: keyboard.KeyCtrlT},
|
||||
{key: tcell.KeyCtrlU, want: keyboard.KeyCtrlU},
|
||||
{key: tcell.KeyCtrlV, want: keyboard.KeyCtrlV},
|
||||
{key: tcell.KeyCtrlW, want: keyboard.KeyCtrlW},
|
||||
{key: tcell.KeyCtrlX, want: keyboard.KeyCtrlX},
|
||||
{key: tcell.KeyCtrlY, want: keyboard.KeyCtrlY},
|
||||
{key: tcell.KeyCtrlZ, want: keyboard.KeyCtrlZ},
|
||||
{key: tcell.KeyEsc, want: keyboard.KeyEsc},
|
||||
{key: tcell.KeyEsc, want: keyboard.KeyCtrlLsqBracket},
|
||||
{key: tcell.KeyEsc, want: keyboard.KeyCtrl3},
|
||||
{key: tcell.KeyCtrlLeftSq, want: keyboard.KeyEsc},
|
||||
{key: tcell.KeyCtrlBackslash, want: keyboard.KeyCtrl4},
|
||||
{key: tcell.KeyCtrlRightSq, want: keyboard.KeyCtrl5},
|
||||
{key: tcell.KeyCtrlUnderscore, want: keyboard.KeyCtrlUnderscore},
|
||||
{key: tcell.KeyBackspace2, want: keyboard.KeyBackspace2},
|
||||
}
|
||||
|
||||
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 := toTermdashEvents(tcell.NewEventKey(tc.key, tc.ch, tcell.ModNone))
|
||||
|
||||
gotCount := len(evs)
|
||||
wantCount := 1
|
||||
if gotCount != wantCount {
|
||||
t.Fatalf("toTermdashEvents => got %d events, want %d, events were:\n%v", gotCount, wantCount, pretty.Sprint(evs))
|
||||
}
|
||||
ev := evs[0]
|
||||
|
||||
if err, ok := ev.(*terminalapi.Error); ok != tc.wantErr {
|
||||
t.Fatalf("toTermdashEvents => unexpected error:%v, wantErr: %v", err, tc.wantErr)
|
||||
}
|
||||
if _, ok := ev.(*terminalapi.Error); ok {
|
||||
return
|
||||
}
|
||||
|
||||
switch e := ev.(type) {
|
||||
case *terminalapi.Keyboard:
|
||||
if got, want := e.Key, tc.want; got != want {
|
||||
t.Errorf("toTermdashEvents => got key %v, want %v", got, want)
|
||||
}
|
||||
|
||||
default:
|
||||
t.Fatalf("toTermdashEvents => unexpected event type %T", e)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user