5
5
*/
6
6
7
7
#include <fcntl.h>
8
+ #include <libudev.h>
8
9
#include <linux/input.h>
9
10
#include <poll.h>
10
11
#include <pthread.h>
18
19
19
20
#define EVDEV_CNT_MAX 32
20
21
#define EVDEV_NAME_SIZE_MAX 50
22
+ #define UDEV_RESERVED_CNT 1
23
+ #define UDEV_EVDEV_FD_CNT (EVDEV_CNT_MAX + UDEV_RESERVED_CNT)
24
+
25
+ struct evdev_info {
26
+ int idx ;
27
+ int fd ;
28
+ };
21
29
22
30
typedef struct {
23
31
twin_screen_t * screen ;
24
32
pthread_t evdev_thread ;
33
+ struct evdev_info evdevs [EVDEV_CNT_MAX ];
34
+ size_t evdev_cnt ;
35
+ size_t udev_cnt ;
25
36
int fd ;
26
37
int btns ;
27
38
int x , y ;
28
39
} twin_linux_input_t ;
29
40
30
- static int evdev_fd [EVDEV_CNT_MAX ];
31
- static int evdev_cnt ;
32
-
33
41
static void check_mouse_bounds (twin_linux_input_t * tm )
34
42
{
35
43
if (tm -> x < 0 )
@@ -101,37 +109,165 @@ static void twin_linux_input_events(struct input_event *ev,
101
109
}
102
110
}
103
111
104
- static void * twin_linux_evdev_thread ( void * arg )
112
+ static int twin_linux_udev_init ( struct udev * * udev , struct udev_monitor * * mon )
105
113
{
106
- twin_linux_input_t * tm = arg ;
114
+ /* Create udev object */
115
+ * udev = udev_new ();
116
+ if (!* udev ) {
117
+ log_error ("Failed to create udev object" );
118
+ return -1 ;
119
+ }
120
+
121
+ /* Create a monitor for kernel events */
122
+ * mon = udev_monitor_new_from_netlink (* udev , "udev" );
123
+ if (!* mon ) {
124
+ log_error ("Failed to create udev monitor" );
125
+ udev_unref (* udev );
126
+ return -1 ;
127
+ }
128
+
129
+ /* Filter for input subsystem */
130
+ udev_monitor_filter_add_match_subsystem_devtype (* mon , "input" , NULL );
131
+ udev_monitor_enable_receiving (* mon );
132
+
133
+ /* File descriptor for the monitor */
134
+ return udev_monitor_get_fd (* mon );
135
+ }
136
+
137
+ static bool twin_linux_udev_update (struct udev_monitor * mon )
138
+ {
139
+ struct udev_device * dev = NULL ;
140
+
141
+ /* Get the device that caused the event */
142
+ dev = udev_monitor_receive_device (mon );
143
+ if (dev ) {
144
+ const char * action = udev_device_get_action (dev );
145
+ const char * dev_node = udev_device_get_devnode (dev );
146
+
147
+ if (action && dev_node ) {
148
+ const char * keyboard =
149
+ udev_device_get_property_value (dev , "ID_INPUT_KEYBOARD" );
150
+ const char * mouse =
151
+ udev_device_get_property_value (dev , "ID_INPUT_MOUSE" );
152
+
153
+ /* Ensure udev event is for mouse or keyboard */
154
+ if (!keyboard && !mouse ) {
155
+ udev_device_unref (dev );
156
+ return false;
157
+ }
158
+
159
+ /* Capture only add and remove events */
160
+ if (!strcmp (action , "add" ) || !strcmp (action , "remove" )) {
161
+ log_info ("udev: %s: %s" , action , dev_node );
162
+ udev_device_unref (dev );
163
+ return true;
164
+ }
165
+ }
166
+ }
167
+
168
+ /* No event is caputured */
169
+ return false;
170
+ }
171
+
172
+ static void twin_linux_edev_open (struct pollfd * pfds , twin_linux_input_t * tm )
173
+ {
174
+ /* New event device list */
175
+ struct evdev_info evdevs [EVDEV_CNT_MAX ];
176
+ int new_evdev_cnt = 0 ;
177
+ memset (evdevs , 0 , sizeof (evdevs ));
107
178
108
179
/* Open all event devices */
109
180
char evdev_name [EVDEV_NAME_SIZE_MAX ] = {0 };
110
181
for (int i = 0 ; i < EVDEV_CNT_MAX ; i ++ ) {
182
+ /* Check if the file exists */
111
183
snprintf (evdev_name , EVDEV_NAME_SIZE_MAX , "/dev/input/event%d" , i );
184
+ if (access (evdev_name , F_OK ) != 0 )
185
+ continue ;
186
+
187
+ /* Match device with the old device list */
188
+ bool opened = false;
189
+ for (size_t j = 0 ; j < tm -> evdev_cnt ; j ++ ) {
190
+ /* Copy the fd if the device is already on the list */
191
+ if (tm -> evdevs [j ].idx == i ) {
192
+ evdevs [new_evdev_cnt ].idx = tm -> evdevs [j ].idx ;
193
+ evdevs [new_evdev_cnt ].fd = tm -> evdevs [j ].fd ;
194
+ tm -> evdevs [j ].fd = -1 ;
195
+ new_evdev_cnt ++ ;
196
+ opened = true;
197
+ break ;
198
+ }
199
+ }
200
+
201
+ /* Open the file if it is not on the list */
112
202
int fd = open (evdev_name , O_RDWR | O_NONBLOCK );
113
- if (fd > 0 ) {
114
- evdev_fd [evdev_cnt ] = fd ;
115
- evdev_cnt ++ ;
203
+ if (fd > 0 && !opened ) {
204
+ evdevs [new_evdev_cnt ].idx = i ;
205
+ evdevs [new_evdev_cnt ].fd = fd ;
206
+ new_evdev_cnt ++ ;
116
207
}
117
208
}
118
209
119
- /* Initialize pollfd array */
120
- struct pollfd pfds [EVDEV_CNT_MAX ];
121
- for (int i = 0 ; i < evdev_cnt ; i ++ ) {
122
- pfds [i ].fd = evdev_fd [i ];
210
+ /* Close disconnected devices */
211
+ for (size_t i = 0 ; i < tm -> evdev_cnt ; i ++ ) {
212
+ if (tm -> evdevs [i ].fd > 0 )
213
+ close (tm -> evdevs [i ].fd );
214
+ }
215
+
216
+ /* Overwrite the evdev list */
217
+ memcpy (tm -> evdevs , evdevs , sizeof (tm -> evdevs ));
218
+ tm -> evdev_cnt = new_evdev_cnt ;
219
+
220
+ /* Initialize evdev poll file descriptors */
221
+ for (size_t i = tm -> udev_cnt ; i < tm -> evdev_cnt + tm -> udev_cnt ; i ++ ) {
222
+ pfds [i ].fd = tm -> evdevs [i - 1 ].fd ;
123
223
pfds [i ].events = POLLIN ;
124
224
}
225
+ }
226
+
227
+ static void * twin_linux_evdev_thread (void * arg )
228
+ {
229
+ twin_linux_input_t * tm = arg ;
230
+
231
+ struct udev * udev = NULL ;
232
+ struct udev_monitor * mon = NULL ;
233
+
234
+ /* Open Linux udev (user space device manager) */
235
+ int udev_fd = twin_linux_udev_init (& udev , & mon );
236
+ if (udev_fd >= 0 )
237
+ tm -> udev_cnt = 1 ;
238
+
239
+ /* Place the udev fd into the poll fds */
240
+ struct pollfd pfds [UDEV_EVDEV_FD_CNT ];
241
+ pfds [0 ].fd = udev_fd ;
242
+ pfds [0 ].events = POLLIN ;
243
+
244
+ /* Open event devices */
245
+ twin_linux_edev_open (pfds , tm );
246
+
247
+ /* Accessing to input devices is impossible, terminate the thread */
248
+ if (tm -> evdev_cnt == 0 && tm -> udev_cnt == 0 ) {
249
+ log_error ("Failed to open udev and evdev" );
250
+ pthread_exit (NULL );
251
+ }
125
252
126
253
/* Event polling */
127
254
struct input_event ev ;
128
255
while (1 ) {
129
256
/* Wait until any event is available */
130
- if (poll (pfds , evdev_cnt , -1 ) <= 0 )
257
+ if (poll (pfds , tm -> evdev_cnt + tm -> udev_cnt , -1 ) <= 0 )
131
258
continue ;
132
259
133
260
/* Iterate through all file descriptors */
134
- for (int i = 0 ; i < evdev_cnt ; i ++ ) {
261
+ for (size_t i = 0 ; i < tm -> evdev_cnt + tm -> udev_cnt ; i ++ ) {
262
+ if (i < tm -> udev_cnt ) {
263
+ /* Check udev event */
264
+ if (twin_linux_udev_update (mon )) {
265
+ /* Re-open event devices */
266
+ twin_linux_edev_open (pfds , tm );
267
+ break ;
268
+ }
269
+ continue ;
270
+ }
135
271
/* Try reading events */
136
272
ssize_t n = read (pfds [i ].fd , & ev , sizeof (ev ));
137
273
if (n == sizeof (ev )) {
@@ -141,6 +277,10 @@ static void *twin_linux_evdev_thread(void *arg)
141
277
}
142
278
}
143
279
280
+ /* Clean up */
281
+ udev_monitor_unref (mon );
282
+ udev_unref (udev );
283
+
144
284
return NULL ;
145
285
}
146
286
0 commit comments