This repository has been archived by the owner on Mar 19, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 31
/
multitouch.go
203 lines (167 loc) · 5.03 KB
/
multitouch.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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
package uinput
import (
"fmt"
"io"
"os"
)
// MultiTouch is an input device that uses absolute axis events.
// Unlike the TouchPad, MultiTouch supports the simulation of multiple inputs (contacts)
// allowing for different gestures, for exmaple pinch to zoom.
// Each contact point is assigned a slot, making it necessary to define the maxmimum
// expected amount of contact points .
// Since MultiTouch uses absolute axis events, it is necessary to define the size
// of the rectangle in which the contacs may move upon creation of the device.
type MultiTouch interface {
//Gets all contacts which can then be manipulated
GetContacts() []multiTouchContact
// FetchSyspath will return the syspath to the device file.
FetchSyspath() (string, error)
io.Closer
}
type vMultiTouch struct {
name []byte
deviceFile *os.File
contacts []multiTouchContact
}
// The contact can be described as a finger contacting the surface of the MultiTouch device.
type multiTouchContact struct {
multitouch *vMultiTouch
slot int32
tracking_id int32
}
// CreateMultiTouch will create a new multitouch device. Note that you will need to define the x and y-axis boundaries
// (min and max) within which the contacs maybe moved around, as well as the maximum amount of contacts allowed.
func CreateMultiTouch(path string, name []byte, minX int32, maxX int32, minY int32, maxY int32, maxContacts int32) (MultiTouch, error) {
err := validateDevicePath(path)
if err != nil {
return nil, err
}
err = validateUinputName(name)
if err != nil {
return nil, err
}
fd, err := createMultiTouch(path, name, minX, maxX, minY, maxY, maxContacts)
if err != nil {
return nil, err
}
var multitouch vMultiTouch = vMultiTouch{name: name, deviceFile: fd}
for i := int32(0); i < maxContacts; i++ {
multitouch.contacts = append(multitouch.contacts, multiTouchContact{slot: i, multitouch: &multitouch})
}
return multitouch, nil
}
func (vMulti vMultiTouch) GetContacts() []multiTouchContact {
return vMulti.contacts
}
func (vMulti vMultiTouch) FetchSyspath() (string, error) {
return fetchSyspath(vMulti.deviceFile)
}
func (vMulti vMultiTouch) Close() error {
return closeDevice(vMulti.deviceFile)
}
func createMultiTouch(path string, name []byte, minX int32, maxX int32, minY int32, maxY int32, maxContacts int32) (fd *os.File, err error) {
deviceFile, err := createDeviceFile(path)
if err != nil {
return nil, fmt.Errorf("could not create absolute axis input device: %v", err)
}
err = registerDevice(deviceFile, uintptr(evKey))
if err != nil {
_ = deviceFile.Close()
return nil, fmt.Errorf("failed to register key device: %v", err)
}
for _, event := range []int{evBtnTouch} {
err = ioctl(deviceFile, uiSetKeyBit, uintptr(event))
if err != nil {
_ = deviceFile.Close()
return nil, fmt.Errorf("failed to register button event %v: %v", event, err)
}
}
err = registerDevice(deviceFile, uintptr(evAbs))
if err != nil {
_ = deviceFile.Close()
return nil, fmt.Errorf("failed to register absolute axis input device: %v", err)
}
for _, event := range []int{
absMtSlot,
absMtTrackingId,
absMtPositionX,
absMtPositionY,
} {
err = ioctl(deviceFile, uiSetAbsBit, uintptr(event))
if err != nil {
_ = deviceFile.Close()
return nil, fmt.Errorf("failed to register absolute axis event %v: %v", event, err)
}
}
var absMin [absSize]int32
absMin[absMtPositionX] = minX
absMin[absMtPositionY] = minY
absMin[absMtTrackingId] = 0x00
absMin[absMtSlot] = 0x00
var absMax [absSize]int32
absMax[absMtPositionX] = maxX
absMax[absMtPositionY] = maxY
absMax[absMtTrackingId] = maxContacts
absMax[absMtSlot] = maxContacts
return createUsbDevice(deviceFile,
uinputUserDev{
Name: toUinputName(name),
ID: inputID{
Bustype: busUsb,
Vendor: 0x0,
Product: 0x0,
Version: 0},
Absmin: absMin,
Absmax: absMax})
}
// The contact will be held down at the coordinates specified
func (c multiTouchContact) TouchDownAt(x int32, y int32) error {
var events []inputEvent
events = append(events, inputEvent{
Type: evAbs,
Code: absMtPositionX,
Value: x,
})
if x == 0 && y == 0 {
y--
}
events = append(events, inputEvent{
Type: evAbs,
Code: absMtPositionY,
Value: y,
})
c.tracking_id = c.slot
return c.sendAbsEvent(events)
}
// The contact will be raised off of the surface
func (c multiTouchContact) TouchUp() error {
c.tracking_id = -1
return c.sendAbsEvent(nil)
}
func (c multiTouchContact) sendAbsEvent(events []inputEvent) error {
var ev []inputEvent
ev = append(ev, inputEvent{
Type: evAbs,
Code: absMtSlot,
Value: c.slot,
})
ev = append(ev, inputEvent{
Type: evAbs,
Code: absMtTrackingId,
Value: c.tracking_id,
})
if events != nil {
ev = append(ev, events...)
}
for _, iev := range ev {
buf, err := inputEventToBuffer(iev)
if err != nil {
return fmt.Errorf("writing abs event failed: %v", err)
}
_, err = c.multitouch.deviceFile.Write(buf)
if err != nil {
return fmt.Errorf("failed to write abs event to device file: %v", err)
}
}
return syncEvents(c.multitouch.deviceFile)
}