mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-03-19 21:28:28 +02:00
move recording code into gocui
This commit is contained in:
parent
41747b5b34
commit
d4622bac30
@ -3,6 +3,7 @@ package gui
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
@ -89,11 +90,6 @@ type Gui struct {
|
|||||||
// recent repo with the recent repos popup showing
|
// recent repo with the recent repos popup showing
|
||||||
showRecentRepos bool
|
showRecentRepos bool
|
||||||
|
|
||||||
// this array either includes the events that we're recording in this session
|
|
||||||
// or the events we've recorded in a prior session
|
|
||||||
RecordedEvents []RecordedEvent
|
|
||||||
StartTime time.Time
|
|
||||||
|
|
||||||
Mutexes guiStateMutexes
|
Mutexes guiStateMutexes
|
||||||
|
|
||||||
// findSuggestions will take a string that the user has typed into a prompt
|
// findSuggestions will take a string that the user has typed into a prompt
|
||||||
@ -110,11 +106,6 @@ type Gui struct {
|
|||||||
Views Views
|
Views Views
|
||||||
}
|
}
|
||||||
|
|
||||||
type RecordedEvent struct {
|
|
||||||
Timestamp int64
|
|
||||||
Event *gocui.GocuiEvent
|
|
||||||
}
|
|
||||||
|
|
||||||
type listPanelState struct {
|
type listPanelState struct {
|
||||||
SelectedLineIdx int
|
SelectedLineIdx int
|
||||||
}
|
}
|
||||||
@ -446,7 +437,6 @@ func NewGui(log *logrus.Entry, gitCommand *commands.GitCommand, oSCommand *oscom
|
|||||||
statusManager: &statusManager{},
|
statusManager: &statusManager{},
|
||||||
viewBufferManagerMap: map[string]*tasks.ViewBufferManager{},
|
viewBufferManagerMap: map[string]*tasks.ViewBufferManager{},
|
||||||
showRecentRepos: showRecentRepos,
|
showRecentRepos: showRecentRepos,
|
||||||
RecordedEvents: []RecordedEvent{},
|
|
||||||
RepoPathStack: []string{},
|
RepoPathStack: []string{},
|
||||||
RepoStateMap: map[Repo]*guiState{},
|
RepoStateMap: map[Repo]*guiState{},
|
||||||
}
|
}
|
||||||
@ -461,16 +451,35 @@ func NewGui(log *logrus.Entry, gitCommand *commands.GitCommand, oSCommand *oscom
|
|||||||
// Run setup the gui with keybindings and start the mainloop
|
// Run setup the gui with keybindings and start the mainloop
|
||||||
func (gui *Gui) Run() error {
|
func (gui *Gui) Run() error {
|
||||||
recordEvents := recordingEvents()
|
recordEvents := recordingEvents()
|
||||||
|
playMode := gocui.NORMAL
|
||||||
|
if recordEvents {
|
||||||
|
playMode = gocui.RECORDING
|
||||||
|
} else if replaying() {
|
||||||
|
playMode = gocui.REPLAYING
|
||||||
|
}
|
||||||
|
|
||||||
g, err := gocui.NewGui(gocui.OutputTrue, OverlappingEdges, recordEvents)
|
g, err := gocui.NewGui(gocui.OutputTrue, OverlappingEdges, playMode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
gui.g = g // TODO: always use gui.g rather than passing g around everywhere
|
gui.g = g // TODO: always use gui.g rather than passing g around everywhere
|
||||||
defer g.Close()
|
defer g.Close()
|
||||||
|
|
||||||
if recordEvents {
|
if replaying() {
|
||||||
go utils.Safe(gui.recordEvents)
|
g.RecordingConfig = gocui.RecordingConfig{
|
||||||
|
Speed: getRecordingSpeed(),
|
||||||
|
Leeway: 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
g.Recording, err = gui.loadRecording()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
go utils.Safe(func() {
|
||||||
|
time.Sleep(time.Second * 20)
|
||||||
|
log.Fatal("20 seconds is up, lazygit recording took too long to complete")
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
g.OnSearchEscape = gui.onSearchEscape
|
g.OnSearchEscape = gui.onSearchEscape
|
||||||
@ -518,9 +527,6 @@ func (gui *Gui) Run() error {
|
|||||||
|
|
||||||
// RunAndHandleError
|
// RunAndHandleError
|
||||||
func (gui *Gui) RunAndHandleError() error {
|
func (gui *Gui) RunAndHandleError() error {
|
||||||
gui.StartTime = time.Now()
|
|
||||||
go utils.Safe(gui.replayRecordedEvents)
|
|
||||||
|
|
||||||
gui.stopChan = make(chan struct{})
|
gui.stopChan = make(chan struct{})
|
||||||
return utils.SafeWithError(func() error {
|
return utils.SafeWithError(func() error {
|
||||||
if err := gui.Run(); err != nil {
|
if err := gui.Run(); err != nil {
|
||||||
@ -542,7 +548,7 @@ func (gui *Gui) RunAndHandleError() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := gui.saveRecordedEvents(); err != nil {
|
if err := gui.saveRecording(gui.g.Recording); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,10 +6,8 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/jesseduffield/gocui"
|
"github.com/jesseduffield/gocui"
|
||||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func recordingEvents() bool {
|
func recordingEvents() bool {
|
||||||
@ -20,31 +18,11 @@ func recordEventsTo() string {
|
|||||||
return os.Getenv("RECORD_EVENTS_TO")
|
return os.Getenv("RECORD_EVENTS_TO")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) timeSinceStart() int64 {
|
func replaying() bool {
|
||||||
return time.Since(gui.StartTime).Nanoseconds() / 1e6
|
return os.Getenv("REPLAY_EVENTS_FROM") != ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) replayRecordedEvents() {
|
func getRecordingSpeed() int {
|
||||||
gui.Log.Warn("going to replay events")
|
|
||||||
if os.Getenv("REPLAY_EVENTS_FROM") == "" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
go utils.Safe(func() {
|
|
||||||
time.Sleep(time.Second * 20)
|
|
||||||
log.Fatal("20 seconds is up, lazygit recording took too long to complete")
|
|
||||||
})
|
|
||||||
|
|
||||||
events, err := gui.loadRecordedEvents()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
ticker := time.NewTicker(time.Millisecond)
|
|
||||||
defer ticker.Stop()
|
|
||||||
|
|
||||||
// might need to add leeway if this ends up flakey
|
|
||||||
var leeway int64 = 0
|
|
||||||
// humans are slow so this speeds things up.
|
// humans are slow so this speeds things up.
|
||||||
speed := 1
|
speed := 1
|
||||||
envReplaySpeed := os.Getenv("REPLAY_SPEED")
|
envReplaySpeed := os.Getenv("REPLAY_SPEED")
|
||||||
@ -55,49 +33,10 @@ func (gui *Gui) replayRecordedEvents() {
|
|||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return speed
|
||||||
// The playback could be paused at any time because integration tests run concurrently.
|
|
||||||
// Therefore we can't just check for a given event whether we've passed its timestamp,
|
|
||||||
// or else we'll have an explosion of keypresses after the test is resumed.
|
|
||||||
// We need to check if we've waited long enough since the last event was replayed.
|
|
||||||
for i, event := range events {
|
|
||||||
var prevEventTimestamp int64 = 0
|
|
||||||
if i > 0 {
|
|
||||||
prevEventTimestamp = events[i-1].Timestamp
|
|
||||||
}
|
|
||||||
timeToWait := (event.Timestamp - prevEventTimestamp) / int64(speed)
|
|
||||||
if i == 0 {
|
|
||||||
timeToWait += leeway
|
|
||||||
}
|
|
||||||
var timeWaited int64 = 0
|
|
||||||
middle:
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-ticker.C:
|
|
||||||
timeWaited += 1
|
|
||||||
if gui.g != nil && timeWaited >= timeToWait {
|
|
||||||
gui.Log.Warn("replaying event")
|
|
||||||
gui.g.ReplayedEvents <- *event.Event
|
|
||||||
break middle
|
|
||||||
}
|
|
||||||
case <-gui.stopChan:
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
time.Sleep(time.Second * 1)
|
|
||||||
|
|
||||||
gui.g.Update(func(*gocui.Gui) error {
|
|
||||||
return gocui.ErrQuit
|
|
||||||
})
|
|
||||||
|
|
||||||
time.Sleep(time.Second * 1)
|
|
||||||
|
|
||||||
log.Fatal("lazygit should have already exited")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) loadRecordedEvents() ([]RecordedEvent, error) {
|
func (gui *Gui) loadRecording() (*gocui.Recording, error) {
|
||||||
path := os.Getenv("REPLAY_EVENTS_FROM")
|
path := os.Getenv("REPLAY_EVENTS_FROM")
|
||||||
|
|
||||||
data, err := ioutil.ReadFile(path)
|
data, err := ioutil.ReadFile(path)
|
||||||
@ -105,22 +44,22 @@ func (gui *Gui) loadRecordedEvents() ([]RecordedEvent, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
events := []RecordedEvent{}
|
recording := &gocui.Recording{}
|
||||||
|
|
||||||
err = json.Unmarshal(data, &events)
|
err = json.Unmarshal(data, &recording)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return events, nil
|
return recording, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) saveRecordedEvents() error {
|
func (gui *Gui) saveRecording(recording *gocui.Recording) error {
|
||||||
if !recordingEvents() {
|
if !recordingEvents() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
jsonEvents, err := json.Marshal(gui.RecordedEvents)
|
jsonEvents, err := json.Marshal(recording)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -129,14 +68,3 @@ func (gui *Gui) saveRecordedEvents() error {
|
|||||||
|
|
||||||
return ioutil.WriteFile(path, jsonEvents, 0600)
|
return ioutil.WriteFile(path, jsonEvents, 0600)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gui *Gui) recordEvents() {
|
|
||||||
for event := range gui.g.RecordedEvents {
|
|
||||||
recordedEvent := RecordedEvent{
|
|
||||||
Timestamp: gui.timeSinceStart(),
|
|
||||||
Event: event,
|
|
||||||
}
|
|
||||||
|
|
||||||
gui.RecordedEvents = append(gui.RecordedEvents, recordedEvent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
65
vendor/github.com/jesseduffield/gocui/gui.go
generated
vendored
65
vendor/github.com/jesseduffield/gocui/gui.go
generated
vendored
@ -75,13 +75,36 @@ type GuiMutexes struct {
|
|||||||
ViewsMutex sync.Mutex
|
ViewsMutex sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PlayMode int
|
||||||
|
|
||||||
|
const (
|
||||||
|
NORMAL PlayMode = iota
|
||||||
|
RECORDING
|
||||||
|
REPLAYING
|
||||||
|
)
|
||||||
|
|
||||||
|
type Recording struct {
|
||||||
|
KeyEvents []*TcellKeyEventWrapper
|
||||||
|
}
|
||||||
|
|
||||||
|
type replayedEvents struct {
|
||||||
|
keys chan *TcellKeyEventWrapper
|
||||||
|
}
|
||||||
|
|
||||||
|
type RecordingConfig struct {
|
||||||
|
Speed int
|
||||||
|
Leeway int
|
||||||
|
}
|
||||||
|
|
||||||
// Gui represents the whole User Interface, including the views, layouts
|
// Gui represents the whole User Interface, including the views, layouts
|
||||||
// and keybindings.
|
// and keybindings.
|
||||||
type Gui struct {
|
type Gui struct {
|
||||||
// ReplayedEvents is a channel for passing pre-recorded input events, for the purposes of testing
|
RecordingConfig
|
||||||
ReplayedEvents chan GocuiEvent
|
Recording *Recording
|
||||||
RecordEvents bool
|
// ReplayedEvents is for passing pre-recorded input events, for the purposes of testing
|
||||||
RecordedEvents chan *GocuiEvent
|
ReplayedEvents replayedEvents
|
||||||
|
PlayMode PlayMode
|
||||||
|
StartTime time.Time
|
||||||
|
|
||||||
tabClickBindings []*tabClickBinding
|
tabClickBindings []*tabClickBinding
|
||||||
gEvents chan GocuiEvent
|
gEvents chan GocuiEvent
|
||||||
@ -135,7 +158,7 @@ type Gui struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewGui returns a new Gui object with a given output mode.
|
// NewGui returns a new Gui object with a given output mode.
|
||||||
func NewGui(mode OutputMode, supportOverlaps bool, recordEvents bool) (*Gui, error) {
|
func NewGui(mode OutputMode, supportOverlaps bool, playMode PlayMode) (*Gui, error) {
|
||||||
err := tcellInit()
|
err := tcellInit()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -147,10 +170,18 @@ func NewGui(mode OutputMode, supportOverlaps bool, recordEvents bool) (*Gui, err
|
|||||||
|
|
||||||
g.stop = make(chan struct{})
|
g.stop = make(chan struct{})
|
||||||
|
|
||||||
g.ReplayedEvents = make(chan GocuiEvent)
|
|
||||||
g.gEvents = make(chan GocuiEvent, 20)
|
g.gEvents = make(chan GocuiEvent, 20)
|
||||||
g.userEvents = make(chan userEvent, 20)
|
g.userEvents = make(chan userEvent, 20)
|
||||||
g.RecordedEvents = make(chan *GocuiEvent)
|
|
||||||
|
if playMode == RECORDING {
|
||||||
|
g.Recording = &Recording{
|
||||||
|
KeyEvents: []*TcellKeyEventWrapper{},
|
||||||
|
}
|
||||||
|
} else if playMode == REPLAYING {
|
||||||
|
g.ReplayedEvents = replayedEvents{
|
||||||
|
keys: make(chan *TcellKeyEventWrapper),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if runtime.GOOS != "windows" {
|
if runtime.GOOS != "windows" {
|
||||||
g.maxX, g.maxY, err = g.getTermWindowSize()
|
g.maxX, g.maxY, err = g.getTermWindowSize()
|
||||||
@ -173,7 +204,7 @@ func NewGui(mode OutputMode, supportOverlaps bool, recordEvents bool) (*Gui, err
|
|||||||
g.NextSearchMatchKey = 'n'
|
g.NextSearchMatchKey = 'n'
|
||||||
g.PrevSearchMatchKey = 'N'
|
g.PrevSearchMatchKey = 'N'
|
||||||
|
|
||||||
g.RecordEvents = recordEvents
|
g.PlayMode = playMode
|
||||||
|
|
||||||
return g, nil
|
return g, nil
|
||||||
}
|
}
|
||||||
@ -533,13 +564,17 @@ func (g *Gui) SetManagerFunc(manager func(*Gui) error) {
|
|||||||
// MainLoop runs the main loop until an error is returned. A successful
|
// MainLoop runs the main loop until an error is returned. A successful
|
||||||
// finish should return ErrQuit.
|
// finish should return ErrQuit.
|
||||||
func (g *Gui) MainLoop() error {
|
func (g *Gui) MainLoop() error {
|
||||||
|
if g.PlayMode == REPLAYING {
|
||||||
|
g.replayRecording()
|
||||||
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-g.stop:
|
case <-g.stop:
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
g.gEvents <- pollEvent()
|
g.gEvents <- g.pollEvent()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@ -554,10 +589,6 @@ func (g *Gui) MainLoop() error {
|
|||||||
if err := g.handleEvent(&ev); err != nil {
|
if err := g.handleEvent(&ev); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case ev := <-g.ReplayedEvents:
|
|
||||||
if err := g.handleEvent(&ev); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
case ev := <-g.userEvents:
|
case ev := <-g.userEvents:
|
||||||
if err := ev.f(g); err != nil {
|
if err := ev.f(g); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -580,10 +611,6 @@ func (g *Gui) consumeevents() error {
|
|||||||
if err := g.handleEvent(&ev); err != nil {
|
if err := g.handleEvent(&ev); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
case ev := <-g.ReplayedEvents:
|
|
||||||
if err := g.handleEvent(&ev); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
case ev := <-g.userEvents:
|
case ev := <-g.userEvents:
|
||||||
if err := ev.f(g); err != nil {
|
if err := ev.f(g); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -597,10 +624,6 @@ func (g *Gui) consumeevents() error {
|
|||||||
// handleEvent handles an event, based on its type (key-press, error,
|
// handleEvent handles an event, based on its type (key-press, error,
|
||||||
// etc.)
|
// etc.)
|
||||||
func (g *Gui) handleEvent(ev *GocuiEvent) error {
|
func (g *Gui) handleEvent(ev *GocuiEvent) error {
|
||||||
if g.RecordEvents {
|
|
||||||
g.RecordedEvents <- ev
|
|
||||||
}
|
|
||||||
|
|
||||||
switch ev.Type {
|
switch ev.Type {
|
||||||
case eventKey, eventMouse:
|
case eventKey, eventMouse:
|
||||||
return g.onKey(ev)
|
return g.onKey(ev)
|
||||||
|
52
vendor/github.com/jesseduffield/gocui/recording.go
generated
vendored
Normal file
52
vendor/github.com/jesseduffield/gocui/recording.go
generated
vendored
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
package gocui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (g *Gui) replayRecording() {
|
||||||
|
ticker := time.NewTicker(time.Millisecond)
|
||||||
|
defer ticker.Stop()
|
||||||
|
|
||||||
|
// The playback could be paused at any time because integration tests run concurrently.
|
||||||
|
// Therefore we can't just check for a given event whether we've passed its timestamp,
|
||||||
|
// or else we'll have an explosion of keypresses after the test is resumed.
|
||||||
|
// We need to check if we've waited long enough since the last event was replayed.
|
||||||
|
// Only handling key events for now.
|
||||||
|
for i, event := range g.Recording.KeyEvents {
|
||||||
|
var prevEventTimestamp int64 = 0
|
||||||
|
if i > 0 {
|
||||||
|
prevEventTimestamp = g.Recording.KeyEvents[i-1].Timestamp
|
||||||
|
}
|
||||||
|
timeToWait := (event.Timestamp - prevEventTimestamp) / int64(g.RecordingConfig.Speed)
|
||||||
|
if i == 0 {
|
||||||
|
timeToWait += int64(g.RecordingConfig.Leeway)
|
||||||
|
}
|
||||||
|
var timeWaited int64 = 0
|
||||||
|
middle:
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ticker.C:
|
||||||
|
timeWaited += 1
|
||||||
|
if g != nil && timeWaited >= timeToWait {
|
||||||
|
g.ReplayedEvents.keys <- event
|
||||||
|
break middle
|
||||||
|
}
|
||||||
|
case <-g.stop:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// leaving some time for any handlers to execute before quitting
|
||||||
|
time.Sleep(time.Second * 1)
|
||||||
|
|
||||||
|
g.Update(func(*Gui) error {
|
||||||
|
return ErrQuit
|
||||||
|
})
|
||||||
|
|
||||||
|
time.Sleep(time.Second * 1)
|
||||||
|
|
||||||
|
log.Fatal("gocui should have already exited")
|
||||||
|
}
|
43
vendor/github.com/jesseduffield/gocui/tcell_driver.go
generated
vendored
43
vendor/github.com/jesseduffield/gocui/tcell_driver.go
generated
vendored
@ -6,6 +6,7 @@ package gocui
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/gdamore/tcell/v2"
|
"github.com/gdamore/tcell/v2"
|
||||||
)
|
)
|
||||||
@ -144,9 +145,43 @@ var (
|
|||||||
lastY int = 0
|
lastY int = 0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// this wrapper struct has public keys so we can easily serialize/deserialize to JSON
|
||||||
|
type TcellKeyEventWrapper struct {
|
||||||
|
Timestamp int64
|
||||||
|
Mod tcell.ModMask
|
||||||
|
Key tcell.Key
|
||||||
|
Ch rune
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTcellKeyEventWrapper(event *tcell.EventKey, timestamp int64) *TcellKeyEventWrapper {
|
||||||
|
return &TcellKeyEventWrapper{
|
||||||
|
Timestamp: timestamp,
|
||||||
|
Mod: event.Modifiers(),
|
||||||
|
Key: event.Key(),
|
||||||
|
Ch: event.Rune(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wrapper TcellKeyEventWrapper) toTcellEvent() tcell.Event {
|
||||||
|
return tcell.NewEventKey(wrapper.Key, wrapper.Ch, wrapper.Mod)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Gui) timeSinceStart() int64 {
|
||||||
|
return time.Since(g.StartTime).Nanoseconds() / 1e6
|
||||||
|
}
|
||||||
|
|
||||||
// pollEvent get tcell.Event and transform it into gocuiEvent
|
// pollEvent get tcell.Event and transform it into gocuiEvent
|
||||||
func pollEvent() GocuiEvent {
|
func (g *Gui) pollEvent() GocuiEvent {
|
||||||
tev := Screen.PollEvent()
|
var tev tcell.Event
|
||||||
|
if g.PlayMode == REPLAYING {
|
||||||
|
select {
|
||||||
|
case ev := <-g.ReplayedEvents.keys:
|
||||||
|
tev = (ev).toTcellEvent()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tev = Screen.PollEvent()
|
||||||
|
}
|
||||||
|
|
||||||
switch tev := tev.(type) {
|
switch tev := tev.(type) {
|
||||||
case *tcell.EventInterrupt:
|
case *tcell.EventInterrupt:
|
||||||
return GocuiEvent{Type: eventInterrupt}
|
return GocuiEvent{Type: eventInterrupt}
|
||||||
@ -154,6 +189,10 @@ func pollEvent() GocuiEvent {
|
|||||||
w, h := tev.Size()
|
w, h := tev.Size()
|
||||||
return GocuiEvent{Type: eventResize, Width: w, Height: h}
|
return GocuiEvent{Type: eventResize, Width: w, Height: h}
|
||||||
case *tcell.EventKey:
|
case *tcell.EventKey:
|
||||||
|
if g.PlayMode == RECORDING {
|
||||||
|
g.Recording.KeyEvents = append(g.Recording.KeyEvents, NewTcellKeyEventWrapper(tev, g.timeSinceStart()))
|
||||||
|
}
|
||||||
|
|
||||||
k := tev.Key()
|
k := tev.Key()
|
||||||
ch := rune(0)
|
ch := rune(0)
|
||||||
if k == tcell.KeyRune {
|
if k == tcell.KeyRune {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user