55 */
66
77#include <fcntl.h>
8+ #include <libudev.h>
89#include <linux/input.h>
910#include <poll.h>
1011#include <pthread.h>
1819
1920#define EVDEV_CNT_MAX 32
2021#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+ };
2129
2230typedef struct {
2331 twin_screen_t * screen ;
2432 pthread_t evdev_thread ;
33+ struct evdev_info evdevs [EVDEV_CNT_MAX ];
34+ size_t evdev_cnt ;
35+ size_t udev_cnt ;
2536 int fd ;
2637 int btns ;
2738 int x , y ;
2839} twin_linux_input_t ;
2940
30- static int evdev_fd [EVDEV_CNT_MAX ];
31- static int evdev_cnt ;
32-
3341static void check_mouse_bounds (twin_linux_input_t * tm )
3442{
3543 if (tm -> x < 0 )
@@ -101,37 +109,165 @@ static void twin_linux_input_events(struct input_event *ev,
101109 }
102110}
103111
104- static void * twin_linux_evdev_thread ( void * arg )
112+ static int twin_linux_udev_init ( struct udev * * udev , struct udev_monitor * * mon )
105113{
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 ));
107178
108179 /* Open all event devices */
109180 char evdev_name [EVDEV_NAME_SIZE_MAX ] = {0 };
110181 for (int i = 0 ; i < EVDEV_CNT_MAX ; i ++ ) {
182+ /* Check if the file exists */
111183 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 */
112202 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 ++ ;
116207 }
117208 }
118209
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 ;
123223 pfds [i ].events = POLLIN ;
124224 }
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+ }
125252
126253 /* Event polling */
127254 struct input_event ev ;
128255 while (1 ) {
129256 /* 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 )
131258 continue ;
132259
133260 /* 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+ }
135271 /* Try reading events */
136272 ssize_t n = read (pfds [i ].fd , & ev , sizeof (ev ));
137273 if (n == sizeof (ev )) {
@@ -141,6 +277,10 @@ static void *twin_linux_evdev_thread(void *arg)
141277 }
142278 }
143279
280+ /* Clean up */
281+ udev_monitor_unref (mon );
282+ udev_unref (udev );
283+
144284 return NULL ;
145285}
146286
0 commit comments