mirror of
https://github.com/taigrr/adb.git
synced 2026-04-02 02:58:42 -07:00
Add multidevice support to eventcapture, complete bubbletea UI for tapRec example
This commit is contained in:
47
capture.go
47
capture.go
@@ -2,6 +2,7 @@ package adb
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"log"
|
"log"
|
||||||
"regexp"
|
"regexp"
|
||||||
@@ -42,6 +43,29 @@ type SequenceImporter struct {
|
|||||||
Start time.Time
|
Start time.Time
|
||||||
End time.Time
|
End time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (si SequenceImporter) ToInput() Input {
|
||||||
|
switch si.Type {
|
||||||
|
case SeqSleep:
|
||||||
|
return SequenceSleep{Duration: si.Duration, Type: SeqSleep}
|
||||||
|
case SeqSwipe:
|
||||||
|
return SequenceSwipe{
|
||||||
|
X1: si.X1, Y1: si.Y1,
|
||||||
|
X2: si.X2, Y2: si.Y2,
|
||||||
|
Start: si.Start,
|
||||||
|
End: si.End, Type: SeqSwipe,
|
||||||
|
}
|
||||||
|
case SeqTap:
|
||||||
|
return SequenceTap{
|
||||||
|
X: si.X, Y: si.Y,
|
||||||
|
Start: si.Start,
|
||||||
|
End: si.End, Type: SeqTap,
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return SequenceSleep{Duration: time.Millisecond * 0, Type: SeqSleep}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type SequenceSleep struct {
|
type SequenceSleep struct {
|
||||||
Duration time.Duration
|
Duration time.Duration
|
||||||
Type SeqType
|
Type SeqType
|
||||||
@@ -131,6 +155,25 @@ type Resolution struct {
|
|||||||
Height int
|
Height int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t TapSequence) ToJSON() []byte {
|
||||||
|
b, _ := json.Marshal(t)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func TapSequenceFromJSON(j []byte) (TapSequence, error) {
|
||||||
|
var ti TapSequenceImporter
|
||||||
|
var t TapSequence
|
||||||
|
err := json.Unmarshal(j, &ti)
|
||||||
|
if err != nil {
|
||||||
|
return t, err
|
||||||
|
}
|
||||||
|
t.Resolution = ti.Resolution
|
||||||
|
for _, ie := range ti.Events {
|
||||||
|
t.Events = append(t.Events, ie.ToInput())
|
||||||
|
}
|
||||||
|
return t, nil
|
||||||
|
}
|
||||||
|
|
||||||
// ShortenSleep allows you to shorten all the sleep times between tap and swipe events.
|
// ShortenSleep allows you to shorten all the sleep times between tap and swipe events.
|
||||||
//
|
//
|
||||||
// Provide a scalar value to divide the sleeps by. Providing `2` will halve all
|
// Provide a scalar value to divide the sleeps by. Providing `2` will halve all
|
||||||
@@ -188,12 +231,12 @@ func (d Device) CaptureSequence(ctx context.Context) (t TapSequence, err error)
|
|||||||
}
|
}
|
||||||
// this command will never finish without ctx expiring. As a result,
|
// this command will never finish without ctx expiring. As a result,
|
||||||
// it will always return error code 130 if successful
|
// it will always return error code 130 if successful
|
||||||
stdout, _, errCode, err := execute(ctx, []string{"shell", "getevent", "-tl"})
|
stdout, _, errCode, err := execute(ctx, []string{"-s", string(d.SerialNo), "shell", "getevent", "-tl"})
|
||||||
// TODO better error checking here
|
// TODO better error checking here
|
||||||
if errors.Is(err, ErrUnspecified) {
|
if errors.Is(err, ErrUnspecified) {
|
||||||
err = nil
|
err = nil
|
||||||
}
|
}
|
||||||
if errCode != 130 && errCode != -1 {
|
if errCode != 130 && errCode != -1 && errCode != 1 {
|
||||||
// TODO remove log output here
|
// TODO remove log output here
|
||||||
log.Printf("Expected error code 130 or -1, but got %d\n", errCode)
|
log.Printf("Expected error code 130 or -1, but got %d\n", errCode)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,26 @@ go 1.19
|
|||||||
|
|
||||||
replace github.com/taigrr/adb => ../..
|
replace github.com/taigrr/adb => ../..
|
||||||
|
|
||||||
require github.com/taigrr/adb v0.0.0-20220803063720-bd9524431495
|
require (
|
||||||
|
github.com/charmbracelet/bubbles v0.13.0
|
||||||
|
github.com/charmbracelet/bubbletea v0.22.0
|
||||||
|
github.com/charmbracelet/lipgloss v0.5.0
|
||||||
|
github.com/taigrr/adb v0.0.0-20220803063720-bd9524431495
|
||||||
|
)
|
||||||
|
|
||||||
require github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
require (
|
||||||
|
github.com/atotto/clipboard v0.1.4 // indirect
|
||||||
|
github.com/containerd/console v1.0.3 // indirect
|
||||||
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||||
|
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||||
|
github.com/mattn/go-runewidth v0.0.13 // indirect
|
||||||
|
github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b // indirect
|
||||||
|
github.com/muesli/cancelreader v0.2.1 // indirect
|
||||||
|
github.com/muesli/reflow v0.3.0 // indirect
|
||||||
|
github.com/muesli/termenv v0.11.1-0.20220212125758-44cd13922739 // indirect
|
||||||
|
github.com/rivo/uniseg v0.2.0 // indirect
|
||||||
|
github.com/sahilm/fuzzy v0.1.0 // indirect
|
||||||
|
golang.org/x/sys v0.0.0-20220209214540-3681064d5158 // indirect
|
||||||
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
|
||||||
|
)
|
||||||
|
|||||||
@@ -1,2 +1,48 @@
|
|||||||
|
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
|
||||||
|
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
|
||||||
|
github.com/charmbracelet/bubbles v0.13.0 h1:zP/ROH3wJEBqZWKIsD50ZKKlx3ydLInq3LdD/Nrlb8w=
|
||||||
|
github.com/charmbracelet/bubbles v0.13.0/go.mod h1:bbeTiXwPww4M031aGi8UK2HT9RDWoiNibae+1yCMtcc=
|
||||||
|
github.com/charmbracelet/bubbletea v0.21.0/go.mod h1:GgmJMec61d08zXsOhqRC/AiOx4K4pmz+VIcRIm1FKr4=
|
||||||
|
github.com/charmbracelet/bubbletea v0.22.0 h1:E1BTNSE3iIrq0G0X6TjGAmrQ32cGCbFDPcIuImikrUc=
|
||||||
|
github.com/charmbracelet/bubbletea v0.22.0/go.mod h1:aoVIwlNlr5wbCB26KhxfrqAn0bMp4YpJcoOelbxApjs=
|
||||||
|
github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao=
|
||||||
|
github.com/charmbracelet/lipgloss v0.5.0 h1:lulQHuVeodSgDez+3rGiuxlPVXSnhth442DATR2/8t8=
|
||||||
|
github.com/charmbracelet/lipgloss v0.5.0/go.mod h1:EZLha/HbzEt7cYqdFPovlqy5FZPj0xFhg5SaqxScmgs=
|
||||||
|
github.com/containerd/console v1.0.3 h1:lIr7SlA5PxZyMV30bDW0MGbiOPXwc63yRuCP0ARubLw=
|
||||||
|
github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
||||||
|
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||||
|
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||||
|
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
||||||
|
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||||
|
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||||
|
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||||
|
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||||
|
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||||
|
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
|
||||||
|
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
|
github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b h1:1XF24mVaiu7u+CFywTdcDo2ie1pzzhwjt6RHqzpMU34=
|
||||||
|
github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho=
|
||||||
|
github.com/muesli/cancelreader v0.2.0/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
|
||||||
|
github.com/muesli/cancelreader v0.2.1 h1:Xzd1B4U5bWQOuSKuN398MyynIGTNT89dxzpEDsalXZs=
|
||||||
|
github.com/muesli/cancelreader v0.2.1/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
|
||||||
|
github.com/muesli/reflow v0.2.1-0.20210115123740-9e1d0d53df68/go.mod h1:Xk+z4oIWdQqJzsxyjgl3P22oYZnHdZ8FFTHAQQt5BMQ=
|
||||||
|
github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
|
||||||
|
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
|
||||||
|
github.com/muesli/termenv v0.11.1-0.20220204035834-5ac8409525e0/go.mod h1:Bd5NYQ7pd+SrtBSrSNoBBmXlcY8+Xj4BMJgh8qcZrvs=
|
||||||
|
github.com/muesli/termenv v0.11.1-0.20220212125758-44cd13922739 h1:QANkGiGr39l1EESqrE0gZw0/AJNYzIvoGLhIoVYtluI=
|
||||||
|
github.com/muesli/termenv v0.11.1-0.20220212125758-44cd13922739/go.mod h1:Bd5NYQ7pd+SrtBSrSNoBBmXlcY8+Xj4BMJgh8qcZrvs=
|
||||||
|
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
|
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||||
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
|
github.com/sahilm/fuzzy v0.1.0 h1:FzWGaw2Opqyu+794ZQ9SYifWv2EIXpwP4q8dY1kDAwI=
|
||||||
|
github.com/sahilm/fuzzy v0.1.0/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
|
||||||
|
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220209214540-3681064d5158 h1:rm+CHSpPEEW2IsXUib1ThaHIjuBVZjxNgSKmBLFfD4c=
|
||||||
|
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||||
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
|
|||||||
@@ -6,22 +6,38 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/charmbracelet/bubbles/list"
|
||||||
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
|
"github.com/charmbracelet/lipgloss"
|
||||||
"github.com/taigrr/adb"
|
"github.com/taigrr/adb"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
command string
|
command string
|
||||||
file string
|
file string
|
||||||
|
|
||||||
|
chosen adb.Serial
|
||||||
|
titleStyle = lipgloss.NewStyle().MarginLeft(2)
|
||||||
|
itemStyle = lipgloss.NewStyle().PaddingLeft(4)
|
||||||
|
selectedItemStyle = lipgloss.NewStyle().PaddingLeft(2).Foreground(lipgloss.Color("170"))
|
||||||
|
paginationStyle = list.DefaultStyles().PaginationStyle.PaddingLeft(4)
|
||||||
|
helpStyle = list.DefaultStyles().HelpStyle.PaddingLeft(4).PaddingBottom(1)
|
||||||
|
quitTextStyle = lipgloss.NewStyle().Margin(1, 0, 2, 4)
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
flag.StringVar(&command, "command", "rec", "rec or play")
|
flag.StringVar(&command, "command", "rec", "rec or play")
|
||||||
flag.StringVar(&file, "file", "taps.json", "Name of the file to save taps to or to play from")
|
flag.StringVar(&file, "file", "taps.json", "Name of the file to save taps to or to play from")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
if command != "play" && command != "rec" {
|
||||||
|
flag.PrintDefaults()
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
sigChan := make(chan os.Signal)
|
sigChan := make(chan os.Signal)
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
go func() {
|
go func() {
|
||||||
@@ -34,16 +50,20 @@ func main() {
|
|||||||
fmt.Printf("Error enumerating devices: %v\n", err)
|
fmt.Printf("Error enumerating devices: %v\n", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
devNames := []adb.Serial{}
|
||||||
for _, dev := range devs {
|
for _, dev := range devs {
|
||||||
|
devNames = append(devNames, dev.SerialNo)
|
||||||
|
}
|
||||||
|
selected := chooseDev(devNames)
|
||||||
|
|
||||||
|
for _, dev := range devs {
|
||||||
|
if dev.SerialNo != selected {
|
||||||
|
continue
|
||||||
|
}
|
||||||
if !dev.IsAuthorized {
|
if !dev.IsAuthorized {
|
||||||
fmt.Printf("Dev `%s` is not authorized, authorize it to continue.\n", dev.SerialNo)
|
fmt.Printf("Dev `%s` is not authorized, authorize it to continue.\n", dev.SerialNo)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
//w, h, err := dev.GetScreenResolution(ctx)
|
|
||||||
//if err != nil {
|
|
||||||
// // handle error here
|
|
||||||
// fmt.Printf("Error: %v\n", err)
|
|
||||||
//}
|
|
||||||
switch command {
|
switch command {
|
||||||
case "rec":
|
case "rec":
|
||||||
fmt.Println("Recording taps now. Hit ctrl+c to stop.")
|
fmt.Println("Recording taps now. Hit ctrl+c to stop.")
|
||||||
@@ -68,55 +88,114 @@ func main() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
var j map[string]interface{}
|
|
||||||
var t adb.TapSequence
|
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
b.ReadFrom(f)
|
b.ReadFrom(f)
|
||||||
err = json.Unmarshal(b.Bytes(), &j)
|
t, err := adb.TapSequenceFromJSON(b.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Error parsing tap file %s: %v", file, err)
|
fmt.Printf("Error parsing tap file %s: %v", file, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if events, ok := j["Events"]; ok {
|
|
||||||
if sliceEvent, ok := events.([]interface{}); ok {
|
|
||||||
for _, e := range sliceEvent {
|
|
||||||
if mapEvent, ok := e.(map[string]interface{}); ok {
|
|
||||||
if eventType, ok := mapEvent["Type"]; ok {
|
|
||||||
if et, ok := eventType.(float64); ok {
|
|
||||||
switch int(et) {
|
|
||||||
case int(adb.SeqSleep):
|
|
||||||
t.Events = append(t.Events, adb.SequenceSleep{})
|
|
||||||
case int(adb.SeqSwipe):
|
|
||||||
t.Events = append(t.Events, adb.SequenceSwipe{})
|
|
||||||
case int(adb.SeqTap):
|
|
||||||
t.Events = append(t.Events, adb.SequenceTap{})
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fmt.Printf("Could not parse %v (%T) into JSON! 1\n", eventType, eventType)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fmt.Println("Could not parse JSON! 2")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fmt.Println("Could not parse JSON! 3")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fmt.Println("Could not parse JSON! 4")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fmt.Println("Could not parse JSON! 5")
|
|
||||||
}
|
|
||||||
dev.ReplayTapSequence(ctx, t)
|
dev.ReplayTapSequence(ctx, t)
|
||||||
err = json.Unmarshal(b.Bytes(), &t)
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("struct: %v\n",t)
|
|
||||||
fmt.Printf("bytes: %v\n",b.String())
|
|
||||||
fmt.Printf("Error parsing tap file %s: %v", file, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewModel(devs []adb.Serial) Model {
|
||||||
|
var m Model
|
||||||
|
items := []list.Item{}
|
||||||
|
for _, d := range devs {
|
||||||
|
items = append(items, DevEntry(d))
|
||||||
|
}
|
||||||
|
m.List = list.New(items, itemDelegate{}, 0, len(devs)+15)
|
||||||
|
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func chooseDev(devs []adb.Serial) adb.Serial {
|
||||||
|
if len(devs) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if len(devs) == 1 {
|
||||||
|
return devs[0]
|
||||||
|
}
|
||||||
|
m := NewModel(devs)
|
||||||
|
m.List.Title = "Which device?"
|
||||||
|
m.List.SetShowStatusBar(false)
|
||||||
|
m.List.SetFilteringEnabled(false)
|
||||||
|
m.List.Styles.Title = titleStyle
|
||||||
|
m.List.Styles.PaginationStyle = paginationStyle
|
||||||
|
m.List.Styles.HelpStyle = helpStyle
|
||||||
|
|
||||||
|
if err := tea.NewProgram(m).Start(); err != nil {
|
||||||
|
fmt.Println("Error running program:", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
return adb.Serial(chosen)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Model struct {
|
||||||
|
List list.Model
|
||||||
|
quitting bool
|
||||||
|
Choice DevEntry
|
||||||
|
}
|
||||||
|
|
||||||
|
type DevEntry adb.Serial
|
||||||
|
|
||||||
|
func (d DevEntry) FilterValue() string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m Model) Init() tea.Cmd {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||||
|
switch msg := msg.(type) {
|
||||||
|
case tea.WindowSizeMsg:
|
||||||
|
m.List.SetWidth(msg.Width)
|
||||||
|
return m, nil
|
||||||
|
case tea.KeyMsg:
|
||||||
|
switch keypress := msg.String(); keypress {
|
||||||
|
case "ctrl+c":
|
||||||
|
m.quitting = true
|
||||||
|
return m, tea.Quit
|
||||||
|
case "enter":
|
||||||
|
i, ok := m.List.SelectedItem().(DevEntry)
|
||||||
|
if ok {
|
||||||
|
chosen = adb.Serial(i)
|
||||||
|
}
|
||||||
|
return m, tea.Quit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var cmd tea.Cmd
|
||||||
|
m.List, cmd = m.List.Update(msg)
|
||||||
|
return m, cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m Model) View() string {
|
||||||
|
if chosen != "" {
|
||||||
|
return quitTextStyle.Render("Chosen device: " + string(chosen))
|
||||||
|
}
|
||||||
|
return "\n" + m.List.View()
|
||||||
|
}
|
||||||
|
|
||||||
|
type itemDelegate struct{}
|
||||||
|
|
||||||
|
func (d itemDelegate) Height() int { return 1 }
|
||||||
|
func (d itemDelegate) Spacing() int { return 0 }
|
||||||
|
func (d itemDelegate) Update(msg tea.Msg, m *list.Model) tea.Cmd { return nil }
|
||||||
|
func (d itemDelegate) Render(w io.Writer, m list.Model, index int, listItem list.Item) {
|
||||||
|
i, ok := listItem.(DevEntry)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
str := fmt.Sprintf("%d. %s", index+1, i)
|
||||||
|
fn := itemStyle.Render
|
||||||
|
if index == m.Index() {
|
||||||
|
fn = func(s string) string {
|
||||||
|
return selectedItemStyle.Render("> " + s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Fprint(w, fn(str))
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,13 +8,6 @@ import (
|
|||||||
"github.com/taigrr/adb"
|
"github.com/taigrr/adb"
|
||||||
)
|
)
|
||||||
|
|
||||||
var command string
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
// TODO allow for any input to be used as the command
|
|
||||||
command = "ls"
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
@@ -28,11 +21,6 @@ func main() {
|
|||||||
fmt.Printf("Dev `%s` is not authorized, authorize it to continue.\n", dev.SerialNo)
|
fmt.Printf("Dev `%s` is not authorized, authorize it to continue.\n", dev.SerialNo)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
//w, h, err := dev.GetScreenResolution(ctx)
|
|
||||||
//if err != nil {
|
|
||||||
// // handle error here
|
|
||||||
// fmt.Printf("Error: %v\n", err)
|
|
||||||
//}
|
|
||||||
fmt.Printf("Begin tapping on device %s now...\n", dev.SerialNo)
|
fmt.Printf("Begin tapping on device %s now...\n", dev.SerialNo)
|
||||||
t, err := dev.CaptureSequence(ctx)
|
t, err := dev.CaptureSequence(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
Reference in New Issue
Block a user