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:
@@ -4,6 +4,26 @@ go 1.19
|
||||
|
||||
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/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"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"github.com/charmbracelet/bubbles/list"
|
||||
tea "github.com/charmbracelet/bubbletea"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
"github.com/taigrr/adb"
|
||||
)
|
||||
|
||||
var (
|
||||
command 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() {
|
||||
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.Parse()
|
||||
if command != "play" && command != "rec" {
|
||||
flag.PrintDefaults()
|
||||
os.Exit(1)
|
||||
}
|
||||
sigChan := make(chan os.Signal)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
go func() {
|
||||
@@ -34,16 +50,20 @@ func main() {
|
||||
fmt.Printf("Error enumerating devices: %v\n", err)
|
||||
return
|
||||
}
|
||||
devNames := []adb.Serial{}
|
||||
for _, dev := range devs {
|
||||
devNames = append(devNames, dev.SerialNo)
|
||||
}
|
||||
selected := chooseDev(devNames)
|
||||
|
||||
for _, dev := range devs {
|
||||
if dev.SerialNo != selected {
|
||||
continue
|
||||
}
|
||||
if !dev.IsAuthorized {
|
||||
fmt.Printf("Dev `%s` is not authorized, authorize it to continue.\n", dev.SerialNo)
|
||||
continue
|
||||
}
|
||||
//w, h, err := dev.GetScreenResolution(ctx)
|
||||
//if err != nil {
|
||||
// // handle error here
|
||||
// fmt.Printf("Error: %v\n", err)
|
||||
//}
|
||||
switch command {
|
||||
case "rec":
|
||||
fmt.Println("Recording taps now. Hit ctrl+c to stop.")
|
||||
@@ -68,55 +88,114 @@ func main() {
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
var j map[string]interface{}
|
||||
var t adb.TapSequence
|
||||
var b bytes.Buffer
|
||||
b.ReadFrom(f)
|
||||
err = json.Unmarshal(b.Bytes(), &j)
|
||||
t, err := adb.TapSequenceFromJSON(b.Bytes())
|
||||
if err != nil {
|
||||
fmt.Printf("Error parsing tap file %s: %v", file, err)
|
||||
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)
|
||||
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))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user