Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/usr.sbin/bluetooth/bthidd/btuinput.c
103352 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2015-2017 Vladimir Kondratyev <[email protected]>
5
* All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in the
14
* documentation and/or other materials provided with the distribution.
15
*
16
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
* SUCH DAMAGE.
27
*/
28
29
#include <sys/param.h>
30
#include <sys/ioctl.h>
31
#include <sys/kbio.h>
32
#include <sys/sysctl.h>
33
34
#include <dev/evdev/input.h>
35
#include <dev/evdev/uinput.h>
36
#include <dev/usb/usb.h>
37
#include <dev/usb/usbhid.h>
38
39
#include <assert.h>
40
#define L2CAP_SOCKET_CHECKED
41
#include <bluetooth.h>
42
#include <errno.h>
43
#include <fcntl.h>
44
#include <stdio.h>
45
#include <string.h>
46
#include <syslog.h>
47
#include <time.h>
48
#include <unistd.h>
49
#include <usbhid.h>
50
51
#include "bthid_config.h"
52
#include "bthidd.h"
53
#include "btuinput.h"
54
55
static int16_t const mbuttons[8] = {
56
BTN_LEFT,
57
BTN_MIDDLE,
58
BTN_RIGHT,
59
BTN_SIDE,
60
BTN_EXTRA,
61
BTN_FORWARD,
62
BTN_BACK,
63
BTN_TASK
64
};
65
66
static uint16_t const led_codes[3] = {
67
LED_CAPSL, /* CLKED */
68
LED_NUML, /* NLKED */
69
LED_SCROLLL, /* SLKED */
70
};
71
72
#define NONE KEY_RESERVED
73
74
static uint16_t const keymap[0x100] = {
75
/* 0x00 - 0x27 */
76
NONE, NONE, NONE, NONE, KEY_A, KEY_B, KEY_C, KEY_D,
77
KEY_E, KEY_F, KEY_G, KEY_H, KEY_I, KEY_J, KEY_K, KEY_L,
78
KEY_M, KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T,
79
KEY_U, KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z, KEY_1, KEY_2,
80
KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_0,
81
/* 0x28 - 0x3f */
82
KEY_ENTER, KEY_ESC, KEY_BACKSPACE, KEY_TAB,
83
KEY_SPACE, KEY_MINUS, KEY_EQUAL, KEY_LEFTBRACE,
84
KEY_RIGHTBRACE, KEY_BACKSLASH, KEY_BACKSLASH, KEY_SEMICOLON,
85
KEY_APOSTROPHE, KEY_GRAVE, KEY_COMMA, KEY_DOT,
86
KEY_SLASH, KEY_CAPSLOCK, KEY_F1, KEY_F2,
87
KEY_F3, KEY_F4, KEY_F5, KEY_F6,
88
/* 0x40 - 0x5f */
89
KEY_F7, KEY_F8, KEY_F9, KEY_F10,
90
KEY_F11, KEY_F12, KEY_SYSRQ, KEY_SCROLLLOCK,
91
KEY_PAUSE, KEY_INSERT, KEY_HOME, KEY_PAGEUP,
92
KEY_DELETE, KEY_END, KEY_PAGEDOWN, KEY_RIGHT,
93
KEY_LEFT, KEY_DOWN, KEY_UP, KEY_NUMLOCK,
94
KEY_KPSLASH, KEY_KPASTERISK, KEY_KPMINUS, KEY_KPPLUS,
95
KEY_KPENTER, KEY_KP1, KEY_KP2, KEY_KP3,
96
KEY_KP4, KEY_KP5, KEY_KP6, KEY_KP7,
97
/* 0x60 - 0x7f */
98
KEY_KP8, KEY_KP9, KEY_KP0, KEY_KPDOT,
99
KEY_102ND, KEY_COMPOSE, KEY_POWER, KEY_KPEQUAL,
100
KEY_F13, KEY_F14, KEY_F15, KEY_F16,
101
KEY_F17, KEY_F18, KEY_F19, KEY_F20,
102
KEY_F21, KEY_F22, KEY_F23, KEY_F24,
103
KEY_OPEN, KEY_HELP, KEY_PROPS, KEY_FRONT,
104
KEY_STOP, KEY_AGAIN, KEY_UNDO, KEY_CUT,
105
KEY_COPY, KEY_PASTE, KEY_FIND, KEY_MUTE,
106
/* 0x80 - 0x9f */
107
KEY_VOLUMEUP, KEY_VOLUMEDOWN, NONE, NONE,
108
NONE, KEY_KPCOMMA, NONE, KEY_RO,
109
KEY_KATAKANAHIRAGANA, KEY_YEN,KEY_HENKAN, KEY_MUHENKAN,
110
KEY_KPJPCOMMA, NONE, NONE, NONE,
111
KEY_HANGEUL, KEY_HANJA, KEY_KATAKANA, KEY_HIRAGANA,
112
KEY_ZENKAKUHANKAKU, NONE, NONE, NONE,
113
NONE, NONE, NONE, NONE,
114
NONE, NONE, NONE, NONE,
115
/* 0xa0 - 0xbf */
116
NONE, NONE, NONE, NONE,
117
NONE, NONE, NONE, NONE,
118
NONE, NONE, NONE, NONE,
119
NONE, NONE, NONE, NONE,
120
NONE, NONE, NONE, NONE,
121
NONE, NONE, NONE, NONE,
122
NONE, NONE, NONE, NONE,
123
NONE, NONE, NONE, NONE,
124
/* 0xc0 - 0xdf */
125
NONE, NONE, NONE, NONE,
126
NONE, NONE, NONE, NONE,
127
NONE, NONE, NONE, NONE,
128
NONE, NONE, NONE, NONE,
129
NONE, NONE, NONE, NONE,
130
NONE, NONE, NONE, NONE,
131
NONE, NONE, NONE, NONE,
132
NONE, NONE, NONE, NONE,
133
/* 0xe0 - 0xff */
134
KEY_LEFTCTRL, KEY_LEFTSHIFT, KEY_LEFTALT, KEY_LEFTMETA,
135
KEY_RIGHTCTRL, KEY_RIGHTSHIFT, KEY_RIGHTALT, KEY_RIGHTMETA,
136
KEY_PLAYPAUSE, KEY_STOPCD, KEY_PREVIOUSSONG,KEY_NEXTSONG,
137
KEY_EJECTCD, KEY_VOLUMEUP, KEY_VOLUMEDOWN, KEY_MUTE,
138
KEY_WWW, KEY_BACK, KEY_FORWARD, KEY_STOP,
139
KEY_FIND, KEY_SCROLLUP, KEY_SCROLLDOWN, KEY_EDIT,
140
KEY_SLEEP, KEY_COFFEE, KEY_REFRESH, KEY_CALC,
141
NONE, NONE, NONE, NONE,
142
};
143
144
/* Consumer page usage mapping */
145
static uint16_t const consmap[0x300] = {
146
[0x030] = KEY_POWER,
147
[0x031] = KEY_RESTART,
148
[0x032] = KEY_SLEEP,
149
[0x034] = KEY_SLEEP,
150
[0x035] = KEY_KBDILLUMTOGGLE,
151
[0x036] = BTN_MISC,
152
[0x040] = KEY_MENU,
153
[0x041] = KEY_SELECT,
154
[0x042] = KEY_UP,
155
[0x043] = KEY_DOWN,
156
[0x044] = KEY_LEFT,
157
[0x045] = KEY_RIGHT,
158
[0x046] = KEY_ESC,
159
[0x047] = KEY_KPPLUS,
160
[0x048] = KEY_KPMINUS,
161
[0x060] = KEY_INFO,
162
[0x061] = KEY_SUBTITLE,
163
[0x063] = KEY_VCR,
164
[0x065] = KEY_CAMERA,
165
[0x069] = KEY_RED,
166
[0x06a] = KEY_GREEN,
167
[0x06b] = KEY_BLUE,
168
[0x06c] = KEY_YELLOW,
169
[0x06d] = KEY_ZOOM,
170
[0x06f] = KEY_BRIGHTNESSUP,
171
[0x070] = KEY_BRIGHTNESSDOWN,
172
[0x072] = KEY_BRIGHTNESS_TOGGLE,
173
[0x073] = KEY_BRIGHTNESS_MIN,
174
[0x074] = KEY_BRIGHTNESS_MAX,
175
[0x075] = KEY_BRIGHTNESS_AUTO,
176
[0x082] = KEY_VIDEO_NEXT,
177
[0x083] = KEY_LAST,
178
[0x084] = KEY_ENTER,
179
[0x088] = KEY_PC,
180
[0x089] = KEY_TV,
181
[0x08a] = KEY_WWW,
182
[0x08b] = KEY_DVD,
183
[0x08c] = KEY_PHONE,
184
[0x08d] = KEY_PROGRAM,
185
[0x08e] = KEY_VIDEOPHONE,
186
[0x08f] = KEY_GAMES,
187
[0x090] = KEY_MEMO,
188
[0x091] = KEY_CD,
189
[0x092] = KEY_VCR,
190
[0x093] = KEY_TUNER,
191
[0x094] = KEY_EXIT,
192
[0x095] = KEY_HELP,
193
[0x096] = KEY_TAPE,
194
[0x097] = KEY_TV2,
195
[0x098] = KEY_SAT,
196
[0x09a] = KEY_PVR,
197
[0x09c] = KEY_CHANNELUP,
198
[0x09d] = KEY_CHANNELDOWN,
199
[0x0a0] = KEY_VCR2,
200
[0x0b0] = KEY_PLAY,
201
[0x0b1] = KEY_PAUSE,
202
[0x0b2] = KEY_RECORD,
203
[0x0b3] = KEY_FASTFORWARD,
204
[0x0b4] = KEY_REWIND,
205
[0x0b5] = KEY_NEXTSONG,
206
[0x0b6] = KEY_PREVIOUSSONG,
207
[0x0b7] = KEY_STOPCD,
208
[0x0b8] = KEY_EJECTCD,
209
[0x0bc] = KEY_MEDIA_REPEAT,
210
[0x0b9] = KEY_SHUFFLE,
211
[0x0bf] = KEY_SLOW,
212
[0x0cd] = KEY_PLAYPAUSE,
213
[0x0cf] = KEY_VOICECOMMAND,
214
[0x0e2] = KEY_MUTE,
215
[0x0e5] = KEY_BASSBOOST,
216
[0x0e9] = KEY_VOLUMEUP,
217
[0x0ea] = KEY_VOLUMEDOWN,
218
[0x0f5] = KEY_SLOW,
219
[0x181] = KEY_BUTTONCONFIG,
220
[0x182] = KEY_BOOKMARKS,
221
[0x183] = KEY_CONFIG,
222
[0x184] = KEY_WORDPROCESSOR,
223
[0x185] = KEY_EDITOR,
224
[0x186] = KEY_SPREADSHEET,
225
[0x187] = KEY_GRAPHICSEDITOR,
226
[0x188] = KEY_PRESENTATION,
227
[0x189] = KEY_DATABASE,
228
[0x18a] = KEY_MAIL,
229
[0x18b] = KEY_NEWS,
230
[0x18c] = KEY_VOICEMAIL,
231
[0x18d] = KEY_ADDRESSBOOK,
232
[0x18e] = KEY_CALENDAR,
233
[0x18f] = KEY_TASKMANAGER,
234
[0x190] = KEY_JOURNAL,
235
[0x191] = KEY_FINANCE,
236
[0x192] = KEY_CALC,
237
[0x193] = KEY_PLAYER,
238
[0x194] = KEY_FILE,
239
[0x196] = KEY_WWW,
240
[0x199] = KEY_CHAT,
241
[0x19c] = KEY_LOGOFF,
242
[0x19e] = KEY_COFFEE,
243
[0x19f] = KEY_CONTROLPANEL,
244
[0x1a2] = KEY_APPSELECT,
245
[0x1a3] = KEY_NEXT,
246
[0x1a4] = KEY_PREVIOUS,
247
[0x1a6] = KEY_HELP,
248
[0x1a7] = KEY_DOCUMENTS,
249
[0x1ab] = KEY_SPELLCHECK,
250
[0x1ae] = KEY_KEYBOARD,
251
[0x1b1] = KEY_SCREENSAVER,
252
[0x1b4] = KEY_FILE,
253
[0x1b6] = KEY_IMAGES,
254
[0x1b7] = KEY_AUDIO,
255
[0x1b8] = KEY_VIDEO,
256
[0x1bc] = KEY_MESSENGER,
257
[0x1bd] = KEY_INFO,
258
[0x201] = KEY_NEW,
259
[0x202] = KEY_OPEN,
260
[0x203] = KEY_CLOSE,
261
[0x204] = KEY_EXIT,
262
[0x207] = KEY_SAVE,
263
[0x208] = KEY_PRINT,
264
[0x209] = KEY_PROPS,
265
[0x21a] = KEY_UNDO,
266
[0x21b] = KEY_COPY,
267
[0x21c] = KEY_CUT,
268
[0x21d] = KEY_PASTE,
269
[0x21f] = KEY_FIND,
270
[0x221] = KEY_SEARCH,
271
[0x222] = KEY_GOTO,
272
[0x223] = KEY_HOMEPAGE,
273
[0x224] = KEY_BACK,
274
[0x225] = KEY_FORWARD,
275
[0x226] = KEY_STOP,
276
[0x227] = KEY_REFRESH,
277
[0x22a] = KEY_BOOKMARKS,
278
[0x22d] = KEY_ZOOMIN,
279
[0x22e] = KEY_ZOOMOUT,
280
[0x22f] = KEY_ZOOMRESET,
281
[0x233] = KEY_SCROLLUP,
282
[0x234] = KEY_SCROLLDOWN,
283
[0x23d] = KEY_EDIT,
284
[0x25f] = KEY_CANCEL,
285
[0x269] = KEY_INSERT,
286
[0x26a] = KEY_DELETE,
287
[0x279] = KEY_REDO,
288
[0x289] = KEY_REPLY,
289
[0x28b] = KEY_FORWARDMAIL,
290
[0x28c] = KEY_SEND,
291
[0x2c7] = KEY_KBDINPUTASSIST_PREV,
292
[0x2c8] = KEY_KBDINPUTASSIST_NEXT,
293
[0x2c9] = KEY_KBDINPUTASSIST_PREVGROUP,
294
[0x2ca] = KEY_KBDINPUTASSIST_NEXTGROUP,
295
[0x2cb] = KEY_KBDINPUTASSIST_ACCEPT,
296
[0x2cc] = KEY_KBDINPUTASSIST_CANCEL,
297
};
298
299
static int32_t
300
uinput_open_common(hid_device_p const p, bdaddr_p local, const uint8_t *name)
301
{
302
struct uinput_setup uisetup;
303
uint8_t phys[UINPUT_MAX_NAME_SIZE];
304
uint8_t uniq[UINPUT_MAX_NAME_SIZE];
305
int32_t fd;
306
307
/* Take local and remote bdaddr */
308
bt_ntoa(local, phys);
309
bt_ntoa(&p->bdaddr, uniq);
310
311
/* Take device name from bthidd.conf. Fallback to generic name. */
312
if (p->name != NULL)
313
name = p->name;
314
315
/* Set device name and bus/vendor information */
316
memset(&uisetup, 0, sizeof(uisetup));
317
snprintf(uisetup.name, UINPUT_MAX_NAME_SIZE,
318
"%s, bdaddr %s", name, uniq);
319
uisetup.id.bustype = BUS_BLUETOOTH;
320
uisetup.id.vendor = p->vendor_id;
321
uisetup.id.product = p->product_id;
322
uisetup.id.version = p->version;
323
324
fd = open("/dev/uinput", O_RDWR | O_NONBLOCK);
325
326
if (ioctl(fd, UI_SET_PHYS, phys) < 0 ||
327
ioctl(fd, UI_SET_BSDUNIQ, uniq) < 0 ||
328
ioctl(fd, UI_DEV_SETUP, &uisetup) < 0)
329
return (-1);
330
331
return (fd);
332
}
333
334
/*
335
* Setup uinput device as 8button mouse with wheel(s)
336
* TODO: bring in more feature detection code from ums
337
*/
338
int32_t
339
uinput_open_mouse(hid_device_p const p, bdaddr_p local)
340
{
341
size_t i;
342
int32_t fd;
343
344
assert(p != NULL);
345
346
if ((fd = uinput_open_common(p, local, "Bluetooth Mouse")) < 0)
347
goto bail_out;
348
349
/* Advertise events and axes */
350
if (ioctl(fd, UI_SET_EVBIT, EV_SYN) < 0 ||
351
ioctl(fd, UI_SET_EVBIT, EV_KEY) < 0 ||
352
ioctl(fd, UI_SET_EVBIT, EV_REL) < 0 ||
353
ioctl(fd, UI_SET_RELBIT, REL_X) < 0 ||
354
ioctl(fd, UI_SET_RELBIT, REL_Y) < 0 ||
355
(p->has_wheel && ioctl(fd, UI_SET_RELBIT, REL_WHEEL) < 0) ||
356
(p->has_hwheel && ioctl(fd, UI_SET_RELBIT, REL_HWHEEL) < 0) ||
357
ioctl(fd, UI_SET_PROPBIT, INPUT_PROP_POINTER) < 0)
358
goto bail_out;
359
360
/* Advertise mouse buttons */
361
for (i = 0; i < nitems(mbuttons); i++)
362
if (ioctl(fd, UI_SET_KEYBIT, mbuttons[i]) < 0)
363
goto bail_out;
364
365
if (ioctl(fd, UI_DEV_CREATE) >= 0)
366
return (fd); /* SUCCESS */
367
368
bail_out:
369
if (fd >= 0)
370
close(fd);
371
return (-1);
372
}
373
374
/*
375
* Setup uinput keyboard
376
*/
377
int32_t
378
uinput_open_keyboard(hid_device_p const p, bdaddr_p local)
379
{
380
size_t i;
381
int32_t fd;
382
383
assert(p != NULL);
384
385
if ((fd = uinput_open_common(p, local, "Bluetooth Keyboard")) < 0)
386
goto bail_out;
387
388
/* Advertise key events and LEDs */
389
if (ioctl(fd, UI_SET_EVBIT, EV_KEY) < 0 ||
390
ioctl(fd, UI_SET_EVBIT, EV_LED) < 0 ||
391
ioctl(fd, UI_SET_EVBIT, EV_SYN) < 0 ||
392
ioctl(fd, UI_SET_EVBIT, EV_REP) < 0 ||
393
ioctl(fd, UI_SET_LEDBIT, LED_CAPSL) < 0 ||
394
ioctl(fd, UI_SET_LEDBIT, LED_NUML) < 0 ||
395
ioctl(fd, UI_SET_LEDBIT, LED_SCROLLL))
396
goto bail_out;
397
398
/* Advertise keycodes */
399
for (i = 0; i < nitems(keymap); i++)
400
if (keymap[i] != NONE &&
401
ioctl(fd, UI_SET_KEYBIT, keymap[i]) < 0)
402
goto bail_out;
403
404
/* Advertise consumer page keys if any */
405
if (p->has_cons) {
406
for (i = 0; i < nitems(consmap); i++) {
407
if (consmap[i] != NONE &&
408
ioctl(fd, UI_SET_KEYBIT, consmap[i]) < 0)
409
goto bail_out;
410
}
411
}
412
413
if (ioctl(fd, UI_DEV_CREATE) >= 0)
414
return (fd); /* SUCCESS */
415
416
bail_out:
417
if (fd >= 0)
418
close(fd);
419
return (-1);
420
}
421
422
/* from sys/dev/evdev/evdev.h */
423
#define EVDEV_RCPT_HW_MOUSE (1<<2)
424
#define EVDEV_RCPT_HW_KBD (1<<3)
425
426
#define MASK_POLL_INTERVAL 5 /* seconds */
427
#define MASK_SYSCTL "kern.evdev.rcpt_mask"
428
429
static int32_t
430
uinput_get_rcpt_mask(void)
431
{
432
static struct timespec last = { 0, 0 };
433
struct timespec now;
434
static int32_t mask = 0;
435
size_t len;
436
time_t elapsed;
437
438
if (clock_gettime(CLOCK_MONOTONIC_FAST, &now) == -1)
439
return mask;
440
441
elapsed = now.tv_sec - last.tv_sec;
442
if (now.tv_nsec < last.tv_nsec)
443
elapsed--;
444
445
if (elapsed >= MASK_POLL_INTERVAL) {
446
len = sizeof(mask);
447
if (sysctlbyname(MASK_SYSCTL, &mask, &len, NULL, 0) < 0) {
448
if (errno == ENOENT)
449
/* kernel is compiled w/o EVDEV_SUPPORT */
450
mask = EVDEV_RCPT_HW_MOUSE | EVDEV_RCPT_HW_KBD;
451
else
452
mask = 0;
453
}
454
last = now;
455
}
456
return mask;
457
}
458
459
static int32_t
460
uinput_write_event(int32_t fd, uint16_t type, uint16_t code, int32_t value)
461
{
462
struct input_event ie;
463
464
assert(fd >= 0);
465
466
memset(&ie, 0, sizeof(ie));
467
ie.type = type;
468
ie.code = code;
469
ie.value = value;
470
return (write(fd, &ie, sizeof(ie)));
471
}
472
473
int32_t
474
uinput_rep_mouse(int32_t fd, int32_t x, int32_t y, int32_t z, int32_t t,
475
int32_t buttons, int32_t obuttons)
476
{
477
size_t i;
478
int32_t rcpt_mask, mask;
479
480
assert(fd >= 0);
481
482
rcpt_mask = uinput_get_rcpt_mask();
483
if (!(rcpt_mask & EVDEV_RCPT_HW_MOUSE))
484
return (0);
485
486
if ((x != 0 && uinput_write_event(fd, EV_REL, REL_X, x) < 0) ||
487
(y != 0 && uinput_write_event(fd, EV_REL, REL_Y, y) < 0) ||
488
(z != 0 && uinput_write_event(fd, EV_REL, REL_WHEEL, -z) < 0) ||
489
(t != 0 && uinput_write_event(fd, EV_REL, REL_HWHEEL, t) < 0))
490
return (-1);
491
492
for (i = 0; i < nitems(mbuttons); i++) {
493
mask = 1 << i;
494
if ((buttons & mask) == (obuttons & mask))
495
continue;
496
if (uinput_write_event(fd, EV_KEY, mbuttons[i],
497
(buttons & mask) != 0) < 0)
498
return (-1);
499
}
500
501
if (uinput_write_event(fd, EV_SYN, SYN_REPORT, 0) < 0)
502
return (-1);
503
504
return (0);
505
}
506
507
/*
508
* Translate and report keyboard page key events
509
*/
510
int32_t
511
uinput_rep_key(int32_t fd, int32_t key, int32_t make)
512
{
513
int32_t rcpt_mask;
514
515
assert(fd >= 0);
516
517
rcpt_mask = uinput_get_rcpt_mask();
518
if (!(rcpt_mask & EVDEV_RCPT_HW_KBD))
519
return (0);
520
521
if (key >= 0 && key < (int32_t)nitems(keymap) &&
522
keymap[key] != NONE) {
523
if (uinput_write_event(fd, EV_KEY, keymap[key], make) > 0 &&
524
uinput_write_event(fd, EV_SYN, SYN_REPORT, 0) > 0)
525
return (0);
526
}
527
return (-1);
528
}
529
530
/*
531
* Translate and report consumer page key events
532
*/
533
int32_t
534
uinput_rep_cons(int32_t fd, int32_t key, int32_t make)
535
{
536
int32_t rcpt_mask;
537
538
assert(fd >= 0);
539
540
rcpt_mask = uinput_get_rcpt_mask();
541
if (!(rcpt_mask & EVDEV_RCPT_HW_KBD))
542
return (0);
543
544
if (key >= 0 && key < (int32_t)nitems(consmap) &&
545
consmap[key] != NONE) {
546
if (uinput_write_event(fd, EV_KEY, consmap[key], make) > 0 &&
547
uinput_write_event(fd, EV_SYN, SYN_REPORT, 0) > 0)
548
return (0);
549
}
550
return (-1);
551
}
552
553
/*
554
* Translate and report LED events
555
*/
556
int32_t
557
uinput_rep_leds(int32_t fd, int state, int mask)
558
{
559
size_t i;
560
int32_t rcpt_mask;
561
562
assert(fd >= 0);
563
564
rcpt_mask = uinput_get_rcpt_mask();
565
if (!(rcpt_mask & EVDEV_RCPT_HW_KBD))
566
return (0);
567
568
for (i = 0; i < nitems(led_codes); i++) {
569
if (mask & (1 << i) &&
570
uinput_write_event(fd, EV_LED, led_codes[i],
571
state & (1 << i) ? 1 : 0) < 0)
572
return (-1);
573
}
574
575
return (0);
576
}
577
578
/*
579
* Process status change from evdev
580
*/
581
int32_t
582
uinput_kbd_status_changed(bthid_session_p s, uint8_t *data, int32_t len)
583
{
584
struct input_event ie;
585
int32_t leds, oleds;
586
size_t i;
587
588
assert(s != NULL);
589
assert(s->vkbd >= 0);
590
assert(len == sizeof(struct input_event));
591
592
memcpy(&ie, data, sizeof(ie));
593
switch (ie.type) {
594
case EV_LED:
595
ioctl(s->vkbd, KDGETLED, &oleds);
596
leds = oleds;
597
for (i = 0; i < nitems(led_codes); i++) {
598
if (led_codes[i] == ie.code) {
599
if (ie.value)
600
leds |= 1 << i;
601
else
602
leds &= ~(1 << i);
603
if (leds != oleds)
604
ioctl(s->vkbd, KDSETLED, leds);
605
break;
606
}
607
}
608
break;
609
case EV_REP:
610
/* FALLTHROUGH. Repeats are handled by evdev subsystem */
611
default:
612
break;
613
}
614
615
return (0);
616
}
617
618