forked from jbensmann/mouseless
-
Notifications
You must be signed in to change notification settings - Fork 0
/
keyboard.go
148 lines (129 loc) · 3.34 KB
/
keyboard.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
142
143
144
145
146
147
148
package main
import (
"fmt"
"time"
evdev "github.com/gvalkov/golang-evdev"
log "github.com/sirupsen/logrus"
)
type KeyboardDevice struct {
deviceName string
device *evdev.InputDevice
state DeviceState
lastOpenError string
eventChan chan<- KeyboardEvent
}
type KeyboardEvent struct {
code uint16
isPress bool
holdKey bool
}
type DeviceState int
const (
StateNotOpen DeviceState = iota
StateOpenFailed
StateOpen
)
func NewKeyboardDevice(deviceName string, eventChan chan<- KeyboardEvent) *KeyboardDevice {
k := KeyboardDevice{
deviceName: deviceName,
device: nil,
state: StateNotOpen,
eventChan: eventChan,
}
return &k
}
// ReadLoop reads from the keyboard device in an infinite loop.
// When the device is not opened or disconnects in between, it tries to open again.
func (k *KeyboardDevice) ReadLoop() {
ticker := time.NewTicker(5 * time.Second)
for {
if k.state != StateOpen {
if err := k.openDevice(); err != nil {
k.lastOpenError = fmt.Sprintf("%v", err)
if k.state == StateOpenFailed {
log.Debugf("Failed to open %v: %v", k.deviceName, err)
} else {
log.Warnf("Failed to open %v: %v", k.deviceName, err)
}
}
}
select {
case <-ticker.C:
continue
}
}
}
// openDevice tries to open and grab the keyboard device.
func (k *KeyboardDevice) openDevice() error {
log.Debugf("opening the keyboard device %v", k.deviceName)
device, err := evdev.Open(k.deviceName)
if err != nil {
k.state = StateOpenFailed
return err
}
err = device.Grab()
if err != nil {
k.state = StateOpenFailed
return err
}
log.Debug(device)
log.Debugf("Device name: %s", device.Name)
log.Debugf("Evdev protocol version: %d", device.EvdevVersion)
info := fmt.Sprintf("bus 0x%04x, vendor 0x%04x, product 0x%04x, version 0x%04x",
device.Bustype, device.Vendor, device.Product, device.Version)
log.Debugf("Device info: %s", info)
k.device = device
k.state = StateOpen
go k.readKeyboard()
return nil
}
// readKeyboard reads from the device in an infinite loop.
// The device has to be opened, and if it disconnects in between this method returns and sets the state to not open.
func (k *KeyboardDevice) readKeyboard() {
var events []evdev.InputEvent
var err error
for {
if k.state != StateOpen {
return
}
events, err = k.device.Read()
if err != nil {
log.Warnf("Failed to read keyboard: %v", err)
k.state = StateNotOpen
return
}
for _, event := range events {
if event.Type == evdev.EV_KEY {
if event.Value == 0 || event.Value == 1 {
var codeName string
val, ok := keyAliasesReversed[event.Code]
if ok {
codeName = val
} else {
codeName = "?"
}
fmtString := "Pressed: "
if event.Value == 0 {
fmtString = "Released: "
}
fmtString += "%s (%d)"
log.Debugf(fmtString, codeName, event.Code)
e := KeyboardEvent{code: event.Code, isPress: event.Value == 1}
k.eventChan <- e
}
}
}
}
}
// DeviceName returns the name of the keyboard device.
func (k *KeyboardDevice) DeviceName() string {
return k.deviceName
}
// IsOpen returns true if the device has been opened successfully.
func (k *KeyboardDevice) IsOpen() bool {
return k.state == StateOpen
}
// LastOpenError returns the last error on opening the device.
func (k *KeyboardDevice) LastOpenError() string {
return k.lastOpenError
}