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 EVDEV_IDX_START 1
23
+
24
+ #define UDEV_RESERVED_CNT 1
25
+ #define UDEV_EVDEV_FD_CNT (EVDEV_CNT_MAX + EVDEV_IDX_START)
21
26
22
27
typedef struct {
23
28
twin_screen_t * screen ;
@@ -101,9 +106,73 @@ static void twin_linux_input_events(struct input_event *ev,
101
106
}
102
107
}
103
108
104
- static void * twin_linux_evdev_thread ( void * arg )
109
+ static int twin_linux_udev_init ( struct udev * * udev , struct udev_monitor * * mon )
105
110
{
106
- twin_linux_input_t * tm = arg ;
111
+ /* Create udev object */
112
+ * udev = udev_new ();
113
+ if (!* udev ) {
114
+ log_error ("Failed to create udev object" );
115
+ return -1 ;
116
+ }
117
+
118
+ /* Create a monitor for kernel events */
119
+ * mon = udev_monitor_new_from_netlink (* udev , "udev" );
120
+ if (!* mon ) {
121
+ log_error ("Failed to create udev monitor" );
122
+ udev_unref (* udev );
123
+ return -1 ;
124
+ }
125
+
126
+ /* Filter for input subsystem */
127
+ udev_monitor_filter_add_match_subsystem_devtype (* mon , "input" , NULL );
128
+ udev_monitor_enable_receiving (* mon );
129
+
130
+ /* File descriptor for the monitor */
131
+ return udev_monitor_get_fd (* mon );
132
+ }
133
+
134
+ static bool twin_linux_udev_update (struct udev_monitor * mon )
135
+ {
136
+ struct udev_device * dev = NULL ;
137
+
138
+ /* Get the device that caused the event */
139
+ dev = udev_monitor_receive_device (mon );
140
+ if (dev ) {
141
+ const char * action = udev_device_get_action (dev );
142
+ const char * dev_node = udev_device_get_devnode (dev );
143
+
144
+ if (action && dev_node ) {
145
+ const char * keyboard =
146
+ udev_device_get_property_value (dev , "ID_INPUT_KEYBOARD" );
147
+ const char * mouse =
148
+ udev_device_get_property_value (dev , "ID_INPUT_MOUSE" );
149
+
150
+ /* Ensure udev event is for mouse or keyboard */
151
+ if (!keyboard && !mouse ) {
152
+ udev_device_unref (dev );
153
+ return false;
154
+ }
155
+
156
+ /* Capture only add and remove events */
157
+ if (!strcmp (action , "add" ) || !strcmp (action , "remove" )) {
158
+ log_info ("udev: %s: %s" , action , dev_node );
159
+ udev_device_unref (dev );
160
+ return true;
161
+ }
162
+ }
163
+ }
164
+
165
+ /* No event is caputured */
166
+ return false;
167
+ }
168
+
169
+ static void twin_linux_edev_open (struct pollfd * pfds )
170
+ {
171
+ /* Reset evdev fd table */
172
+ for (int i = 0 ; i < evdev_cnt ; i ++ ) {
173
+ close (evdev_fd [i ]);
174
+ }
175
+ evdev_cnt = 0 ;
107
176
108
177
/* Open all event devices */
109
178
char evdev_name [EVDEV_NAME_SIZE_MAX ] = {0 };
@@ -116,22 +185,53 @@ static void *twin_linux_evdev_thread(void *arg)
116
185
}
117
186
}
118
187
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 ];
188
+ /* Initialize evdev poll file descriptors */
189
+ for (int i = EVDEV_IDX_START ; i < evdev_cnt + UDEV_RESERVED_CNT ; i ++ ) {
190
+ pfds [i ].fd = evdev_fd [i - 1 ];
123
191
pfds [i ].events = POLLIN ;
124
192
}
193
+ }
194
+
195
+ static void * twin_linux_evdev_thread (void * arg )
196
+ {
197
+ twin_linux_input_t * tm = arg ;
198
+
199
+ struct udev * udev = NULL ;
200
+ struct udev_monitor * mon = NULL ;
201
+
202
+ /* Open Linux udev (user space device manager) */
203
+ int udev_fd = twin_linux_udev_init (& udev , & mon );
204
+ if (udev_fd < 0 ) {
205
+ exit (2 );
206
+ }
207
+
208
+ /* Place the udev fd into the poll fds */
209
+ struct pollfd pfds [UDEV_EVDEV_FD_CNT ];
210
+ pfds [0 ].fd = udev_fd ;
211
+ pfds [0 ].events = POLLIN ;
212
+
213
+ /* Open event devices */
214
+ twin_linux_edev_open (pfds );
125
215
126
216
/* Event polling */
127
217
struct input_event ev ;
128
218
while (1 ) {
129
219
/* Wait until any event is available */
130
- if (poll (pfds , evdev_cnt , -1 ) <= 0 )
220
+ if (poll (pfds , evdev_cnt + UDEV_RESERVED_CNT , -1 ) <= 0 )
131
221
continue ;
132
222
133
223
/* Iterate through all file descriptors */
134
- for (int i = 0 ; i < evdev_cnt ; i ++ ) {
224
+ for (int i = 0 ; i < evdev_cnt + UDEV_RESERVED_CNT ; i ++ ) {
225
+ if (i == 0 ) {
226
+ /* Check udev event */
227
+ if (twin_linux_udev_update (mon )) {
228
+ /* Re-open event devices */
229
+ twin_linux_edev_open (pfds );
230
+ break ;
231
+ }
232
+ continue ;
233
+ }
234
+
135
235
/* Try reading events */
136
236
ssize_t n = read (pfds [i ].fd , & ev , sizeof (ev ));
137
237
if (n == sizeof (ev )) {
@@ -141,6 +241,10 @@ static void *twin_linux_evdev_thread(void *arg)
141
241
}
142
242
}
143
243
244
+ /* Clean up */
245
+ udev_monitor_unref (mon );
246
+ udev_unref (udev );
247
+
144
248
return NULL ;
145
249
}
146
250
0 commit comments