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 44extern int LinuxConsoleFd; 45 46static 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 138static unsigned char at2lnx[] = 139{ 140 0x0, /* no valid scancode */ 141 0x01, /* KEY_Escape */ 0x02, /* KEY_1 */ 142 0x03, /* KEY_2 */ 0x04, /* KEY_3 */ 143 0x05, /* KEY_4 */ 0x06, /* KEY_5 */ 144 0x07, /* KEY_6 */ 0x08, /* KEY_7 */ 145 0x09, /* KEY_8 */ 0x0a, /* KEY_9 */ 146 0x0b, /* KEY_0 */ 0x0c, /* KEY_Minus */ 147 0x0d, /* KEY_Equal */ 0x0e, /* KEY_BackSpace */ 148 0x0f, /* KEY_Tab */ 0x10, /* KEY_Q */ 149 0x11, /* KEY_W */ 0x12, /* KEY_E */ 150 0x13, /* KEY_R */ 0x14, /* KEY_T */ 151 0x15, /* KEY_Y */ 0x16, /* KEY_U */ 152 0x17, /* KEY_I */ 0x18, /* KEY_O */ 153 0x19, /* KEY_P */ 0x1a, /* KEY_LBrace */ 154 0x1b, /* KEY_RBrace */ 0x1c, /* KEY_Enter */ 155 0x1d, /* KEY_LCtrl */ 0x1e, /* KEY_A */ 156 0x1f, /* KEY_S */ 0x20, /* KEY_D */ 157 0x21, /* KEY_F */ 0x22, /* KEY_G */ 158 0x23, /* KEY_H */ 0x24, /* KEY_J */ 159 0x25, /* KEY_K */ 0x26, /* KEY_L */ 160 0x27, /* KEY_SemiColon */ 0x28, /* KEY_Quote */ 161 0x29, /* KEY_Tilde */ 0x2a, /* KEY_ShiftL */ 162 0x2b, /* KEY_BSlash */ 0x2c, /* KEY_Z */ 163 0x2d, /* KEY_X */ 0x2e, /* KEY_C */ 164 0x2f, /* KEY_V */ 0x30, /* KEY_B */ 165 0x31, /* KEY_N */ 0x32, /* KEY_M */ 166 0x33, /* KEY_Comma */ 0x34, /* KEY_Period */ 167 0x35, /* KEY_Slash */ 0x36, /* KEY_ShiftR */ 168 0x37, /* KEY_KP_Multiply */ 0x38, /* KEY_Alt */ 169 0x39, /* KEY_Space */ 0x3a, /* KEY_CapsLock */ 170 0x3b, /* KEY_F1 */ 0x3c, /* KEY_F2 */ 171 0x3d, /* KEY_F3 */ 0x3e, /* KEY_F4 */ 172 0x3f, /* KEY_F5 */ 0x40, /* KEY_F6 */ 173 0x41, /* KEY_F7 */ 0x42, /* KEY_F8 */ 174 0x43, /* KEY_F9 */ 0x44, /* KEY_F10 */ 175 0x45, /* KEY_NumLock */ 0x46, /* KEY_ScrollLock */ 176 0x47, /* KEY_KP_7 */ 0x48, /* KEY_KP_8 */ 177 0x49, /* KEY_KP_9 */ 0x4a, /* KEY_KP_Minus */ 178 0x4b, /* KEY_KP_4 */ 0x4c, /* KEY_KP_5 */ 179 0x4d, /* KEY_KP_6 */ 0x4e, /* KEY_KP_Plus */ 180 0x4f, /* KEY_KP_1 */ 0x50, /* KEY_KP_2 */ 181 0x51, /* KEY_KP_3 */ 0x52, /* KEY_KP_0 */ 182 0x53, /* KEY_KP_Decimal */ 0x54, /* KEY_SysReqest */ 183 0x00, /* 0x55 */ 0x56, /* KEY_Less */ 184 0x57, /* KEY_F11 */ 0x58, /* KEY_F12 */ 185 0x66, /* KEY_Home */ 0x67, /* KEY_Up */ 186 0x68, /* KEY_PgUp */ 0x69, /* KEY_Left */ 187 0x5d, /* KEY_Begin */ 0x6a, /* KEY_Right */ 188 0x6b, /* KEY_End */ 0x6c, /* KEY_Down */ 189 0x6d, /* KEY_PgDown */ 0x6e, /* KEY_Insert */ 190 0x6f, /* KEY_Delete */ 0x60, /* KEY_KP_Enter */ 191 0x61, /* KEY_RCtrl */ 0x77, /* KEY_Pause */ 192 0x63, /* KEY_Print */ 0x62, /* KEY_KP_Divide */ 193 0x64, /* KEY_AltLang */ 0x65, /* KEY_Break */ 194 0x00, /* KEY_LMeta */ 0x00, /* KEY_RMeta */ 195 0x7A, /* KEY_Menu/FOCUS_PF11*/0x00, /* 0x6e */ 196 0x7B, /* FOCUS_PF12 */ 0x00, /* 0x70 */ 197 0x00, /* 0x71 */ 0x00, /* 0x72 */ 198 0x59, /* FOCUS_PF2 */ 0x78, /* FOCUS_PF9 */ 199 0x00, /* 0x75 */ 0x00, /* 0x76 */ 200 0x5A, /* FOCUS_PF3 */ 0x5B, /* FOCUS_PF4 */ 201 0x5C, /* FOCUS_PF5 */ 0x5D, /* FOCUS_PF6 */ 202 0x5E, /* FOCUS_PF7 */ 0x5F, /* FOCUS_PF8 */ 203 0x7C, /* JAP_86 */ 0x79, /* FOCUS_PF10 */ 204 0x00, /* 0x7f */ 205}; 206 207#define NUM_AT_KEYS (sizeof(at2lnx)/sizeof(at2lnx[0])) 208#define LNX_KEY_INDEX(n) n < NUM_AT_KEYS ? at2lnx[n] : 0 209 210static unsigned char tbl[KD_MAX_WIDTH] = 211{ 212 0, 213 1 << KG_SHIFT, 214 (1 << KG_ALTGR), 215 (1 << KG_ALTGR) | (1 << KG_SHIFT) 216}; 217#endif 218 219static void 220readKernelMapping(KdKeyboardInfo *ki) 221{ 222#if 0 223 KeySym *k; 224 int i, j; 225 struct kbentry kbe; 226 int minKeyCode, maxKeyCode; 227 int row; 228 int fd; 229 230 if (!ki) 231 return; 232 233 fd = LinuxConsoleFd; 234 235 minKeyCode = NR_KEYS; 236 maxKeyCode = 0; 237 row = 0; 238 ki->keySyms.mapWidth = KD_MAX_WIDTH; 239 for (i = 0; i < NR_KEYS && row < KD_MAX_LENGTH; ++i) 240 { 241 kbe.kb_index = LNX_KEY_INDEX(i); 242 243 k = ki->keySyms.map + row * ki->keySyms.mapWidth; 244 245 for (j = 0; j < ki->keySyms.mapWidth; ++j) 246 { 247 unsigned short kval; 248 249 k[j] = NoSymbol; 250 251 kbe.kb_table = tbl[j]; 252 kbe.kb_value = 0; 253 if (ioctl(fd, KDGKBENT, &kbe)) 254 continue; 255 256 kval = KVAL(kbe.kb_value); 257 switch (KTYP(kbe.kb_value)) 258 { 259 case KT_LATIN: 260 case KT_LETTER: 261 k[j] = linux_to_x[kval]; 262 break; 263 264 case KT_FN: 265 if (kval <= 19) 266 k[j] = XK_F1 + kval; 267 else switch (kbe.kb_value) 268 { 269 case K_FIND: 270 k[j] = XK_Home; /* or XK_Find */ 271 break; 272 case K_INSERT: 273 k[j] = XK_Insert; 274 break; 275 case K_REMOVE: 276 k[j] = XK_Delete; 277 break; 278 case K_SELECT: 279 k[j] = XK_End; /* or XK_Select */ 280 break; 281 case K_PGUP: 282 k[j] = XK_Prior; 283 break; 284 case K_PGDN: 285 k[j] = XK_Next; 286 break; 287 case K_HELP: 288 k[j] = XK_Help; 289 break; 290 case K_DO: 291 k[j] = XK_Execute; 292 break; 293 case K_PAUSE: 294 k[j] = XK_Pause; 295 break; 296 case K_MACRO: 297 k[j] = XK_Menu; 298 break; 299 default: 300 break; 301 } 302 break; 303 304 case KT_SPEC: 305 switch (kbe.kb_value) 306 { 307 case K_ENTER: 308 k[j] = XK_Return; 309 break; 310 case K_BREAK: 311 k[j] = XK_Break; 312 break; 313 case K_CAPS: 314 k[j] = XK_Caps_Lock; 315 break; 316 case K_NUM: 317 k[j] = XK_Num_Lock; 318 break; 319 case K_HOLD: 320 k[j] = XK_Scroll_Lock; 321 break; 322 case K_COMPOSE: 323 k[j] = XK_Multi_key; 324 break; 325 default: 326 break; 327 } 328 break; 329 330 case KT_PAD: 331 switch (kbe.kb_value) 332 { 333 case K_PPLUS: 334 k[j] = XK_KP_Add; 335 break; 336 case K_PMINUS: 337 k[j] = XK_KP_Subtract; 338 break; 339 case K_PSTAR: 340 k[j] = XK_KP_Multiply; 341 break; 342 case K_PSLASH: 343 k[j] = XK_KP_Divide; 344 break; 345 case K_PENTER: 346 k[j] = XK_KP_Enter; 347 break; 348 case K_PCOMMA: 349 k[j] = XK_KP_Separator; 350 break; 351 case K_PDOT: 352 k[j] = XK_KP_Decimal; 353 break; 354 case K_PPLUSMINUS: 355 k[j] = XK_KP_Subtract; 356 break; 357 default: 358 if (kval <= 9) 359 k[j] = XK_KP_0 + kval; 360 break; 361 } 362 break; 363 364 /* 365 * KT_DEAD keys are for accelerated diacritical creation. 366 */ 367 case KT_DEAD: 368 switch (kbe.kb_value) 369 { 370 case K_DGRAVE: 371 k[j] = XK_dead_grave; 372 break; 373 case K_DACUTE: 374 k[j] = XK_dead_acute; 375 break; 376 case K_DCIRCM: 377 k[j] = XK_dead_circumflex; 378 break; 379 case K_DTILDE: 380 k[j] = XK_dead_tilde; 381 break; 382 case K_DDIERE: 383 k[j] = XK_dead_diaeresis; 384 break; 385 } 386 break; 387 388 case KT_CUR: 389 switch (kbe.kb_value) 390 { 391 case K_DOWN: 392 k[j] = XK_Down; 393 break; 394 case K_LEFT: 395 k[j] = XK_Left; 396 break; 397 case K_RIGHT: 398 k[j] = XK_Right; 399 break; 400 case K_UP: 401 k[j] = XK_Up; 402 break; 403 } 404 break; 405 406 case KT_SHIFT: 407 switch (kbe.kb_value) 408 { 409 case K_ALTGR: 410 k[j] = XK_Mode_switch; 411 break; 412 case K_ALT: 413 k[j] = (kbe.kb_index == 0x64 ? 414 XK_Alt_R : XK_Alt_L); 415 break; 416 case K_CTRL: 417 k[j] = (kbe.kb_index == 0x61 ? 418 XK_Control_R : XK_Control_L); 419 break; 420 case K_CTRLL: 421 k[j] = XK_Control_L; 422 break; 423 case K_CTRLR: 424 k[j] = XK_Control_R; 425 break; 426 case K_SHIFT: 427 k[j] = (kbe.kb_index == 0x36 ? 428 XK_Shift_R : XK_Shift_L); 429 break; 430 case K_SHIFTL: 431 k[j] = XK_Shift_L; 432 break; 433 case K_SHIFTR: 434 k[j] = XK_Shift_R; 435 break; 436 default: 437 break; 438 } 439 break; 440 441 /* 442 * KT_ASCII keys accumulate a 3 digit decimal number that gets 443 * emitted when the shift state changes. We can't emulate that. 444 */ 445 case KT_ASCII: 446 break; 447 448 case KT_LOCK: 449 if (kbe.kb_value == K_SHIFTLOCK) 450 k[j] = XK_Shift_Lock; 451 break; 452 453#ifdef KT_X 454 case KT_X: 455 /* depends on new keyboard symbols in file linux/keyboard.h */ 456 if(kbe.kb_value == K_XMENU) k[j] = XK_Menu; 457 if(kbe.kb_value == K_XTELEPHONE) k[j] = XK_telephone; 458 break; 459#endif 460#ifdef KT_XF 461 case KT_XF: 462 /* special linux keysyms which map directly to XF86 keysyms */ 463 k[j] = (kbe.kb_value & 0xFF) + 0x1008FF00; 464 break; 465#endif 466 467 default: 468 break; 469 } 470 if (i < minKeyCode) 471 minKeyCode = i; 472 if (i > maxKeyCode) 473 maxKeyCode = i; 474 } 475 476 if (minKeyCode == NR_KEYS) 477 continue; 478 479 if (k[3] == k[2]) k[3] = NoSymbol; 480 if (k[2] == k[1]) k[2] = NoSymbol; 481 if (k[1] == k[0]) k[1] = NoSymbol; 482 if (k[0] == k[2] && k[1] == k[3]) k[2] = k[3] = NoSymbol; 483 if (k[3] == k[0] && k[2] == k[1] && k[2] == NoSymbol) k[3] =NoSymbol; 484 row++; 485 } 486 ki->minScanCode = minKeyCode; 487 ki->maxScanCode = maxKeyCode; 488#endif 489} 490 491/* 492 * We need these to handle extended scancodes correctly (I could just use the 493 * numbers below, but this makes the code more readable 494 */ 495 496/* The prefix codes */ 497#define KEY_Prefix0 /* special 0x60 */ 96 498#define KEY_Prefix1 /* special 0x61 */ 97 499 500/* The raw scancodes */ 501#define KEY_Enter /* Enter 0x1c */ 28 502#define KEY_LCtrl /* Ctrl(left) 0x1d */ 29 503#define KEY_Slash /* / (Slash) ? 0x35 */ 53 504#define KEY_KP_Multiply /* * 0x37 */ 55 505#define KEY_Alt /* Alt(left) 0x38 */ 56 506#define KEY_F3 /* F3 0x3d */ 61 507#define KEY_F4 /* F4 0x3e */ 62 508#define KEY_F5 /* F5 0x3f */ 63 509#define KEY_F6 /* F6 0x40 */ 64 510#define KEY_F7 /* F7 0x41 */ 65 511#define KEY_ScrollLock /* ScrollLock 0x46 */ 70 512#define KEY_KP_7 /* 7 Home 0x47 */ 71 513#define KEY_KP_8 /* 8 Up 0x48 */ 72 514#define KEY_KP_9 /* 9 PgUp 0x49 */ 73 515#define KEY_KP_Minus /* - (Minus) 0x4a */ 74 516#define KEY_KP_4 /* 4 Left 0x4b */ 75 517#define KEY_KP_5 /* 5 0x4c */ 76 518#define KEY_KP_6 /* 6 Right 0x4d */ 77 519#define KEY_KP_Plus /* + (Plus) 0x4e */ 78 520#define KEY_KP_1 /* 1 End 0x4f */ 79 521#define KEY_KP_2 /* 2 Down 0x50 */ 80 522#define KEY_KP_3 /* 3 PgDown 0x51 */ 81 523#define KEY_KP_0 /* 0 Insert 0x52 */ 82 524#define KEY_KP_Decimal /* . (Decimal) Delete 0x53 */ 83 525#define KEY_Home /* Home 0x59 */ 89 526#define KEY_Up /* Up 0x5a */ 90 527#define KEY_PgUp /* PgUp 0x5b */ 91 528#define KEY_Left /* Left 0x5c */ 92 529#define KEY_Begin /* Begin 0x5d */ 93 530#define KEY_Right /* Right 0x5e */ 94 531#define KEY_End /* End 0x5f */ 95 532#define KEY_Down /* Down 0x60 */ 96 533#define KEY_PgDown /* PgDown 0x61 */ 97 534#define KEY_Insert /* Insert 0x62 */ 98 535#define KEY_Delete /* Delete 0x63 */ 99 536#define KEY_KP_Enter /* Enter 0x64 */ 100 537#define KEY_RCtrl /* Ctrl(right) 0x65 */ 101 538#define KEY_Pause /* Pause 0x66 */ 102 539#define KEY_Print /* Print 0x67 */ 103 540#define KEY_KP_Divide /* Divide 0x68 */ 104 541#define KEY_AltLang /* AtlLang(right) 0x69 */ 105 542#define KEY_Break /* Break 0x6a */ 106 543#define KEY_LMeta /* Left Meta 0x6b */ 107 544#define KEY_RMeta /* Right Meta 0x6c */ 108 545#define KEY_Menu /* Menu 0x6d */ 109 546#define KEY_F13 /* F13 0x6e */ 110 547#define KEY_F14 /* F14 0x6f */ 111 548#define KEY_F15 /* F15 0x70 */ 112 549#define KEY_F16 /* F16 0x71 */ 113 550#define KEY_F17 /* F17 0x72 */ 114 551#define KEY_KP_DEC /* KP_DEC 0x73 */ 115 552 553static void 554LinuxKeyboardRead (int fd, void *closure) 555{ 556 unsigned char buf[256], *b; 557 int n; 558 unsigned char prefix = 0, scancode = 0; 559 560 while ((n = read (fd, buf, sizeof (buf))) > 0) { 561 b = buf; 562 while (n--) { 563 /* 564 * With xkb we use RAW mode for reading the console, which allows us 565 * process extended scancodes. 566 * 567 * See if this is a prefix extending the following keycode 568 */ 569 if (!prefix && ((b[0] & 0x7f) == KEY_Prefix0)) 570 { 571 prefix = KEY_Prefix0; 572 /* swallow this up */ 573 b++; 574 continue; 575 } 576 else if (!prefix && ((b[0] & 0x7f) == KEY_Prefix1)) 577 { 578 prefix = KEY_Prefix1; 579 /* swallow this up */ 580 b++; 581 continue; 582 } 583 scancode = b[0] & 0x7f; 584 585 switch (prefix) { 586 /* from xf86Events.c */ 587 case KEY_Prefix0: 588 { 589 switch (scancode) { 590 case KEY_KP_7: 591 scancode = KEY_Home; break; /* curs home */ 592 case KEY_KP_8: 593 scancode = KEY_Up; break; /* curs up */ 594 case KEY_KP_9: 595 scancode = KEY_PgUp; break; /* curs pgup */ 596 case KEY_KP_4: 597 scancode = KEY_Left; break; /* curs left */ 598 case KEY_KP_5: 599 scancode = KEY_Begin; break; /* curs begin */ 600 case KEY_KP_6: 601 scancode = KEY_Right; break; /* curs right */ 602 case KEY_KP_1: 603 scancode = KEY_End; break; /* curs end */ 604 case KEY_KP_2: 605 scancode = KEY_Down; break; /* curs down */ 606 case KEY_KP_3: 607 scancode = KEY_PgDown; break; /* curs pgdown */ 608 case KEY_KP_0: 609 scancode = KEY_Insert; break; /* curs insert */ 610 case KEY_KP_Decimal: 611 scancode = KEY_Delete; break; /* curs delete */ 612 case KEY_Enter: 613 scancode = KEY_KP_Enter; break; /* keypad enter */ 614 case KEY_LCtrl: 615 scancode = KEY_RCtrl; break; /* right ctrl */ 616 case KEY_KP_Multiply: 617 scancode = KEY_Print; break; /* print */ 618 case KEY_Slash: 619 scancode = KEY_KP_Divide; break; /* keyp divide */ 620 case KEY_Alt: 621 scancode = KEY_AltLang; break; /* right alt */ 622 case KEY_ScrollLock: 623 scancode = KEY_Break; break; /* curs break */ 624 case 0x5b: 625 scancode = KEY_LMeta; break; 626 case 0x5c: 627 scancode = KEY_RMeta; break; 628 case 0x5d: 629 scancode = KEY_Menu; break; 630 case KEY_F3: 631 scancode = KEY_F13; break; 632 case KEY_F4: 633 scancode = KEY_F14; break; 634 case KEY_F5: 635 scancode = KEY_F15; break; 636 case KEY_F6: 637 scancode = KEY_F16; break; 638 case KEY_F7: 639 scancode = KEY_F17; break; 640 case KEY_KP_Plus: 641 scancode = KEY_KP_DEC; break; 642 /* Ignore virtual shifts (E0 2A, E0 AA, E0 36, E0 B6) */ 643 case 0x2A: 644 case 0x36: 645 b++; 646 prefix = 0; 647 continue; 648 default: 649 /* 650 * "Internet" keyboards are generating lots of new 651 * codes. Let them pass. There is little consistency 652 * between them, so don't bother with symbolic names at 653 * this level. 654 */ 655 scancode += 0x78; 656 } 657 break; 658 } 659 660 case KEY_Prefix1: 661 { 662 /* we do no handle these */ 663 b++; 664 prefix = 0; 665 continue; 666 } 667 668 default: /* should not happen*/ 669 case 0: /* do nothing */ 670 ; 671 } 672 673 prefix = 0; 674 KdEnqueueKeyboardEvent (closure, scancode, b[0] & 0x80); 675 b++; 676 } 677 } 678} 679 680static int LinuxKbdTrans; 681static struct termios LinuxTermios; 682 683static Status 684LinuxKeyboardEnable (KdKeyboardInfo *ki) 685{ 686 struct termios nTty; 687 unsigned char buf[256]; 688 int n; 689 int fd; 690 691 if (!ki) 692 return !Success; 693 694 fd = LinuxConsoleFd; 695 ki->driverPrivate = (void *) (intptr_t) fd; 696 697 ioctl (fd, KDGKBMODE, &LinuxKbdTrans); 698 tcgetattr (fd, &LinuxTermios); 699 ioctl(fd, KDSKBMODE, K_RAW); 700 nTty = LinuxTermios; 701 nTty.c_iflag = (IGNPAR | IGNBRK) & (~PARMRK) & (~ISTRIP); 702 nTty.c_oflag = 0; 703 nTty.c_cflag = CREAD | CS8; 704 nTty.c_lflag = 0; 705 nTty.c_cc[VTIME]=0; 706 nTty.c_cc[VMIN]=1; 707 cfsetispeed(&nTty, 9600); 708 cfsetospeed(&nTty, 9600); 709 tcsetattr(fd, TCSANOW, &nTty); 710 /* 711 * Flush any pending keystrokes 712 */ 713 while ((n = read (fd, buf, sizeof (buf))) > 0) 714 ; 715 KdRegisterFd (fd, LinuxKeyboardRead, ki); 716 return Success; 717} 718 719static void 720LinuxKeyboardDisable (KdKeyboardInfo *ki) 721{ 722 int fd; 723 724 if (!ki) 725 return; 726 727 fd = (int) (intptr_t) ki->driverPrivate; 728 729 KdUnregisterFd(ki, fd, FALSE); 730 ioctl(fd, KDSKBMODE, LinuxKbdTrans); 731 tcsetattr(fd, TCSANOW, &LinuxTermios); 732} 733 734static Status 735LinuxKeyboardInit (KdKeyboardInfo *ki) 736{ 737 if (!ki) 738 return !Success; 739 740 free(ki->path); 741 ki->path = strdup("console"); 742 free(ki->name); 743 ki->name = strdup("Linux console keyboard"); 744 745 readKernelMapping (ki); 746 747 return Success; 748} 749 750static void 751LinuxKeyboardLeds (KdKeyboardInfo *ki, int leds) 752{ 753 if (!ki) 754 return; 755 756 ioctl ((int)(intptr_t)ki->driverPrivate, KDSETLED, leds & 7); 757} 758 759KdKeyboardDriver LinuxKeyboardDriver = { 760 "keyboard", 761 .Init = LinuxKeyboardInit, 762 .Enable = LinuxKeyboardEnable, 763 .Leds = LinuxKeyboardLeds, 764 .Disable = LinuxKeyboardDisable, 765}; 766