micro/internal/action/events.go

155 lines
3 KiB
Go
Raw Normal View History

2018-08-28 02:53:08 +03:00
package action
2018-08-26 06:06:44 +03:00
2018-08-27 22:53:10 +03:00
import (
2020-06-29 07:50:19 +03:00
"bytes"
"errors"
"fmt"
"strings"
2020-01-01 04:15:45 +03:00
"github.com/zyedidia/tcell"
2018-08-27 22:53:10 +03:00
)
2018-08-26 06:06:44 +03:00
2020-06-29 07:50:19 +03:00
type Event interface {
String() string
}
2018-08-26 06:06:44 +03:00
2018-08-27 22:53:10 +03:00
// RawEvent is simply an escape code
// We allow users to directly bind escape codes
// to get around some of a limitations of terminals
type RawEvent struct {
esc string
}
2018-08-26 06:06:44 +03:00
2020-06-29 07:50:19 +03:00
func (r RawEvent) String() string {
return r.esc
}
2018-08-27 22:53:10 +03:00
// KeyEvent is a key event containing a key code,
// some possible modifiers (alt, ctrl, etc...) and
// a rune if it was simply a character press
// Note: to be compatible with tcell events,
// for ctrl keys r=code
type KeyEvent struct {
code tcell.Key
mod tcell.ModMask
r rune
2020-06-29 07:50:19 +03:00
any bool
}
func (k KeyEvent) String() string {
if k.any {
return "<any>"
}
s := ""
m := []string{}
if k.mod&tcell.ModShift != 0 {
m = append(m, "Shift")
}
if k.mod&tcell.ModAlt != 0 {
m = append(m, "Alt")
}
if k.mod&tcell.ModMeta != 0 {
m = append(m, "Meta")
}
if k.mod&tcell.ModCtrl != 0 {
m = append(m, "Ctrl")
}
ok := false
if s, ok = tcell.KeyNames[k.code]; !ok {
if k.code == tcell.KeyRune {
s = string(k.r)
} else {
s = fmt.Sprintf("Key[%d,%d]", k.code, int(k.r))
}
}
if len(m) != 0 {
if k.mod&tcell.ModCtrl != 0 && strings.HasPrefix(s, "Ctrl-") {
s = s[5:]
if len(s) == 1 {
s = strings.ToLower(s)
}
}
return fmt.Sprintf("%s-%s", strings.Join(m, "-"), s)
}
return s
}
// A KeySequence defines a list of consecutive
2020-06-30 00:13:22 +03:00
// events. All events in the sequence must be KeyEvents
// or MouseEvents.
2020-06-29 07:50:19 +03:00
type KeySequenceEvent struct {
2020-06-30 00:13:22 +03:00
keys []Event
2020-06-29 07:50:19 +03:00
}
func (k KeySequenceEvent) String() string {
buf := bytes.Buffer{}
for _, e := range k.keys {
buf.WriteString(e.String())
}
return buf.String()
2018-08-27 22:53:10 +03:00
}
2018-08-26 06:06:44 +03:00
2018-08-27 22:53:10 +03:00
// MouseEvent is a mouse event with a mouse button and
// any possible key modifiers
type MouseEvent struct {
btn tcell.ButtonMask
mod tcell.ModMask
}
2018-08-26 06:06:44 +03:00
2020-06-29 07:50:19 +03:00
func (m MouseEvent) String() string {
mod := ""
if m.mod&tcell.ModShift != 0 {
mod = "Shift-"
}
if m.mod&tcell.ModAlt != 0 {
mod = "Alt-"
}
if m.mod&tcell.ModMeta != 0 {
mod = "Meta-"
}
if m.mod&tcell.ModCtrl != 0 {
mod = "Ctrl-"
}
for k, v := range mouseEvents {
if v == m.btn {
return fmt.Sprintf("%s%s", mod, k)
}
}
return ""
}
// ConstructEvent takes a tcell event and returns a micro
// event. Note that tcell events can't express certain
// micro events such as key sequences. This function is
// mostly used for debugging/raw panes or constructing
// intermediate micro events while parsing a sequence.
func ConstructEvent(event tcell.Event) (Event, error) {
switch e := event.(type) {
case *tcell.EventKey:
return KeyEvent{
code: e.Key(),
mod: e.Modifiers(),
r: e.Rune(),
}, nil
case *tcell.EventRaw:
return RawEvent{
esc: e.EscSeq(),
}, nil
case *tcell.EventMouse:
return MouseEvent{
btn: e.Buttons(),
mod: e.Modifiers(),
}, nil
}
return nil, errors.New("No micro event equivalent")
}
2018-08-29 01:44:52 +03:00
2018-08-28 02:53:08 +03:00
// A Handler will take a tcell event and execute it
2018-08-27 22:53:10 +03:00
// appropriately
2018-08-28 02:53:08 +03:00
type Handler interface {
2018-08-27 22:53:10 +03:00
HandleEvent(tcell.Event)
2019-01-11 22:49:22 +03:00
HandleCommand(string)
2018-08-26 06:06:44 +03:00
}