~rockorager/tcell-term

c74329339ab66644f3e799acc43244c8711dd96d — Tim Culverhouse 1 year, 5 months ago 1eef87f
example: add a show_keys example

Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
1 files changed, 201 insertions(+), 0 deletions(-)

A example/show_keys.go
A example/show_keys.go => example/show_keys.go +201 -0
@@ 0,0 1,201 @@
//go:build ignore
// +build ignore

package main

import (
	"fmt"
	"log"
	"os"
	"os/exec"
	"strings"
	"time"

	tcellterm "git.sr.ht/~rockorager/tcell-term"
	"github.com/gdamore/tcell/v2"
	"github.com/gdamore/tcell/v2/views"
)

type model struct {
	term       *tcellterm.VT
	s          tcell.Screen
	termView   views.View
	title      *views.TextBar
	titleStyle tcell.Style
	titleView  views.View

	keyClear *time.Timer
	keys     string
}

// Update is the main event handler. It should only be called by the main thread
func (m *model) Update(ev tcell.Event) {
	switch ev := ev.(type) {
	case *tcell.EventKey:
		switch ev.Key() {
		case tcell.KeyCtrlC:
			m.term.Close()
			m.s.Fini()
			return
		}
		m.keyClear.Stop()
		m.keyClear = time.AfterFunc(1*time.Second, func() {
			m.s.PostEvent(tcell.NewEventInterrupt(""))
		})
		if m.term != nil {
			m.term.HandleEvent(ev)
		}
		m.keys += keyNames(ev)
		m.title.SetCenter(m.keys, m.titleStyle)
		m.term.Draw()
		m.s.Show()
	case *tcell.EventInterrupt:
		m.keys = ""
		m.title.SetLeft(m.keys, m.titleStyle)
		m.s.Show()
	case *tcell.EventResize:
		_, h := ev.Size()
		if m.term != nil {
			m.termView.Resize(0, 0, -1, h-1)
			m.term.Resize(m.termView.Size())
		}
		m.titleView.Resize(0, h-1, -1, 1)
		m.title.Resize()
		m.title.Draw()
		m.term.Draw()
		m.s.Sync()
		return
	case *tcellterm.EventRedraw:
		m.term.Draw()
		m.title.Draw()

		row, col, style, vis := m.term.Cursor()
		if vis {
			m.s.SetCursorStyle(style)
			m.s.ShowCursor(col, row)

		} else {
			m.s.HideCursor()
		}
		m.s.Show()
		return
	case *tcellterm.EventClosed:
		m.s.Clear()
		m.s.Fini()
		return
	case *tcell.EventPaste:
		m.term.HandleEvent(ev)
		return
	case *tcell.EventMouse:
		// Translate the coordinates to our global coordinates (y-2)
		x, y := ev.Position()
		if y-2 < 0 {
			// Event is outside our view
			return
		}
		e := tcell.NewEventMouse(x, y, ev.Buttons(), ev.Modifiers())
		m.term.HandleEvent(e)
		return
	case *tcellterm.EventMouseMode:
		m.s.EnableMouse(ev.Flags()...)
	case *tcellterm.EventPanic:
		m.s.Clear()
		m.s.Fini()
		fmt.Println(ev.Error)
	}
	return
}

// HandleEvent is used to handle events from underlying widgets. Any events
// which redraw must be executed in the main goroutine by posting the event back
// to tcell
func (m *model) HandleEvent(ev tcell.Event) {
	m.s.PostEvent(ev)
}

func main() {
	f, _ := os.Create("recording.log")
	log.SetOutput(f)
	var err error
	m := &model{}
	m.s, err = tcell.NewScreen()
	if err != nil {
		fmt.Fprintf(os.Stderr, "%v\n", err)
		os.Exit(1)
	}
	if err = m.s.Init(); err != nil {
		fmt.Fprintf(os.Stderr, "%v\n", err)
		os.Exit(1)
	}
	m.s.EnablePaste()
	m.keyClear = time.NewTimer(0)

	m.title = views.NewTextBar()
	m.title.SetStyle(tcell.StyleDefault.Reverse(true))

	_, h := m.s.Size()
	fmt.Print(h)
	m.titleView = views.NewViewPort(m.s, 0, h-1, -1, 1)
	m.title.SetView(m.titleView)

	m.termView = views.NewViewPort(m.s, 0, 0, -1, h-1)
	m.term = tcellterm.New()
	m.term.SetSurface(m.termView)
	m.term.Attach(m.HandleEvent)
	m.term.Logger = log.New(f, "", log.Flags())
	m.s.EnableMouse()

	cmd := exec.Command(os.Getenv("SHELL"))
	err = m.term.Start(cmd)
	if err != nil {
		panic(err)
	}
	for {
		ev := m.s.PollEvent()
		if ev == nil {
			break
		}
		m.Update(ev)
	}
}

func keyNames(ev *tcell.EventKey) string {
	s := ""
	m := []string{}
	if ev.Modifiers()&tcell.ModShift != 0 {
		m = append(m, "Shift")
	}
	if ev.Modifiers()&tcell.ModAlt != 0 {
		m = append(m, "Alt")
	}
	if ev.Modifiers()&tcell.ModMeta != 0 {
		m = append(m, "Meta")
	}
	if ev.Modifiers()&tcell.ModCtrl != 0 {
		m = append(m, "Ctrl")
	}

	ok := false
	if s, ok = tcell.KeyNames[ev.Key()]; !ok {
		if ev.Key() == tcell.KeyRune {
			switch ev.Rune() {
			case ' ':
				s = "Space+"
			default:
				s = string(ev.Rune())
			}
		} else {
			s = fmt.Sprintf("Key[%d,%d]", ev.Key(), int(ev.Rune()))
		}
	}
	if ok {
		s += "+"
	}
	if len(m) != 0 {
		if ev.Modifiers()&tcell.ModCtrl != 0 && strings.HasPrefix(s, "Ctrl-") {
			s = s[5:]
		}
		return fmt.Sprintf("%s+%s", strings.Join(m, "+"), s)
	}
	return s
}