-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlibevdev.go
More file actions
148 lines (128 loc) · 3.33 KB
/
libevdev.go
File metadata and controls
148 lines (128 loc) · 3.33 KB
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 golibevdev
// #cgo pkg-config: libevdev
// #include <libevdev/libevdev.h>
import "C"
import (
"fmt"
"os"
"time"
)
type InputDev struct {
fd *os.File
name string
cStruct *C.struct_libevdev
}
func NewInputDev(path string) (*InputDev, error) {
fd, err := os.Open(path)
if err != nil {
return nil, fmt.Errorf("failed to open %s: %w", path, err)
}
cStruct := C.libevdev_new()
if cStruct == nil {
return nil, fmt.Errorf("failed to create libevdev struct")
}
rc := C.libevdev_set_fd(cStruct, C.int(fd.Fd()))
if rc != 0 {
C.libevdev_free(cStruct)
return nil, fmt.Errorf("failed to set fd: %v", strError(rc))
}
name := C.GoString(C.libevdev_get_name(cStruct))
if name == "" {
C.libevdev_free(cStruct)
return nil, fmt.Errorf("failed to get device name")
}
return &InputDev{
fd: fd,
name: name,
cStruct: cStruct,
}, nil
}
func (dev *InputDev) Close() {
C.libevdev_free(dev.cStruct)
_ = dev.fd.Close()
}
func (dev *InputDev) Name() string {
return dev.name
}
func (dev *InputDev) HasEventType(typ EventType) bool {
return C.libevdev_has_event_type(dev.cStruct, C.uint(typ)) == 1
}
func (dev *InputDev) HasEventCode(typ EventType, code KeyEventCode) bool {
return C.libevdev_has_event_code(dev.cStruct, C.uint(typ), C.uint(code)) == 1
}
// Event is a struct that represents an event from the input device.
// https://www.kernel.org/doc/html/v4.18/input/input.html#event-interface
type Event struct {
Time time.Time
Type EventType
Code EventCode
Value int32
}
type ReadFlag int
const (
ReadFlagSync ReadFlag = 1
ReadFlagNormal ReadFlag = 2
ReadFlagForceSync ReadFlag = 4
ReadFlagGetRepeat ReadFlag = 8
)
func (dev *InputDev) NextEvent(flag ReadFlag) (Event, error) {
var ev C.struct_input_event
rc := C.libevdev_next_event(dev.cStruct, C.uint(flag), &ev)
if rc != 0 {
return Event{}, fmt.Errorf("failed to get next event: %v", strError(rc))
}
var code EventCode
switch ev._type {
case C.EV_KEY:
code = KeyEventCode(ev.code)
case C.EV_REL:
code = RelativeEventCode(ev.code)
case C.EV_SYN:
code = SyncEventCode(ev.code)
case C.EV_MSC:
code = MiscEventCode(ev.code)
case C.EV_SW:
code = SwitchEventCode(ev.code)
case C.EV_LED:
code = LEDEventCode(ev.code)
case C.EV_SND:
code = SoundEventCode(ev.code)
case C.EV_REP:
code = RepeatEventCode(ev.code)
case C.EV_FF:
code = ForceEventCode(ev.code)
case C.EV_FF_STATUS:
code = FFStatusEventCode(ev.code)
case C.EV_PWR:
code = PowerEventCode(ev.code)
default:
code = UnknownEventCode(ev.code)
}
return Event{
Time: time.Unix(int64(ev.time.tv_sec), int64(ev.time.tv_usec*1000)),
Type: EventType(ev._type),
Code: code,
Value: int32(ev.value),
}, nil
}
func (dev *InputDev) Grab() error {
rc := C.libevdev_grab(dev.cStruct, C.LIBEVDEV_GRAB)
if rc != 0 {
return fmt.Errorf("failed to grab device: %v", strError(rc))
}
return nil
}
func (dev *InputDev) EnableEventType(typ EventType) error {
rc := C.libevdev_enable_event_type(dev.cStruct, C.uint(typ))
if rc != 0 {
return fmt.Errorf("failed to enable event type: %v", strError(rc))
}
return nil
}
func (dev *InputDev) EnableEventCode(typ EventType, code EventCode) error {
rc := C.libevdev_enable_event_code(dev.cStruct, C.uint(typ), C.uint(code.Value()), nil)
if rc != 0 {
return fmt.Errorf("failed to enable event code: %v", strError(rc))
}
return nil
}