1 /* 2 * ReactOS kernel 3 * Copyright (C) 2002 ReactOS Team 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 */ 19 /* 20 * COPYRIGHT: See COPYING in the top level directory 21 * PROJECT: ReactOS text-mode setup 22 * FILE: base/setup/usetup/keytrans.c 23 * PURPOSE: Console support functions: keyboard translation 24 * PROGRAMMER: Tinus 25 * 26 * NB: Hardcoded to US keyboard 27 */ 28 #include <usetup.h> 29 #include "keytrans.h" 30 31 #define NDEBUG 32 #include <debug.h> 33 34 static WORD KeyTable[] = { 35 /* 0x00 */ 36 0x00, VK_ESCAPE, 0x31, 0x32, 37 0x33, 0x34, 0x35, 0x36, 38 0x37, 0x38, 0x39, 0x30, 39 VK_OEM_MINUS, VK_OEM_PLUS, VK_BACK, VK_TAB, 40 /* 0x10 */ 41 0x51, 0x57, 0x45, 0x52, 42 0x54, 0x59, 0x55, 0x49, 43 0x4f, 0x50, VK_OEM_4, VK_OEM_6, 44 VK_RETURN, VK_CONTROL, 0x41, 0x53, 45 /* 0x20 */ 46 0x44, 0x46, 0x47, 0x48, 47 0x4a, 0x4b, 0x4c, VK_OEM_1, 48 VK_OEM_7, 0xc0, VK_LSHIFT, VK_OEM_5, 49 0x5a, 0x58, 0x43, 0x56, 50 /* 0x30 */ 51 0x42, 0x4e, 0x4d, VK_OEM_COMMA, 52 VK_OEM_PERIOD, VK_OEM_2, VK_RSHIFT, VK_MULTIPLY, 53 VK_LMENU, VK_SPACE, VK_CAPITAL, VK_F1, 54 VK_F2, VK_F3, VK_F4, VK_F5, 55 /* 0x40 */ 56 VK_F6, VK_F7, VK_F8, VK_F9, 57 VK_F10, VK_NUMLOCK, VK_SCROLL, VK_HOME, 58 VK_UP, VK_PRIOR, VK_SUBTRACT, VK_LEFT, 59 0, VK_RIGHT, VK_ADD, VK_END, 60 /* 0x50 */ 61 VK_DOWN, VK_NEXT, VK_INSERT, VK_DELETE, 62 0, 0, 0, VK_F11, 63 VK_F12, 0, 0, 0, 64 0, 0, 0, 0, 65 /* 0x60 */ 66 0, 0, 0, 0, 67 0, 0, 0, 0, 68 0, 0, 0, 0, 69 0, 0, 0, 0, 70 /* 0x70 */ 71 0, 0, 0, 0, 72 0, 0, 0, 0, 73 0, 0, 0, 0, 74 0, 0, 0, 0 75 }; 76 77 static WORD KeyTableEnhanced[] = { 78 /* 0x00 */ 79 0, 0, 0, 0, 80 0, 0, 0, 0, 81 0, 0, 0, 0, 82 0, 0, 0, 0, 83 /* 0x10 */ 84 0, 0, 0, 0, 85 0, 0, 0, 0, 86 0, 0, 0, 0, 87 VK_RETURN, VK_RCONTROL, 0, 0, 88 /* 0x20 */ 89 0, 0, 0, 0, 90 0, 0, 0, 0, 91 0, 0, 0, 0, 92 0, 0, 0, 0, 93 /* 0x30 */ 94 0, 0, 0, 0, 95 0, VK_DIVIDE, 0, VK_SNAPSHOT, 96 VK_RMENU, 0, 0, 0, 97 0, 0, 0, 0, 98 /* 0x40 */ 99 0, 0, 0, 0, 100 0, 0, 0, VK_HOME, 101 VK_UP, VK_PRIOR, 0, VK_LEFT, 102 0, VK_RIGHT, 0, VK_END, 103 /* 0x50 */ 104 VK_DOWN, VK_NEXT, VK_INSERT, VK_DELETE, 105 0, 0, 0, 0, 106 0, 0, 0, 0, 107 0, 0, 0, 0, 108 /* 0x60 */ 109 0, 0, 0, 0, 110 0, 0, 0, 0, 111 0, 0, 0, 0, 112 0, 0, 0, 0, 113 /* 0x70 */ 114 0, 0, 0, 0, 115 0, 0, 0, 0, 116 0, 0, 0, 0, 117 0, 0, 0, 0 118 }; 119 120 static WORD KeyTableNumlock[] = { 121 /* 0x00 */ 122 0, 0, 0, 0, 123 0, 0, 0, 0, 124 0, 0, 0, 0, 125 0, 0, 0, 0, 126 /* 0x10 */ 127 0, 0, 0, 0, 128 0, 0, 0, 0, 129 0, 0, 0, 0, 130 0, 0, 0, 0, 131 /* 0x20 */ 132 0, 0, 0, 0, 133 0, 0, 0, 0, 134 0, 0, 0, 0, 135 0, 0, 0, 0, 136 /* 0x30 */ 137 0, 0, 0, 0, 138 0, 0, 0, 0, 139 0, 0, 0, 0, 140 0, 0, 0, 0, 141 /* 0x40 */ 142 0, 0, 0, 0, 143 0, 0, 0, VK_NUMPAD7, 144 VK_NUMPAD8, VK_NUMPAD9, 0, VK_NUMPAD4, 145 VK_NUMPAD5, VK_NUMPAD6, 0, VK_NUMPAD1, 146 /* 0x50 */ 147 VK_NUMPAD2, VK_NUMPAD3, VK_NUMPAD0, 0, 148 0, 0, 0, 0, 149 0, 0, 0, 0, 150 0, 0, 0, 0, 151 /* 0x60 */ 152 0, 0, 0, 0, 153 0, 0, 0, 0, 154 0, 0, 0, 0, 155 0, 0, 0, 0, 156 /* 0x70 */ 157 0, 0, 0, 0, 158 0, 0, 0, 0, 159 0, 0, 0, 0, 160 0, 0, 0, 0 161 }; 162 163 typedef struct _SCANTOASCII { 164 USHORT ScanCode; 165 USHORT Enhanced; 166 UCHAR Normal; 167 UCHAR Shift; 168 UCHAR NumLock; 169 UCHAR bCAPS; 170 } SCANTOASCII, *PSCANTOASCII; 171 172 SCANTOASCII ScanToAscii[] = { 173 { 0x1e, 0, 'a', 'A', 0, TRUE }, 174 { 0x30, 0, 'b', 'B', 0, TRUE }, 175 { 0x2e, 0, 'c', 'C', 0, TRUE }, 176 { 0x20, 0, 'd', 'D', 0, TRUE }, 177 { 0x12, 0, 'e', 'E', 0, TRUE }, 178 { 0x21, 0, 'f', 'F', 0, TRUE }, 179 { 0x22, 0, 'g', 'G', 0, TRUE }, 180 { 0x23, 0, 'h', 'H', 0, TRUE }, 181 { 0x17, 0, 'i', 'I', 0, TRUE }, 182 { 0x24, 0, 'j', 'J', 0, TRUE }, 183 { 0x25, 0, 'k', 'K', 0, TRUE }, 184 { 0x26, 0, 'l', 'L', 0, TRUE }, 185 { 0x32, 0, 'm', 'M', 0, TRUE }, 186 { 0x31, 0, 'n', 'N', 0, TRUE }, 187 { 0x18, 0, 'o', 'O', 0, TRUE }, 188 { 0x19, 0, 'p', 'P', 0, TRUE }, 189 { 0x10, 0, 'q', 'Q', 0, TRUE }, 190 { 0x13, 0, 'r', 'R', 0, TRUE }, 191 { 0x1f, 0, 's', 'S', 0, TRUE }, 192 { 0x14, 0, 't', 'T', 0, TRUE }, 193 { 0x16, 0, 'u', 'U', 0, TRUE }, 194 { 0x2f, 0, 'v', 'V', 0, TRUE }, 195 { 0x11, 0, 'w', 'W', 0, TRUE }, 196 { 0x2d, 0, 'x', 'X', 0, TRUE }, 197 { 0x15, 0, 'y', 'Y', 0, TRUE }, 198 { 0x2c, 0, 'z', 'Z', 0, TRUE }, 199 200 { 0x02, 0, '1', '!', 0, FALSE }, 201 { 0x03, 0, '2', '@', 0, FALSE }, 202 { 0x04, 0, '3', '#', 0, FALSE }, 203 { 0x05, 0, '4', '$', 0, FALSE }, 204 { 0x06, 0, '5', '%', 0, FALSE }, 205 { 0x07, 0, '6', '^', 0, FALSE }, 206 { 0x08, 0, '7', '&', 0, FALSE }, 207 { 0x09, 0, '8', '*', 0, FALSE }, 208 { 0x0a, 0, '9', '(', 0, FALSE }, 209 { 0x0b, 0, '0', ')', 0, FALSE }, 210 211 { 0x29, 0, '\'', '~', 0, FALSE }, 212 { 0x0c, 0, '-', '_', 0, FALSE }, 213 { 0x0d, 0, '=', '+', 0, FALSE }, 214 { 0x1a, 0, '[', '{', 0, FALSE }, 215 { 0x1b, 0, ']', '}', 0, FALSE }, 216 { 0x2b, 0, '\\', '|', 0, FALSE }, 217 { 0x27, 0, ';', ':', 0, FALSE }, 218 { 0x28, 0, '\'', '"', 0, FALSE }, 219 { 0x33, 0, ',', '<', 0, FALSE }, 220 { 0x34, 0, '.', '>', 0, FALSE }, 221 { 0x35, 0, '/', '?', 0, FALSE }, 222 223 { 0x4f, 0, 0, 0, '1', FALSE }, 224 { 0x50, 0, 0, 0, '2', FALSE }, 225 { 0x51, 0, 0, 0, '3', FALSE }, 226 { 0x4b, 0, 0, 0, '4', FALSE }, 227 { 0x4c, 0, 0, 0, '5', FALSE }, 228 { 0x4d, 0, 0, 0, '6', FALSE }, 229 { 0x47, 0, 0, 0, '7', FALSE }, 230 { 0x48, 0, 0, 0, '8', FALSE }, 231 { 0x49, 0, 0, 0, '9', FALSE }, 232 { 0x52, 0, 0, 0, '0', FALSE }, 233 234 { 0x4a, 0, '-', '-', 0, FALSE }, 235 { 0x4e, 0, '+', '+', 0, FALSE }, 236 { 0x37, 0, '*', '*', 0, FALSE }, 237 { 0x35, 1, '/', '/', 0, FALSE }, 238 { 0x53, 0, 0, 0, '.', FALSE }, 239 240 { 0x39, 0, ' ', ' ', 0, FALSE }, 241 242 { 0x1c, 0, '\r', '\r', 0, FALSE }, 243 { 0x1c, 1, '\r', '\r', 0, FALSE }, 244 { 0x0e, 0, 0x08, 0x08, 0, FALSE }, /* backspace */ 245 246 { 0, 0, 0, 0, 0, FALSE } 247 }; 248 249 250 static void 251 IntUpdateControlKeyState(HANDLE hConsoleInput, LPDWORD State, PKEYBOARD_INPUT_DATA InputData) 252 { 253 DWORD Value = 0; 254 DWORD oldState, newState; 255 256 if (InputData->Flags & KEY_E1) /* Only the pause key has E1 */ 257 return; 258 259 oldState = newState = *State; 260 261 if (!(InputData->Flags & KEY_E0)) { 262 switch (InputData->MakeCode) { 263 case 0x2a: 264 case 0x36: 265 Value = SHIFT_PRESSED; 266 break; 267 268 case 0x1d: 269 Value = LEFT_CTRL_PRESSED; 270 break; 271 272 case 0x38: 273 Value = LEFT_ALT_PRESSED; 274 break; 275 276 case 0x3A: 277 if (!(InputData->Flags & KEY_BREAK)) 278 newState ^= CAPSLOCK_ON; 279 break; 280 281 case 0x45: 282 if (!(InputData->Flags & KEY_BREAK)) 283 newState ^= NUMLOCK_ON; 284 break; 285 286 case 0x46: 287 if (!(InputData->Flags & KEY_BREAK)) 288 newState ^= SCROLLLOCK_ON; 289 break; 290 291 default: 292 return; 293 } 294 } else { 295 switch (InputData->MakeCode) { 296 case 0x1d: 297 Value = RIGHT_CTRL_PRESSED; 298 break; 299 300 case 0x38: 301 Value = RIGHT_ALT_PRESSED; 302 break; 303 304 default: 305 return; 306 } 307 } 308 309 /* Check if the state of the indicators has been changed */ 310 if ((oldState ^ newState) & (NUMLOCK_ON | CAPSLOCK_ON | SCROLLLOCK_ON)) 311 { 312 IO_STATUS_BLOCK IoStatusBlock; 313 NTSTATUS Status; 314 KEYBOARD_INDICATOR_PARAMETERS kip; 315 316 kip.LedFlags = 0; 317 kip.UnitId = 0; 318 319 if ((newState & NUMLOCK_ON)) 320 kip.LedFlags |= KEYBOARD_NUM_LOCK_ON; 321 322 if ((newState & CAPSLOCK_ON)) 323 kip.LedFlags |= KEYBOARD_CAPS_LOCK_ON; 324 325 if ((newState & SCROLLLOCK_ON)) 326 kip.LedFlags |= KEYBOARD_SCROLL_LOCK_ON; 327 328 /* Update the state of the leds on primary keyboard */ 329 DPRINT("NtDeviceIoControlFile dwLeds=%x\n", kip.LedFlags); 330 331 Status = NtDeviceIoControlFile( 332 hConsoleInput, 333 NULL, 334 NULL, 335 NULL, 336 &IoStatusBlock, 337 IOCTL_KEYBOARD_SET_INDICATORS, 338 &kip, 339 sizeof(kip), 340 NULL, 341 0); 342 343 if (!NT_SUCCESS(Status)) 344 { 345 DPRINT1("NtDeviceIoControlFile(IOCTL_KEYBOARD_SET_INDICATORS) failed (Status %lx)\n", Status); 346 } 347 } else 348 /* Normal press/release state handling */ 349 if (InputData->Flags & KEY_BREAK) 350 newState &= ~Value; 351 else 352 newState |= Value; 353 354 *State = newState; 355 } 356 357 static DWORD 358 IntVKFromKbdInput(PKEYBOARD_INPUT_DATA InputData, DWORD KeyState) 359 { 360 if (!(KeyState & ENHANCED_KEY)) { 361 if ((KeyState & NUMLOCK_ON) && 362 KeyTableNumlock[InputData->MakeCode & 0x7f]) { 363 DPRINT("Numlock, using %x\n", 364 InputData->MakeCode & 0x7f); 365 return KeyTableNumlock[InputData->MakeCode & 0x7f]; 366 } 367 DPRINT("Not enhanced, using %x\n", InputData->MakeCode & 0x7f); 368 return KeyTable[InputData->MakeCode & 0x7f]; 369 } 370 371 DPRINT("Enhanced, using %x\n", InputData->MakeCode & 0x7f); 372 return KeyTableEnhanced[InputData->MakeCode & 0x7f]; 373 } 374 375 static UCHAR 376 IntAsciiFromInput(PKEYBOARD_INPUT_DATA InputData, DWORD KeyState) 377 { 378 UINT Counter = 0; 379 USHORT Enhanced = 0; 380 381 if (KeyState & ENHANCED_KEY) Enhanced = 1; 382 383 while (ScanToAscii[Counter].ScanCode != 0) { 384 if ((ScanToAscii[Counter].ScanCode == InputData->MakeCode) && 385 (ScanToAscii[Counter].Enhanced == Enhanced)) { 386 if (ScanToAscii[Counter].NumLock) { 387 if ((KeyState & NUMLOCK_ON) && 388 !(KeyState & SHIFT_PRESSED)) { 389 return ScanToAscii[Counter].NumLock; 390 } else { 391 return ScanToAscii[Counter].Normal; 392 } 393 } 394 395 if ((KeyState & CAPSLOCK_ON) && ScanToAscii[Counter].bCAPS) 396 KeyState ^= SHIFT_PRESSED; 397 398 if (KeyState & SHIFT_PRESSED) 399 return ScanToAscii[Counter].Shift; 400 401 return ScanToAscii[Counter].Normal; 402 } 403 Counter++; 404 } 405 406 return 0; 407 } 408 409 /* This is going to be quick and messy. The usetup app runs in native mode 410 * so it cannot use the translation routines in win32k which means it'll have 411 * to be done here too. 412 * 413 * Only the bKeyDown, AsciiChar and wVirtualKeyCode members are used 414 * in the app so I'll just fill the others with somewhat sane values 415 */ 416 NTSTATUS 417 IntTranslateKey(HANDLE hConsoleInput, PKEYBOARD_INPUT_DATA InputData, KEY_EVENT_RECORD *Event) 418 { 419 static DWORD dwControlKeyState; 420 421 RtlZeroMemory(Event, sizeof(KEY_EVENT_RECORD)); 422 423 if (!(InputData->Flags & KEY_BREAK)) 424 Event->bKeyDown = TRUE; 425 else 426 Event->bKeyDown = FALSE; 427 428 Event->wRepeatCount = 1; 429 Event->wVirtualScanCode = InputData->MakeCode; 430 431 DPRINT("Translating: %x\n", InputData->MakeCode); 432 433 IntUpdateControlKeyState(hConsoleInput, &dwControlKeyState, InputData); 434 Event->dwControlKeyState = dwControlKeyState; 435 436 if (InputData->Flags & KEY_E0) 437 Event->dwControlKeyState |= ENHANCED_KEY; 438 439 Event->wVirtualKeyCode = IntVKFromKbdInput(InputData, 440 Event->dwControlKeyState); 441 442 DPRINT("Result: %x\n", Event->wVirtualKeyCode); 443 444 if (Event->bKeyDown) { 445 Event->uChar.AsciiChar = 446 IntAsciiFromInput(InputData, 447 Event->dwControlKeyState); 448 DPRINT("Char: %x\n", Event->uChar.AsciiChar); 449 } else { 450 Event->uChar.AsciiChar = 0; 451 } 452 453 return STATUS_SUCCESS; 454 } 455