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-09-05 21:52:35 +03:00
|
|
|
"github.com/zyedidia/tcell/v2"
|
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 {
|
2020-07-01 04:25:54 +03:00
|
|
|
Name() string
|
2020-06-29 07:50:19 +03:00
|
|
|
}
|
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-07-01 04:25:54 +03:00
|
|
|
func (r RawEvent) Name() string {
|
2020-06-29 07:50:19 +03:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2020-09-06 04:59:19 +03:00
|
|
|
func metaToAlt(mod tcell.ModMask) tcell.ModMask {
|
|
|
|
if mod&tcell.ModMeta != 0 {
|
|
|
|
mod &= ^tcell.ModMeta
|
|
|
|
mod |= tcell.ModAlt
|
|
|
|
}
|
|
|
|
return mod
|
|
|
|
}
|
|
|
|
|
2020-07-01 04:25:54 +03:00
|
|
|
func (k KeyEvent) Name() string {
|
2020-06-29 07:50:19 +03:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2020-07-01 04:25:54 +03:00
|
|
|
func (k KeySequenceEvent) Name() string {
|
2020-06-29 07:50:19 +03:00
|
|
|
buf := bytes.Buffer{}
|
|
|
|
for _, e := range k.keys {
|
2020-07-01 04:25:54 +03:00
|
|
|
buf.WriteByte('<')
|
|
|
|
buf.WriteString(e.Name())
|
|
|
|
buf.WriteByte('>')
|
2020-06-29 07:50:19 +03:00
|
|
|
}
|
|
|
|
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-07-01 04:25:54 +03:00
|
|
|
func (m MouseEvent) Name() string {
|
2020-06-29 07:50:19 +03:00
|
|
|
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(),
|
2020-09-06 04:59:19 +03:00
|
|
|
mod: metaToAlt(e.Modifiers()),
|
2020-06-29 07:50:19 +03:00
|
|
|
r: e.Rune(),
|
|
|
|
}, nil
|
|
|
|
case *tcell.EventRaw:
|
|
|
|
return RawEvent{
|
|
|
|
esc: e.EscSeq(),
|
|
|
|
}, nil
|
|
|
|
case *tcell.EventMouse:
|
|
|
|
return MouseEvent{
|
|
|
|
btn: e.Buttons(),
|
2020-09-06 04:59:19 +03:00
|
|
|
mod: metaToAlt(e.Modifiers()),
|
2020-06-29 07:50:19 +03:00
|
|
|
}, 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
|
|
|
}
|