diff options
Diffstat (limited to 'Godeps/_workspace/src/github.com/gizak/termui/events.go')
-rw-r--r-- | Godeps/_workspace/src/github.com/gizak/termui/events.go | 455 |
1 files changed, 276 insertions, 179 deletions
diff --git a/Godeps/_workspace/src/github.com/gizak/termui/events.go b/Godeps/_workspace/src/github.com/gizak/termui/events.go index 23a189b56..177bbb4b0 100644 --- a/Godeps/_workspace/src/github.com/gizak/termui/events.go +++ b/Godeps/_workspace/src/github.com/gizak/termui/events.go @@ -1,219 +1,316 @@ -// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved. +// Copyright 2016 Zack Guo <gizak@icloud.com>. All rights reserved. // Use of this source code is governed by a MIT license that can // be found in the LICENSE file. -// -// Portions of this file uses [termbox-go](https://github.com/nsf/termbox-go/blob/54b74d087b7c397c402d0e3b66d2ccb6eaf5c2b4/api_common.go) -// by [authors](https://github.com/nsf/termbox-go/blob/master/AUTHORS) -// under [license](https://github.com/nsf/termbox-go/blob/master/LICENSE) package termui -import "github.com/nsf/termbox-go" +import ( + "path" + "strconv" + "sync" + "time" -/***********************************termbox-go**************************************/ - -type ( - EventType uint8 - Modifier uint8 - Key uint16 + "github.com/nsf/termbox-go" ) -// This type represents a termbox event. The 'Mod', 'Key' and 'Ch' fields are -// valid if 'Type' is EventKey. The 'Width' and 'Height' fields are valid if -// 'Type' is EventResize. The 'Err' field is valid if 'Type' is EventError. type Event struct { - Type EventType // one of Event* constants - Mod Modifier // one of Mod* constants or 0 - Key Key // one of Key* constants, invalid if 'Ch' is not 0 - Ch rune // a unicode character - Width int // width of the screen - Height int // height of the screen - Err error // error in case if input failed - MouseX int // x coord of mouse - MouseY int // y coord of mouse - N int // number of bytes written when getting a raw event -} - -const ( - KeyF1 Key = 0xFFFF - iota - KeyF2 - KeyF3 - KeyF4 - KeyF5 - KeyF6 - KeyF7 - KeyF8 - KeyF9 - KeyF10 - KeyF11 - KeyF12 - KeyInsert - KeyDelete - KeyHome - KeyEnd - KeyPgup - KeyPgdn - KeyArrowUp - KeyArrowDown - KeyArrowLeft - KeyArrowRight - key_min // see terminfo - MouseLeft - MouseMiddle - MouseRight -) + Type string + Path string + From string + To string + Data interface{} + Time int64 +} -const ( - KeyCtrlTilde Key = 0x00 - KeyCtrl2 Key = 0x00 - KeyCtrlSpace Key = 0x00 - KeyCtrlA Key = 0x01 - KeyCtrlB Key = 0x02 - KeyCtrlC Key = 0x03 - KeyCtrlD Key = 0x04 - KeyCtrlE Key = 0x05 - KeyCtrlF Key = 0x06 - KeyCtrlG Key = 0x07 - KeyBackspace Key = 0x08 - KeyCtrlH Key = 0x08 - KeyTab Key = 0x09 - KeyCtrlI Key = 0x09 - KeyCtrlJ Key = 0x0A - KeyCtrlK Key = 0x0B - KeyCtrlL Key = 0x0C - KeyEnter Key = 0x0D - KeyCtrlM Key = 0x0D - KeyCtrlN Key = 0x0E - KeyCtrlO Key = 0x0F - KeyCtrlP Key = 0x10 - KeyCtrlQ Key = 0x11 - KeyCtrlR Key = 0x12 - KeyCtrlS Key = 0x13 - KeyCtrlT Key = 0x14 - KeyCtrlU Key = 0x15 - KeyCtrlV Key = 0x16 - KeyCtrlW Key = 0x17 - KeyCtrlX Key = 0x18 - KeyCtrlY Key = 0x19 - KeyCtrlZ Key = 0x1A - KeyEsc Key = 0x1B - KeyCtrlLsqBracket Key = 0x1B - KeyCtrl3 Key = 0x1B - KeyCtrl4 Key = 0x1C - KeyCtrlBackslash Key = 0x1C - KeyCtrl5 Key = 0x1D - KeyCtrlRsqBracket Key = 0x1D - KeyCtrl6 Key = 0x1E - KeyCtrl7 Key = 0x1F - KeyCtrlSlash Key = 0x1F - KeyCtrlUnderscore Key = 0x1F - KeySpace Key = 0x20 - KeyBackspace2 Key = 0x7F - KeyCtrl8 Key = 0x7F -) +var sysEvtChs []chan Event -// Alt modifier constant, see Event.Mod field and SetInputMode function. -const ( - ModAlt Modifier = 0x01 -) +type EvtKbd struct { + KeyStr string +} -// Event type. See Event.Type field. -const ( - EventKey EventType = iota - EventResize - EventMouse - EventError - EventInterrupt - EventRaw - EventNone -) +func evtKbd(e termbox.Event) EvtKbd { + ek := EvtKbd{} -/**************************************end**************************************/ + k := string(e.Ch) + pre := "" + mod := "" -// convert termbox.Event to termui.Event -func uiEvt(e termbox.Event) Event { - event := Event{} - event.Type = EventType(e.Type) - event.Mod = Modifier(e.Mod) - event.Key = Key(e.Key) - event.Ch = e.Ch - event.Width = e.Width - event.Height = e.Height - event.Err = e.Err - event.MouseX = e.MouseX - event.MouseY = e.MouseY - event.N = e.N + if e.Mod == termbox.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] + } - return event + if e.Key <= 0x7F { + pre = "C-" + k = string('a' - 1 + int(e.Key)) + kmap := map[termbox.Key][2]string{ + termbox.KeyCtrlSpace: {"C-", "<space>"}, + termbox.KeyBackspace: {"", "<backspace>"}, + termbox.KeyTab: {"", "<tab>"}, + termbox.KeyEnter: {"", "<enter>"}, + termbox.KeyEsc: {"", "<escape>"}, + termbox.KeyCtrlBackslash: {"C-", "\\"}, + termbox.KeyCtrlSlash: {"C-", "/"}, + termbox.KeySpace: {"", "<space>"}, + termbox.KeyCtrl8: {"C-", "8"}, + } + if sk, ok := kmap[e.Key]; ok { + pre = sk[0] + k = sk[1] + } + } + } + + ek.KeyStr = pre + mod + k + return ek } -var evtChs = make([]chan Event, 0) +func crtTermboxEvt(e termbox.Event) Event { + systypemap := map[termbox.EventType]string{ + termbox.EventKey: "keyboard", + termbox.EventResize: "window", + termbox.EventMouse: "mouse", + termbox.EventError: "error", + termbox.EventInterrupt: "interrupt", + } + ne := Event{From: "/sys", Time: time.Now().Unix()} + typ := e.Type + ne.Type = systypemap[typ] + + switch typ { + case termbox.EventKey: + kbd := evtKbd(e) + ne.Path = "/sys/kbd/" + kbd.KeyStr + ne.Data = kbd + case termbox.EventResize: + wnd := EvtWnd{} + wnd.Width = e.Width + wnd.Height = e.Height + ne.Path = "/sys/wnd/resize" + ne.Data = wnd + case termbox.EventError: + err := EvtErr(e.Err) + ne.Path = "/sys/err" + ne.Data = err + case termbox.EventMouse: + m := EvtMouse{} + m.X = e.MouseX + m.Y = e.MouseY + ne.Path = "/sys/mouse" + ne.Data = m + } + return ne +} -// EventCh returns an output-only event channel. -// This function can be called many times (multiplexer). -func EventCh() <-chan Event { - out := make(chan Event) - evtChs = append(evtChs, out) - return out +type EvtWnd struct { + Width int + Height int } -// turn on event listener -func evtListen() { - go func() { - for { - e := termbox.PollEvent() - // dispatch - for _, c := range evtChs { - go func(ch chan Event) { - ch <- uiEvt(e) - }(c) - } +type EvtMouse struct { + X int + Y int + Press string +} + +type EvtErr error + +func hookTermboxEvt() { + for { + e := termbox.PollEvent() + + for _, c := range sysEvtChs { + go func(ch chan Event) { + ch <- crtTermboxEvt(e) + }(c) } + } +} + +func NewSysEvtCh() chan Event { + ec := make(chan Event) + sysEvtChs = append(sysEvtChs, ec) + return ec +} + +var DefaultEvtStream = NewEvtStream() + +type EvtStream struct { + sync.RWMutex + srcMap map[string]chan Event + stream chan Event + wg sync.WaitGroup + sigStopLoop chan Event + Handlers map[string]func(Event) + hook func(Event) +} + +func NewEvtStream() *EvtStream { + return &EvtStream{ + srcMap: make(map[string]chan Event), + stream: make(chan Event), + Handlers: make(map[string]func(Event)), + sigStopLoop: make(chan Event), + } +} + +func (es *EvtStream) Init() { + es.Merge("internal", es.sigStopLoop) + go func() { + es.wg.Wait() + close(es.stream) }() } -/* -// EventHandlers is a handler sequence -var EventHandlers []func(Event) +func cleanPath(p string) string { + if p == "" { + return "/" + } + if p[0] != '/' { + p = "/" + p + } + return path.Clean(p) +} -var signalQuit = make(chan bool) +func isPathMatch(pattern, path string) bool { + if len(pattern) == 0 { + return false + } + n := len(pattern) + return len(path) >= n && path[0:n] == pattern +} + +func (es *EvtStream) Merge(name string, ec chan Event) { + es.Lock() + defer es.Unlock() + + es.wg.Add(1) + es.srcMap[name] = ec -// Quit sends quit signal to terminate termui -func Quit() { - signalQuit <- true + go func(a chan Event) { + for n := range a { + n.From = name + es.stream <- n + } + es.wg.Done() + }(ec) } -// Wait listening to signalQuit, block operation. -func Wait() { - <-signalQuit +func (es *EvtStream) Handle(path string, handler func(Event)) { + es.Handlers[cleanPath(path)] = handler } -// RegEvtHandler register function into TSEventHandler sequence. -func RegEvtHandler(fn func(Event)) { - EventHandlers = append(EventHandlers, fn) +func findMatch(mux map[string]func(Event), path string) string { + n := -1 + pattern := "" + for m := range mux { + if !isPathMatch(m, path) { + continue + } + if len(m) > n { + pattern = m + n = len(m) + } + } + return pattern + } -// EventLoop handles all events and -// redirects every event to callbacks in EventHandlers -func EventLoop() { - evt := make(chan termbox.Event) +func (es *EvtStream) match(path string) string { + return findMatch(es.Handlers, path) +} + +func (es *EvtStream) Hook(f func(Event)) { + es.hook = f +} +func (es *EvtStream) Loop() { + for e := range es.stream { + switch e.Path { + case "/sig/stoploop": + return + } + go func(a Event) { + es.RLock() + defer es.RUnlock() + if pattern := es.match(a.Path); pattern != "" { + es.Handlers[pattern](a) + } + }(e) + if es.hook != nil { + es.hook(e) + } + } +} + +func (es *EvtStream) StopLoop() { go func() { - for { - evt <- termbox.PollEvent() + e := Event{ + Path: "/sig/stoploop", } + es.sigStopLoop <- e }() +} - for { - select { - case c := <-signalQuit: - defer func() { signalQuit <- c }() - return - case e := <-evt: - for _, fn := range EventHandlers { - fn(uiEvt(e)) +func Merge(name string, ec chan Event) { + DefaultEvtStream.Merge(name, ec) +} + +func Handle(path string, handler func(Event)) { + DefaultEvtStream.Handle(path, handler) +} + +func Loop() { + DefaultEvtStream.Loop() +} + +func StopLoop() { + DefaultEvtStream.StopLoop() +} + +type EvtTimer struct { + Duration time.Duration + Count uint64 +} + +func NewTimerCh(du time.Duration) chan Event { + t := make(chan Event) + + go func(a chan Event) { + n := uint64(0) + for { + n++ + time.Sleep(du) + e := Event{} + e.Type = "timer" + e.Path = "/timer/" + du.String() + e.Time = time.Now().Unix() + e.Data = EvtTimer{ + Duration: du, + Count: n, } + t <- e + } - } + }(t) + return t +} + +var DefualtHandler = func(e Event) { +} + +var usrEvtCh = make(chan Event) + +func SendCustomEvt(path string, data interface{}) { + e := Event{} + e.Path = path + e.Data = data + e.Time = time.Now().Unix() + usrEvtCh <- e } -*/ |