mirror of https://github.com/cjbassi/gotop.git
178 lines
4.0 KiB
Go
178 lines
4.0 KiB
Go
package termui
|
|
|
|
import (
|
|
"strconv"
|
|
|
|
tb "github.com/nsf/termbox-go"
|
|
)
|
|
|
|
var eventStream = EventStream{
|
|
make(map[string]func(Event)),
|
|
"",
|
|
make(chan bool, 1),
|
|
make(chan tb.Event),
|
|
}
|
|
|
|
type EventStream struct {
|
|
eventHandlers map[string]func(Event)
|
|
prevKey string // previous keypress
|
|
stopLoop chan bool
|
|
eventQueue chan tb.Event // list of events from termbox
|
|
}
|
|
|
|
// Event includes only the termbox.Event attributes we need.
|
|
type Event struct {
|
|
Key string
|
|
Width int
|
|
Height int
|
|
MouseX int
|
|
MouseY int
|
|
}
|
|
|
|
// handleEvent calls the approriate callback function if there is one.
|
|
func handleEvent(e tb.Event) {
|
|
if e.Type == tb.EventError {
|
|
panic(e.Err)
|
|
}
|
|
|
|
ne := convertTermboxEvent(e)
|
|
|
|
if val, ok := eventStream.eventHandlers[ne.Key]; ok {
|
|
val(ne)
|
|
eventStream.prevKey = ""
|
|
} else { // check if the last 2 keys form a key combo with a handler
|
|
// if this is a keyboard event and the previous event was unhandled
|
|
if e.Type == tb.EventKey && eventStream.prevKey != "" {
|
|
combo := eventStream.prevKey + ne.Key
|
|
if val, ok := eventStream.eventHandlers[combo]; ok {
|
|
ne.Key = combo
|
|
val(ne)
|
|
eventStream.prevKey = ""
|
|
} else {
|
|
eventStream.prevKey = ne.Key
|
|
}
|
|
} else {
|
|
eventStream.prevKey = ne.Key
|
|
}
|
|
}
|
|
}
|
|
|
|
// Loop gets events from termbox and passes them off to handleEvent.
|
|
// Stops when StopLoop is called.
|
|
func Loop() {
|
|
go func() {
|
|
for {
|
|
eventStream.eventQueue <- tb.PollEvent()
|
|
}
|
|
}()
|
|
|
|
for {
|
|
select {
|
|
case <-eventStream.stopLoop:
|
|
return
|
|
case e := <-eventStream.eventQueue:
|
|
handleEvent(e)
|
|
}
|
|
}
|
|
}
|
|
|
|
// StopLoop stops the events Loop
|
|
func StopLoop() {
|
|
eventStream.stopLoop <- true
|
|
}
|
|
|
|
// On assigns event names to their handlers. Takes a string, strings, or a slice of strings, and a function.
|
|
func On(things ...interface{}) {
|
|
function := things[len(things)-1].(func(Event))
|
|
for _, thing := range things {
|
|
if value, ok := thing.(string); ok {
|
|
eventStream.eventHandlers[value] = function
|
|
}
|
|
if value, ok := thing.([]string); ok {
|
|
for _, name := range value {
|
|
eventStream.eventHandlers[name] = function
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// convertTermboxKeyValue converts a termbox keyboard event to a more friendly string format.
|
|
// Combines modifiers into the string instead of having them as additional fields in an event.
|
|
func convertTermboxKeyValue(e tb.Event) string {
|
|
k := string(e.Ch)
|
|
pre := ""
|
|
mod := ""
|
|
|
|
if e.Mod == tb.ModAlt {
|
|
mod = "M-"
|
|
}
|
|
if e.Ch == 0 {
|
|
if e.Key > 0xFFFF-12 {
|
|
k = "<f" + strconv.Itoa(0xFFFF-int(e.Key)+1) + ">"
|
|
} else if e.Key > 0xFFFF-25 {
|
|
ks := []string{"<insert>", "<delete>", "<home>", "<end>", "<previous>", "<next>", "<up>", "<down>", "<left>", "<right>"}
|
|
k = ks[0xFFFF-int(e.Key)-12]
|
|
}
|
|
|
|
if e.Key <= 0x7F {
|
|
pre = "C-"
|
|
k = string('a' - 1 + int(e.Key))
|
|
kmap := map[tb.Key][2]string{
|
|
tb.KeyCtrlSpace: {"C-", "<space>"},
|
|
tb.KeyBackspace: {"", "<backspace>"},
|
|
tb.KeyTab: {"", "<tab>"},
|
|
tb.KeyEnter: {"", "<enter>"},
|
|
tb.KeyEsc: {"", "<escape>"},
|
|
tb.KeyCtrlBackslash: {"C-", "\\"},
|
|
tb.KeyCtrlSlash: {"C-", "/"},
|
|
tb.KeySpace: {"", "<space>"},
|
|
tb.KeyCtrl8: {"C-", "8"},
|
|
}
|
|
if sk, ok := kmap[e.Key]; ok {
|
|
pre = sk[0]
|
|
k = sk[1]
|
|
}
|
|
}
|
|
}
|
|
|
|
return pre + mod + k
|
|
}
|
|
|
|
func convertTermboxMouseValue(e tb.Event) string {
|
|
switch e.Key {
|
|
case tb.MouseLeft:
|
|
return "MouseLeft"
|
|
case tb.MouseMiddle:
|
|
return "MouseMiddle"
|
|
case tb.MouseRight:
|
|
return "MouseRight"
|
|
case tb.MouseWheelUp:
|
|
return "MouseWheelUp"
|
|
case tb.MouseWheelDown:
|
|
return "MouseWheelDown"
|
|
case tb.MouseRelease:
|
|
return "MouseRelease"
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// convertTermboxEvent turns a termbox event into a termui event
|
|
func convertTermboxEvent(e tb.Event) Event {
|
|
ne := Event{} // new event
|
|
|
|
switch e.Type {
|
|
case tb.EventKey:
|
|
ne.Key = convertTermboxKeyValue(e)
|
|
case tb.EventMouse:
|
|
ne.Key = convertTermboxMouseValue(e)
|
|
ne.MouseX = e.MouseX
|
|
ne.MouseY = e.MouseY
|
|
case tb.EventResize:
|
|
ne.Key = "resize"
|
|
ne.Width = e.Width
|
|
ne.Height = e.Height
|
|
}
|
|
|
|
return ne
|
|
}
|