4 * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
28 * $Id: kbd.c,v 1.2 2004/11/17 21:59:42 max Exp $
32 #include <sys/consio.h>
33 #include <sys/ioctl.h>
35 #include <sys/queue.h>
38 #include <bluetooth.h>
51 static void kbd_write(bitstr_t *m, int fb, int make, int fd);
52 static int kbd_xlate(int code, int make, int *b, int const *eob);
55 * HID code to PS/2 set 1 code translation table.
57 * http://www.microsoft.com/whdc/device/input/Scancode.mspx
59 * The table only contains "make" (key pressed) codes.
60 * The "break" (key released) code is generated as "make" | 0x80
63 #define E0PREFIX (1 << 31)
64 #define NOBREAK (1 << 30)
65 #define CODEMASK (~(E0PREFIX|NOBREAK))
67 static int const x[] =
69 /*==================================================*/
70 /* Name HID code Make Break*/
71 /*==================================================*/
72 /* No Event 00 */ -1, /* None */
73 /* Overrun Error 01 */ NOBREAK|0xFF, /* None */
74 /* POST Fail 02 */ NOBREAK|0xFC, /* None */
75 /* ErrorUndefined 03 */ -1, /* Unassigned */
76 /* a A 04 */ 0x1E, /* 9E */
77 /* b B 05 */ 0x30, /* B0 */
78 /* c C 06 */ 0x2E, /* AE */
79 /* d D 07 */ 0x20, /* A0 */
80 /* e E 08 */ 0x12, /* 92 */
81 /* f F 09 */ 0x21, /* A1 */
82 /* g G 0A */ 0x22, /* A2 */
83 /* h H 0B */ 0x23, /* A3 */
84 /* i I 0C */ 0x17, /* 97 */
85 /* j J 0D */ 0x24, /* A4 */
86 /* k K 0E */ 0x25, /* A5 */
87 /* l L 0F */ 0x26, /* A6 */
88 /* m M 10 */ 0x32, /* B2 */
89 /* n N 11 */ 0x31, /* B1 */
90 /* o O 12 */ 0x18, /* 98 */
91 /* p P 13 */ 0x19, /* 99 */
92 /* q Q 14 */ 0x10, /* 90 */
93 /* r R 15 */ 0x13, /* 93 */
94 /* s S 16 */ 0x1F, /* 9F */
95 /* t T 17 */ 0x14, /* 94 */
96 /* u U 18 */ 0x16, /* 96 */
97 /* v V 19 */ 0x2F, /* AF */
98 /* w W 1A */ 0x11, /* 91 */
99 /* x X 1B */ 0x2D, /* AD */
100 /* y Y 1C */ 0x15, /* 95 */
101 /* z Z 1D */ 0x2C, /* AC */
102 /* 1 ! 1E */ 0x02, /* 82 */
103 /* 2 @ 1F */ 0x03, /* 83 */
104 /* 3 # 20 */ 0x04, /* 84 */
105 /* 4 $ 21 */ 0x05, /* 85 */
106 /* 5 % 22 */ 0x06, /* 86 */
107 /* 6 ^ 23 */ 0x07, /* 87 */
108 /* 7 & 24 */ 0x08, /* 88 */
109 /* 8 * 25 */ 0x09, /* 89 */
110 /* 9 ( 26 */ 0x0A, /* 8A */
111 /* 0 ) 27 */ 0x0B, /* 8B */
112 /* Return 28 */ 0x1C, /* 9C */
113 /* Escape 29 */ 0x01, /* 81 */
114 /* Backspace 2A */ 0x0E, /* 8E */
115 /* Tab 2B */ 0x0F, /* 8F */
116 /* Space 2C */ 0x39, /* B9 */
117 /* - _ 2D */ 0x0C, /* 8C */
118 /* = + 2E */ 0x0D, /* 8D */
119 /* [ { 2F */ 0x1A, /* 9A */
120 /* ] } 30 */ 0x1B, /* 9B */
121 /* \ | 31 */ 0x2B, /* AB */
122 /* Europe 1 32 */ 0x2B, /* AB */
123 /* ; : 33 */ 0x27, /* A7 */
124 /* " ' 34 */ 0x28, /* A8 */
125 /* ` ~ 35 */ 0x29, /* A9 */
126 /* comma < 36 */ 0x33, /* B3 */
127 /* . > 37 */ 0x34, /* B4 */
128 /* / ? 38 */ 0x35, /* B5 */
129 /* Caps Lock 39 */ 0x3A, /* BA */
130 /* F1 3A */ 0x3B, /* BB */
131 /* F2 3B */ 0x3C, /* BC */
132 /* F3 3C */ 0x3D, /* BD */
133 /* F4 3D */ 0x3E, /* BE */
134 /* F5 3E */ 0x3F, /* BF */
135 /* F6 3F */ 0x40, /* C0 */
136 /* F7 40 */ 0x41, /* C1 */
137 /* F8 41 */ 0x42, /* C2 */
138 /* F9 42 */ 0x43, /* C3 */
139 /* F10 43 */ 0x44, /* C4 */
140 /* F11 44 */ 0x57, /* D7 */
141 /* F12 45 */ 0x58, /* D8 */
142 /* Print Screen 46 */ E0PREFIX|37, /* E0 B7 */
143 /* Scroll Lock 47 */ 0x46, /* C6 */
145 /* Break (Ctrl-Pause) 48 */ E0 46 E0 C6, /* None */
146 /* Pause 48 */ E1 1D 45 E1 9D C5, /* None */
148 /* Break (Ctrl-Pause)/Pause 48 */ NOBREAK /* Special case */, /* None */
150 /* Insert 49 */ E0PREFIX|0x52, /* E0 D2 */
151 /* Home 4A */ E0PREFIX|0x47, /* E0 C7 */
152 /* Page Up 4B */ E0PREFIX|0x49, /* E0 C9 */
153 /* Delete 4C */ E0PREFIX|0x53, /* E0 D3 */
154 /* End 4D */ E0PREFIX|0x4F, /* E0 CF */
155 /* Page Down 4E */ E0PREFIX|0x51, /* E0 D1 */
156 /* Right Arrow 4F */ E0PREFIX|0x4D, /* E0 CD */
157 /* Left Arrow 50 */ E0PREFIX|0x4B, /* E0 CB */
158 /* Down Arrow 51 */ E0PREFIX|0x50, /* E0 D0 */
159 /* Up Arrow 52 */ E0PREFIX|0x48, /* E0 C8 */
160 /* Num Lock 53 */ 0x45, /* C5 */
161 /* Keypad / 54 */ E0PREFIX|0x35, /* E0 B5 */
162 /* Keypad * 55 */ 0x37, /* B7 */
163 /* Keypad - 56 */ 0x4A, /* CA */
164 /* Keypad + 57 */ 0x4E, /* CE */
165 /* Keypad Enter 58 */ E0PREFIX|0x1C, /* E0 9C */
166 /* Keypad 1 End 59 */ 0x4F, /* CF */
167 /* Keypad 2 Down 5A */ 0x50, /* D0 */
168 /* Keypad 3 PageDn 5B */ 0x51, /* D1 */
169 /* Keypad 4 Left 5C */ 0x4B, /* CB */
170 /* Keypad 5 5D */ 0x4C, /* CC */
171 /* Keypad 6 Right 5E */ 0x4D, /* CD */
172 /* Keypad 7 Home 5F */ 0x47, /* C7 */
173 /* Keypad 8 Up 60 */ 0x48, /* C8 */
174 /* Keypad 9 PageUp 61 */ 0x49, /* C9 */
175 /* Keypad 0 Insert 62 */ 0x52, /* D2 */
176 /* Keypad . Delete 63 */ 0x53, /* D3 */
177 /* Europe 2 64 */ 0x56, /* D6 */
178 /* App 65 */ E0PREFIX|0x5D, /* E0 DD */
179 /* Keyboard Power 66 */ E0PREFIX|0x5E, /* E0 DE */
180 /* Keypad = 67 */ 0x59, /* D9 */
181 /* F13 68 */ 0x64, /* E4 */
182 /* F14 69 */ 0x65, /* E5 */
183 /* F15 6A */ 0x66, /* E6 */
184 /* F16 6B */ 0x67, /* E7 */
185 /* F17 6C */ 0x68, /* E8 */
186 /* F18 6D */ 0x69, /* E9 */
187 /* F19 6E */ 0x6A, /* EA */
188 /* F20 6F */ 0x6B, /* EB */
189 /* F21 70 */ 0x6C, /* EC */
190 /* F22 71 */ 0x6D, /* ED */
191 /* F23 72 */ 0x6E, /* EE */
192 /* F24 73 */ 0x76, /* F6 */
193 /* Keyboard Execute 74 */ -1, /* Unassigned */
194 /* Keyboard Help 75 */ -1, /* Unassigned */
195 /* Keyboard Menu 76 */ -1, /* Unassigned */
196 /* Keyboard Select 77 */ -1, /* Unassigned */
197 /* Keyboard Stop 78 */ -1, /* Unassigned */
198 /* Keyboard Again 79 */ -1, /* Unassigned */
199 /* Keyboard Undo 7A */ -1, /* Unassigned */
200 /* Keyboard Cut 7B */ -1, /* Unassigned */
201 /* Keyboard Copy 7C */ -1, /* Unassigned */
202 /* Keyboard Paste 7D */ -1, /* Unassigned */
203 /* Keyboard Find 7E */ -1, /* Unassigned */
204 /* Keyboard Mute 7F */ -1, /* Unassigned */
205 /* Keyboard Volume Up 80 */ -1, /* Unassigned */
206 /* Keyboard Volume Dn 81 */ -1, /* Unassigned */
207 /* Keyboard Locking Caps Lock 82 */ -1, /* Unassigned */
208 /* Keyboard Locking Num Lock 83 */ -1, /* Unassigned */
209 /* Keyboard Locking Scroll Lock 84 */ -1, /* Unassigned */
210 /* Keypad comma 85 */ 0x7E, /* FE */
211 /* Keyboard Equal Sign 86 */ -1, /* Unassigned */
212 /* Keyboard Int'l 1 87 */ 0x73, /* F3 */
213 /* Keyboard Int'l 2 88 */ 0x70, /* F0 */
214 /* Keyboard Int'l 2 89 */ 0x7D, /* FD */
215 /* Keyboard Int'l 4 8A */ 0x79, /* F9 */
216 /* Keyboard Int'l 5 8B */ 0x7B, /* FB */
217 /* Keyboard Int'l 6 8C */ 0x5C, /* DC */
218 /* Keyboard Int'l 7 8D */ -1, /* Unassigned */
219 /* Keyboard Int'l 8 8E */ -1, /* Unassigned */
220 /* Keyboard Int'l 9 8F */ -1, /* Unassigned */
221 /* Keyboard Lang 1 90 */ NOBREAK|0xF2, /* None */
222 /* Keyboard Lang 2 91 */ NOBREAK|0xF1, /* None */
223 /* Keyboard Lang 3 92 */ 0x78, /* F8 */
224 /* Keyboard Lang 4 93 */ 0x77, /* F7 */
225 /* Keyboard Lang 5 94 */ 0x76, /* F6 */
226 /* Keyboard Lang 6 95 */ -1, /* Unassigned */
227 /* Keyboard Lang 7 96 */ -1, /* Unassigned */
228 /* Keyboard Lang 8 97 */ -1, /* Unassigned */
229 /* Keyboard Lang 9 98 */ -1, /* Unassigned */
230 /* Keyboard Alternate Erase 99 */ -1, /* Unassigned */
231 /* Keyboard SysReq/Attention 9A */ -1, /* Unassigned */
232 /* Keyboard Cancel 9B */ -1, /* Unassigned */
233 /* Keyboard Clear 9C */ -1, /* Unassigned */
234 /* Keyboard Prior 9D */ -1, /* Unassigned */
235 /* Keyboard Return 9E */ -1, /* Unassigned */
236 /* Keyboard Separator 9F */ -1, /* Unassigned */
237 /* Keyboard Out A0 */ -1, /* Unassigned */
238 /* Keyboard Oper A1 */ -1, /* Unassigned */
239 /* Keyboard Clear/Again A2 */ -1, /* Unassigned */
240 /* Keyboard CrSel/Props A3 */ -1, /* Unassigned */
241 /* Keyboard ExSel A4 */ -1, /* Unassigned */
242 /* Reserved A5 */ -1, /* Reserved */
243 /* Reserved A6 */ -1, /* Reserved */
244 /* Reserved A7 */ -1, /* Reserved */
245 /* Reserved A8 */ -1, /* Reserved */
246 /* Reserved A9 */ -1, /* Reserved */
247 /* Reserved AA */ -1, /* Reserved */
248 /* Reserved AB */ -1, /* Reserved */
249 /* Reserved AC */ -1, /* Reserved */
250 /* Reserved AD */ -1, /* Reserved */
251 /* Reserved AE */ -1, /* Reserved */
252 /* Reserved AF */ -1, /* Reserved */
253 /* Reserved B0 */ -1, /* Reserved */
254 /* Reserved B1 */ -1, /* Reserved */
255 /* Reserved B2 */ -1, /* Reserved */
256 /* Reserved B3 */ -1, /* Reserved */
257 /* Reserved B4 */ -1, /* Reserved */
258 /* Reserved B5 */ -1, /* Reserved */
259 /* Reserved B6 */ -1, /* Reserved */
260 /* Reserved B7 */ -1, /* Reserved */
261 /* Reserved B8 */ -1, /* Reserved */
262 /* Reserved B9 */ -1, /* Reserved */
263 /* Reserved BA */ -1, /* Reserved */
264 /* Reserved BB */ -1, /* Reserved */
265 /* Reserved BC */ -1, /* Reserved */
266 /* Reserved BD */ -1, /* Reserved */
267 /* Reserved BE */ -1, /* Reserved */
268 /* Reserved BF */ -1, /* Reserved */
269 /* Reserved C0 */ -1, /* Reserved */
270 /* Reserved C1 */ -1, /* Reserved */
271 /* Reserved C2 */ -1, /* Reserved */
272 /* Reserved C3 */ -1, /* Reserved */
273 /* Reserved C4 */ -1, /* Reserved */
274 /* Reserved C5 */ -1, /* Reserved */
275 /* Reserved C6 */ -1, /* Reserved */
276 /* Reserved C8 */ -1, /* Reserved */
277 /* Reserved C9 */ -1, /* Reserved */
278 /* Reserved CA */ -1, /* Reserved */
279 /* Reserved CB */ -1, /* Reserved */
280 /* Reserved CC */ -1, /* Reserved */
281 /* Reserved CD */ -1, /* Reserved */
282 /* Reserved CE */ -1, /* Reserved */
283 /* Reserved CF */ -1, /* Reserved */
284 /* Reserved D0 */ -1, /* Reserved */
285 /* Reserved D1 */ -1, /* Reserved */
286 /* Reserved D2 */ -1, /* Reserved */
287 /* Reserved D3 */ -1, /* Reserved */
288 /* Reserved D4 */ -1, /* Reserved */
289 /* Reserved D5 */ -1, /* Reserved */
290 /* Reserved D6 */ -1, /* Reserved */
291 /* Reserved D8 */ -1, /* Reserved */
292 /* Reserved D9 */ -1, /* Reserved */
293 /* Reserved DA */ -1, /* Reserved */
294 /* Reserved DB */ -1, /* Reserved */
295 /* Reserved DC */ -1, /* Reserved */
296 /* Reserved DD */ -1, /* Reserved */
297 /* Reserved DE */ -1, /* Reserved */
298 /* Reserved DF */ -1, /* Reserved */
299 /* Left Control E0 */ 0x1D, /* 9D */
300 /* Left Control E0 */ 0x1D, /* 9D */
301 /* Left Shift E1 */ 0x2A, /* AA */
302 /* Left Alt E2 */ 0x38, /* B8 */
303 /* Left GUI E3 */ E0PREFIX|0x5B, /* E0 DB */
304 /* Right Control E4 */ E0PREFIX|0x1D, /* E0 9D */
305 /* Right Shift E5 */ 0x36, /* B6 */
306 /* Right Alt E6 */ E0PREFIX|0x38, /* E0 B8 */
307 /* Right GUI E7 */ E0PREFIX|0x5C /* E0 DC */
310 #define xsize (sizeof(x)/sizeof(x[0]))
313 * Get a max HID keycode (aligned)
327 kbd_process_keys(bthid_session_p s)
329 bitstr_t r[bitstr_size(xsize)];
333 assert(s->srv != NULL);
335 bit_ffs(s->srv->keys, xsize, &f0);
336 bit_ffs(s->keys, xsize, &f1);
339 /* all keys are released, no keys pressed */
341 kbd_write(s->keys, f1, 0, s->srv->vkbd);
342 memset(s->keys, 0, bitstr_size(xsize));
349 /* some keys got pressed, no keys released */
351 memcpy(s->keys, s->srv->keys, bitstr_size(xsize));
352 kbd_write(s->keys, f0, 1, s->srv->vkbd);
353 memset(s->srv->keys, 0, bitstr_size(xsize));
359 /* some keys got pressed, some keys got released */
360 memset(r, 0, bitstr_size(xsize));
362 for (i = f1; i < xsize; i++) {
363 if (bit_test(s->keys, i)) {
364 if (!bit_test(s->srv->keys, i)) {
365 bit_clear(s->keys, i);
368 bit_clear(s->srv->keys, i);
372 for (i = f0; i < xsize; i++) {
373 if (bit_test(s->srv->keys, i)) {
374 if (!bit_test(s->keys, i))
377 bit_clear(s->srv->keys, i);
381 bit_ffs(r, xsize, &f0);
382 bit_ffs(s->srv->keys, xsize, &f1);
385 kbd_write(r, f0, 0, s->srv->vkbd);
388 kbd_write(s->srv->keys, f1, 1, s->srv->vkbd);
389 memset(s->srv->keys, 0, bitstr_size(xsize));
396 * Get current keyboard index (fd version)
400 kbd_get_index_fd(int fd)
402 keyboard_info_t info;
404 return ((ioctl(fd, KDGKBINFO, &info) < 0)? -1 : info.kb_index);
408 * Get current keyboard index (device node version)
412 kbd_get_index(char const *device)
416 fd = open(device, O_RDONLY);
420 index = kbd_get_index_fd(fd);
428 * Switch keyboards. Execute external script to switch keyboards. The keyboard
429 * index will be passed to the script in the first argument (argv[1]). We use
430 * external script here to allow user to customize his/her wireless keyboard,
431 * i.e. set mapping etc. In theory, all parameters could be picked up from the
436 kbd_switch(char const *script, int index)
441 if (script == NULL) {
442 syslog(LOG_NOTICE, "Could not switch keyboards. " \
443 "Switch script is not defined");
447 if (access(script, X_OK) < 0) {
448 syslog(LOG_ERR, "The %s is not executable. %s (%d)",
449 script, strerror(errno), errno);
455 if (pid == (pid_t) -1) {
456 syslog(LOG_ERR, "Could not create process for %s. %s (%d)",
457 script, strerror(errno), errno);
463 char *argv[3] = { (char *) script, arg, NULL };
465 snprintf(arg, sizeof(arg), "%d", index);
468 syslog(LOG_ERR, "Could not execute '%s %d'. %s (%d)",
469 script, index, strerror(errno), errno);
474 if (waitpid(pid, &status, 0) < 0) {
475 syslog(LOG_ERR, "Could not waitpid for %s. %s (%d)",
476 script, strerror(errno), errno);
480 if (WIFEXITED(status) && WEXITSTATUS(status)) {
481 syslog(LOG_ERR, "External command '%s %d' failed, exit code %d",
482 script, index, WEXITSTATUS(status));
490 * Translate given keymap and write keyscodes
494 kbd_write(bitstr_t *m, int fb, int make, int fd)
496 int i, *b, *eob, n, buf[64];
499 eob = b + sizeof(buf)/sizeof(buf[0]);
503 if (bit_test(m, i)) {
504 n = kbd_xlate(i, make, b, eob);
506 write(fd, buf, (b - buf) * sizeof(buf[0]));
518 write(fd, buf, (b - buf) * sizeof(buf[0]));
523 * Translate HID code into PS/2 code and put codes into buffer b.
524 * Returns the number of codes put in b. Return -1 if buffer has not
529 #define PUT(c, n, b, eob) \
539 kbd_xlate(int code, int make, int *b, int const *eob)
546 return (0); /* HID code is not in the table */
548 /* Handle special case - Pause/Break */
551 return (0); /* No break code */
555 if (ctrl_is_pressed) {
556 /* Break (Ctrl-Pause) */
557 PUT(0xe0, n, b, eob);
558 PUT(0x46, n, b, eob);
559 PUT(0xe0, n, b, eob);
560 PUT(0xc6, n, b, eob);
563 PUT(0xe1, n, b, eob);
564 PUT(0x1d, n, b, eob);
565 PUT(0x45, n, b, eob);
566 PUT(0xe1, n, b, eob);
567 PUT(0x9d, n, b, eob);
568 PUT(0xc5, n, b, eob);
575 if ((c = x[code]) == -1)
576 return (0); /* HID code translation is not defined */
580 PUT(0xe0, n, b, eob);
582 PUT((c & CODEMASK), n, b, eob);
583 } else if (!(c & NOBREAK)) {
585 PUT(0xe0, n, b, eob);
587 PUT((0x80|(c & CODEMASK)), n, b, eob);