// Copyright 2017 Zack Guo . All rights reserved. // Use of this source code is governed by a MIT license that can // be found in the LICENSE file. package termui import ( "fmt" tb "github.com/nsf/termbox-go" ) /* List of events: mouse events: keyboard events: any uppercase or lowercase letter like j or J etc etc > etc terminal events: */ type EventType int const ( KeyboardEvent EventType = iota MouseEvent ResizeEvent ) type Event struct { Type EventType ID string Payload interface{} } // Mouse payload. type Mouse struct { Drag bool X int Y int } // Resize payload. type Resize struct { Width int Height int } // PollEvents gets events from termbox, converts them, then sends them to each of its channels. func PollEvents() <-chan Event { ch := make(chan Event) go func() { for { ch <- convertTermboxEvent(tb.PollEvent()) } }() return ch } // convertTermboxKeyboardEvent 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 convertTermboxKeyboardEvent(e tb.Event) Event { ID := "%s" if e.Mod == tb.ModAlt { ID = "" } if e.Ch != 0 { ID = fmt.Sprintf(ID, string(e.Ch)) } else { switchExpression := func() string { switch e.Key { case tb.KeyF1: return "" case tb.KeyF2: return "" case tb.KeyF3: return "" case tb.KeyF4: return "" case tb.KeyF5: return "" case tb.KeyF6: return "" case tb.KeyF7: return "" case tb.KeyF8: return "" case tb.KeyF9: return "" case tb.KeyF10: return "" case tb.KeyF11: return "" case tb.KeyF12: return "" case tb.KeyInsert: return "" case tb.KeyDelete: return "" case tb.KeyHome: return "" case tb.KeyEnd: return "" case tb.KeyPgup: return "" case tb.KeyPgdn: return "" case tb.KeyArrowUp: return "" case tb.KeyArrowDown: return "" case tb.KeyArrowLeft: return "" case tb.KeyArrowRight: return "" case tb.KeyCtrlTilde: // tb.KeyCtrl2 tb.KeyCtrlSpace // doesn't work // doesn't work return ">" case tb.KeyCtrlA: return "" case tb.KeyCtrlB: return "" case tb.KeyCtrlC: return "" case tb.KeyCtrlD: return "" case tb.KeyCtrlE: return "" case tb.KeyCtrlF: return "" case tb.KeyCtrlG: return "" case tb.KeyBackspace: // tb.KeyCtrlH // doesn't work return ">" case tb.KeyTab: // tb.KeyCtrlI // doesn't work return "" case tb.KeyCtrlJ: return "" case tb.KeyCtrlK: return "" case tb.KeyCtrlL: return "" case tb.KeyEnter: // tb.KeyCtrlM // doesn't work return "" case tb.KeyCtrlN: return "" case tb.KeyCtrlO: return "" case tb.KeyCtrlP: return "" case tb.KeyCtrlQ: return "" case tb.KeyCtrlR: return "" case tb.KeyCtrlS: return "" case tb.KeyCtrlT: return "" case tb.KeyCtrlU: return "" case tb.KeyCtrlV: return "" case tb.KeyCtrlW: return "" case tb.KeyCtrlX: return "" case tb.KeyCtrlY: return "" case tb.KeyCtrlZ: return "" case tb.KeyEsc: // tb.KeyCtrlLsqBracket tb.KeyCtrl3 // doesn't work // doesn't work return "" case tb.KeyCtrl4: // tb.KeyCtrlBackslash // doesn't work return "" case tb.KeyCtrl5: // tb.KeyCtrlRsqBracket // doesn't work return "" case tb.KeyCtrl6: return "" case tb.KeyCtrl7: // tb.KeyCtrlSlash tb.KeyCtrlUnderscore // doesn't work // doesn't work return "" case tb.KeySpace: return "" case tb.KeyBackspace2: // tb.KeyCtrl8: // doesn't work return "" } // doesn't work return "" } ID = fmt.Sprintf(ID, switchExpression()) } return Event{ Type: KeyboardEvent, ID: ID, } } func convertTermboxMouseEvent(e tb.Event) Event { mouseButtonMap := map[tb.Key]string{ tb.MouseLeft: "", tb.MouseMiddle: "", tb.MouseRight: "", tb.MouseRelease: "", tb.MouseWheelUp: "", tb.MouseWheelDown: "", } converted, ok := mouseButtonMap[e.Key] if !ok { converted = "Unknown_Mouse_Button" } Drag := false if e.Mod == tb.ModMotion { Drag = true } return Event{ Type: MouseEvent, ID: converted, Payload: Mouse{ X: e.MouseX, Y: e.MouseY, Drag: Drag, }, } } // convertTermboxEvent turns a termbox event into a termui event. func convertTermboxEvent(e tb.Event) Event { if e.Type == tb.EventError { panic(e.Err) } var event Event switch e.Type { case tb.EventKey: event = convertTermboxKeyboardEvent(e) case tb.EventMouse: event = convertTermboxMouseEvent(e) case tb.EventResize: event = Event{ Type: ResizeEvent, ID: "", Payload: Resize{ Width: e.Width, Height: e.Height, }, } } return event }