Commit | Line | Data |
---|---|---|
a09e091a JB |
1 | /* |
2 | * Copyright © 1999 Keith Packard | |
3 | * XKB integration © 2006 Nokia Corporation, author: Tomas Frydrych <tf@o-hand.com> | |
4 | * | |
5 | * LinuxKeyboardRead() XKB code based on xf86KbdLnx.c: | |
6 | * Copyright © 1990,91 by Thomas Roell, Dinkelscherben, Germany. | |
7 | * Copyright © 1994-2001 by The XFree86 Project, Inc. | |
8 | * | |
9 | * Permission is hereby granted, free of charge, to any person obtaining a | |
10 | * copy of this software and associated documentation files (the "Software"), | |
11 | * to deal in the Software without restriction, including without limitation | |
12 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
13 | * and/or sell copies of the Software, and to permit persons to whom the | |
14 | * Software is furnished to do so, subject to the following conditions: | |
15 | * | |
16 | * The above copyright notice and this permission notice shall be included in | |
17 | * all copies or substantial portions of the Software. | |
18 | * | |
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
22 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | |
23 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |
24 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
25 | * OTHER DEALINGS IN THE SOFTWARE. | |
26 | * | |
27 | * Except as contained in this notice, the name of the copyright holder(s) | |
28 | * and author(s) shall not be used in advertising or otherwise to promote | |
29 | * the sale, use or other dealings in this Software without prior written | |
30 | * authorization from the copyright holder(s) and author(s). | |
31 | */ | |
32 | ||
33 | #ifdef HAVE_CONFIG_H | |
34 | #include <kdrive-config.h> | |
35 | #endif | |
36 | #include "kdrive.h" | |
37 | #include <linux/keyboard.h> | |
38 | #include <linux/kd.h> | |
39 | #define XK_PUBLISHING | |
40 | #include <X11/keysym.h> | |
41 | #include <termios.h> | |
42 | #include <sys/ioctl.h> | |
43 | ||
44 | extern int LinuxConsoleFd; | |
45 | ||
46 | static const KeySym linux_to_x[256] = { | |
47 | NoSymbol, NoSymbol, NoSymbol, NoSymbol, | |
48 | NoSymbol, NoSymbol, NoSymbol, NoSymbol, | |
49 | XK_BackSpace, XK_Tab, XK_Linefeed, NoSymbol, | |
50 | NoSymbol, NoSymbol, NoSymbol, NoSymbol, | |
51 | NoSymbol, NoSymbol, NoSymbol, NoSymbol, | |
52 | NoSymbol, NoSymbol, NoSymbol, NoSymbol, | |
53 | NoSymbol, NoSymbol, NoSymbol, XK_Escape, | |
54 | NoSymbol, NoSymbol, NoSymbol, NoSymbol, | |
55 | XK_space, XK_exclam, XK_quotedbl, XK_numbersign, | |
56 | XK_dollar, XK_percent, XK_ampersand, XK_apostrophe, | |
57 | XK_parenleft, XK_parenright, XK_asterisk, XK_plus, | |
58 | XK_comma, XK_minus, XK_period, XK_slash, | |
59 | XK_0, XK_1, XK_2, XK_3, | |
60 | XK_4, XK_5, XK_6, XK_7, | |
61 | XK_8, XK_9, XK_colon, XK_semicolon, | |
62 | XK_less, XK_equal, XK_greater, XK_question, | |
63 | XK_at, XK_A, XK_B, XK_C, | |
64 | XK_D, XK_E, XK_F, XK_G, | |
65 | XK_H, XK_I, XK_J, XK_K, | |
66 | XK_L, XK_M, XK_N, XK_O, | |
67 | XK_P, XK_Q, XK_R, XK_S, | |
68 | XK_T, XK_U, XK_V, XK_W, | |
69 | XK_X, XK_Y, XK_Z, XK_bracketleft, | |
70 | XK_backslash, XK_bracketright, XK_asciicircum, XK_underscore, | |
71 | XK_grave, XK_a, XK_b, XK_c, | |
72 | XK_d, XK_e, XK_f, XK_g, | |
73 | XK_h, XK_i, XK_j, XK_k, | |
74 | XK_l, XK_m, XK_n, XK_o, | |
75 | XK_p, XK_q, XK_r, XK_s, | |
76 | XK_t, XK_u, XK_v, XK_w, | |
77 | XK_x, XK_y, XK_z, XK_braceleft, | |
78 | XK_bar, XK_braceright, XK_asciitilde, XK_BackSpace, | |
79 | NoSymbol, NoSymbol, NoSymbol, NoSymbol, | |
80 | NoSymbol, NoSymbol, NoSymbol, NoSymbol, | |
81 | NoSymbol, NoSymbol, NoSymbol, NoSymbol, | |
82 | NoSymbol, NoSymbol, NoSymbol, NoSymbol, | |
83 | NoSymbol, NoSymbol, NoSymbol, NoSymbol, | |
84 | NoSymbol, NoSymbol, NoSymbol, NoSymbol, | |
85 | NoSymbol, NoSymbol, NoSymbol, NoSymbol, | |
86 | NoSymbol, NoSymbol, NoSymbol, NoSymbol, | |
87 | XK_nobreakspace, XK_exclamdown, XK_cent, XK_sterling, | |
88 | XK_currency, XK_yen, XK_brokenbar, XK_section, | |
89 | XK_diaeresis, XK_copyright, XK_ordfeminine, XK_guillemotleft, | |
90 | XK_notsign, XK_hyphen, XK_registered, XK_macron, | |
91 | XK_degree, XK_plusminus, XK_twosuperior, XK_threesuperior, | |
92 | XK_acute, XK_mu, XK_paragraph, XK_periodcentered, | |
93 | XK_cedilla, XK_onesuperior, XK_masculine, XK_guillemotright, | |
94 | XK_onequarter, XK_onehalf, XK_threequarters, XK_questiondown, | |
95 | XK_Agrave, XK_Aacute, XK_Acircumflex, XK_Atilde, | |
96 | XK_Adiaeresis, XK_Aring, XK_AE, XK_Ccedilla, | |
97 | XK_Egrave, XK_Eacute, XK_Ecircumflex, XK_Ediaeresis, | |
98 | XK_Igrave, XK_Iacute, XK_Icircumflex, XK_Idiaeresis, | |
99 | XK_ETH, XK_Ntilde, XK_Ograve, XK_Oacute, | |
100 | XK_Ocircumflex, XK_Otilde, XK_Odiaeresis, XK_multiply, | |
101 | XK_Ooblique, XK_Ugrave, XK_Uacute, XK_Ucircumflex, | |
102 | XK_Udiaeresis, XK_Yacute, XK_THORN, XK_ssharp, | |
103 | XK_agrave, XK_aacute, XK_acircumflex, XK_atilde, | |
104 | XK_adiaeresis, XK_aring, XK_ae, XK_ccedilla, | |
105 | XK_egrave, XK_eacute, XK_ecircumflex, XK_ediaeresis, | |
106 | XK_igrave, XK_iacute, XK_icircumflex, XK_idiaeresis, | |
107 | XK_eth, XK_ntilde, XK_ograve, XK_oacute, | |
108 | XK_ocircumflex, XK_otilde, XK_odiaeresis, XK_division, | |
109 | XK_oslash, XK_ugrave, XK_uacute, XK_ucircumflex, | |
110 | XK_udiaeresis, XK_yacute, XK_thorn, XK_ydiaeresis | |
111 | }; | |
112 | ||
113 | /* | |
114 | * Getting a keycode from scancode | |
115 | * | |
116 | * With XKB | |
117 | * -------- | |
118 | * | |
119 | * We have to enqueue keyboard events using standard X keycodes which correspond | |
120 | * to AT scancode + 8; this means that we need to translate the Linux scancode | |
121 | * provided by the kernel to an AT scancode -- this translation is not linear | |
122 | * and requires that we use a LUT. | |
123 | * | |
124 | * | |
125 | * Without XKB | |
126 | * ----------- | |
127 | * | |
128 | * We can use custom keycodes, which makes things simpler; we define our custom | |
129 | * keycodes as Linux scancodes + KD_KEY_OFFSET | |
130 | */ | |
131 | ||
132 | /* | |
133 | This LUT translates AT scancodes into Linux ones -- the keymap we create | |
134 | for the core X keyboard protocol has to be AT-scancode based so that it | |
135 | corresponds to the Xkb keymap. | |
136 | */ | |
137 | #if 0 | |
138 | static unsigned char at2lnx[] = { | |
139 | 0x0, /* no valid scancode */ | |
140 | 0x01, /* KEY_Escape */ 0x02, /* KEY_1 */ | |
141 | 0x03, /* KEY_2 */ 0x04, /* KEY_3 */ | |
142 | 0x05, /* KEY_4 */ 0x06, /* KEY_5 */ | |
143 | 0x07, /* KEY_6 */ 0x08, /* KEY_7 */ | |
144 | 0x09, /* KEY_8 */ 0x0a, /* KEY_9 */ | |
145 | 0x0b, /* KEY_0 */ 0x0c, /* KEY_Minus */ | |
146 | 0x0d, /* KEY_Equal */ 0x0e, /* KEY_BackSpace */ | |
147 | 0x0f, /* KEY_Tab */ 0x10, /* KEY_Q */ | |
148 | 0x11, /* KEY_W */ 0x12, /* KEY_E */ | |
149 | 0x13, /* KEY_R */ 0x14, /* KEY_T */ | |
150 | 0x15, /* KEY_Y */ 0x16, /* KEY_U */ | |
151 | 0x17, /* KEY_I */ 0x18, /* KEY_O */ | |
152 | 0x19, /* KEY_P */ 0x1a, /* KEY_LBrace */ | |
153 | 0x1b, /* KEY_RBrace */ 0x1c, /* KEY_Enter */ | |
154 | 0x1d, /* KEY_LCtrl */ 0x1e, /* KEY_A */ | |
155 | 0x1f, /* KEY_S */ 0x20, /* KEY_D */ | |
156 | 0x21, /* KEY_F */ 0x22, /* KEY_G */ | |
157 | 0x23, /* KEY_H */ 0x24, /* KEY_J */ | |
158 | 0x25, /* KEY_K */ 0x26, /* KEY_L */ | |
159 | 0x27, /* KEY_SemiColon */ 0x28, /* KEY_Quote */ | |
160 | 0x29, /* KEY_Tilde */ 0x2a, /* KEY_ShiftL */ | |
161 | 0x2b, /* KEY_BSlash */ 0x2c, /* KEY_Z */ | |
162 | 0x2d, /* KEY_X */ 0x2e, /* KEY_C */ | |
163 | 0x2f, /* KEY_V */ 0x30, /* KEY_B */ | |
164 | 0x31, /* KEY_N */ 0x32, /* KEY_M */ | |
165 | 0x33, /* KEY_Comma */ 0x34, /* KEY_Period */ | |
166 | 0x35, /* KEY_Slash */ 0x36, /* KEY_ShiftR */ | |
167 | 0x37, /* KEY_KP_Multiply */ 0x38, /* KEY_Alt */ | |
168 | 0x39, /* KEY_Space */ 0x3a, /* KEY_CapsLock */ | |
169 | 0x3b, /* KEY_F1 */ 0x3c, /* KEY_F2 */ | |
170 | 0x3d, /* KEY_F3 */ 0x3e, /* KEY_F4 */ | |
171 | 0x3f, /* KEY_F5 */ 0x40, /* KEY_F6 */ | |
172 | 0x41, /* KEY_F7 */ 0x42, /* KEY_F8 */ | |
173 | 0x43, /* KEY_F9 */ 0x44, /* KEY_F10 */ | |
174 | 0x45, /* KEY_NumLock */ 0x46, /* KEY_ScrollLock */ | |
175 | 0x47, /* KEY_KP_7 */ 0x48, /* KEY_KP_8 */ | |
176 | 0x49, /* KEY_KP_9 */ 0x4a, /* KEY_KP_Minus */ | |
177 | 0x4b, /* KEY_KP_4 */ 0x4c, /* KEY_KP_5 */ | |
178 | 0x4d, /* KEY_KP_6 */ 0x4e, /* KEY_KP_Plus */ | |
179 | 0x4f, /* KEY_KP_1 */ 0x50, /* KEY_KP_2 */ | |
180 | 0x51, /* KEY_KP_3 */ 0x52, /* KEY_KP_0 */ | |
181 | 0x53, /* KEY_KP_Decimal */ 0x54, /* KEY_SysReqest */ | |
182 | 0x00, /* 0x55 */ 0x56, /* KEY_Less */ | |
183 | 0x57, /* KEY_F11 */ 0x58, /* KEY_F12 */ | |
184 | 0x66, /* KEY_Home */ 0x67, /* KEY_Up */ | |
185 | 0x68, /* KEY_PgUp */ 0x69, /* KEY_Left */ | |
186 | 0x5d, /* KEY_Begin */ 0x6a, /* KEY_Right */ | |
187 | 0x6b, /* KEY_End */ 0x6c, /* KEY_Down */ | |
188 | 0x6d, /* KEY_PgDown */ 0x6e, /* KEY_Insert */ | |
189 | 0x6f, /* KEY_Delete */ 0x60, /* KEY_KP_Enter */ | |
190 | 0x61, /* KEY_RCtrl */ 0x77, /* KEY_Pause */ | |
191 | 0x63, /* KEY_Print */ 0x62, /* KEY_KP_Divide */ | |
192 | 0x64, /* KEY_AltLang */ 0x65, /* KEY_Break */ | |
193 | 0x00, /* KEY_LMeta */ 0x00, /* KEY_RMeta */ | |
194 | 0x7A, /* KEY_Menu/FOCUS_PF11 */ 0x00, /* 0x6e */ | |
195 | 0x7B, /* FOCUS_PF12 */ 0x00, /* 0x70 */ | |
196 | 0x00, /* 0x71 */ 0x00, /* 0x72 */ | |
197 | 0x59, /* FOCUS_PF2 */ 0x78, /* FOCUS_PF9 */ | |
198 | 0x00, /* 0x75 */ 0x00, /* 0x76 */ | |
199 | 0x5A, /* FOCUS_PF3 */ 0x5B, /* FOCUS_PF4 */ | |
200 | 0x5C, /* FOCUS_PF5 */ 0x5D, /* FOCUS_PF6 */ | |
201 | 0x5E, /* FOCUS_PF7 */ 0x5F, /* FOCUS_PF8 */ | |
202 | 0x7C, /* JAP_86 */ 0x79, /* FOCUS_PF10 */ | |
203 | 0x00, /* 0x7f */ | |
204 | }; | |
205 | ||
206 | #define NUM_AT_KEYS (sizeof(at2lnx)/sizeof(at2lnx[0])) | |
207 | #define LNX_KEY_INDEX(n) n < NUM_AT_KEYS ? at2lnx[n] : 0 | |
208 | ||
209 | static unsigned char tbl[KD_MAX_WIDTH] = { | |
210 | 0, | |
211 | 1 << KG_SHIFT, | |
212 | (1 << KG_ALTGR), | |
213 | (1 << KG_ALTGR) | (1 << KG_SHIFT) | |
214 | }; | |
215 | #endif | |
216 | ||
217 | static void | |
218 | readKernelMapping(KdKeyboardInfo * ki) | |
219 | { | |
220 | #if 0 | |
221 | KeySym *k; | |
222 | int i, j; | |
223 | struct kbentry kbe; | |
224 | int minKeyCode, maxKeyCode; | |
225 | int row; | |
226 | int fd; | |
227 | ||
228 | if (!ki) | |
229 | return; | |
230 | ||
231 | fd = LinuxConsoleFd; | |
232 | ||
233 | minKeyCode = NR_KEYS; | |
234 | maxKeyCode = 0; | |
235 | row = 0; | |
236 | ki->keySyms.mapWidth = KD_MAX_WIDTH; | |
237 | for (i = 0; i < NR_KEYS && row < KD_MAX_LENGTH; ++i) { | |
238 | kbe.kb_index = LNX_KEY_INDEX(i); | |
239 | ||
240 | k = ki->keySyms.map + row * ki->keySyms.mapWidth; | |
241 | ||
242 | for (j = 0; j < ki->keySyms.mapWidth; ++j) { | |
243 | unsigned short kval; | |
244 | ||
245 | k[j] = NoSymbol; | |
246 | ||
247 | kbe.kb_table = tbl[j]; | |
248 | kbe.kb_value = 0; | |
249 | if (ioctl(fd, KDGKBENT, &kbe)) | |
250 | continue; | |
251 | ||
252 | kval = KVAL(kbe.kb_value); | |
253 | switch (KTYP(kbe.kb_value)) { | |
254 | case KT_LATIN: | |
255 | case KT_LETTER: | |
256 | k[j] = linux_to_x[kval]; | |
257 | break; | |
258 | ||
259 | case KT_FN: | |
260 | if (kval <= 19) | |
261 | k[j] = XK_F1 + kval; | |
262 | else | |
263 | switch (kbe.kb_value) { | |
264 | case K_FIND: | |
265 | k[j] = XK_Home; /* or XK_Find */ | |
266 | break; | |
267 | case K_INSERT: | |
268 | k[j] = XK_Insert; | |
269 | break; | |
270 | case K_REMOVE: | |
271 | k[j] = XK_Delete; | |
272 | break; | |
273 | case K_SELECT: | |
274 | k[j] = XK_End; /* or XK_Select */ | |
275 | break; | |
276 | case K_PGUP: | |
277 | k[j] = XK_Prior; | |
278 | break; | |
279 | case K_PGDN: | |
280 | k[j] = XK_Next; | |
281 | break; | |
282 | case K_HELP: | |
283 | k[j] = XK_Help; | |
284 | break; | |
285 | case K_DO: | |
286 | k[j] = XK_Execute; | |
287 | break; | |
288 | case K_PAUSE: | |
289 | k[j] = XK_Pause; | |
290 | break; | |
291 | case K_MACRO: | |
292 | k[j] = XK_Menu; | |
293 | break; | |
294 | default: | |
295 | break; | |
296 | } | |
297 | break; | |
298 | ||
299 | case KT_SPEC: | |
300 | switch (kbe.kb_value) { | |
301 | case K_ENTER: | |
302 | k[j] = XK_Return; | |
303 | break; | |
304 | case K_BREAK: | |
305 | k[j] = XK_Break; | |
306 | break; | |
307 | case K_CAPS: | |
308 | k[j] = XK_Caps_Lock; | |
309 | break; | |
310 | case K_NUM: | |
311 | k[j] = XK_Num_Lock; | |
312 | break; | |
313 | case K_HOLD: | |
314 | k[j] = XK_Scroll_Lock; | |
315 | break; | |
316 | case K_COMPOSE: | |
317 | k[j] = XK_Multi_key; | |
318 | break; | |
319 | default: | |
320 | break; | |
321 | } | |
322 | break; | |
323 | ||
324 | case KT_PAD: | |
325 | switch (kbe.kb_value) { | |
326 | case K_PPLUS: | |
327 | k[j] = XK_KP_Add; | |
328 | break; | |
329 | case K_PMINUS: | |
330 | k[j] = XK_KP_Subtract; | |
331 | break; | |
332 | case K_PSTAR: | |
333 | k[j] = XK_KP_Multiply; | |
334 | break; | |
335 | case K_PSLASH: | |
336 | k[j] = XK_KP_Divide; | |
337 | break; | |
338 | case K_PENTER: | |
339 | k[j] = XK_KP_Enter; | |
340 | break; | |
341 | case K_PCOMMA: | |
342 | k[j] = XK_KP_Separator; | |
343 | break; | |
344 | case K_PDOT: | |
345 | k[j] = XK_KP_Decimal; | |
346 | break; | |
347 | case K_PPLUSMINUS: | |
348 | k[j] = XK_KP_Subtract; | |
349 | break; | |
350 | default: | |
351 | if (kval <= 9) | |
352 | k[j] = XK_KP_0 + kval; | |
353 | break; | |
354 | } | |
355 | break; | |
356 | ||
357 | /* | |
358 | * KT_DEAD keys are for accelerated diacritical creation. | |
359 | */ | |
360 | case KT_DEAD: | |
361 | switch (kbe.kb_value) { | |
362 | case K_DGRAVE: | |
363 | k[j] = XK_dead_grave; | |
364 | break; | |
365 | case K_DACUTE: | |
366 | k[j] = XK_dead_acute; | |
367 | break; | |
368 | case K_DCIRCM: | |
369 | k[j] = XK_dead_circumflex; | |
370 | break; | |
371 | case K_DTILDE: | |
372 | k[j] = XK_dead_tilde; | |
373 | break; | |
374 | case K_DDIERE: | |
375 | k[j] = XK_dead_diaeresis; | |
376 | break; | |
377 | } | |
378 | break; | |
379 | ||
380 | case KT_CUR: | |
381 | switch (kbe.kb_value) { | |
382 | case K_DOWN: | |
383 | k[j] = XK_Down; | |
384 | break; | |
385 | case K_LEFT: | |
386 | k[j] = XK_Left; | |
387 | break; | |
388 | case K_RIGHT: | |
389 | k[j] = XK_Right; | |
390 | break; | |
391 | case K_UP: | |
392 | k[j] = XK_Up; | |
393 | break; | |
394 | } | |
395 | break; | |
396 | ||
397 | case KT_SHIFT: | |
398 | switch (kbe.kb_value) { | |
399 | case K_ALTGR: | |
400 | k[j] = XK_Mode_switch; | |
401 | break; | |
402 | case K_ALT: | |
403 | k[j] = (kbe.kb_index == 0x64 ? XK_Alt_R : XK_Alt_L); | |
404 | break; | |
405 | case K_CTRL: | |
406 | k[j] = (kbe.kb_index == 0x61 ? XK_Control_R : XK_Control_L); | |
407 | break; | |
408 | case K_CTRLL: | |
409 | k[j] = XK_Control_L; | |
410 | break; | |
411 | case K_CTRLR: | |
412 | k[j] = XK_Control_R; | |
413 | break; | |
414 | case K_SHIFT: | |
415 | k[j] = (kbe.kb_index == 0x36 ? XK_Shift_R : XK_Shift_L); | |
416 | break; | |
417 | case K_SHIFTL: | |
418 | k[j] = XK_Shift_L; | |
419 | break; | |
420 | case K_SHIFTR: | |
421 | k[j] = XK_Shift_R; | |
422 | break; | |
423 | default: | |
424 | break; | |
425 | } | |
426 | break; | |
427 | ||
428 | /* | |
429 | * KT_ASCII keys accumulate a 3 digit decimal number that gets | |
430 | * emitted when the shift state changes. We can't emulate that. | |
431 | */ | |
432 | case KT_ASCII: | |
433 | break; | |
434 | ||
435 | case KT_LOCK: | |
436 | if (kbe.kb_value == K_SHIFTLOCK) | |
437 | k[j] = XK_Shift_Lock; | |
438 | break; | |
439 | ||
440 | #ifdef KT_X | |
441 | case KT_X: | |
442 | /* depends on new keyboard symbols in file linux/keyboard.h */ | |
443 | if (kbe.kb_value == K_XMENU) | |
444 | k[j] = XK_Menu; | |
445 | if (kbe.kb_value == K_XTELEPHONE) | |
446 | k[j] = XK_telephone; | |
447 | break; | |
448 | #endif | |
449 | #ifdef KT_XF | |
450 | case KT_XF: | |
451 | /* special linux keysyms which map directly to XF86 keysyms */ | |
452 | k[j] = (kbe.kb_value & 0xFF) + 0x1008FF00; | |
453 | break; | |
454 | #endif | |
455 | ||
456 | default: | |
457 | break; | |
458 | } | |
459 | if (i < minKeyCode) | |
460 | minKeyCode = i; | |
461 | if (i > maxKeyCode) | |
462 | maxKeyCode = i; | |
463 | } | |
464 | ||
465 | if (minKeyCode == NR_KEYS) | |
466 | continue; | |
467 | ||
468 | if (k[3] == k[2]) | |
469 | k[3] = NoSymbol; | |
470 | if (k[2] == k[1]) | |
471 | k[2] = NoSymbol; | |
472 | if (k[1] == k[0]) | |
473 | k[1] = NoSymbol; | |
474 | if (k[0] == k[2] && k[1] == k[3]) | |
475 | k[2] = k[3] = NoSymbol; | |
476 | if (k[3] == k[0] && k[2] == k[1] && k[2] == NoSymbol) | |
477 | k[3] = NoSymbol; | |
478 | row++; | |
479 | } | |
480 | ki->minScanCode = minKeyCode; | |
481 | ki->maxScanCode = maxKeyCode; | |
482 | #endif | |
483 | } | |
484 | ||
485 | /* | |
486 | * We need these to handle extended scancodes correctly (I could just use the | |
487 | * numbers below, but this makes the code more readable | |
488 | */ | |
489 | ||
490 | /* The prefix codes */ | |
491 | #define KEY_Prefix0 /* special 0x60 */ 96 | |
492 | #define KEY_Prefix1 /* special 0x61 */ 97 | |
493 | ||
494 | /* The raw scancodes */ | |
495 | #define KEY_Enter /* Enter 0x1c */ 28 | |
496 | #define KEY_LCtrl /* Ctrl(left) 0x1d */ 29 | |
497 | #define KEY_Slash /* / (Slash) ? 0x35 */ 53 | |
498 | #define KEY_KP_Multiply /* * 0x37 */ 55 | |
499 | #define KEY_Alt /* Alt(left) 0x38 */ 56 | |
500 | #define KEY_F3 /* F3 0x3d */ 61 | |
501 | #define KEY_F4 /* F4 0x3e */ 62 | |
502 | #define KEY_F5 /* F5 0x3f */ 63 | |
503 | #define KEY_F6 /* F6 0x40 */ 64 | |
504 | #define KEY_F7 /* F7 0x41 */ 65 | |
505 | #define KEY_ScrollLock /* ScrollLock 0x46 */ 70 | |
506 | #define KEY_KP_7 /* 7 Home 0x47 */ 71 | |
507 | #define KEY_KP_8 /* 8 Up 0x48 */ 72 | |
508 | #define KEY_KP_9 /* 9 PgUp 0x49 */ 73 | |
509 | #define KEY_KP_Minus /* - (Minus) 0x4a */ 74 | |
510 | #define KEY_KP_4 /* 4 Left 0x4b */ 75 | |
511 | #define KEY_KP_5 /* 5 0x4c */ 76 | |
512 | #define KEY_KP_6 /* 6 Right 0x4d */ 77 | |
513 | #define KEY_KP_Plus /* + (Plus) 0x4e */ 78 | |
514 | #define KEY_KP_1 /* 1 End 0x4f */ 79 | |
515 | #define KEY_KP_2 /* 2 Down 0x50 */ 80 | |
516 | #define KEY_KP_3 /* 3 PgDown 0x51 */ 81 | |
517 | #define KEY_KP_0 /* 0 Insert 0x52 */ 82 | |
518 | #define KEY_KP_Decimal /* . (Decimal) Delete 0x53 */ 83 | |
519 | #define KEY_Home /* Home 0x59 */ 89 | |
520 | #define KEY_Up /* Up 0x5a */ 90 | |
521 | #define KEY_PgUp /* PgUp 0x5b */ 91 | |
522 | #define KEY_Left /* Left 0x5c */ 92 | |
523 | #define KEY_Begin /* Begin 0x5d */ 93 | |
524 | #define KEY_Right /* Right 0x5e */ 94 | |
525 | #define KEY_End /* End 0x5f */ 95 | |
526 | #define KEY_Down /* Down 0x60 */ 96 | |
527 | #define KEY_PgDown /* PgDown 0x61 */ 97 | |
528 | #define KEY_Insert /* Insert 0x62 */ 98 | |
529 | #define KEY_Delete /* Delete 0x63 */ 99 | |
530 | #define KEY_KP_Enter /* Enter 0x64 */ 100 | |
531 | #define KEY_RCtrl /* Ctrl(right) 0x65 */ 101 | |
532 | #define KEY_Pause /* Pause 0x66 */ 102 | |
533 | #define KEY_Print /* Print 0x67 */ 103 | |
534 | #define KEY_KP_Divide /* Divide 0x68 */ 104 | |
535 | #define KEY_AltLang /* AtlLang(right) 0x69 */ 105 | |
536 | #define KEY_Break /* Break 0x6a */ 106 | |
537 | #define KEY_LMeta /* Left Meta 0x6b */ 107 | |
538 | #define KEY_RMeta /* Right Meta 0x6c */ 108 | |
539 | #define KEY_Menu /* Menu 0x6d */ 109 | |
540 | #define KEY_F13 /* F13 0x6e */ 110 | |
541 | #define KEY_F14 /* F14 0x6f */ 111 | |
542 | #define KEY_F15 /* F15 0x70 */ 112 | |
543 | #define KEY_F16 /* F16 0x71 */ 113 | |
544 | #define KEY_F17 /* F17 0x72 */ 114 | |
545 | #define KEY_KP_DEC /* KP_DEC 0x73 */ 115 | |
546 | ||
547 | static void | |
548 | LinuxKeyboardRead(int fd, void *closure) | |
549 | { | |
550 | unsigned char buf[256], *b; | |
551 | int n; | |
552 | unsigned char prefix = 0, scancode = 0; | |
553 | ||
554 | while ((n = read(fd, buf, sizeof(buf))) > 0) { | |
555 | b = buf; | |
556 | while (n--) { | |
557 | /* | |
558 | * With xkb we use RAW mode for reading the console, which allows us | |
559 | * process extended scancodes. | |
560 | * | |
561 | * See if this is a prefix extending the following keycode | |
562 | */ | |
563 | if (!prefix && ((b[0] & 0x7f) == KEY_Prefix0)) { | |
564 | prefix = KEY_Prefix0; | |
565 | /* swallow this up */ | |
566 | b++; | |
567 | continue; | |
568 | } | |
569 | else if (!prefix && ((b[0] & 0x7f) == KEY_Prefix1)) { | |
570 | prefix = KEY_Prefix1; | |
571 | /* swallow this up */ | |
572 | b++; | |
573 | continue; | |
574 | } | |
575 | scancode = b[0] & 0x7f; | |
576 | ||
577 | switch (prefix) { | |
578 | /* from xf86Events.c */ | |
579 | case KEY_Prefix0: | |
580 | { | |
581 | switch (scancode) { | |
582 | case KEY_KP_7: | |
583 | scancode = KEY_Home; | |
584 | break; /* curs home */ | |
585 | case KEY_KP_8: | |
586 | scancode = KEY_Up; | |
587 | break; /* curs up */ | |
588 | case KEY_KP_9: | |
589 | scancode = KEY_PgUp; | |
590 | break; /* curs pgup */ | |
591 | case KEY_KP_4: | |
592 | scancode = KEY_Left; | |
593 | break; /* curs left */ | |
594 | case KEY_KP_5: | |
595 | scancode = KEY_Begin; | |
596 | break; /* curs begin */ | |
597 | case KEY_KP_6: | |
598 | scancode = KEY_Right; | |
599 | break; /* curs right */ | |
600 | case KEY_KP_1: | |
601 | scancode = KEY_End; | |
602 | break; /* curs end */ | |
603 | case KEY_KP_2: | |
604 | scancode = KEY_Down; | |
605 | break; /* curs down */ | |
606 | case KEY_KP_3: | |
607 | scancode = KEY_PgDown; | |
608 | break; /* curs pgdown */ | |
609 | case KEY_KP_0: | |
610 | scancode = KEY_Insert; | |
611 | break; /* curs insert */ | |
612 | case KEY_KP_Decimal: | |
613 | scancode = KEY_Delete; | |
614 | break; /* curs delete */ | |
615 | case KEY_Enter: | |
616 | scancode = KEY_KP_Enter; | |
617 | break; /* keypad enter */ | |
618 | case KEY_LCtrl: | |
619 | scancode = KEY_RCtrl; | |
620 | break; /* right ctrl */ | |
621 | case KEY_KP_Multiply: | |
622 | scancode = KEY_Print; | |
623 | break; /* print */ | |
624 | case KEY_Slash: | |
625 | scancode = KEY_KP_Divide; | |
626 | break; /* keyp divide */ | |
627 | case KEY_Alt: | |
628 | scancode = KEY_AltLang; | |
629 | break; /* right alt */ | |
630 | case KEY_ScrollLock: | |
631 | scancode = KEY_Break; | |
632 | break; /* curs break */ | |
633 | case 0x5b: | |
634 | scancode = KEY_LMeta; | |
635 | break; | |
636 | case 0x5c: | |
637 | scancode = KEY_RMeta; | |
638 | break; | |
639 | case 0x5d: | |
640 | scancode = KEY_Menu; | |
641 | break; | |
642 | case KEY_F3: | |
643 | scancode = KEY_F13; | |
644 | break; | |
645 | case KEY_F4: | |
646 | scancode = KEY_F14; | |
647 | break; | |
648 | case KEY_F5: | |
649 | scancode = KEY_F15; | |
650 | break; | |
651 | case KEY_F6: | |
652 | scancode = KEY_F16; | |
653 | break; | |
654 | case KEY_F7: | |
655 | scancode = KEY_F17; | |
656 | break; | |
657 | case KEY_KP_Plus: | |
658 | scancode = KEY_KP_DEC; | |
659 | break; | |
660 | /* Ignore virtual shifts (E0 2A, E0 AA, E0 36, E0 B6) */ | |
661 | case 0x2A: | |
662 | case 0x36: | |
663 | b++; | |
664 | prefix = 0; | |
665 | continue; | |
666 | default: | |
667 | /* | |
668 | * "Internet" keyboards are generating lots of new | |
669 | * codes. Let them pass. There is little consistency | |
670 | * between them, so don't bother with symbolic names at | |
671 | * this level. | |
672 | */ | |
673 | scancode += 0x78; | |
674 | } | |
675 | break; | |
676 | } | |
677 | ||
678 | case KEY_Prefix1: | |
679 | { | |
680 | /* we do no handle these */ | |
681 | b++; | |
682 | prefix = 0; | |
683 | continue; | |
684 | } | |
685 | ||
686 | default: /* should not happen */ | |
687 | case 0: /* do nothing */ | |
688 | ; | |
689 | } | |
690 | ||
691 | prefix = 0; | |
692 | KdEnqueueKeyboardEvent(closure, scancode, b[0] & 0x80); | |
693 | b++; | |
694 | } | |
695 | } | |
696 | } | |
697 | ||
698 | static int LinuxKbdTrans; | |
699 | static struct termios LinuxTermios; | |
700 | ||
701 | static Status | |
702 | LinuxKeyboardEnable(KdKeyboardInfo * ki) | |
703 | { | |
704 | struct termios nTty; | |
705 | unsigned char buf[256]; | |
706 | int n; | |
707 | int fd; | |
708 | ||
709 | if (!ki) | |
710 | return !Success; | |
711 | ||
712 | fd = LinuxConsoleFd; | |
713 | ki->driverPrivate = (void *) (intptr_t) fd; | |
714 | ||
715 | ioctl(fd, KDGKBMODE, &LinuxKbdTrans); | |
716 | tcgetattr(fd, &LinuxTermios); | |
717 | ioctl(fd, KDSKBMODE, K_RAW); | |
718 | nTty = LinuxTermios; | |
719 | nTty.c_iflag = (IGNPAR | IGNBRK) & (~PARMRK) & (~ISTRIP); | |
720 | nTty.c_oflag = 0; | |
721 | nTty.c_cflag = CREAD | CS8; | |
722 | nTty.c_lflag = 0; | |
723 | nTty.c_cc[VTIME] = 0; | |
724 | nTty.c_cc[VMIN] = 1; | |
725 | cfsetispeed(&nTty, 9600); | |
726 | cfsetospeed(&nTty, 9600); | |
727 | tcsetattr(fd, TCSANOW, &nTty); | |
728 | /* | |
729 | * Flush any pending keystrokes | |
730 | */ | |
731 | while ((n = read(fd, buf, sizeof(buf))) > 0); | |
732 | KdRegisterFd(fd, LinuxKeyboardRead, ki); | |
733 | return Success; | |
734 | } | |
735 | ||
736 | static void | |
737 | LinuxKeyboardDisable(KdKeyboardInfo * ki) | |
738 | { | |
739 | int fd; | |
740 | ||
741 | if (!ki) | |
742 | return; | |
743 | ||
744 | fd = (int) (intptr_t) ki->driverPrivate; | |
745 | ||
746 | KdUnregisterFd(ki, fd, FALSE); | |
747 | ioctl(fd, KDSKBMODE, LinuxKbdTrans); | |
748 | tcsetattr(fd, TCSANOW, &LinuxTermios); | |
749 | } | |
750 | ||
751 | static Status | |
752 | LinuxKeyboardInit(KdKeyboardInfo * ki) | |
753 | { | |
754 | if (!ki) | |
755 | return !Success; | |
756 | ||
757 | free(ki->path); | |
758 | ki->path = strdup("console"); | |
759 | free(ki->name); | |
760 | ki->name = strdup("Linux console keyboard"); | |
761 | ||
762 | readKernelMapping(ki); | |
763 | ||
764 | return Success; | |
765 | } | |
766 | ||
767 | static void | |
768 | LinuxKeyboardLeds(KdKeyboardInfo * ki, int leds) | |
769 | { | |
770 | if (!ki) | |
771 | return; | |
772 | ||
773 | ioctl((int) (intptr_t) ki->driverPrivate, KDSETLED, leds & 7); | |
774 | } | |
775 | ||
776 | KdKeyboardDriver LinuxKeyboardDriver = { | |
777 | "keyboard", | |
778 | .Init = LinuxKeyboardInit, | |
779 | .Enable = LinuxKeyboardEnable, | |
780 | .Leds = LinuxKeyboardLeds, | |
781 | .Disable = LinuxKeyboardDisable, | |
782 | }; |