-
Notifications
You must be signed in to change notification settings - Fork 0
/
input.go
147 lines (123 loc) · 3.05 KB
/
input.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
package lis
import (
"fmt"
"io/ioutil"
"github.com/mikkeloscar/evdev"
)
const (
deviceDir = "/dev/input/"
)
// this way we can compare evt.Type to defined eventtypes
const (
evKeys = uint16(evdev.EvKeys)
evRel = uint16(evdev.EvRelative)
)
type inputDev struct {
devPath string
stop chan struct{}
errors chan error
}
// InputDevs defines a map of valid input devices.
type InputDevs struct {
devs map[string]*inputDev
Activity chan struct{}
errors chan error
}
func handleDevice(inputDevice *inputDev, activity chan struct{}) {
dev, err := evdev.Open(inputDevice.devPath)
if err != nil {
inputDevice.errors <- err
return
}
defer dev.Close()
for {
select {
case evt := <-dev.Inbox:
if evt.Type != evKeys && evt.Type != evRel {
continue // not the event we are looking for
}
// the user is still alive
activity <- struct{}{}
case <-inputDevice.stop:
return
}
}
}
// GetInputDevices return a InputDevs containing valid input devices.
func GetInputDevices(errors chan error) (*InputDevs, error) {
devices := &InputDevs{
make(map[string]*inputDev),
make(chan struct{}),
errors,
}
devNames, err := ioutil.ReadDir(deviceDir)
if err != nil {
return nil, err
}
// loop through all event devices and check if they are keyboard/mouse like
for _, d := range devNames {
if len(d.Name()) >= 5 && d.Name()[:5] == "event" {
devicePath := deviceDir + d.Name()
dev, err := evdev.Open(devicePath)
if err != nil {
return nil, err
}
name, isInput := checkDevice(dev)
if isInput {
// don't add the same device twice
_, ok := devices.devs[name]
if ok {
dev.Close()
continue
}
devices.devs[name] = &inputDev{
devicePath,
make(chan struct{}, 1),
errors,
}
}
// close the device, since we are not gonna use it.
dev.Close()
}
}
return devices, nil
}
// Wait monitor and wait for input events and shut down on event.
func (devices *InputDevs) Wait(heartbeat chan struct{}) {
if len(devices.devs) == 0 {
devices.errors <- fmt.Errorf("no devices available")
return
}
for _, device := range devices.devs {
go handleDevice(device, devices.Activity)
}
<-devices.Activity // wait for some activity
// fmt.Printf("Got activity!\n")
// stop all input device listeners
for _, device := range devices.devs {
device.stop <- struct{}{}
}
heartbeat <- struct{}{} // send heartbeat to listener
}
func checkDevice(dev *evdev.Device) (string, bool) {
if !correctDevice(dev) {
return "", false
}
return dev.Name(), true
}
// check if device is a keyboard, mouse or touchpad.
func correctDevice(dev *evdev.Device) bool {
// check if device is a keyboard
if dev.Test(dev.EventTypes(), evdev.EvSync, evdev.EvKeys, evdev.EvMisc, evdev.EvLed, evdev.EvRepeat) {
return true
}
// check if device is a mouse
if dev.Test(dev.EventTypes(), evdev.EvSync, evdev.EvKeys, evdev.EvRelative, evdev.EvMisc) {
return true
}
// check if device is a touchpad
if dev.Test(dev.EventTypes(), evdev.EvSync, evdev.EvKeys, evdev.EvAbsolute) {
return true
}
return false
}