mirror of https://github.com/rivo/tview.git
All primitives now offer a way to intercept all key events sent to them. Also made the global key event intercept handler more general/consistent. Resolves #22
This commit is contained in:
parent
f61c66bb82
commit
626453b2a6
|
@ -62,6 +62,9 @@ Add your issue here on GitHub. Feel free to get in touch if you have any questio
|
||||||
|
|
||||||
## Releases
|
## Releases
|
||||||
|
|
||||||
|
- v0.6 (2018-01-14)
|
||||||
|
- All primitives can now intercept all key events when they have focus.
|
||||||
|
- Key events can also be intercepted globally (changed to a more general, consistent handling)
|
||||||
- v0.5 (2018-01-13)
|
- v0.5 (2018-01-13)
|
||||||
- `TextView` now has word wrapping and text alignment
|
- `TextView` now has word wrapping and text alignment
|
||||||
- v0.4 (2018-01-12)
|
- v0.4 (2018-01-12)
|
||||||
|
|
|
@ -26,55 +26,28 @@ type Application struct {
|
||||||
// Whether or not the application resizes the root primitive.
|
// Whether or not the application resizes the root primitive.
|
||||||
rootAutoSize bool
|
rootAutoSize bool
|
||||||
|
|
||||||
// Key overrides.
|
// An optional capture function which receives a key event and returns the
|
||||||
keyOverrides map[tcell.Key]func(p Primitive) bool
|
// event to be forwarded to the default input handler (nil if nothing should
|
||||||
|
// be forwarded).
|
||||||
// Rune overrides.
|
inputCapture func(event *tcell.EventKey) *tcell.EventKey
|
||||||
runeOverrides map[rune]func(p Primitive) bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewApplication creates and returns a new application.
|
// NewApplication creates and returns a new application.
|
||||||
func NewApplication() *Application {
|
func NewApplication() *Application {
|
||||||
return &Application{
|
return &Application{}
|
||||||
keyOverrides: make(map[tcell.Key]func(p Primitive) bool),
|
|
||||||
runeOverrides: make(map[rune]func(p Primitive) bool),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetKeyCapture installs a global capture function for the given key. It
|
// SetInputCapture sets a function which captures all key events before they are
|
||||||
// intercepts all events for the given key and routes them to the handler.
|
// forwarded to the key event handler of the primitive which currently has
|
||||||
// The handler receives the Primitive to which the key is originally redirected,
|
// focus. This function can then choose to forward that key event (or a
|
||||||
// the one which has focus, or nil if it was not directed to a Primitive. The
|
// different one) by returning it or stop the key event processing by returning
|
||||||
// handler also returns whether or not the key event is then forwarded to that
|
// nil.
|
||||||
// Primitive. Draw() is called implicitly if the event is not forwarded.
|
|
||||||
//
|
//
|
||||||
// Special keys (e.g. Escape, Enter, or Ctrl-A) are defined by the "key"
|
// Note that this also affects the default event handling of the application
|
||||||
// argument. The "ch" rune is ignored. Other keys (e.g. "a", "h", or "5") are
|
// itself: Such a handler can intercept the Ctrl-C event which closes the
|
||||||
// specified by their rune, with key set to tcell.KeyRune. See also
|
// applicaton.
|
||||||
// https://godoc.org/github.com/gdamore/tcell#EventKey for more information.
|
func (a *Application) SetInputCapture(capture func(event *tcell.EventKey) *tcell.EventKey) *Application {
|
||||||
//
|
a.inputCapture = capture
|
||||||
// To remove a handler again, provide a nil handler for the same key.
|
|
||||||
//
|
|
||||||
// The application itself will exit when Ctrl-C is pressed. You can intercept
|
|
||||||
// this with this function as well.
|
|
||||||
func (a *Application) SetKeyCapture(key tcell.Key, ch rune, handler func(p Primitive) bool) *Application {
|
|
||||||
if key == tcell.KeyRune {
|
|
||||||
if handler != nil {
|
|
||||||
a.runeOverrides[ch] = handler
|
|
||||||
} else {
|
|
||||||
if _, ok := a.runeOverrides[ch]; ok {
|
|
||||||
delete(a.runeOverrides, ch)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if handler != nil {
|
|
||||||
a.keyOverrides[key] = handler
|
|
||||||
} else {
|
|
||||||
if _, ok := a.keyOverrides[key]; ok {
|
|
||||||
delete(a.keyOverrides, key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,23 +104,10 @@ func (a *Application) Run() error {
|
||||||
a.RUnlock()
|
a.RUnlock()
|
||||||
|
|
||||||
// Intercept keys.
|
// Intercept keys.
|
||||||
if event.Key() == tcell.KeyRune {
|
if a.inputCapture != nil {
|
||||||
if handler, ok := a.runeOverrides[event.Rune()]; ok {
|
event = a.inputCapture(event)
|
||||||
if !handler(p) {
|
if event == nil {
|
||||||
a.Draw()
|
break // Don't forward event.
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if handler, ok := a.keyOverrides[event.Key()]; ok {
|
|
||||||
pr := p
|
|
||||||
if event.Key() == tcell.KeyCtrlC {
|
|
||||||
pr = nil
|
|
||||||
}
|
|
||||||
if !handler(pr) {
|
|
||||||
a.Draw()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
34
box.go
34
box.go
|
@ -9,6 +9,9 @@ import (
|
||||||
// border and a title. Most subclasses keep their content contained in the box
|
// border and a title. Most subclasses keep their content contained in the box
|
||||||
// but don't necessarily have to.
|
// but don't necessarily have to.
|
||||||
//
|
//
|
||||||
|
// Note that all classes which subclass from Box will also have access to its
|
||||||
|
// functions.
|
||||||
|
//
|
||||||
// See https://github.com/rivo/tview/wiki/Box for an example.
|
// See https://github.com/rivo/tview/wiki/Box for an example.
|
||||||
type Box struct {
|
type Box struct {
|
||||||
// The position of the rect.
|
// The position of the rect.
|
||||||
|
@ -42,6 +45,11 @@ type Box struct {
|
||||||
|
|
||||||
// Whether or not this box has focus.
|
// Whether or not this box has focus.
|
||||||
hasFocus bool
|
hasFocus bool
|
||||||
|
|
||||||
|
// An optional capture function which receives a key event and returns the
|
||||||
|
// event to be forwarded to the primitive's default input handler (nil if
|
||||||
|
// nothing should be forwarded).
|
||||||
|
inputCapture func(event *tcell.EventKey) *tcell.EventKey
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBox returns a Box without a border.
|
// NewBox returns a Box without a border.
|
||||||
|
@ -94,9 +102,33 @@ func (b *Box) SetRect(x, y, width, height int) {
|
||||||
b.height = height
|
b.height = height
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// wrapInputHandler wraps an input handler (see InputHandler()) with the
|
||||||
|
// functionality to capture input (see SetInputCapture()) before passing it
|
||||||
|
// on to the provided (default) input handler.
|
||||||
|
func (b *Box) wrapInputHandler(inputHandler func(*tcell.EventKey, func(p Primitive))) func(*tcell.EventKey, func(p Primitive)) {
|
||||||
|
return func(event *tcell.EventKey, setFocus func(p Primitive)) {
|
||||||
|
if b.inputCapture != nil {
|
||||||
|
event = b.inputCapture(event)
|
||||||
|
}
|
||||||
|
if event != nil && inputHandler != nil {
|
||||||
|
inputHandler(event, setFocus)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// InputHandler returns nil.
|
// InputHandler returns nil.
|
||||||
func (b *Box) InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive)) {
|
func (b *Box) InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive)) {
|
||||||
return nil
|
return b.wrapInputHandler(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetInputCapture sets a function which captures key events before they are
|
||||||
|
// forwarded to the primitive's default key event handler. This function can
|
||||||
|
// then choose to forward that key event (or a different one) to the default
|
||||||
|
// handler by returning it. If nil is returned, the default handler will not
|
||||||
|
// be called.
|
||||||
|
func (b *Box) SetInputCapture(capture func(event *tcell.EventKey) *tcell.EventKey) *Box {
|
||||||
|
b.inputCapture = capture
|
||||||
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetBackgroundColor sets the box's background color.
|
// SetBackgroundColor sets the box's background color.
|
||||||
|
|
|
@ -122,7 +122,7 @@ func (b *Button) Draw(screen tcell.Screen) {
|
||||||
|
|
||||||
// InputHandler returns the handler for this primitive.
|
// InputHandler returns the handler for this primitive.
|
||||||
func (b *Button) InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive)) {
|
func (b *Button) InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive)) {
|
||||||
return func(event *tcell.EventKey, setFocus func(p Primitive)) {
|
return b.wrapInputHandler(func(event *tcell.EventKey, setFocus func(p Primitive)) {
|
||||||
// Process key event.
|
// Process key event.
|
||||||
switch key := event.Key(); key {
|
switch key := event.Key(); key {
|
||||||
case tcell.KeyEnter: // Selected.
|
case tcell.KeyEnter: // Selected.
|
||||||
|
@ -134,5 +134,5 @@ func (b *Button) InputHandler() func(event *tcell.EventKey, setFocus func(p Prim
|
||||||
b.blur(key)
|
b.blur(key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -150,7 +150,7 @@ func (c *Checkbox) Draw(screen tcell.Screen) {
|
||||||
|
|
||||||
// InputHandler returns the handler for this primitive.
|
// InputHandler returns the handler for this primitive.
|
||||||
func (c *Checkbox) InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive)) {
|
func (c *Checkbox) InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive)) {
|
||||||
return func(event *tcell.EventKey, setFocus func(p Primitive)) {
|
return c.wrapInputHandler(func(event *tcell.EventKey, setFocus func(p Primitive)) {
|
||||||
// Process key event.
|
// Process key event.
|
||||||
switch key := event.Key(); key {
|
switch key := event.Key(); key {
|
||||||
case tcell.KeyRune, tcell.KeyEnter: // Check.
|
case tcell.KeyRune, tcell.KeyEnter: // Check.
|
||||||
|
@ -166,5 +166,5 @@ func (c *Checkbox) InputHandler() func(event *tcell.EventKey, setFocus func(p Pr
|
||||||
c.done(key)
|
c.done(key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,12 +77,13 @@ func main() {
|
||||||
AddItem(info, 1, 1, false)
|
AddItem(info, 1, 1, false)
|
||||||
|
|
||||||
// Shortcuts to navigate the slides.
|
// Shortcuts to navigate the slides.
|
||||||
app.SetKeyCapture(tcell.KeyCtrlN, 0, func(p tview.Primitive) bool {
|
app.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
|
||||||
|
if event.Key() == tcell.KeyCtrlN {
|
||||||
nextSlide()
|
nextSlide()
|
||||||
return false
|
} else if event.Key() == tcell.KeyCtrlP {
|
||||||
}).SetKeyCapture(tcell.KeyCtrlP, 0, func(p tview.Primitive) bool {
|
|
||||||
previousSlide()
|
previousSlide()
|
||||||
return false
|
}
|
||||||
|
return event
|
||||||
})
|
})
|
||||||
|
|
||||||
// Start the application.
|
// Start the application.
|
||||||
|
|
|
@ -249,7 +249,7 @@ func (d *DropDown) Draw(screen tcell.Screen) {
|
||||||
|
|
||||||
// InputHandler returns the handler for this primitive.
|
// InputHandler returns the handler for this primitive.
|
||||||
func (d *DropDown) InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive)) {
|
func (d *DropDown) InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive)) {
|
||||||
return func(event *tcell.EventKey, setFocus func(p Primitive)) {
|
return d.wrapInputHandler(func(event *tcell.EventKey, setFocus func(p Primitive)) {
|
||||||
// Process key event.
|
// Process key event.
|
||||||
switch key := event.Key(); key {
|
switch key := event.Key(); key {
|
||||||
case tcell.KeyEnter, tcell.KeyRune, tcell.KeyDown:
|
case tcell.KeyEnter, tcell.KeyRune, tcell.KeyDown:
|
||||||
|
@ -274,7 +274,7 @@ func (d *DropDown) InputHandler() func(event *tcell.EventKey, setFocus func(p Pr
|
||||||
d.done(key)
|
d.done(key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Focus is called by the application when the primitive receives focus.
|
// Focus is called by the application when the primitive receives focus.
|
||||||
|
|
|
@ -236,7 +236,7 @@ func (i *InputField) setCursor(screen tcell.Screen) {
|
||||||
|
|
||||||
// InputHandler returns the handler for this primitive.
|
// InputHandler returns the handler for this primitive.
|
||||||
func (i *InputField) InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive)) {
|
func (i *InputField) InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive)) {
|
||||||
return func(event *tcell.EventKey, setFocus func(p Primitive)) {
|
return i.wrapInputHandler(func(event *tcell.EventKey, setFocus func(p Primitive)) {
|
||||||
// Trigger changed events.
|
// Trigger changed events.
|
||||||
currentText := i.text
|
currentText := i.text
|
||||||
defer func() {
|
defer func() {
|
||||||
|
@ -271,5 +271,5 @@ func (i *InputField) InputHandler() func(event *tcell.EventKey, setFocus func(p
|
||||||
i.done(key)
|
i.done(key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
4
list.go
4
list.go
|
@ -232,7 +232,7 @@ func (l *List) Draw(screen tcell.Screen) {
|
||||||
|
|
||||||
// InputHandler returns the handler for this primitive.
|
// InputHandler returns the handler for this primitive.
|
||||||
func (l *List) InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive)) {
|
func (l *List) InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive)) {
|
||||||
return func(event *tcell.EventKey, setFocus func(p Primitive)) {
|
return l.wrapInputHandler(func(event *tcell.EventKey, setFocus func(p Primitive)) {
|
||||||
previousItem := l.currentItem
|
previousItem := l.currentItem
|
||||||
|
|
||||||
switch key := event.Key(); key {
|
switch key := event.Key(); key {
|
||||||
|
@ -296,5 +296,5 @@ func (l *List) InputHandler() func(event *tcell.EventKey, setFocus func(p Primit
|
||||||
item := l.items[l.currentItem]
|
item := l.items[l.currentItem]
|
||||||
l.changed(l.currentItem, item.MainText, item.SecondaryText, item.Shortcut)
|
l.changed(l.currentItem, item.MainText, item.SecondaryText, item.Shortcut)
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,10 @@ type Primitive interface {
|
||||||
//
|
//
|
||||||
// The Application's Draw() function will be called automatically after the
|
// The Application's Draw() function will be called automatically after the
|
||||||
// handler returns.
|
// handler returns.
|
||||||
|
//
|
||||||
|
// The Box class provides functionality to intercept keyboard input. If you
|
||||||
|
// subclass from Box, it is recommended that you wrap your handler using
|
||||||
|
// Box.wrapInputHandler() so you inherit that functionality.
|
||||||
InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive))
|
InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive))
|
||||||
|
|
||||||
// Focus is called by the application when the primitive receives focus.
|
// Focus is called by the application when the primitive receives focus.
|
||||||
|
|
4
table.go
4
table.go
|
@ -717,7 +717,7 @@ ColumnLoop:
|
||||||
|
|
||||||
// InputHandler returns the handler for this primitive.
|
// InputHandler returns the handler for this primitive.
|
||||||
func (t *Table) InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive)) {
|
func (t *Table) InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive)) {
|
||||||
return func(event *tcell.EventKey, setFocus func(p Primitive)) {
|
return t.wrapInputHandler(func(event *tcell.EventKey, setFocus func(p Primitive)) {
|
||||||
key := event.Key()
|
key := event.Key()
|
||||||
|
|
||||||
if (!t.rowsSelectable && !t.columnsSelectable && key == tcell.KeyEnter) ||
|
if (!t.rowsSelectable && !t.columnsSelectable && key == tcell.KeyEnter) ||
|
||||||
|
@ -920,5 +920,5 @@ func (t *Table) InputHandler() func(event *tcell.EventKey, setFocus func(p Primi
|
||||||
t.columnsSelectable && previouslySelectedColumn != t.selectedColumn) {
|
t.columnsSelectable && previouslySelectedColumn != t.selectedColumn) {
|
||||||
t.selectionChanged(t.selectedRow, t.selectedColumn)
|
t.selectionChanged(t.selectedRow, t.selectedColumn)
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -836,7 +836,7 @@ func (t *TextView) Draw(screen tcell.Screen) {
|
||||||
|
|
||||||
// InputHandler returns the handler for this primitive.
|
// InputHandler returns the handler for this primitive.
|
||||||
func (t *TextView) InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive)) {
|
func (t *TextView) InputHandler() func(event *tcell.EventKey, setFocus func(p Primitive)) {
|
||||||
return func(event *tcell.EventKey, setFocus func(p Primitive)) {
|
return t.wrapInputHandler(func(event *tcell.EventKey, setFocus func(p Primitive)) {
|
||||||
// Do we pass this event on?
|
// Do we pass this event on?
|
||||||
if t.capture != nil {
|
if t.capture != nil {
|
||||||
if !t.capture(event) {
|
if !t.capture(event) {
|
||||||
|
@ -899,5 +899,5 @@ func (t *TextView) InputHandler() func(event *tcell.EventKey, setFocus func(p Pr
|
||||||
t.trackEnd = false
|
t.trackEnd = false
|
||||||
t.lineOffset -= t.pageSize
|
t.lineOffset -= t.pageSize
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue