1 /*
2 * Copyright 2014-2020, Björn Ståhl
3 * License: 3-Clause BSD, see COPYING file in arcan source repository.
4 * Reference: http://arcan-fe.com
5 */
6
7 #include <stdlib.h>
8 #include <stdint.h>
9 #include <stdbool.h>
10 #include <assert.h>
11 #include <string.h>
12 #include <stdio.h>
13 #include <unistd.h>
14 #include <inttypes.h>
15 #include <stdio.h>
16 #include <errno.h>
17 #include <poll.h>
18 #include <glob.h>
19
20 #include <sys/types.h>
21 #include <sys/param.h>
22 #include <sys/stat.h>
23 #include <fcntl.h>
24
25 #include <linux/input.h>
26
27 #include "arcan_shmif.h"
28 #include "arcan_math.h"
29 #include "arcan_general.h"
30 #include "arcan_event.h"
31 #include "arcan_led.h"
32 #include "arcan_video.h"
33 #include "arcan_videoint.h"
34 #include "keycode_xlate.h"
35
36 #ifndef __FreeBSD__
37 #include <sys/inotify.h>
38 #endif
39
40 #ifdef HAVE_XKBCOMMON
41 #include <xkbcommon/xkbcommon.h>
42 #include <xkbcommon/xkbcommon-keysyms.h>
43 #include <xkbcommon/xkbcommon-compose.h>
44 /*
45 * shared between all event queues
46 */
47 static struct xkb_context* xkb_context;
48 #endif
49
50 #ifdef _DEBUG
51 #define DEBUG 1
52 #else
53 #define DEBUG 0
54 #endif
55
56 #define debug_print(fmt, ...) \
57 do { if (DEBUG) arcan_warning("[%lld]%s:%d:%s(): " fmt "\n", \
58 arcan_timemillis(), "evdev:", __LINE__, __func__,##__VA_ARGS__); \
59 } while (0)
60
61 #define verbose_print
62
63 /*
64 * scan / probe a node- dir (ENVV overridable)
65 */
66 #ifndef NOTIFY_SCAN_DIR
67 #define NOTIFY_SCAN_DIR "/dev/input"
68 #endif
69
70 static char* notify_scan_dir;
71
72 /*
73 * In happy-fun everything is user-space land, we face the policy problem of
74 * device nodes not being created with the desired permissions in an atomic
75 * manner. Combine with inotify and we may beat some deaemon to the races and
76 * there we go. For EACCES we go the 'retry a little later' route.
77 */
78 static const int default_eacces_tries = 8;
79 static const int default_eacces_delay = 1000;
80
81 static struct {
82 char* path;
83 int tries;
84 int64_t last_ts;
85 } pending[8];
86
87 static struct {
88 bool mute, init;
89 int tty, notify;
90 int pending;
91 }
92 gstate = {
93
94 .notify = -1,
95 };
96
97 static const char* envopts[] = {
98 "scandir=path/to/folder", "Directory to monitor for device node hotplug "
99 "(Default: "NOTIFY_SCAN_DIR")",
100 "disable_ttyswap", "Disable tty- swapping signal handler",
101 "[evdev_type=label]", "suffix evdev_type with _n for (n = 2, 3, ...)",
102 "evdev_keyboard=label", "Force device matching 'label' as a keyboard",
103 "evdev_game=label", "Force device matching 'label' as a game device",
104 "evdev_mouse=label", "Force device matching 'label' as a mouse",
105 #ifdef HAVE_XKBCOMMON
106 "", "",
107 "[XKB-ARGUMENTS]", "[these are ENV- only (fwd to libxkbcommon)]",
108 "XKB_DEFAULT_LAYOUT=lang", "enable XKB translation maps for keyboards",
109 "XKB_DEFAULT_VARIANT=variant", "define XKB layout variant",
110 "XKB_DEFAULT_MODEL=pc101", "define XKB keyboard model",
111 #endif
112 NULL
113 };
114
115 /*
116 * need a reasonable limit on the amount of allowed devices, should this become
117 * a problem -- whitelist. See lookup_devnode for an explanation on the problem
118 * with devid-.
119 */
120 #define MAX_DEVICES 256
121
122 struct devnode;
123 #include "device_db.h"
124
125 struct axis_opts {
126 /* none, avg, drop */
127 enum ARCAN_ANALOGFILTER_KIND mode;
128 enum ARCAN_ANALOGFILTER_KIND oldmode;
129
130 int lower, upper, deadzone;
131
132 /* we won't get access to a good range distribution if we don't emit the first
133 * / last sample that got into the drop range */
134 bool inlzone, inuzone, indzone;
135
136 int kernel_sz;
137 int kernel_ofs;
138 int32_t flt_kernel[64];
139 };
140
141 static struct {
142 size_t n_devs, sz_nodes;
143
144 /* repeat is currently enforced uniformly across all keyboards, might be
145 * usecases where this is not preferable but there is no higher-level api
146 * that provides this granularity. */
147 unsigned period, delay;
148
149 unsigned short mouseid;
150 struct devnode* nodes;
151
152 struct pollfd* pollset;
153 } iodev = {0};
154
155 struct devnode {
156 int handle;
157
158 /* NULL&size terminated, with chain-block set of the previous one could not
159 * handle. This is to cover devices that could expose themselves as being
160 * aggregated KEY/DEV/etc. */
161 struct evhandler hnd;
162
163 char label[256];
164 char* path;
165 unsigned short devnum;
166 size_t button_count;
167
168 enum devnode_type type;
169 union {
170 struct {
171 struct axis_opts data;
172 } sensor;
173 struct {
174 unsigned short axes;
175 unsigned short buttons;
176 unsigned short relofs;
177 char hats[16];
178 struct axis_opts* adata;
179 } game;
180 struct {
181 uint16_t mx;
182 uint16_t my;
183 struct axis_opts flt[2];
184 } cursor;
185 struct {
186 unsigned state;
187 #ifdef HAVE_XKBCOMMON
188 struct xkb_keymap* xkb_layout;
189 struct xkb_state* xkb_state;
190 #endif
191 } keyboard;
192 };
193 /* because in this universe, pretty much any normal input device can
194 * also have a touch display. */
195 struct {
196 bool active;
197 bool pending;
198 int x;
199 int y;
200 int pressure;
201 int size;
202 int ind;
203 } touch;
204
205 /* and also possible act as a LED controller */
206 struct {
207 bool gotled;
208 int ctrlid;
209 int ind;
210 int fds[2];
211 } led;
212 };
213
214 static void got_device(struct arcan_evctx* ctx, int fd, const char*);
215
216 /* for other platforms and legacy, devid used to be allocated sequentially
217 * and swept linear, even though this platform do not work like that and we
218 * have a dynamic set of devices. For this reason, we split the 16 bit space
219 * into < MAX_DEVICES and >= MAX_DEVICES and a device a can be accessed by
220 * either id */
lookup_devnode(int devid)221 static struct devnode* lookup_devnode(int devid)
222 {
223 if (devid <= 0)
224 devid = iodev.mouseid;
225
226 if (devid < iodev.sz_nodes){
227 verbose_print("lookup(%d) => %"PRIxPTR, devid, &iodev.nodes[devid]);
228 return &iodev.nodes[devid];
229 }
230
231 for (size_t i = 0; i < iodev.sz_nodes; i++){
232 if (iodev.nodes[i].devnum == devid){
233 verbose_print("lookup(%d:%zu) => %"PRIxPTR, devid, i, &iodev.nodes[i]);
234 return &iodev.nodes[i];
235 }
236 }
237
238 verbose_print("%zu => %d", devid, -1);
239 return NULL;
240 }
241
242 /* another option to this mess (as the hashing thing doesn't seem to work out
243 * is to move identification/etc. to another level and just let whatever device
244 * node generator is active populate with coherent names. and use a hash of that
245 * name as the ID */
identify(int fd,const char * path,char * label,size_t label_sz,unsigned short * dnum)246 static bool identify(int fd, const char* path,
247 char* label, size_t label_sz, unsigned short* dnum)
248 {
249 if (-1 == ioctl(fd, EVIOCGNAME(label_sz), label)){
250 debug_print("input/identify: bad EVIOCGNAME, setting unknown\n");
251 snprintf(label, label_sz, "unknown");
252 }
253 else
254 verbose_print(
255 "input/identify(%d): %s name resolved to %s", fd, path, label);
256
257 struct input_id nodeid;
258 if (-1 == ioctl(fd, EVIOCGID, &nodeid)){
259 debug_print(
260 "input/identify(%d): no EVIOCGID, reason:%s", fd, strerror(errno));
261 return false;
262 }
263
264 /*
265 * first, check if any other subsystem knows about this one and ignore if so
266 */
267 if (arcan_led_known(nodeid.vendor, nodeid.product)){
268 debug_print(
269 "led subsys know %d, %d\n", (int)nodeid.vendor, (int)nodeid.product);
270 arcan_led_init();
271 return false;
272 }
273
274 /* didn't find much on how unique eviocguniq actually was, nor common lengths
275 * or what not so just mix them in a buffer, hash and let unsigned overflow
276 * modulo take us down to 16bit */
277 size_t bpl = sizeof(long) * 8;
278 size_t nbits = ((EV_MAX)-1) / bpl + 1;
279
280 char buf[12 + nbits * sizeof(long)];
281 char bbuf[sizeof(buf)];
282 memset(buf, '\0', sizeof(buf));
283 memset(bbuf, '\0', sizeof(bbuf));
284
285 /* some test devices here answered to the ioctl and returned full empty UNIQs,
286 * do something to lower the likelihood of collisions */
287 unsigned long hash = 5381;
288
289 if (-1 == ioctl(fd, EVIOCGUNIQ(sizeof(buf)), buf) ||
290 memcmp(buf, bbuf, sizeof(buf)) == 0){
291
292 size_t llen = strlen(label);
293 for (size_t i = 0; i < llen; i++)
294 hash = ((hash << 5) + hash) + label[i];
295
296 llen = strlen(path);
297 for (size_t i = 0; i < llen; i++)
298 hash = ((hash << 5) + hash) + path[i];
299
300 buf[11] ^= nodeid.vendor >> 8;
301 buf[10] ^= nodeid.vendor;
302 buf[9] ^= nodeid.product >> 8;
303 buf[8] ^= nodeid.product;
304 buf[7] ^= nodeid.version >> 8;
305 buf[6] ^= nodeid.version;
306
307 /* even this point has a few collisions, particularly some keyboards and mice
308 * that don't respond to CGUNIQ and expose multiple- subdevices but with
309 * different button/axis count */
310 ioctl(fd, EVIOCGBIT(0, EV_MAX), &buf);
311 }
312
313 for (size_t i = 0; i < sizeof(buf); i++)
314 hash = ((hash << 5) + hash) + buf[i];
315
316 /* 16-bit clamp is legacy in the scripting layer, also leave the highest
317 * bit unset as that is reserved for synthetic devices */
318 hash &= 0xfffe;
319 if (hash < MAX_DEVICES)
320 hash += MAX_DEVICES;
321
322 /* scan for collisions, if there is one, random and repeat. We lose
323 * repeatability but don't risk collision-disconnect spam */
324 for (ssize_t i = 0; i < iodev.sz_nodes; i++){
325 while (hash == iodev.nodes[i].devnum){
326 uint16_t rv;
327 arcan_random((uint8_t*)&rv, 2);
328 hash = rv & (uint16_t) 0xfffe;
329 if (hash < MAX_DEVICES)
330 hash += MAX_DEVICES;
331 if (i)
332 i -= 1;
333 continue;
334 }
335 }
336
337 *dnum = hash;
338
339 return true;
340 }
341
process_axis(struct arcan_evctx * ctx,struct axis_opts * daxis,int16_t samplev,int16_t * outv)342 static inline bool process_axis(struct arcan_evctx* ctx,
343 struct axis_opts* daxis, int16_t samplev, int16_t* outv)
344 {
345 if (daxis->mode == ARCAN_ANALOGFILTER_NONE)
346 return false;
347
348 if (daxis->mode == ARCAN_ANALOGFILTER_PASS)
349 goto accept_sample;
350
351 /* quickfilter deadzone */
352 if (abs(samplev) < daxis->deadzone){
353 if (!daxis->indzone){
354 samplev = 0;
355 daxis->indzone = true;
356 }
357 else
358 return false;
359 }
360 else
361 daxis->indzone = false;
362
363 /* quickfilter out controller edgenoise */
364 if (samplev < daxis->lower){
365 if (!daxis->inlzone){
366 samplev = daxis->lower;
367 daxis->inlzone = true;
368 daxis->inuzone = false;
369 }
370 else
371 return false;
372 }
373 else if (samplev > daxis->upper){
374 if (!daxis->inuzone){
375 samplev = daxis->upper;
376 daxis->inuzone = true;
377 daxis->inlzone = false;
378 }
379 else
380 return false;
381 }
382 else
383 daxis->inlzone = daxis->inuzone = false;
384
385 daxis->flt_kernel[ daxis->kernel_ofs++ ] = samplev;
386
387 /* don't proceed until the kernel is filled */
388 if (daxis->kernel_ofs < daxis->kernel_sz)
389 return false;
390
391 if (daxis->kernel_sz > 1){
392 int32_t tot = 0;
393
394 if (daxis->mode == ARCAN_ANALOGFILTER_ALAST){
395 samplev = daxis->flt_kernel[daxis->kernel_sz - 1];
396 }
397 else {
398 for (int i = 0; i < daxis->kernel_sz; i++)
399 tot += daxis->flt_kernel[i];
400
401 samplev = tot != 0 ? tot / daxis->kernel_sz : 0;
402 }
403
404 }
405 else;
406 daxis->kernel_ofs = 0;
407
408 accept_sample:
409 *outv = samplev;
410 return true;
411 }
412
set_analogstate(struct axis_opts * dst,int lower_bound,int upper_bound,int deadzone,int kernel_size,enum ARCAN_ANALOGFILTER_KIND mode)413 static void set_analogstate(struct axis_opts* dst,
414 int lower_bound, int upper_bound, int deadzone,
415 int kernel_size, enum ARCAN_ANALOGFILTER_KIND mode)
416 {
417 dst->lower = lower_bound;
418 dst->upper = upper_bound;
419 dst->deadzone = deadzone;
420 dst->kernel_sz = kernel_size;
421 dst->mode = mode;
422
423 dst->kernel_ofs = 0;
424 }
425
find_axis(int devid,unsigned axisid,bool * outn)426 static struct axis_opts* find_axis(int devid, unsigned axisid, bool* outn)
427 {
428 struct devnode* node = lookup_devnode(devid);
429 *outn = node != NULL;
430
431 if (!node)
432 return NULL;
433
434 switch(node->type){
435 case DEVNODE_SENSOR:
436 return axisid == 0 ? &node->sensor.data : NULL;
437 break;
438
439 case DEVNODE_GAME:
440 if (axisid < node->game.axes)
441 return &node->game.adata[axisid];
442 break;
443
444 case DEVNODE_MOUSE:
445 if (axisid == 0)
446 return &node->cursor.flt[0];
447 else if (axisid == 1)
448 return &node->cursor.flt[1];
449 break;
450
451 default:
452 break;
453 }
454
455 return NULL;
456 }
457
platform_event_analogstate(int devid,int axisid,int * lower_bound,int * upper_bound,int * deadzone,int * kernel_size,enum ARCAN_ANALOGFILTER_KIND * mode)458 arcan_errc platform_event_analogstate(int devid, int axisid,
459 int* lower_bound, int* upper_bound, int* deadzone,
460 int* kernel_size, enum ARCAN_ANALOGFILTER_KIND* mode)
461 {
462 bool gotnode;
463 struct axis_opts* axis = find_axis(devid, axisid, &gotnode);
464
465 if (!axis)
466 return gotnode ?
467 ARCAN_ERRC_BAD_RESOURCE : ARCAN_ERRC_NO_SUCH_OBJECT;
468
469 *lower_bound = axis->lower;
470 *upper_bound = axis->upper;
471 *deadzone = axis->deadzone;
472 *kernel_size = axis->kernel_sz;
473 *mode = axis->mode;
474
475 return ARCAN_OK;
476 }
477
platform_event_analogall(bool enable,bool mouse)478 void platform_event_analogall(bool enable, bool mouse)
479 {
480 struct devnode* node = lookup_devnode(iodev.mouseid);
481 if (!node)
482 return;
483
484 /*
485 * FIXME sweep all devices and all axes (or just mouseid) if (enable) then set
486 * whatever the previous mode was, else store current mode and set NONE
487 */
488 }
489
490 static void disconnect(struct arcan_evctx* ctx, struct devnode* node);
platform_event_analogfilter(int devid,int axisid,int lower_bound,int upper_bound,int deadzone,int buffer_sz,enum ARCAN_ANALOGFILTER_KIND kind)491 void platform_event_analogfilter(int devid,
492 int axisid, int lower_bound, int upper_bound, int deadzone,
493 int buffer_sz, enum ARCAN_ANALOGFILTER_KIND kind)
494 {
495 /* this was added here rather than a separate entry-point to deal with backward
496 * and forward compatiblity from an API angle */
497 if (kind == ARCAN_ANALOGFILTER_FORGET){
498 struct devnode* node = lookup_devnode(devid);
499
500 /* this is also a piece of legacy, other functions operate on an explicit
501 * context, but there is really only one */
502 if (node)
503 disconnect(arcan_event_defaultctx(), node);
504 return;
505 }
506
507 bool node;
508 struct axis_opts* axis = find_axis(devid, axisid, &node);
509 if (!axis)
510 return;
511
512 int kernel_lim = sizeof(axis->flt_kernel) / sizeof(axis->flt_kernel[0]);
513
514 if (buffer_sz > kernel_lim)
515 buffer_sz = kernel_lim;
516
517 if (buffer_sz <= 0)
518 buffer_sz = 1;
519
520 set_analogstate(axis,lower_bound, upper_bound, deadzone, buffer_sz, kind);
521 }
522
discovered(struct arcan_evctx * ctx,const char * name,size_t name_len,bool nopending)523 static bool discovered(struct arcan_evctx* ctx,
524 const char* name, size_t name_len, bool nopending)
525 {
526 char buffer[name_len+sizeof(notify_scan_dir)];
527 char outbuffer[MAXPATHLEN];
528
529 /* need to resolve a symlink if there is one as the platform_device_open
530 * has a whitelist that is rather picky about which devices it will open */
531 snprintf(buffer, sizeof(buffer), "%s/%.*s", notify_scan_dir, (int)name_len, name);
532
533 TRACE_MARK_ENTER("event", "open-device", TRACE_SYS_DEFAULT, 0, 0, name);
534
535 int fd = platform_device_open(
536 readlink(buffer, outbuffer, sizeof(outbuffer)) > 0 ?
537 outbuffer : buffer, O_NONBLOCK| O_RDWR);
538
539 TRACE_MARK_EXIT("event", "open-device", TRACE_SYS_DEFAULT, 0, fd, name);
540
541 verbose_print("input: trying to add %s/%.*s",
542 notify_scan_dir, (int)name_len, name);
543
544 if (-1 == fd && errno == EACCES){
545 if (gstate.pending >= COUNT_OF(pending)){
546 debug_print(
547 "input: pending queue limit exceeded, possibly something wrong"
548 " with monitored folder (%s) and permissions.", notify_scan_dir
549 );
550 return false;
551 }
552
553 /* already know about this one */
554 if (nopending)
555 return false;
556
557 /* sign that someone is impatient and plugging / unplugging while pending */
558 size_t i;
559 ssize_t j = -1;
560 for (i = 0; i < COUNT_OF(pending); i++){
561 if (!pending[i].path && j == -1)
562 j = i;
563 if (pending[i].path && strcmp(name, pending[i].path) == 0)
564 return false;
565 }
566 /* name comes from inotify which does not have to terminate */
567 gstate.pending++;
568 pending[j].path = malloc(name_len + 1);
569 sprintf(pending[j].path, "%.*s", (int)name_len, name);
570 pending[j].tries = default_eacces_tries;
571 pending[j].last_ts = arcan_frametime();
572 return false;
573 }
574
575 /* even if we can access it and it is of the right type, it is not certain
576 * that we can actually identify and use it according with evdev */
577 if (-1 != fd){
578 got_device(ctx, fd, name);
579 return true;
580 }
581 else
582 arcan_warning("input: couldn't open new device (%s), reason: %s\n",
583 name, strerror(errno));
584 return false;
585 }
586
process_pending(struct arcan_evctx * ctx)587 static void process_pending(struct arcan_evctx* ctx)
588 {
589 for (size_t i = 0; i < COUNT_OF(pending); i++){
590 if (!pending[i].path)
591 continue;
592
593 /* wait a little longer for each failed attempt */
594 if (arcan_frametime() - pending[i].last_ts < (default_eacces_tries -
595 pending[i].tries + 1) * default_eacces_delay)
596 continue;
597
598 pending[i].last_ts = arcan_frametime();
599
600 if (discovered(ctx, pending[i].path, strlen(pending[i].path), true)){
601 free(pending[i].path);
602 pending[i].path = NULL;
603 gstate.pending--;
604 }
605 else{
606 pending[i].tries--;
607 if (pending[i].tries <= 0){
608 arcan_warning("input(eperm): device(%s) retry count"
609 "exceeded\n", pending[i].path);
610 free(pending[i].path);
611 pending[i].path = NULL;
612 gstate.pending--;
613 }
614 }
615 }
616 }
617
disconnect(struct arcan_evctx * ctx,struct devnode * node)618 static void disconnect(struct arcan_evctx* ctx, struct devnode* node)
619 {
620 struct arcan_event addev = {
621 .category = EVENT_IO,
622 .io.kind = EVENT_IO_STATUS,
623 .io.devid = node->devnum,
624 .io.devkind = EVENT_IDEVKIND_STATUS,
625 .io.input.status.devkind = node->type,
626 .io.input.status.action = EVENT_IDEV_REMOVED
627 };
628 snprintf((char*) &addev.io.label, sizeof(addev.io.label) /
629 sizeof(addev.io.label[0]), "%s", node->label);
630 arcan_event_enqueue(ctx, &addev);
631
632 for (size_t i = 0; i < iodev.sz_nodes; i++)
633 if (node->devnum == iodev.nodes[i].devnum){
634 close(node->handle);
635 free(node->path);
636 node->path = NULL;
637 node->handle = -1;
638 iodev.pollset[i].events = iodev.pollset[i].revents = 0;
639 iodev.pollset[i].fd = -1;
640 if (node->led.gotled){
641 iodev.pollset[i+iodev.sz_nodes].fd = -1;
642 iodev.pollset[i+iodev.sz_nodes].events =
643 iodev.pollset[i+iodev.sz_nodes].revents = 0;
644 node->led.gotled = false;
645 arcan_led_remove(node->led.ctrlid);
646 close(node->led.fds[0]);
647 close(node->led.fds[1]);
648 node->led.fds[0] = -1;
649 node->led.fds[1] = -1;
650 }
651 #ifdef HAVE_XKBCOMMON
652 if (node->type == DEVNODE_KEYBOARD && node->keyboard.xkb_state){
653 xkb_state_unref(node->keyboard.xkb_state);
654 xkb_keymap_unref(node->keyboard.xkb_layout);
655 node->keyboard.xkb_state = NULL;
656 node->keyboard.xkb_layout = NULL;
657 }
658 #endif
659 iodev.n_devs--;
660 }
661 }
662
do_led(struct devnode * node)663 static void do_led(struct devnode* node)
664 {
665 if (!node->led.gotled){
666 arcan_warning("evdev(), pollset corruption? POLLIN on node without LED\n");
667 return;
668 }
669
670 uint8_t buf[2];
671 bool set = false;
672
673 while (2 == read(node->led.fds[0], buf, 2)){
674 switch (tolower(buf[0])){
675 case 'A': node->led.ind = -1; break;
676 case 'a': node->led.ind = buf[1]; break;
677 /* not registered as a RGB led */
678 case 'r': break;
679 case 'g': break;
680 case 'b': break;
681 case 'i': set = buf[1] > 0; break;
682 case 'c':
683 if (node->led.ind == -1){
684 for (size_t i = 0; i < LED_MAX; i++)
685 if (-1 == write(node->handle, &(struct input_event){.type = EV_LED,
686 .code = i, .value = set}, sizeof(struct input_event)))
687 arcan_warning("platform/evdev: failed to write to led device\n");
688 }
689 else {
690 if (-1 == write(node->handle, &(struct input_event){.type = EV_LED,
691 .code = node->led.ind, .value = set}, sizeof(struct input_event)))
692 arcan_warning("platform/evdev: failed to write to led device\n");
693 }
694 break;
695 }
696 }
697 }
698
platform_event_process(struct arcan_evctx * ctx)699 void platform_event_process(struct arcan_evctx* ctx)
700 {
701 /* lovely little variable length field at end of struct here /sarcasm,
702 * could get away with running the notify polling less often than once
703 * every frame, somewhat excessive. */
704 #ifdef __FreeBSD__
705 #else
706 if (-1 != gstate.notify){
707 char inbuf[1024];
708 ssize_t nr = read(gstate.notify, inbuf, sizeof(inbuf));
709 off_t ofs = 0;
710
711 if (-1 != nr)
712 while (nr - ofs > sizeof(struct inotify_event)){
713 struct inotify_event cur;
714 memcpy(&cur, &inbuf[ofs], sizeof(struct inotify_event));
715 ofs += sizeof(struct inotify_event);
716
717 if ((cur.mask & IN_CREATE) && !(cur.mask & IN_ISDIR)){
718 discovered(ctx, &inbuf[ofs], cur.len, false);
719 ofs += cur.len;
720 }
721 }
722 }
723 #endif
724 TRACE_MARK_ENTER("event", "flush-pending-in", TRACE_SYS_DEFAULT, 0, 0, "flush-in");
725
726 if (gstate.pending)
727 process_pending(ctx);
728
729 int nr = poll(iodev.pollset, iodev.sz_nodes * 2, 0);
730 if (nr <= 0){
731 TRACE_MARK_EXIT("event", "flush-pending-in", TRACE_SYS_FAST, 0, 0, "flush-in");
732 return;
733 }
734
735 for (size_t i = 0; i < iodev.sz_nodes; i++){
736 /* recall, sz_nodes is half the count, i + sz_nodes = alt-dev index */
737 if (iodev.pollset[i+iodev.sz_nodes].revents & POLLIN){
738 do_led(&iodev.nodes[i]);
739 }
740
741 if (iodev.pollset[i].fd == -1 || 0 == iodev.pollset[i].revents)
742 continue;
743
744 /* !POLLIN, then something is wrong, remove the node */
745 if (0 == (iodev.pollset[i].revents & POLLIN)){
746 disconnect(ctx, &iodev.nodes[i]);
747 continue;
748 }
749 /* some nodes may get a null handler temporarily or permanently assiged,
750 * drain those for evdev structures */
751 else {
752 if (iodev.nodes[i].hnd.handler)
753 iodev.nodes[i].hnd.handler(ctx, &iodev.nodes[i]);
754 else{
755 char dump[256];
756 size_t nr __attribute__((unused));
757 nr = read(iodev.nodes[i].handle, dump, 256);
758 }
759 }
760 }
761 TRACE_MARK_EXIT("event", "flush-pending-in", TRACE_SYS_DEFAULT, 0, 0, "flush-in");
762 }
763
platform_event_samplebase(int devid,float xyz[3])764 void platform_event_samplebase(int devid, float xyz[3])
765 {
766 struct devnode* node = lookup_devnode(devid);
767 if (!node || node->type != DEVNODE_MOUSE)
768 return;
769
770 node->cursor.mx = xyz[0];
771 node->cursor.my = xyz[1];
772 }
773
platform_event_keyrepeat(struct arcan_evctx * ctx,int * period,int * delay)774 void platform_event_keyrepeat(struct arcan_evctx* ctx, int* period, int* delay)
775 {
776 bool upd = false;
777
778 if (*period < 0){
779 *period = iodev.period;
780 }
781 else{
782 int tmp = *period;
783 *period = iodev.period;
784 iodev.period = tmp;
785 upd = true;
786 }
787
788 if (*delay < 0){
789 *delay = iodev.delay;
790 }
791 else {
792 int tmp = *delay;
793 *delay = iodev.delay;
794 iodev.delay = tmp;
795 upd = true;
796 }
797
798 if (!upd)
799 return;
800
801 for (size_t i = 0; i < iodev.sz_nodes; i++)
802 if (iodev.nodes[i].type == DEVNODE_KEYBOARD){
803 struct input_event ev = {
804 .type = EV_REP,
805 .code = REP_DELAY,
806 .value = *delay
807 };
808 if (-1 == write(iodev.nodes[i].handle,&ev,sizeof(struct input_event)))
809 verbose_print("linux/event: keydelay fail (%s)\n", strerror(errno));
810
811 ev.code = REP_PERIOD;
812 ev.value = *period;
813 if (-1 == write(iodev.nodes[i].handle,&ev,sizeof(struct input_event)))
814 verbose_print("linux/event: keyrepeat fail (%s)\n", strerror(errno));
815 }
816 }
817
lookup_type(int val)818 static const char* lookup_type(int val)
819 {
820 switch(val){
821 case DEVNODE_GAME:
822 return "game";
823 case DEVNODE_MOUSE:
824 return "mouse";
825 case DEVNODE_SENSOR:
826 return "sensor";
827 case DEVNODE_KEYBOARD:
828 return "keyboard";
829 break;
830 default:
831 return "unknown";
832 }
833 }
834
835 #define bit_longn(x) ( (x) / (sizeof(long)*8) )
836 #define bit_ofs(x) ( (x) % (sizeof(long)*8) )
837 #define bit_isset(ary, bit) (( ary[bit_longn(bit)] >> bit_ofs(bit)) & 1)
838 #define bit_count(x) ( ((x) - 1 ) / (sizeof(long) * 8 ) + 1 )
839
button_count(int fd,size_t bitn,bool * got_mouse,bool * got_joy)840 static size_t button_count(int fd, size_t bitn, bool* got_mouse, bool* got_joy)
841 {
842 size_t count = 0;
843
844 unsigned long bits[ bit_count(KEY_MAX) ];
845
846 if (-1 == ioctl(fd, EVIOCGBIT(bitn, KEY_MAX), bits))
847 return false;
848
849 for (size_t i = 0; i < KEY_MAX; i++){
850 if (bit_isset(bits, i)){
851 count++;
852 }
853 }
854
855 *got_mouse = (bit_isset(bits, BTN_MOUSE) || bit_isset(bits, BTN_LEFT) ||
856 bit_isset(bits, BTN_RIGHT) || bit_isset(bits, BTN_MIDDLE));
857
858 *got_joy = (bit_isset(bits, BTN_JOYSTICK) || bit_isset(bits, BTN_GAMEPAD) ||
859 bit_isset(bits, BTN_WHEEL));
860
861 return count;
862 }
863
check_mouse_axis(int fd,size_t bitn)864 static bool check_mouse_axis(int fd, size_t bitn)
865 {
866 unsigned long bits[ bit_count(KEY_MAX) ];
867 if (-1 == ioctl(fd, EVIOCGBIT(bitn, KEY_MAX), bits))
868 return false;
869
870 /* uncertain if other (REL_Z, REL_RX, REL_RY, REL_RZ, REL_DIAL, REL_MISC)
871 * should be used as a failing criteria */
872 return bit_isset(bits, REL_X) && bit_isset(bits, REL_Y);
873 }
874
to_utf8(uint16_t utf16,uint8_t out[4])875 static char* to_utf8(uint16_t utf16, uint8_t out[4])
876 {
877 int count = 1, ofs = 0;
878 uint32_t mask = 0x800;
879
880 if (utf16 >= 0x80)
881 count++;
882
883 for(size_t i=0; i < 5; i++){
884 if ( (uint32_t) utf16 >= mask )
885 count++;
886
887 mask <<= 5;
888 }
889
890 if (count == 1){
891 out[0] = (char) utf16;
892 out[1] = 0x00;
893 }
894 else {
895 for (int i = (count-1 > 4 ? 4 : count - 1); i >= 0; i--){
896 unsigned char ch = ( utf16 >> (6 * i)) & 0x3f;
897 ch |= 0x80;
898 if (i == count-1)
899 ch |= 0xff << (8-count);
900 out[ofs++] = ch;
901 }
902 out[ofs++] = 0x00;
903 }
904
905 return (char*) out;
906 }
907
map_axes(int fd,size_t bitn,struct devnode * node)908 static void map_axes(int fd, size_t bitn, struct devnode* node)
909 {
910 unsigned long bits[ bit_count(ABS_MAX) ];
911 unsigned long rel_bits[ bit_count(REL_MAX) ];
912
913 assert(node->type == DEVNODE_GAME);
914 if (node->game.adata)
915 return;
916 node->game.axes = 0;
917
918 if (-1 != ioctl(fd, EVIOCGBIT(bitn, ABS_MAX), bits)){
919 for (size_t i = 0; i < ABS_MAX; i++){
920 if (bit_isset(bits, i))
921 node->game.axes++;
922 }
923 }
924
925 node->game.relofs = node->game.axes;
926 if (-1 != ioctl(fd, EVIOCGBIT(bitn, REL_MAX), rel_bits)){
927 for (size_t i = 0; i < REL_MAX; i++){
928 if (bit_isset(bits, i)){
929 node->game.axes++;
930 }
931 }
932 }
933
934 if (node->game.axes == 0)
935 return;
936
937 node->game.adata = arcan_alloc_mem(
938 sizeof(struct axis_opts) * node->game.axes,
939 ARCAN_MEM_BINDING, ARCAN_MEM_BZERO, ARCAN_MEMALIGN_NATURAL
940 );
941
942 size_t ac = 0;
943
944 for (size_t i = 0; i < ABS_MAX; i++)
945 if (bit_isset(bits, i)){
946 struct input_absinfo ainf;
947 struct axis_opts* ax = &node->game.adata[ac++];
948
949 memset(ax, '\0', sizeof(struct axis_opts));
950 ax->mode = ax->oldmode = ARCAN_ANALOGFILTER_AVG;
951 ax->lower = -32768;
952 ax->upper = 32767;
953
954 if (-1 == ioctl(fd, EVIOCGABS(i), &ainf))
955 continue;
956
957 ax->upper = ainf.maximum;
958 ax->lower = ainf.minimum;
959 }
960 }
961
962 /*
963 * setup/register/prepare led- controller handler
964 */
setup_led(struct devnode * dst,size_t bitn,int fd)965 static void setup_led(struct devnode* dst, size_t bitn, int fd)
966 {
967 unsigned long bits[ bit_count(LED_MAX) ];
968 if (-1 == ioctl(fd, EVIOCGBIT(bitn, LED_MAX), bits))
969 return;
970
971 size_t count = 0;
972 for (size_t i = 0; i < LED_MAX; i++){
973 if (bit_isset(bits, i))
974 count++;
975 }
976
977 if (!count)
978 return;
979
980 if (pipe(dst->led.fds) == -1)
981 return;
982
983 for (size_t i = 0; i < 2; i++){
984 int flags = fcntl(dst->led.fds[i], F_GETFL);
985 if (-1 != flags)
986 fcntl(dst->led.fds[i], F_SETFL, flags | O_NONBLOCK);
987 flags = fcntl(dst->led.fds[i], F_GETFD);
988 if (-1 != flags)
989 fcntl(dst->led.fds[i], F_SETFD, flags | FD_CLOEXEC);
990 }
991
992 char ledname[16];
993 snprintf(ledname, 16, "%d_led", dst->devnum);
994 dst->led.ctrlid = arcan_led_register(dst->led.fds[1], dst->devnum, ledname,
995 (struct led_capabilities){ .nleds = LED_MAX,
996 .variable_brightness = false, .rgb = false }
997 );
998 if (-1 == dst->led.ctrlid){
999 close(dst->led.fds[0]);
1000 close(dst->led.fds[1]);
1001 dst->led.fds[0] = dst->led.fds[1] = -1;
1002 return;
1003 }
1004 dst->led.gotled = true;
1005 /* reset */
1006 for (size_t i = 0; i < LED_MAX; i++){
1007 if (-1 == write(dst->handle, &(struct input_event){.type = EV_LED,
1008 .code = i, .value = 0}, sizeof(struct input_event)))
1009 arcan_warning("platform/evdev(), error sending reset to led device\n");
1010 }
1011 }
1012
alloc_node_slot(const char * path)1013 static int alloc_node_slot(const char* path)
1014 {
1015 /* pre-existing? close old node and replace with this one, happens
1016 * when we race and the device appears and reappears and we just need
1017 * to reference a new inode */
1018 int hole = -1;
1019
1020 for (size_t i = 0; i < iodev.sz_nodes; i++){
1021 if (-1 == hole && iodev.nodes[i].handle < 0){
1022 hole = i;
1023 continue;
1024 }
1025
1026 /* or collision with existing? we use file-path for this. index
1027 * stays the same and got_device will still register so don't have
1028 * to consider leak for ledset */
1029 if (iodev.nodes[i].path && strcmp(iodev.nodes[i].path, path) == 0){
1030 close(iodev.nodes[i].handle);
1031 iodev.n_devs--;
1032 return i;
1033 }
1034 }
1035
1036 /* no empty slot, grow pollsets and node tracking */
1037 if (hole == -1){
1038 size_t new_cnt = iodev.sz_nodes + 8;
1039 struct devnode* nn = realloc(
1040 iodev.nodes, sizeof(struct devnode) * new_cnt);
1041 if (!nn)
1042 return -1;
1043 iodev.nodes = nn;
1044 memset(nn + iodev.sz_nodes, '\0', sizeof(struct devnode) * 8);
1045 for (size_t i = iodev.sz_nodes; i < new_cnt; i++){
1046 iodev.nodes[i].handle = BADFD;
1047 iodev.nodes[i].led.fds[0] = iodev.nodes[i].led.fds[1] = BADFD;
1048 }
1049
1050 /* pollset size is actually twice the number of nodes to allow a
1051 * 'mirror address' for a possible led- or other special device ref.
1052 * (say sound...) */
1053 struct pollfd* newset = malloc(2 * sizeof(struct pollfd) * new_cnt);
1054 if (!newset)
1055 return -1;
1056
1057 free(iodev.pollset);
1058 for (size_t i = 0; i < new_cnt; i++){
1059 memset(&newset[i], '\0', sizeof(struct pollfd));
1060 memset(&newset[i+new_cnt], '\0', sizeof(struct pollfd));
1061 newset[i].events = POLLIN | POLLERR | POLLHUP;
1062 newset[i].fd = iodev.nodes[i].handle;
1063 newset[i+new_cnt].events = POLLIN;
1064 newset[i+new_cnt].fd = iodev.nodes[i].led.fds[0];
1065 }
1066
1067 /* update pointers, set hole to the first new entry */
1068 iodev.pollset = newset;
1069 hole = iodev.sz_nodes;
1070 iodev.sz_nodes = new_cnt;
1071 }
1072
1073 return hole;
1074 }
1075
send_device_added(struct arcan_evctx * ctx,struct devnode * node)1076 static void send_device_added(struct arcan_evctx* ctx, struct devnode* node)
1077 {
1078 struct arcan_event addev = {
1079 .category = EVENT_IO,
1080 .io.kind = EVENT_IO_STATUS,
1081 .io.devkind = EVENT_IDEVKIND_STATUS,
1082 .io.devid = node->devnum,
1083 .io.input.status.devkind = node->type,
1084 .io.input.status.action = EVENT_IDEV_ADDED
1085 };
1086 snprintf((char*) &addev.io.label, sizeof(addev.io.label) /
1087 sizeof(addev.io.label[0]), "%s", node->label);
1088 arcan_event_enqueue(ctx, &addev);
1089 }
1090
platform_event_translation(int devid,int action,const char ** arg,const char ** err)1091 bool platform_event_translation(
1092 int devid, int action, const char** arg, const char** err)
1093 {
1094 struct devnode* node = NULL;
1095
1096 /* find the n'th device on a negative id */
1097 if (devid < 0){
1098 devid *= -1;
1099
1100 for (size_t i = 0; i < iodev.sz_nodes; i++){
1101 if (iodev.nodes[i].type == DEVNODE_KEYBOARD){
1102 devid--;
1103 if (!devid){
1104 node = &iodev.nodes[i];
1105 break;
1106 }
1107 }
1108 }
1109 }
1110 else
1111 node = lookup_devnode(devid);
1112
1113 if (!node || node->type != DEVNODE_KEYBOARD){
1114 *err = "No such device";
1115 return false;
1116 }
1117
1118 #ifdef HAVE_XKBCOMMON
1119 char* rules = NULL;
1120 char* model = NULL;
1121 char* variant = NULL;
1122 char* options = NULL;
1123 char* layout = NULL;
1124
1125 struct xkb_rule_names names = {0};
1126
1127 if (!xkb_context){
1128 *err = "Missing XKB context";
1129 return false;
1130 }
1131
1132 /* Config takes priority - Then explicitly fill with environment,
1133 *
1134 * An omitted path here is to incrementally index keyboards and allow multiple
1135 * slots so different keyboards can get different layouts from the start. The
1136 * problem with this is the usual one of persistant IDs across instances as
1137 * anyone with a multiple keyboard setup that calls for different layouts
1138 * already have very .. exotic tastes.
1139 */
1140 if (action == EVENT_TRANSLATION_CLEAR){
1141 uintptr_t tag;
1142 cfg_lookup_fun get_config = platform_config_lookup(&tag);
1143 get_config("event_xkb_rules", 0, &rules, tag);
1144 get_config("event_xkb_variant", 0, &variant, tag);
1145 get_config("event_xkb_model", 0, &model, tag);
1146 get_config("event_xkb_options", 0, &options, tag);
1147 get_config("event_xkb_layout", 0, &layout, tag);
1148
1149 names.rules = rules ? rules : getenv("XKB_DEFAULT_RULES");
1150 names.model = model ? model : getenv("XKB_DEFAULT_MODEL");
1151 names.variant = variant ? variant : getenv("XKB_DEFAULT_VARIANT");
1152 names.options = options ? options : getenv("XKB_DEFAULT_OPTIONS");
1153 names.layout = layout ? options : getenv("XKB_DEFAULT_LAYOUT");
1154 }
1155 /* just fill struct from arg */
1156 else if (action == EVENT_TRANSLATION_SET){
1157 names.layout = arg[0];
1158 if (names.layout)
1159 names.model = arg[1];
1160 if (names.model)
1161 names.variant = arg[2];
1162 if (names.variant)
1163 names.options = arg[3];
1164 }
1165 else {
1166 *err = "Unsupported action";
1167 return false;
1168 }
1169
1170 if (node->keyboard.xkb_layout){
1171 if (node->keyboard.xkb_state)
1172 xkb_state_unref(node->keyboard.xkb_state);
1173 xkb_keymap_unref(node->keyboard.xkb_layout);
1174 node->keyboard.xkb_state = NULL;
1175 node->keyboard.xkb_layout = NULL;
1176 }
1177
1178 /* Disable xkb translation entirely */
1179 if (!names.rules && !names.model &&
1180 !names.variant && !names.options && !names.layout)
1181 return false;
1182
1183 node->keyboard.xkb_layout =
1184 xkb_keymap_new_from_names(xkb_context, &names, XKB_KEYMAP_COMPILE_NO_FLAGS);
1185
1186 if (node->keyboard.xkb_layout)
1187 node->keyboard.xkb_state = xkb_state_new(node->keyboard.xkb_layout);
1188
1189 free(rules);
1190 free(model);
1191 free(variant);
1192 free(options);
1193
1194 return true;
1195 #endif
1196
1197 *err = "Engine built without libxkbcommon support";
1198 return false;
1199 }
1200
platform_event_device_request(int space,const char * path)1201 int platform_event_device_request(int space, const char* path)
1202 {
1203 return -EINVAL;
1204 }
1205
got_device(struct arcan_evctx * ctx,int fd,const char * path)1206 static void got_device(struct arcan_evctx* ctx, int fd, const char* path)
1207 {
1208 struct devnode node = {
1209 .handle = fd,
1210 .led.fds = {BADFD, BADFD}
1211 };
1212
1213 struct stat fdstat;
1214 if (-1 == fstat(fd, &fdstat)){
1215 verbose_print(
1216 "input: couldn't stat node to identify (%s)", strerror(errno));
1217 return;
1218 }
1219
1220 if ((fdstat.st_mode & (S_IFCHR | S_IFBLK)) == 0){
1221 verbose_print(
1222 "input: ignoring %s, not a character or block device", path);
1223 return;
1224 }
1225
1226 if (!identify(fd, path, node.label, sizeof(node.label), &node.devnum)){
1227 verbose_print(
1228 "input: identify failed on %s, ignoring unknown.", path);
1229 close(fd);
1230 return;
1231 }
1232
1233 if (iodev.n_devs >= MAX_DEVICES){
1234 arcan_warning("input: device limit reached, ignoring %s.", path);
1235 close(fd);
1236 }
1237
1238 /* figure out what kind of a device this is from the exposed capabilities,
1239 * heuristic nonsense rather than an interface exposing what the driver should
1240 * know or decide, fantastic.
1241 *
1242 * keyboards typically have longer key masks (and we can check for a few common
1243 * ones) no REL/ABS (don't know if those built-in trackball ones expose as two
1244 * devices or not these days), but also a ton of .. keys
1245 */
1246 struct evhandler eh = lookup_dev_handler(node.label);
1247
1248 /* [eh] may contain overrides, but we still need to probe the driver state for
1249 * axes etc. and allocate accordingly */
1250 node.type = DEVNODE_GAME;
1251
1252 bool mouse_ax = false;
1253 bool mouse_btn = false;
1254 bool joystick_btn = false;
1255 int add_led = -1;
1256
1257 size_t bpl = sizeof(long) * 8;
1258 size_t nbits = ((EV_MAX)-1) / bpl + 1;
1259 long prop[ nbits ];
1260
1261 if (-1 == ioctl(fd, EVIOCGBIT(0, EV_MAX), &prop)){
1262 verbose_print(
1263 "input: probing %s failed, %s", path, strerror(errno));
1264 close(fd);
1265 return;
1266 }
1267
1268 for (size_t bit = 0; bit < EV_MAX; bit++)
1269 if ( 1ul & (prop[bit/bpl]) >> (bit & (bpl - 1)) )
1270 switch(bit){
1271 case EV_KEY:
1272 node.button_count = button_count(fd, bit, &mouse_btn, &joystick_btn);
1273 break;
1274
1275 case EV_REL:
1276 mouse_ax = check_mouse_axis(fd, bit);
1277 break;
1278
1279 case EV_ABS:
1280 map_axes(fd, bit, &node);
1281 break;
1282
1283 case EV_SW:
1284 break;
1285
1286 /* useless for the time being */
1287 case EV_MSC:
1288 break;
1289 case EV_SYN:
1290 break;
1291 case EV_LED:
1292 add_led = bit;
1293 break;
1294 case EV_SND:
1295 break;
1296 case EV_REP:
1297 break;
1298 case EV_PWR:
1299 break;
1300 case EV_FF:
1301 case EV_FF_STATUS:
1302 break;
1303 }
1304
1305 if (!eh.handler){
1306 if (mouse_ax && mouse_btn){
1307 node.type = DEVNODE_MOUSE;
1308 node.cursor.flt[0].mode = ARCAN_ANALOGFILTER_PASS;
1309 node.cursor.flt[1].mode = ARCAN_ANALOGFILTER_PASS;
1310
1311 if (!iodev.mouseid)
1312 iodev.mouseid = node.devnum;
1313 }
1314 /* not particularly pretty and rather arbitrary */
1315 else if (!mouse_btn && !joystick_btn && node.button_count > 84){
1316 node.type = DEVNODE_KEYBOARD;
1317 node.keyboard.state = 0;
1318
1319 /* FIX: query current LED states and set corresponding states in the devnode,
1320 * this does not save / restore the built-in repeats */
1321 unsigned rep[2] = {0, 0};
1322 ioctl(node.handle, EVIOCSREP, rep);
1323 }
1324
1325 node.hnd.handler = defhandlers[node.type];
1326 }
1327 else{
1328 node.hnd = eh;
1329 node.type = eh.type;
1330 }
1331
1332 /* finally added */
1333 int hole = alloc_node_slot(path);
1334 if (-1 == hole){
1335 verbose_print(
1336 "input: dropped %s due to errors during scan.", path);
1337 close(fd);
1338 return;
1339 }
1340
1341 iodev.n_devs++;
1342 node.path = strdup(path);
1343 iodev.pollset[hole].fd = fd;
1344 iodev.pollset[hole].events = POLLIN | POLLERR | POLLHUP;
1345 iodev.pollset[hole + iodev.sz_nodes].fd = BADFD;
1346 send_device_added(ctx, &node);
1347
1348 /* had to defer led device creation until now because we didn't
1349 * know if there's a slot for it or not, the pollset actually is
1350 * twice the expected size, one for the main device and one for
1351 * the possible led controller */
1352 if (add_led != -1){
1353 setup_led(&node, add_led, fd);
1354 if (node.led.gotled){
1355 iodev.pollset[hole+iodev.sz_nodes].fd = node.led.fds[0];
1356 }
1357 }
1358 iodev.nodes[hole] = node;
1359
1360 if (node.type == DEVNODE_KEYBOARD){
1361 const char* err;
1362 platform_event_translation(node.devnum, EVENT_TRANSLATION_CLEAR, NULL, &err);
1363 }
1364
1365 verbose_print("input: (%s:%s) added as type: %s",
1366 path, node.label, lookup_type(node.type));
1367
1368 return;
1369 }
1370
1371 #undef bit_isset
1372 #undef bit_ofs
1373 #undef bit_longn
1374 #undef bit_count
1375
platform_event_rescan_idev(struct arcan_evctx * ctx)1376 void platform_event_rescan_idev(struct arcan_evctx* ctx)
1377 {
1378 char ibuf [strlen(notify_scan_dir) + sizeof("/*")];
1379 glob_t res = {0};
1380 snprintf(ibuf, sizeof(ibuf), "%s/*", notify_scan_dir);
1381
1382 if (glob(ibuf, 0, NULL, &res) == 0){
1383 char** beg = res.gl_pathv;
1384
1385 while(*beg){
1386 int fd = platform_device_open(*beg, O_NONBLOCK | O_RDWR);
1387 if (-1 != fd)
1388 got_device(ctx, fd, *beg);
1389 beg++;
1390 }
1391
1392 globfree(&res);
1393 }
1394
1395 verbose_print("input: couldn't scan %s", notify_scan_dir);
1396 }
1397
update_state(int code,bool state,unsigned * statev)1398 static void update_state(int code, bool state, unsigned* statev)
1399 {
1400 int modifier = 0;
1401
1402 switch (klut[code]){
1403 case K_LSHIFT:
1404 modifier = ARKMOD_LSHIFT;
1405 break;
1406 case K_RSHIFT:
1407 modifier = ARKMOD_RSHIFT;
1408 break;
1409 case K_LALT:
1410 modifier = ARKMOD_LALT;
1411 break;
1412 case K_RALT:
1413 modifier = ARKMOD_RALT;
1414 break;
1415 case K_LCTRL:
1416 modifier = ARKMOD_LCTRL;
1417 break;
1418 case K_RCTRL:
1419 modifier = ARKMOD_RCTRL;
1420 break;
1421 case K_LMETA:
1422 modifier = ARKMOD_LMETA;
1423 break;
1424 case K_RMETA:
1425 modifier = ARKMOD_RMETA;
1426 break;
1427 case K_CAPSLOCK:
1428 modifier = ARKMOD_CAPS;
1429 break;
1430 case K_COMPOSE:
1431 modifier = ARKMOD_MODE;
1432 break;
1433 default:
1434 return;
1435 }
1436
1437 if (state)
1438 *statev |= modifier;
1439 else
1440 *statev &= ~modifier;
1441 }
1442
defhandler_kbd(struct arcan_evctx * out,struct devnode * node)1443 static void defhandler_kbd(
1444 struct arcan_evctx* out, struct devnode* node)
1445 {
1446 struct input_event inev[64];
1447 ssize_t evs = read(node->handle, &inev, sizeof(inev));
1448
1449 if (-1 == evs){
1450 if (errno != EINTR && errno != EAGAIN)
1451 disconnect(out, node);
1452 }
1453
1454 if (evs < 0 || evs < sizeof(struct input_event))
1455 return;
1456
1457 arcan_event newev = {
1458 .category = EVENT_IO,
1459 .io = {
1460 .kind = EVENT_IO_BUTTON,
1461 .devid = node->devnum,
1462 .datatype = EVENT_IDATATYPE_TRANSLATED,
1463 .devkind = EVENT_IDEVKIND_KEYBOARD,
1464 }
1465 };
1466
1467 for (size_t i = 0; i < evs / sizeof(struct input_event); i++){
1468 switch(inev[i].type){
1469 case EV_KEY:
1470 newev.io.input.translated.scancode = inev[i].code;
1471 newev.io.input.translated.keysym = lookup_keycode(inev[i].code);
1472 newev.io.input.translated.modifiers = node->keyboard.state;
1473 update_state(inev[i].code, inev[i].value != 0, &node->keyboard.state);
1474 /* possible checkpoint for adding other keyboard layout support here */
1475 newev.io.subid = inev[i].code;
1476
1477 /* default 'fallback' translation */
1478 uint16_t code = lookup_character(inev[i].code, node->keyboard.state, true);
1479 if (code)
1480 to_utf8(code, newev.io.input.translated.utf8);
1481
1482 /* virtual terminal switching for press on LCTRL+LALT+Fn. should possibly have
1483 * more advanced config here to limit # of eligible devices and change
1484 * combination, and option to disable the thing entirely because it is
1485 * just terrible */
1486 if ((node->keyboard.state == (ARKMOD_LALT | ARKMOD_LCTRL)) &&
1487 inev[i].code >= KEY_F1 && inev[i].code <= KEY_F10 && inev[i].value != 0){
1488 platform_device_release("TTY", inev[i].code - KEY_F1 + 1);
1489 }
1490
1491 /* Feed layout statemachine, try to get a translation out of it. Since we
1492 * don't have support for xkeyboard symbols, we either make due with the normal
1493 * kernel keycode to SDL keysym or go with the keyboard layout and try to
1494 * translate that into SDL. */
1495 #ifdef HAVE_XKBCOMMON
1496 if (node->keyboard.xkb_state){
1497 memset(newev.io.input.translated.utf8, '\0', 5);
1498 if (inev[i].value == 0){
1499 xkb_state_update_key(
1500 node->keyboard.xkb_state, inev[i].code + 8, XKB_KEY_UP);
1501 }
1502 else if (inev[i].value == 1 || (inev[i].value == 2 && xkb_keymap_key_repeats(
1503 node->keyboard.xkb_layout, inev[i].code+8))){
1504 xkb_state_key_get_utf8(node->keyboard.xkb_state,
1505 inev[i].code + 8, (char*) newev.io.input.translated.utf8, 5);
1506 xkb_state_update_key(
1507 node->keyboard.xkb_state, inev[i].code + 8, XKB_KEY_DOWN);
1508 }
1509 }
1510 #endif
1511
1512 /* auto-repeat, may get even if we are not in this state because of broken
1513 * drivers or failed mode-setting. */
1514 if (inev[i].value == 2){
1515 if (iodev.period){
1516 newev.io.input.translated.modifiers |= ARKMOD_REPEAT;
1517 newev.io.input.translated.active = false;
1518 arcan_event_enqueue(out, &newev);
1519 newev.io.input.translated.active = true;
1520 arcan_event_enqueue(out, &newev);
1521 }
1522 }
1523 else{
1524 newev.io.input.translated.active = inev[i].value != 0;
1525 arcan_event_enqueue(out, &newev);
1526 }
1527
1528 break;
1529
1530 default:
1531 break;
1532 }
1533
1534 }
1535 }
1536
flush_pending(struct arcan_evctx * ctx,struct devnode * node)1537 static void flush_pending(
1538 struct arcan_evctx* ctx, struct devnode* node)
1539 {
1540 arcan_event newev = {
1541 .category = EVENT_IO,
1542 .io = {
1543 .label = "touch",
1544 .devid = node->devnum,
1545 .subid = node->touch.ind + 128,
1546 .kind = EVENT_IO_TOUCH,
1547 .devkind = EVENT_IDEVKIND_TOUCHDISP,
1548 .datatype = EVENT_IDATATYPE_TOUCH
1549 }
1550 };
1551
1552 verbose_print("kind=touch:device=%d:base=%d", node->devnum, node->touch.ind);
1553
1554 newev.io.input.touch.active = node->touch.active;
1555 newev.io.input.touch.x = node->touch.x;
1556 newev.io.input.touch.y = node->touch.y;
1557 newev.io.input.touch.pressure = node->touch.pressure;
1558 newev.io.input.touch.size = node->touch.size;
1559
1560 arcan_event_enqueue(ctx, &newev);
1561 node->touch.pending = false;
1562 node->touch.active = true;
1563 }
1564
decode_mt(struct arcan_evctx * ctx,struct devnode * node,int code,int val)1565 static void decode_mt(struct arcan_evctx* ctx,
1566 struct devnode* node, int code, int val)
1567 {
1568 /* there are multiple protocols and mappings for this that we don't
1569 * account for here, move it to a toch event with the basic information
1570 * and let higher layers deal with it */
1571 int newind = -1;
1572
1573 switch(code){
1574 case ABS_X:
1575 if (node->touch.ind != 0 && node->touch.pending)
1576 flush_pending(ctx, node);
1577
1578 node->touch.ind = 0;
1579 node->touch.x = val;
1580 node->touch.pending = true;
1581 break;
1582 case ABS_Y:
1583 if (node->touch.ind != 0 && node->touch.pending)
1584 flush_pending(ctx, node);
1585
1586 node->touch.ind = 0;
1587 node->touch.y = val;
1588 node->touch.pending = true;
1589 break;
1590 case ABS_MT_PRESSURE:
1591 node->touch.pressure = val;
1592 break;
1593 case ABS_MT_POSITION_X:
1594 node->touch.x = val;
1595 node->touch.pending = true;
1596 break;
1597 case ABS_MT_POSITION_Y:
1598 node->touch.y = val;
1599 node->touch.pending = true;
1600 break;
1601 case ABS_DISTANCE:
1602 node->touch.pressure = val;
1603 break;
1604 case ABS_MT_TRACKING_ID:
1605 if (-1 == val){
1606 node->touch.active = false;
1607 node->touch.pending = true;
1608 flush_pending(ctx, node);
1609 }
1610 else
1611 ; /* we don't distingush between IDs, only SLOTs */
1612 break;
1613 case ABS_MT_SLOT:
1614 if (node->touch.pending && node->touch.ind != val)
1615 flush_pending(ctx, node);
1616 node->touch.ind = val;
1617 break;
1618 default:
1619 verbose_print("dev=%d:type=multitouch:code=%d"
1620 ":status=unknown", (int) node->devnum, code);
1621 break;
1622 }
1623 }
1624
decode_hat(struct arcan_evctx * ctx,struct devnode * node,int ind,int val)1625 static void decode_hat(struct arcan_evctx* ctx,
1626 struct devnode* node, int ind, int val)
1627 {
1628 arcan_event newev = {
1629 .category = EVENT_IO,
1630 .io = {
1631 .label = "gamepad",
1632 .kind = EVENT_IO_BUTTON,
1633 .devkind = EVENT_IDEVKIND_GAMEDEV,
1634 .datatype = EVENT_IDATATYPE_DIGITAL
1635 }
1636 };
1637
1638 ind *= 2;
1639 const int base = 64;
1640
1641 newev.io.devid = node->devnum;
1642
1643 /* clamp */
1644 if (val < 0)
1645 val = -1;
1646 else if (val > 0)
1647 val = 1;
1648 else {
1649 /* which of the two possibilities was released? */
1650 newev.io.input.digital.active = false;
1651
1652 if (node->game.hats[ind] != 0){
1653 newev.io.subid = base + ind;
1654 node->game.hats[ind] = 0;
1655 arcan_event_enqueue(ctx, &newev);
1656 }
1657
1658 if (node->game.hats[ind+1] != 0){
1659 newev.io.subid = base + ind + 1;
1660 node->game.hats[ind+1] = 0;
1661 arcan_event_enqueue(ctx, &newev);
1662 }
1663
1664 return;
1665 }
1666
1667 if (val > 0)
1668 ind++;
1669
1670 node->game.hats[ind] = val;
1671 newev.io.input.digital.active = true;
1672 newev.io.subid = base + ind;
1673 arcan_event_enqueue(ctx, &newev);
1674 }
1675
defhandler_game(struct arcan_evctx * ctx,struct devnode * node)1676 static void defhandler_game(struct arcan_evctx* ctx, struct devnode* node)
1677 {
1678 struct input_event inev[64];
1679 ssize_t evs = read(node->handle, &inev, sizeof(inev));
1680
1681 if (-1 == evs){
1682 if (errno != EINTR && errno != EAGAIN)
1683 disconnect(ctx, node);
1684 }
1685
1686 if (evs < 0 || evs < sizeof(struct input_event))
1687 return;
1688
1689 arcan_event newev = {
1690 .category = EVENT_IO,
1691 .io = {
1692 .label = "gamepad",
1693 .devkind = EVENT_IDEVKIND_GAMEDEV
1694 }
1695 };
1696
1697 short samplev;
1698
1699 for (size_t i = 0; i < evs / sizeof(struct input_event); i++){
1700 switch(inev[i].type){
1701 case EV_KEY:
1702 if (inev[i].code >= BTN_TOUCH)
1703 inev[i].code -= BTN_TOUCH;
1704 else if (inev[i].code >= BTN_JOYSTICK)
1705 inev[i].code -= BTN_JOYSTICK;
1706 else if (inev[i].code >= BTN_MOUSE)
1707 inev[i].code -= BTN_MOUSE - 1;
1708 if (node->hnd.button_mask && inev[i].code <= 64 &&
1709 ( (node->hnd.button_mask >> inev[i].code) & 1) )
1710 continue;
1711
1712 newev.io.kind = EVENT_IO_BUTTON;
1713 newev.io.datatype = EVENT_IDATATYPE_DIGITAL;
1714 newev.io.input.digital.active = inev[i].value;
1715 newev.io.subid = inev[i].code;
1716 newev.io.devid = node->devnum;
1717 arcan_event_enqueue(ctx, &newev);
1718 break;
1719
1720 case EV_SW:
1721 newev.io.kind = EVENT_IO_BUTTON;
1722 newev.io.datatype = EVENT_IDATATYPE_DIGITAL;
1723 newev.io.input.digital.active = inev[i].value;
1724 newev.io.subid = inev[i].code;
1725 newev.io.devid = node->devnum;
1726 arcan_event_enqueue(ctx, &newev);
1727 break;
1728
1729 case EV_REL:
1730 case EV_ABS:
1731 /* is the axis currently masked? */
1732 if (node->hnd.axis_mask && inev[i].code <= 64 &&
1733 ( (node->hnd.axis_mask >> inev[i].code) & 1) ){
1734 continue;
1735 }
1736 verbose_print("rel? %d - %d\n", inev[i].type, inev[i].code);
1737
1738 if (inev[i].code >= ABS_HAT0X && inev[i].code <= ABS_HAT3Y){
1739 decode_hat(ctx, node, inev[i].code - ABS_HAT0X, inev[i].value);
1740 }
1741 else if (inev[i].code < node->game.axes &&
1742 process_axis(ctx,
1743 &node->game.adata[inev[i].code], inev[i].value, &samplev)){
1744 newev.io.kind = EVENT_IO_AXIS_MOVE;
1745 newev.io.datatype = EVENT_IDATATYPE_ANALOG;
1746 newev.io.input.analog.gotrel = inev[i].type == EV_REL;
1747 newev.io.subid = inev[i].code;
1748 newev.io.devid = node->devnum;
1749 newev.io.input.analog.axisval[0] = samplev;
1750 newev.io.input.analog.nvalues = 2;
1751 arcan_event_enqueue(ctx, &newev);
1752 }
1753 else if ((inev[i].code >= ABS_X && inev[i].code <= ABS_Y) ||
1754 (inev[i].code >= ABS_MT_SLOT && inev[i].code <= ABS_MT_TOOL_Y)){
1755 decode_mt(ctx, node, inev[i].code, inev[i].value);
1756 }
1757 /* though we do reserve axis slots for the relative bits, there is no actual
1758 * filter set to them other than the the mask used above */
1759 else if (
1760 inev[i].code == REL_X ||
1761 inev[i].code == REL_Y ||
1762 inev[i].code == REL_DIAL ||
1763 inev[i].code == REL_Z ||
1764 inev[i].code == REL_RZ ||
1765 inev[i].code == REL_RX ||
1766 inev[i].code == REL_RY)
1767 {
1768 newev.io.kind = EVENT_IO_AXIS_MOVE;
1769 newev.io.datatype = EVENT_IDATATYPE_ANALOG;
1770 newev.io.input.analog.gotrel = true;
1771 newev.io.subid = inev[i].code;
1772 newev.io.devid = node->devnum;
1773 newev.io.input.analog.axisval[0] = inev[i].value;
1774 newev.io.input.analog.nvalues = 1;
1775 arcan_event_enqueue(ctx, &newev);
1776 }
1777 else {
1778 verbose_print("kind=game:device=%d:rel:code=%d:status=unknown", node->devnum, inev[i].code);
1779 }
1780 break;
1781
1782 case EV_SYN:
1783 case EV_REP:
1784 if (node->touch.pending)
1785 flush_pending(ctx, node);
1786 break;
1787
1788 default:
1789 verbose_print("kind=game:device=%d:type=%d:status=unknown", node->devnum, inev[i].type);
1790 break;
1791 }
1792 }
1793
1794 }
1795
code_to_mouse(int code)1796 static inline short code_to_mouse(int code)
1797 {
1798 return (code < BTN_MOUSE || code >= BTN_JOYSTICK) ?
1799 -1 : (code - BTN_MOUSE + 1);
1800 }
1801
defhandler_mouse(struct arcan_evctx * ctx,struct devnode * node)1802 static void defhandler_mouse(struct arcan_evctx* ctx,
1803 struct devnode* node)
1804 {
1805 struct input_event inev[64];
1806
1807 ssize_t evs = read(node->handle, &inev, sizeof(inev));
1808
1809 if (-1 == evs){
1810 if (errno != EINTR && errno != EAGAIN)
1811 disconnect(ctx, node);
1812 }
1813
1814 if (evs < 0 || evs < sizeof(struct input_event))
1815 return;
1816
1817 arcan_event newev = {
1818 .category = EVENT_IO,
1819 .io = {
1820 .label = "mouse",
1821 .devkind = EVENT_IDEVKIND_MOUSE,
1822 }
1823 };
1824
1825 short samplev;
1826 newev.io.devid = node->devnum;
1827
1828 for (size_t i = 0; i < evs / sizeof(struct input_event); i++){
1829 int vofs = 0;
1830
1831 switch(inev[i].type){
1832 case EV_KEY:
1833 samplev = code_to_mouse(inev[i].code);
1834 if (samplev < 0)
1835 continue;
1836
1837 newev.io.kind = EVENT_IO_BUTTON;
1838 newev.io.datatype = EVENT_IDATATYPE_DIGITAL;
1839 newev.io.input.digital.active = inev[i].value;
1840 newev.io.subid = samplev;
1841
1842 arcan_event_enqueue(ctx, &newev);
1843 break;
1844 case EV_REL:
1845 switch (inev[i].code){
1846 case REL_HWHEEL:
1847 vofs += 2;
1848 case REL_WHEEL:
1849 newev.io.kind = EVENT_IO_BUTTON;
1850 newev.io.datatype = EVENT_IDATATYPE_DIGITAL;
1851 newev.io.input.digital.active = 1;
1852 newev.io.subid = vofs + (inev[i].value > 0 ? 256 : 257);
1853 arcan_event_enqueue(ctx, &newev);
1854 newev.io.input.digital.active = 0;
1855 arcan_event_enqueue(ctx, &newev);
1856 break;
1857
1858 case REL_X:
1859 if (process_axis(ctx, &node->cursor.flt[0], inev[i].value, &samplev)){
1860 samplev = inev[i].value;
1861
1862 node->cursor.mx = ((int)node->cursor.mx + samplev < 0) ?
1863 0 : node->cursor.mx + samplev;
1864
1865 newev.io.kind = EVENT_IO_AXIS_MOVE;
1866 newev.io.datatype = EVENT_IDATATYPE_ANALOG;
1867 newev.io.input.analog.gotrel = true;
1868 newev.io.subid = 0;
1869 newev.io.input.analog.axisval[0] = samplev;
1870 newev.io.input.analog.axisval[1] = node->cursor.mx;
1871 newev.io.input.analog.nvalues = 2;
1872
1873 arcan_event_enqueue(ctx, &newev);
1874 }
1875 break;
1876 case REL_Y:
1877 if (process_axis(ctx, &node->cursor.flt[1], inev[i].value, &samplev)){
1878 node->cursor.my = ((int)node->cursor.my + samplev < 0) ?
1879 0 : node->cursor.my + samplev;
1880
1881 newev.io.kind = EVENT_IO_AXIS_MOVE;
1882 newev.io.datatype = EVENT_IDATATYPE_ANALOG;
1883 newev.io.input.analog.gotrel = true;
1884 newev.io.subid = 1;
1885 newev.io.input.analog.axisval[0] = samplev;
1886 newev.io.input.analog.axisval[1] = node->cursor.my;
1887 newev.io.input.analog.nvalues = 2;
1888
1889 arcan_event_enqueue(ctx, &newev);
1890 }
1891 break;
1892 default:
1893 break;
1894 }
1895 break;
1896 case EV_ABS:
1897 break;
1898 }
1899 }
1900 }
1901
defhandler_null(struct arcan_evctx * out,struct devnode * node)1902 static void defhandler_null(struct arcan_evctx* out,
1903 struct devnode* node)
1904 {
1905 char nbuf[256];
1906 ssize_t evs = read(node->handle, nbuf, sizeof(nbuf));
1907 if (-1 == evs){
1908 if (errno != EINTR && errno != EAGAIN)
1909 disconnect(out, node);
1910 }
1911 }
1912
platform_event_devlabel(int devid)1913 const char* platform_event_devlabel(int devid)
1914 {
1915 struct devnode* node = lookup_devnode(devid);
1916 if (!node)
1917 return NULL;
1918
1919 return node->label;
1920 }
1921
1922 /*
1923 * note, this do not currently save/restore individual options between
1924 * init/deinit sessions, which is needed for virtual terminal switching
1925 * and external_launch.
1926 */
platform_event_reset(struct arcan_evctx * ctx)1927 void platform_event_reset(struct arcan_evctx* ctx)
1928 {
1929
1930 }
1931
platform_event_deinit(struct arcan_evctx * ctx)1932 void platform_event_deinit(struct arcan_evctx* ctx)
1933 {
1934 platform_device_release("TTY", -1);
1935
1936 /* note, we purposely leak (let it disappear on close) to avoid the races and
1937 * interactions that come from TTY switching -> deinit -> signal -> init */
1938
1939 if (gstate.notify != -1){
1940 close(gstate.notify);
1941 gstate.notify = -1;
1942 }
1943
1944 /* note, for VT switching this means that the state of devices when it comes
1945 * to filtering etc. do not persist between external launches, should rework
1946 * this */
1947 for (size_t i = 0; i < iodev.n_devs; i++){
1948 if (iodev.nodes[i].handle > 0){
1949 verbose_print("closing %zu:%d", i, iodev.nodes[i].handle);
1950 close(iodev.nodes[i].handle);
1951 memset(&iodev.nodes[i], '\0', sizeof(struct devnode));
1952 iodev.nodes[i].handle = -1;
1953 }
1954 }
1955
1956 iodev.n_devs = 0;
1957 gstate.init = false;
1958 }
1959
platform_device_lock(int devind,bool state)1960 void platform_device_lock(int devind, bool state)
1961 {
1962 struct devnode* node = lookup_devnode(devind);
1963 if (!node || !node->handle)
1964 return;
1965
1966 ioctl(node->handle, EVIOCGRAB, state? 1 : 0);
1967
1968 /*
1969 * doesn't make sense outside some window systems, might be useful to propagate
1970 * further to device locking on systems that are less forgiving.
1971 */
1972 }
1973
platform_event_capabilities(const char ** out)1974 enum PLATFORM_EVENT_CAPABILITIES platform_event_capabilities(const char** out)
1975 {
1976 enum PLATFORM_EVENT_CAPABILITIES rv = 0;
1977 if (out)
1978 *out = "evdev";
1979
1980 for (size_t i = 0; i < iodev.n_devs; i++){
1981 if (iodev.nodes[i].handle)
1982 switch(iodev.nodes[i].type){
1983 /* don't have better granularity in this step at the moment */
1984 case DEVNODE_SENSOR:
1985 rv |= ACAP_POSITION | ACAP_ORIENTATION;
1986 break;
1987 case DEVNODE_MOUSE:
1988 rv |= ACAP_MOUSE;
1989 break;
1990 case DEVNODE_GAME:
1991 rv |= ACAP_GAMING;
1992 break;
1993 case DEVNODE_KEYBOARD:
1994 rv |= ACAP_TRANSLATED;
1995 break;
1996 case DEVNODE_TOUCH:
1997 rv |= ACAP_TOUCH;
1998 break;
1999 default:
2000 break;
2001 }
2002 }
2003
2004 return rv;
2005 }
2006
platform_event_envopts()2007 const char** platform_event_envopts()
2008 {
2009 return (const char**) envopts;
2010 }
2011
2012 /*
2013 * most of this is done priv-side, it is just the actual tty device to use and
2014 * control that is of importance as the privilege side keeps track of the first
2015 * TTY marked device that was opened as use that for the special 'TTY' name
2016 * later on release requests.
2017 */
find_tty()2018 static void find_tty()
2019 {
2020 /* first, check if the env. defines a specific TTY device to use and try that */
2021 const char* newtty = NULL;
2022 int tty = -1;
2023 bool scantty = true;
2024
2025 uintptr_t tag;
2026 cfg_lookup_fun get_config = platform_config_lookup(&tag);
2027 char* ttydev;
2028 if (get_config("event_tty_override", 0, &ttydev, tag) && ttydev){
2029 int fd = platform_device_open(ttydev, O_RDWR);
2030 scantty = false;
2031 if (-1 == fd)
2032 arcan_warning("couldn't open TTYOVERRIDE %s, reason: %s\n",
2033 newtty, strerror(errno));
2034 else
2035 tty = fd;
2036 free(ttydev);
2037 }
2038
2039 /* Failing that, try and find what tty we might be on -- some might redirect
2040 * stdin to something else and then it is not a valid tty to work on. Which,
2041 * of course, brings us back to the special kid in the class, sysfs. */
2042 if (!isatty(tty) && scantty){
2043 FILE* fpek = fopen("/sys/class/tty/tty0/active", "r");
2044 if (fpek){
2045 char line[32] = "/dev/";
2046 if (fgets(line+5, 32-5, fpek)){
2047 char* endl = strrchr(line, '\n');
2048 if (endl)
2049 *endl = '\0';
2050 tty = platform_device_open(line, O_RDWR);
2051 }
2052 fclose(fpek);
2053 }
2054 }
2055 }
2056
platform_event_preinit()2057 void platform_event_preinit()
2058 {
2059 }
2060
platform_event_init(arcan_evctx * ctx)2061 void platform_event_init(arcan_evctx* ctx)
2062 {
2063 uintptr_t tag;
2064
2065 cfg_lookup_fun get_config = platform_config_lookup(&tag);
2066
2067 #ifdef __LINUX
2068 gstate.notify = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
2069 #endif
2070
2071 init_keyblut();
2072 #ifdef HAVE_XKBCOMMON
2073 xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
2074 #endif
2075
2076 if (!notify_scan_dir)
2077 notify_scan_dir = strdup(NOTIFY_SCAN_DIR);
2078
2079 find_tty();
2080
2081 char* newsd;
2082 if (get_config("event_scandir", 0, &newsd, tag) && newsd){
2083 free(notify_scan_dir);
2084 notify_scan_dir = newsd;
2085 }
2086
2087 /* chances are the CREATE events are actually racey, but with the
2088 * _device_open refactor this won't really matter as the suid part
2089 * allows us access anyway */
2090 #ifdef __LINUX
2091 if (-1 == gstate.notify || inotify_add_watch(
2092 gstate.notify, notify_scan_dir, IN_CREATE) == -1){
2093 arcan_warning("inotify initialization failure (%s),"
2094 " device discovery disabled.", strerror(errno));
2095
2096 if (-1 != gstate.notify){
2097 close(gstate.notify);
2098 gstate.notify = -1;
2099 }
2100 }
2101 #elif __FreeBSD__
2102 /* there is a way to get devd to cooperate */
2103 #else
2104 #endif
2105
2106 platform_event_rescan_idev(ctx);
2107 }
2108