1 /*
2 * Copyright 2016-2018, Björn Ståhl
3 * License: 3-Clause BSD, see COPYING file in arcan source repository.
4 * Reference: https://arcan-fe.com
5 * Description: Quick and dirty FreeBSD specific event input layer. It seems
6 * like they will be moving, at least partially, to an evdev implementation so
7 * this is kept as minimal effort.
8 */
9 #include <stdlib.h>
10 #include <limits.h>
11 #include <stdint.h>
12 #include <stdbool.h>
13 #include <assert.h>
14 #include <unistd.h>
15 #include <fcntl.h>
16 #include <termios.h>
17 #include <poll.h>
18
19 #include <sys/consio.h>
20 #include <sys/mouse.h>
21 #include <sys/kbio.h>
22 #include <sys/select.h>
23 #include <sys/time.h>
24 #include <sys/types.h>
25
26 #include <termios.h>
27 #include <ctype.h>
28 #include <signal.h>
29 #include <errno.h>
30
31 #include "arcan_shmif.h"
32 #include "arcan_math.h"
33 #include "arcan_general.h"
34 #include "arcan_event.h"
35
36 enum devtype {
37 /* use the TTY from /dev/console, user-specific device-node on rescan
38 * like /dev/kbd*) or the kbdmux abstraction. We run this in K_CODE mode
39 * and load the keymaps ourselves since there seem to be no mechanism for
40 * getting both from the same device at the same time.
41 * Expected to emit:
42 * datatype: EVENT_IDATATYPE_TRANSLATED,
43 * kind: EVENT_IDEVKIND_KEYBOPARD,
44 * with the input.translated.active set on press/release
45 * devid set to some unique index per device
46 * scancode/subid to scancode
47 * keysym to an SDL1.2 compatible SYM (if available)
48 * and utf8 to a textual representation (if available)
49 */
50 keyboard = 0,
51
52 /*
53 * expected to emit:
54 * label : MOUSE,
55 * kind : EVENT_IO_AXIS_MOVE, EVENT_IO_BUTTON,
56 * datatype : EVENT_IDATATYPE_ANALOG, EVENT_IDATATYPE_DIGITAL
57 * with the reserved devid(-1) for mouse, subid for axis or button index.
58 * Analog values should ideally respect lower_bound, upper_bound, deadzone,
59 * kernel_size and mode (see sdl platform) and allow rebase ("warp") absolute
60 * sample values.
61 */
62 mouse = 1,
63 gamedev = 2,
64 touchdev = 3,
65 toggle = 4
66 };
67
68 struct bsdkey {
69 uint8_t u8[5];
70 uint16_t sym;
71 uint16_t modmask;
72 };
73
74 struct devnode {
75 enum devtype type;
76 int fd;
77 const char* nodepath;
78
79 union {
80 struct {
81 /* go from scancode to */
82 struct bsdkey lut[8][128];
83 uint16_t mods;
84 } keyb;
85 struct {
86 int base[2];
87 int buttons;
88 int mx, my;
89 mousemode_t mode;
90 mousehw_t hw;
91 } mouse;
92 };
93 };
94
95 static struct {
96 struct termios ttystate;
97 struct devnode keyb, mdev;
98 int tty;
99 int sigpipe[2];
100 } evctx = {
101 .tty = -1,
102 .sigpipe = {-1, -1}
103 };
104
105 static char* accents[] = {
106 "dgra", "dacu", "dcir", "dtil", "dmac", "dbre", "ddot", "duml",
107 "ddia", "dsla", "drin", "dced", "dapo", "ddac", "dogo", "dcar",
108 NULL
109 };
110
111 static const int vt_trm = 'z';
sigusr_term(int sign,siginfo_t * info,void * ctx)112 static void sigusr_term(int sign, siginfo_t* info, void* ctx)
113 {
114 int s_errn = errno;
115 if (write(evctx.sigpipe[1], &vt_trm, 1))
116 ;
117 errno = s_errn;
118 }
119
next_tok(char * str,char ** tok,size_t * cofs,size_t * out)120 static bool next_tok(char* str, char** tok, size_t* cofs, size_t* out)
121 {
122 /* scan for beginning */
123 while(str[*cofs] && isspace(str[*cofs]))
124 (*cofs)++;
125
126 if (!str[*cofs] || str[*cofs] == '#')
127 return false;
128 *tok = &str[*cofs];
129
130 /* scan for end */
131 if (str[*cofs] == '\''){
132 (*cofs)++;
133 while (str[*cofs] && str[*cofs] != '\'')
134 (*cofs)++;
135 (*cofs)++;
136 }
137 else {
138 while (str[*cofs] && !isspace(str[*cofs]))
139 (*cofs)++;
140 }
141
142 *out = (uintptr_t)&str[*cofs] - (uintptr_t)*tok;
143 return true;
144 }
145
146 struct bsdk_ent {
147 uint8_t key;
148 uint16_t sym;
149 uint16_t mask;
150 char tok[8];
151 };
152
153 static struct bsdk_ent bsdk_lut[] = {
154 {.tok = "nop"},
155 {.key = 0, .tok = "nul"}, {.key = 1, .tok = "soh"}, {.key = 2, .tok = "stx"},
156 {.key = 3, .tok = "etx"}, {.key = 4, .tok = "eot"}, {.key = 5, .tok = "enq"},
157 {.key = 6, .tok = "ack"}, {.key = 7, .tok = "bel"}, {.key = 8, .tok = "bs", .sym = 8},
158 {.key = 9, .tok = "ht", .sym = 9}, {.key = 10, .tok = "lf"}, {.key = 11, .tok = "vt"},
159 {.key = 12, .tok = "ff"}, {.key = 13, .tok = "cr"}, {.key = 14, .tok = "so"},
160 {.key = 15, .tok = "si"},
161 {.key = 16, .tok = "dle"}, {.key = 17, .tok = "dc1"},
162 {.key = 18, .tok = "dc2"}, {.key = 19, .tok = "dc3"}, {.key = 20, .tok = "dc4"},
163 {.key = 21, .tok = "nak"}, {.key = 22, .tok = "syn"}, {.key = 23, .tok = "etb"},
164 {.key = 24, .tok = "can"}, {.key = 25, .tok = "em"}, {.key = 26, .tok = "sub"},
165 {.key = 27, .tok = "esc"}, {.key = 28, .tok = "fs"}, {.key = 29, .tok = "gs"},
166 {.key = 30, .tok = "rs"}, {.key = 31, .tok = "us"},
167 {.tok = "lshift", .mask = ARKMOD_LSHIFT, .sym = 304},
168 {.tok = "rshift", .mask = ARKMOD_RSHIFT, .sym = 303},
169 {.tok = "lctrl", .mask = ARKMOD_LCTRL, .sym = 306},
170 {.tok = "rctrl", .mask = ARKMOD_RCTRL, .sym = 305},
171 {.tok = "lalt", .mask = ARKMOD_LALT, .sym = 308},
172 {.tok = "ralt", .mask = ARKMOD_RALT, .sym = 307},
173 {.tok = "clock", .mask = ARKMOD_CAPS, .sym = 301},
174 {.tok = "nlock", .mask = ARKMOD_NUM, .sym = 300},
175 {.tok = "meta", .mask = ARKMOD_LMETA, .sym = 309},
176 {.tok = "fkey64", .mask = ARKMOD_RMETA, .sym = 319},
177 {.tok = "slock", .sym = 302}, {.tok = "fkey01", .sym = 282},
178 {.tok = "fkey02", .sym = 283}, {.tok = "fkey03", .sym = 284},
179 {.tok = "fkey04", .sym = 285}, {.tok = "fkey05", .sym = 286},
180 {.tok = "fkey06", .sym = 287}, {.tok = "fkey07", .sym = 288},
181 {.tok = "fkey08", .sym = 289}, {.tok = "fkey09", .sym = 290},
182 {.tok = "fkey10", .sym = 291}, {.tok = "fkey11", .sym = 292},
183 {.tok = "fkey12", .sym = 293}, {.tok = "fkey49", .sym = 278},
184 {.tok = "fkey50", .sym = 273}, {.tok = "fkey51", .sym = 280},
185 {.tok = "fkey52", .sym = 269}, {.tok = "fkey53", .sym = 276},
186 {.tok = "fkey54", .sym = 261}, {.tok = "fkey55", .sym = 275},
187 {.tok = "fkey56", .sym = 270}, {.tok = "fkey57", .sym = 279},
188 {.tok = "fkey58", .sym = 274}, {.tok = "fkey59", .sym = 281},
189 {.tok = "fkey60", .sym = 277}, {.tok = "fkey61", .sym = 127},
190 {.tok = "fkey62", .sym = 311}, {.tok = "fkey63", .sym = 312}
191 };
192
to_utf8(uint16_t utf16,uint8_t out[4])193 static char* to_utf8(uint16_t utf16, uint8_t out[4])
194 {
195 int count = 1, ofs = 0;
196 uint32_t mask = 0x800;
197
198 if (utf16 >= 0x80)
199 count++;
200
201 for(size_t i=0; i < 5; i++){
202 if ( (uint32_t) utf16 >= mask )
203 count++;
204
205 mask <<= 5;
206 }
207
208 if (count == 1){
209 out[0] = (char) utf16;
210 out[1] = 0x00;
211 }
212 else {
213 for (int i = (count-1 > 4 ? 4 : count - 1); i >= 0; i--){
214 unsigned char ch = ( utf16 >> (6 * i)) & 0x3f;
215 ch |= 0x80;
216 if (i == count-1)
217 ch |= 0xff << (8-count);
218 out[ofs++] = ch;
219 }
220 out[ofs++] = 0x00;
221 }
222
223 return (char*) out;
224 }
225
decode_tok(char * tok)226 static struct bsdkey decode_tok(char* tok)
227 {
228 struct bsdkey res = {.sym = 0};
229
230 if (tok[0] == '\''){
231 res.u8[0] = tok[1];
232 res.sym = tolower(res.u8[0]);
233 }
234 /* the manpage says unicode or unicode as hex, but nothing about the
235 * actual encoding format, and some maps really give iso-8859-1 output
236 * but for some in vt/keymaps seem to be UCS2 */
237 else if (isdigit(tok[0])){
238 int ucs2 = strtoul(tok, NULL, tok[1] == 'x' ? 16 : 10);
239 to_utf8(ucs2, res.u8);
240 }
241 else{
242 for (size_t i = 0; i < sizeof(bsdk_lut) / sizeof(bsdk_lut[0]); i++)
243 if (strcmp(tok, bsdk_lut[i].tok) == 0){
244 res.u8[0] = bsdk_lut[i].key;
245 res.modmask = bsdk_lut[i].mask;
246 res.sym = bsdk_lut[i].sym ? bsdk_lut[i].sym : res.u8[0];
247 break;
248 }
249 }
250
251 return res;
252 }
253
platform_event_translation(int devid,int action,const char ** names,const char ** err)254 bool platform_event_translation(
255 int devid, int action, const char** names, const char** err)
256 {
257 *err = "Unsupported";
258 return false;
259 }
260
platform_event_device_request(int space,const char * path)261 int platform_event_device_request(int space, const char* path)
262 {
263 return -1;
264 }
265
load_keymap(struct devnode * dst,const char * path)266 static bool load_keymap(struct devnode* dst, const char* path)
267 {
268 char line_in[128];
269 FILE* fpek = fopen(path, "r");
270 if (!fpek){
271 arcan_warning("couldn't open keymap (%s)\n", path);
272 return false;
273 }
274
275 size_t linec = 0;
276 while (!feof(fpek) && NULL != fgets(line_in, sizeof(line_in), fpek)){
277 char* tok = NULL;
278 size_t ofs = 0, nch;
279
280 /* we're expecting 10 tokens per well-formed line:
281 * code base shft cntrl cntrl/shft alt alt/shft alt/cntrl alt/cntrl/shft lock
282 * num chtok ... CH
283 * then there may be an empty row then the more complex format:
284 * grp ch/num ( chnum chnum ) that may also contain linefeeds
285 where the firstg
286 * is our keycode and the last is the lock-state modifier. The rest
287 * follow modifier patterns */
288 size_t tokofs = 0, code = 0;
289 while(next_tok(line_in, &tok, &ofs, &nch)){
290 char old = tok[nch];
291 tok[nch] = '\0';
292 ofs++;
293 if (tokofs){
294 if (tokofs <= 8){
295 dst->keyb.lut[tokofs-1][code] = decode_tok(tok);
296 }
297 /* ignore the permanent group switch */
298 else
299 break;
300 tokofs++;
301 }
302 else {
303 if (isdigit(tok[0])){
304 code = strtoul(tok, NULL, 10);
305 tokofs++;
306 /* scancodes should be 7-bit with MSB being hold/released */
307 if (code > 127)
308 break;
309 }
310 /* we are in accent, ignore for now */
311 else
312 break;
313 }
314 }
315
316 if (tok != NULL)
317 linec++;
318 }
319 return true;
320 }
321
platform_event_analogstate(int devid,int axisid,int * lower_bound,int * upper_bound,int * deadzone,int * kernel_size,enum ARCAN_ANALOGFILTER_KIND * mode)322 arcan_errc platform_event_analogstate(int devid, int axisid,
323 int* lower_bound, int* upper_bound, int* deadzone,
324 int* kernel_size, enum ARCAN_ANALOGFILTER_KIND* mode)
325 {
326 return ARCAN_ERRC_NO_SUCH_OBJECT;
327 }
328
platform_event_analogall(bool enable,bool mouse)329 void platform_event_analogall(bool enable, bool mouse)
330 {
331 }
332
platform_event_analogfilter(int devid,int axisid,int lower_bound,int upper_bound,int deadzone,int buffer_sz,enum ARCAN_ANALOGFILTER_KIND kind)333 void platform_event_analogfilter(int devid,
334 int axisid, int lower_bound, int upper_bound, int deadzone,
335 int buffer_sz, enum ARCAN_ANALOGFILTER_KIND kind)
336 {
337 }
338
mod_to_ind(uint16_t modmask)339 static int mod_to_ind(uint16_t modmask)
340 {
341 int ind = 0;
342
343 if (modmask & (ARKMOD_LSHIFT | ARKMOD_RSHIFT)){
344 ind += 1;
345 }
346
347 if (modmask & (ARKMOD_LCTRL | ARKMOD_RCTRL)){
348 ind += 2;
349 }
350
351 if (modmask & (ARKMOD_LALT | ARKMOD_RALT)){
352 ind += 4;
353 }
354
355 return ind;
356 }
357
do_touchp(arcan_evctx * ctx,struct devnode * node)358 static void do_touchp(arcan_evctx* ctx, struct devnode* node)
359 {
360 /* see man psm and the MOUSE_SYN_GETHWINFO etc. for synaptics */
361 }
362
check_btn(arcan_evctx * ctx,int oldstate,int newstate,int fl,int ind)363 static inline void check_btn(arcan_evctx* ctx,
364 int oldstate, int newstate, int fl, int ind)
365 {
366 if (!((oldstate & fl) ^ (newstate & fl)))
367 return;
368
369 arcan_event ev = {
370 .category = EVENT_IO,
371 .io = {
372 .kind = EVENT_IO_BUTTON,
373 .subid = MBTN_LEFT_IND + ind,
374 .datatype = EVENT_IDATATYPE_DIGITAL,
375 .devkind = EVENT_IDEVKIND_MOUSE,
376 .input = { .digital = { .active = (oldstate & fl) } }
377 }};
378 arcan_event_enqueue(ctx, &ev);
379 }
380
wheel_ev(arcan_evctx * ctx,int idofs,int val)381 static void wheel_ev(arcan_evctx* ctx, int idofs, int val)
382 {
383 arcan_event aev = {
384 .category = EVENT_IO,
385 .io = {
386 .kind = EVENT_IO_AXIS_MOVE,
387 .datatype = EVENT_IDATATYPE_ANALOG,
388 .devkind = EVENT_IDEVKIND_MOUSE,
389 .subid = 2 + idofs,
390 .input = {
391 .analog = {
392 .nvalues = 1,
393 .gotrel = true,
394 .axisval = {val}
395 }
396 },
397 },
398 };
399 arcan_event_enqueue(ctx, &aev);
400
401 arcan_event dev = {
402 .category = EVENT_IO,
403 .io = {
404 .kind = EVENT_IO_BUTTON,
405 /* sysmouse descriptions says add byte 6, 7 and treat as signed but
406 * from the mice I had to test with, down triggered 127 and up triggered 1 */
407 .subid = MBTN_WHEEL_UP_IND + (val > 0 &&
408 val <= 126 ? 1 : 0) + (idofs * 2),
409 .datatype = EVENT_IDATATYPE_DIGITAL,
410 .devkind = EVENT_IDEVKIND_MOUSE,
411 .input = {
412 .digital = {
413 .active = true
414 }
415 }
416 }
417 };
418 arcan_event_enqueue(ctx, &dev);
419 dev.io.input.digital.active = false;
420 arcan_event_enqueue(ctx, &dev);
421 }
422
do_mouse(arcan_evctx * ctx,struct devnode * node)423 static void do_mouse(arcan_evctx* ctx, struct devnode* node)
424 {
425 size_t pkt_sz = node->mouse.mode.packetsize;
426 uint8_t buf[pkt_sz];
427 arcan_event outev = {
428 .category = EVENT_IO,
429 .io = { .label = "mouse", .devkind = EVENT_IDEVKIND_MOUSE }
430 };
431
432 /* another option here would be to aggregate the motion events at least
433 * to lessen the impact of a pile-up casade from suspend or similar */
434 while (read(node->fd, buf, pkt_sz) == pkt_sz){
435 int buttons, dx, dy, wheel_h, wheel_v;
436 buttons = dx = dy = wheel_h = wheel_v = 0;
437
438 /* mouse.h seems to be the better source of documentation for deciphering */
439 if (pkt_sz >= 5){
440 buttons = (~buf[0] & 0x07);
441 dx = ((int8_t)buf[1] + (int8_t)buf[3]);
442 dy = -((int8_t)buf[2] + (int8_t)buf[4]);
443 }
444
445 /* append the values to the button mask (but shifted, so do the same with
446 * the constant value for it to work. The reason is so that we can do a
447 * simple cmp on each mouse sample to know if we need to recheck individual
448 * buttons */
449 if (pkt_sz >= 8){
450 wheel_v = (int8_t)buf[5]+(int8_t)buf[6];
451 buttons |= (buf[7] & MOUSE_SYS_EXTBUTTONS) << 3;
452 }
453 /*
454 * seen this protocol somewhere but havn't anything to test with that
455 * actually activates it, so keep as a note for now
456 if (pkt_sz >= 16){
457 dx = ((int16_t)((buf[ 8] << 9) | (buf[ 9] << 2)) >> 2);
458 dy = -((int16_t)((buf[10] << 9) | (buf[11] << 2)) >> 2);
459 wheel_v = -((int16_t)((buf[12] << 9) | (buf[13] << 2)) >> 2);
460 wheel_h = ((int16_t)((buf[14] << 9) | (buf[15] << 2)) >> 2);
461 }
462 */
463
464 /* our own input model has its problems too, absolute vs relative,
465 * separate events or grouped together, always %2 events or only on
466 * change, the interface is not particularly pretty */
467 if (dx || dy){
468 node->mouse.mx += dx;
469 outev.io.datatype = EVENT_IDATATYPE_ANALOG;
470 outev.io.kind = EVENT_IO_AXIS_MOVE;
471 outev.io.input.analog.gotrel = true;
472 outev.io.subid = 0;
473 outev.io.input.analog.axisval[0] = node->mouse.mx;
474 outev.io.input.analog.axisval[1] = dx;
475 outev.io.input.analog.nvalues = 2;
476 arcan_event_enqueue(ctx, &outev);
477
478 node->mouse.my += dy;
479 outev.io.datatype = EVENT_IDATATYPE_ANALOG;
480 outev.io.kind = EVENT_IO_AXIS_MOVE;
481 outev.io.input.analog.gotrel = true;
482 outev.io.subid = 1;
483 outev.io.input.analog.axisval[0] = node->mouse.my;
484 outev.io.input.analog.axisval[1] = dy;
485 outev.io.input.analog.nvalues = 2;
486 arcan_event_enqueue(ctx, &outev);
487 }
488
489 /* unfortunately we get a packed state table rather than changes-only,
490 * so we have to extract and check each one. sysmouse uses 1 to indicate
491 * released, we use that to indicate pressed */
492 buttons = ~buttons;
493
494 if (buttons != node->mouse.buttons){
495 check_btn(ctx, node->mouse.buttons, buttons, MOUSE_SYS_BUTTON1UP, 0);
496 check_btn(ctx, node->mouse.buttons, buttons, MOUSE_SYS_BUTTON2UP, 1);
497 check_btn(ctx, node->mouse.buttons, buttons, MOUSE_SYS_BUTTON3UP, 2);
498 /* 3,4 and 5,6 are wheel digitals */
499 check_btn(ctx, node->mouse.buttons, buttons, MOUSE_SYS_BUTTON4UP << 3, 7);
500 check_btn(ctx, node->mouse.buttons, buttons, MOUSE_SYS_BUTTON5UP << 3, 8);
501 check_btn(ctx, node->mouse.buttons, buttons, MOUSE_SYS_BUTTON6UP << 3, 9);
502 check_btn(ctx, node->mouse.buttons, buttons, MOUSE_SYS_BUTTON7UP << 3,10);
503 check_btn(ctx, node->mouse.buttons, buttons, MOUSE_SYS_BUTTON8UP << 3,11);
504 check_btn(ctx, node->mouse.buttons, buttons, MOUSE_SYS_BUTTON9UP << 3,12);
505 check_btn(ctx, node->mouse.buttons, buttons, MOUSE_SYS_BUTTON10UP <<3,13);
506 node->mouse.buttons = buttons;
507 }
508
509 /* this has to be split into three events: [press+release] and analog axis */
510 if (wheel_v)
511 wheel_ev(ctx, 0, wheel_v);
512
513 if (wheel_h)
514 wheel_ev(ctx, 1, wheel_h);
515 }
516 }
517
do_keyb(arcan_evctx * ctx,struct devnode * node)518 static void do_keyb(arcan_evctx* ctx, struct devnode* node)
519 {
520 uint8_t n, code;
521 ssize_t count = read(evctx.tty, &n, 1);
522 if (count <= 0)
523 return;
524
525 code = n & 0x7f;
526 arcan_event ev = {
527 .category = EVENT_IO,
528 .io = {
529 .kind = EVENT_IO_BUTTON,
530 .devid = 1,
531 .datatype = EVENT_IDATATYPE_TRANSLATED,
532 .devkind = EVENT_IDEVKIND_KEYBOARD
533 }
534 };
535
536 ev.io.input.translated.scancode = code;
537 ev.io.subid = code;
538 ev.io.input.translated.active = (n & 0x80) == 0;
539
540 /* it's safe to index based on modifier even though it's lagging behind
541 * here as all state fields repeat the same modifer */
542 struct bsdkey* key = &evctx.keyb.keyb.lut[mod_to_ind(node->keyb.mods)][code];
543 struct bsdkey* okey = &evctx.keyb.keyb.lut[0][code];
544
545 /* the symbols are taken from their non-modified state */
546
547 memcpy(ev.io.input.translated.utf8, key->u8, 5);
548 ev.io.input.translated.keysym = okey->sym;
549 if ((n & 0x80) == 0)
550 node->keyb.mods |= key->modmask;
551 else
552 node->keyb.mods &= ~(key->modmask);
553
554 /* TODO: update code press bitmask table (2x 64-bit fields, 1 bit per code)
555 * and check for repeat, if repeat and not modifier then emit release+press */
556 ev.io.input.translated.modifiers = node->keyb.mods;
557 arcan_event_enqueue(ctx, &ev);
558 }
559
platform_event_process(arcan_evctx * ctx)560 void platform_event_process(arcan_evctx* ctx)
561 {
562 /* KEYBOARD format:
563 * 1. Lookup code according to the current map which will yield
564 * our basic entry.
565 * 2. If (modifier) update state tracking, translate modifier key
566 * 3. lookup entry in map using modifier index
567 * 4. use that to get SDL12 keysym, possible utf8- value
568 * set scancode, subid (dup. code), modifier-states, sym, utf8
569 * 5. enqueue event.
570 */
571 struct pollfd infd[3] = {
572 { .fd = evctx.tty, .events = POLLIN },
573 { .fd = evctx.mdev.fd, .events = POLLIN },
574 { .fd = evctx.sigpipe[0], .events = POLLIN }
575 };
576
577 /* allow one "sweep" */
578 bool okst = true;
579 while (okst && poll(infd, 2, 0) > 0){
580 okst = false;
581 if (infd[0].revents == POLLIN){
582 do_keyb(ctx, &evctx.keyb);
583 okst = true;
584 };
585
586 if (infd[1].revents == POLLIN){
587 do_mouse(ctx, &evctx.mdev);
588 okst = true;
589 }
590
591 if (infd[2].revents == POLLIN){
592 char ch;
593 if (1 == read(infd[2].fd, &ch, 1))
594 switch(ch){
595 case 'z':
596 arcan_event_enqueue(arcan_event_defaultctx(), &(struct arcan_event){
597 .category = EVENT_SYSTEM,
598 .sys.kind = EVENT_SYSTEM_EXIT,
599 .sys.errcode = EXIT_SUCCESS
600 });
601 break;
602 }
603 }
604 }
605 }
606
platform_event_samplebase(int devid,float xyz[3])607 void platform_event_samplebase(int devid, float xyz[3])
608 {
609 /* for mouse dev, run ioctl on the console with struct mouse_info,
610 * int_operttion, union { struct data, mode, event } */
611 }
612
platform_event_keyrepeat(arcan_evctx * ctx,int * period,int * delay)613 void platform_event_keyrepeat(arcan_evctx* ctx, int* period, int* delay)
614 {
615 struct keyboard_repeat rep;
616 if (-1 == ioctl(evctx.keyb.fd, KDGETREPEAT, &rep))
617 return;
618
619 if (*period < 0)
620 *period = rep.kb_repeat[1];
621 else
622 rep.kb_repeat[1] = *period;
623
624 if (*delay < 0)
625 *delay = rep.kb_repeat[0];
626 else
627 rep.kb_repeat[0] = *delay;
628
629 ioctl(evctx.keyb.fd, KDSETREPEAT, &rep);
630 }
631
platform_event_capabilities(const char ** out)632 enum PLATFORM_EVENT_CAPABILITIES platform_event_capabilities(const char** out)
633 {
634 if (out)
635 *out = "freebsd";
636
637 return ACAP_TRANSLATED | ACAP_MOUSE | ACAP_TOUCH;
638 }
639
platform_event_rescan_idev(arcan_evctx * ctx)640 void platform_event_rescan_idev(arcan_evctx* ctx)
641 {
642 }
643
platform_event_devlabel(int devid)644 const char* platform_event_devlabel(int devid)
645 {
646 return NULL;
647 }
648
649 static char* envopts[] = {
650 "ARCAN_INPUT_IGNORETTY", "Don't change terminal processing state",
651 "ARCAN_INPUT_KEYMAPS", "(temporary), path to keymap to use",
652 NULL
653 };
654
platform_event_envopts()655 const char** platform_event_envopts()
656 {
657 return (const char**) envopts;
658 }
659
platform_event_deinit(arcan_evctx * ctx)660 void platform_event_deinit(arcan_evctx* ctx)
661 {
662 /* this is also performed in psep_open */
663 if (-1 != evctx.tty){
664 tcsetattr(evctx.tty, TCSAFLUSH, &evctx.ttystate);
665 ioctl(evctx.tty, KDSETMODE, KD_TEXT);
666 ioctl(evctx.keyb.fd, KDSKBMODE, K_XLATE);
667 }
668 }
669
platform_device_lock(int devind,bool state)670 void platform_device_lock(int devind, bool state)
671 {
672 }
673
platform_event_preinit()674 void platform_event_preinit()
675 {
676 }
677
platform_event_init(arcan_evctx * ctx)678 void platform_event_init(arcan_evctx* ctx)
679 {
680 /* save TTY settings, explicit for devices as we want kbd- access even
681 * when testing from a remote shell */
682 evctx.keyb.fd = STDIN_FILENO;
683
684 /* 7-bit scancode, 7 bit + MSB as active. problem is that we need to do the
685 * translation ourselves because the driver can't output both scancodes and
686 * translated values, which would break cases where we need to forward scancode,
687 * like in VMs
688 */
689 if (getenv("ARCAN_INPUT_KEYMAPS")){
690 load_keymap(&evctx.keyb, getenv("ARCAN_INPUT_KEYMAPS"));
691 }
692 /* just pick a layout, chances are the user can't / won't see the error so
693 * better to do something. Other (real) option should be to check rc.conf or
694 * rc.conf.local after the keymap variable and load that */
695 else{
696 arcan_warning("platform/freebsd: no keymap defined! set "
697 "ARCAN_INPUT_KEYMAPS=/usr/share/syscons/keymaps/???.kbd");
698 load_keymap(&evctx.keyb, "/usr/share/syscons/keymaps/us.iso.kbd");
699 }
700
701 if (getenv("ARCAN_INPUT_IGNORETTY")){
702 evctx.tty = -1;
703 return;
704 }
705
706 evctx.tty = STDIN_FILENO;
707 tcgetattr(evctx.tty, &evctx.ttystate);
708 ioctl(evctx.tty, KDSETMODE, KD_GRAPHICS);
709
710 if (-1 == ioctl(evctx.keyb.fd, KDSKBMODE, K_RAW)){
711 arcan_warning("couldn't set code input mode\n");
712 }
713 struct termios raw = evctx.ttystate;
714 cfmakeraw(&raw);
715 tcsetattr(evctx.tty, TCSAFLUSH, &raw);
716
717 evctx.mdev.fd = platform_device_open("/dev/sysmouse", O_RDWR);
718 if (-1 != evctx.mdev.fd){
719 int level = 1;
720 if (-1 == ioctl(evctx.mdev.fd, MOUSE_SETLEVEL, &level)){
721 close(evctx.mdev.fd);
722 evctx.mdev.fd = -1;
723 arcan_warning("no acceptable mouse protocol found for sysmouse %d, %s\n",
724 errno, strerror(errno));
725 goto sigset;
726 }
727 if (-1 == ioctl(evctx.mdev.fd, MOUSE_GETMODE, &evctx.mdev.mouse.mode)){
728 close(evctx.mdev.fd);
729 arcan_warning("couldn't get mousemode from /dev/sysmouse\n");
730 evctx.mdev.fd = -1;
731 goto sigset;
732 }
733 if (evctx.mdev.mouse.mode.protocol != MOUSE_PROTO_SYSMOUSE ||
734 evctx.mdev.mouse.mode.packetsize < 0){
735 close(evctx.mdev.fd);
736 evctx.mdev.fd = -1;
737 arcan_warning("unexpected mouse protocol state\n");
738 goto sigset;
739 }
740 int flags = fcntl(evctx.mdev.fd, F_GETFL);
741 if (-1 == fcntl(evctx.mdev.fd, F_SETFL, flags | O_NONBLOCK)){
742 close(evctx.mdev.fd);
743 evctx.mdev.fd = -1;
744 arcan_warning("couldn't set non-blocking mouse device\n");
745 goto sigset;
746 }
747 }
748
749 sigset:
750 /* use a pipe to handle TERM / VT switching */
751 if (0 != pipe(evctx.sigpipe)){
752 arcan_fatal("couldn't create signalling pipe, code: %d, reason: %s\n",
753 errno, strerror(errno));
754
755 fcntl(evctx.sigpipe[0], F_SETFD, FD_CLOEXEC);
756 fcntl(evctx.sigpipe[1], F_SETFD, FD_CLOEXEC);
757 struct sigaction er_sh = {.sa_handler = SIG_IGN};
758 sigaction(SIGINT, &er_sh, NULL);
759 er_sh.sa_handler = NULL;
760 er_sh.sa_sigaction = sigusr_term;
761 er_sh.sa_flags = SA_RESTART;
762 sigaction(SIGTERM, &er_sh, NULL);
763 }
764 }
765
platform_event_reset(arcan_evctx * ctx)766 void platform_event_reset(arcan_evctx* ctx)
767 {
768 platform_event_deinit(ctx);
769 platform_event_init(ctx);
770 }
771