forked from zserge/hid
/
main.go
141 lines (127 loc) · 3.24 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package main
import (
"encoding/hex"
"fmt"
"log"
"os"
"strings"
"time"
"github.com/chzyer/readline"
"github.com/zserge/hid"
)
func shell(device hid.Device) {
if err := device.Open(); err != nil {
log.Println("Open error: ", err)
return
}
defer device.Close()
if report, err := device.HIDReport(); err != nil {
log.Println("HID report error:", err)
return
} else {
log.Println("HID report", hex.EncodeToString(report))
}
go func() {
for {
if buf, err := device.Read(-1, 1*time.Second); err == nil {
log.Println("Input report: ", hex.EncodeToString(buf))
}
}
}()
commands := map[string]func([]byte){
"output": func(b []byte) {
if len(b) == 0 {
log.Println("Invalid input: output report data expected")
} else if n, err := device.Write(b, 1*time.Second); err != nil {
log.Println("Output report write failed:", err)
} else {
log.Printf("Output report: written %d bytes\n", n)
}
},
"set-feature": func(b []byte) {
if len(b) == 0 {
log.Println("Invalid input: feature report data expected")
} else if err := device.SetReport(0, b); err != nil {
log.Println("Feature report write failed:", err)
} else {
log.Printf("Feature report: " + hex.EncodeToString(b) + "\n")
}
},
"get-feature": func(b []byte) {
if b, err := device.GetReport(0); err != nil {
log.Println("Feature report read failed:", err)
} else {
log.Println("Feature report: " + hex.EncodeToString(b) + "\n")
}
},
}
var completer = readline.NewPrefixCompleter(
readline.PcItem("output"),
readline.PcItem("set-feature"),
readline.PcItem("get-feature"),
)
rl, err := readline.NewEx(&readline.Config{
Prompt: "> ",
AutoComplete: completer,
})
if err != nil {
panic(err)
}
defer rl.Close()
log.SetOutput(rl.Stderr())
out:
for {
line, err := rl.Readline()
if err != nil {
break
}
line = strings.ToLower(line)
for cmd, f := range commands {
if strings.HasPrefix(line, cmd) {
line = strings.TrimSpace(line[len(cmd):])
raw := []byte{}
if len(line) > 0 {
raw = make([]byte, len(line)/2, len(line)/2)
if _, err := hex.Decode(raw, []byte(line)); err != nil {
log.Println("Invalid input:", err)
log.Println(">>", hex.EncodeToString(raw))
continue out
}
}
f(raw)
continue out
}
}
}
}
func main() {
if len(os.Args) == 2 && (os.Args[1] == "-h" || os.Args[1] == "--help") {
fmt.Println("USAGE:")
fmt.Printf(" %s list USB HID devices\n", os.Args[0])
fmt.Printf(" %s <id> open USB HID device shell for the given input report size\n", os.Args[0])
fmt.Printf(" %s -h|--help show this help\n", os.Args[0])
fmt.Println()
return
}
// Without arguments - enumerate all HID devices
if len(os.Args) == 1 {
found := false
hid.UsbWalk(func(device hid.Device) {
info := device.Info()
fmt.Printf("%04x:%04x:%04x:%02x\n", info.Vendor, info.Product, info.Revision, info.Interface)
found = true
})
if !found {
fmt.Println("No USB HID devices found\n")
}
return
}
hid.UsbWalk(func(device hid.Device) {
info := device.Info()
id := fmt.Sprintf("%04x:%04x:%04x:%02x", info.Vendor, info.Product, info.Revision, info.Interface)
if id != os.Args[1] {
return
}
shell(device)
})
}