Correct handling of dead_char in TryToTranslateChar.
[reactos.git] / reactos / subsys / win32k / ntuser / keyboard.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 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
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id: keyboard.c,v 1.14 2003/11/07 19:58:43 arty Exp $
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * PURPOSE: Messages
24 * FILE: subsys/win32k/ntuser/keyboard.c
25 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
26 * REVISION HISTORY:
27 * 06-06-2001 CSH Created
28 */
29
30 /* INCLUDES ******************************************************************/
31
32 #include <ddk/ntddk.h>
33 #include <win32k/win32k.h>
34 #include <internal/safe.h>
35 #include <internal/kbd.h>
36 #include <include/guicheck.h>
37 #include <include/msgqueue.h>
38 #include <include/window.h>
39 #include <include/class.h>
40 #include <include/error.h>
41 #include <include/object.h>
42 #include <include/winsta.h>
43
44 #define NDEBUG
45 #include <debug.h>
46
47 #define SYSTEMROOT_DIR L"\\SystemRoot\\System32\\"
48
49 BYTE QueueKeyStateTable[256];
50
51 /* arty -- These should be phased out for the general kbdxx.dll tables */
52
53 struct accent_char
54 {
55 BYTE ac_accent;
56 BYTE ac_char;
57 BYTE ac_result;
58 };
59
60 static const struct accent_char accent_chars[] =
61 {
62 /* A good idea should be to read /usr/X11/lib/X11/locale/iso8859-x/Compose */
63 {'`', 'A', '\300'}, {'`', 'a', '\340'},
64 {'\'', 'A', '\301'}, {'\'', 'a', '\341'},
65 {'^', 'A', '\302'}, {'^', 'a', '\342'},
66 {'~', 'A', '\303'}, {'~', 'a', '\343'},
67 {'"', 'A', '\304'}, {'"', 'a', '\344'},
68 {'O', 'A', '\305'}, {'o', 'a', '\345'},
69 {'0', 'A', '\305'}, {'0', 'a', '\345'},
70 {'A', 'A', '\305'}, {'a', 'a', '\345'},
71 {'A', 'E', '\306'}, {'a', 'e', '\346'},
72 {',', 'C', '\307'}, {',', 'c', '\347'},
73 {'`', 'E', '\310'}, {'`', 'e', '\350'},
74 {'\'', 'E', '\311'}, {'\'', 'e', '\351'},
75 {'^', 'E', '\312'}, {'^', 'e', '\352'},
76 {'"', 'E', '\313'}, {'"', 'e', '\353'},
77 {'`', 'I', '\314'}, {'`', 'i', '\354'},
78 {'\'', 'I', '\315'}, {'\'', 'i', '\355'},
79 {'^', 'I', '\316'}, {'^', 'i', '\356'},
80 {'"', 'I', '\317'}, {'"', 'i', '\357'},
81 {'-', 'D', '\320'}, {'-', 'd', '\360'},
82 {'~', 'N', '\321'}, {'~', 'n', '\361'},
83 {'`', 'O', '\322'}, {'`', 'o', '\362'},
84 {'\'', 'O', '\323'}, {'\'', 'o', '\363'},
85 {'^', 'O', '\324'}, {'^', 'o', '\364'},
86 {'~', 'O', '\325'}, {'~', 'o', '\365'},
87 {'"', 'O', '\326'}, {'"', 'o', '\366'},
88 {'/', 'O', '\330'}, {'/', 'o', '\370'},
89 {'`', 'U', '\331'}, {'`', 'u', '\371'},
90 {'\'', 'U', '\332'}, {'\'', 'u', '\372'},
91 {'^', 'U', '\333'}, {'^', 'u', '\373'},
92 {'"', 'U', '\334'}, {'"', 'u', '\374'},
93 {'\'', 'Y', '\335'}, {'\'', 'y', '\375'},
94 {'T', 'H', '\336'}, {'t', 'h', '\376'},
95 {'s', 's', '\337'}, {'"', 'y', '\377'},
96 {'s', 'z', '\337'}, {'i', 'j', '\377'},
97 /* iso-8859-2 uses this */
98 {'<', 'L', '\245'}, {'<', 'l', '\265'}, /* caron */
99 {'<', 'S', '\251'}, {'<', 's', '\271'},
100 {'<', 'T', '\253'}, {'<', 't', '\273'},
101 {'<', 'Z', '\256'}, {'<', 'z', '\276'},
102 {'<', 'C', '\310'}, {'<', 'c', '\350'},
103 {'<', 'E', '\314'}, {'<', 'e', '\354'},
104 {'<', 'D', '\317'}, {'<', 'd', '\357'},
105 {'<', 'N', '\322'}, {'<', 'n', '\362'},
106 {'<', 'R', '\330'}, {'<', 'r', '\370'},
107 {';', 'A', '\241'}, {';', 'a', '\261'}, /* ogonek */
108 {';', 'E', '\312'}, {';', 'e', '\332'},
109 {'\'', 'Z', '\254'}, {'\'', 'z', '\274'}, /* acute */
110 {'\'', 'R', '\300'}, {'\'', 'r', '\340'},
111 {'\'', 'L', '\305'}, {'\'', 'l', '\345'},
112 {'\'', 'C', '\306'}, {'\'', 'c', '\346'},
113 {'\'', 'N', '\321'}, {'\'', 'n', '\361'},
114 /* collision whith S, from iso-8859-9 !!! */
115 {',', 'S', '\252'}, {',', 's', '\272'}, /* cedilla */
116 {',', 'T', '\336'}, {',', 't', '\376'},
117 {'.', 'Z', '\257'}, {'.', 'z', '\277'}, /* dot above */
118 {'/', 'L', '\243'}, {'/', 'l', '\263'}, /* slash */
119 {'/', 'D', '\320'}, {'/', 'd', '\360'},
120 {'(', 'A', '\303'}, {'(', 'a', '\343'}, /* breve */
121 {'\275', 'O', '\325'}, {'\275', 'o', '\365'}, /* double acute */
122 {'\275', 'U', '\334'}, {'\275', 'u', '\374'},
123 {'0', 'U', '\332'}, {'0', 'u', '\372'}, /* ring above */
124 /* iso-8859-3 uses this */
125 {'/', 'H', '\241'}, {'/', 'h', '\261'}, /* slash */
126 {'>', 'H', '\246'}, {'>', 'h', '\266'}, /* circumflex */
127 {'>', 'J', '\254'}, {'>', 'j', '\274'},
128 {'>', 'C', '\306'}, {'>', 'c', '\346'},
129 {'>', 'G', '\330'}, {'>', 'g', '\370'},
130 {'>', 'S', '\336'}, {'>', 's', '\376'},
131 /* collision whith G( from iso-8859-9 !!! */
132 {'(', 'G', '\253'}, {'(', 'g', '\273'}, /* breve */
133 {'(', 'U', '\335'}, {'(', 'u', '\375'},
134 /* collision whith I. from iso-8859-3 !!! */
135 {'.', 'I', '\251'}, {'.', 'i', '\271'}, /* dot above */
136 {'.', 'C', '\305'}, {'.', 'c', '\345'},
137 {'.', 'G', '\325'}, {'.', 'g', '\365'},
138 /* iso-8859-4 uses this */
139 {',', 'R', '\243'}, {',', 'r', '\263'}, /* cedilla */
140 {',', 'L', '\246'}, {',', 'l', '\266'},
141 {',', 'G', '\253'}, {',', 'g', '\273'},
142 {',', 'N', '\321'}, {',', 'n', '\361'},
143 {',', 'K', '\323'}, {',', 'k', '\363'},
144 {'~', 'I', '\245'}, {'~', 'i', '\265'}, /* tilde */
145 {'-', 'E', '\252'}, {'-', 'e', '\272'}, /* macron */
146 {'-', 'A', '\300'}, {'-', 'a', '\340'},
147 {'-', 'I', '\317'}, {'-', 'i', '\357'},
148 {'-', 'O', '\322'}, {'-', 'o', '\362'},
149 {'-', 'U', '\336'}, {'-', 'u', '\376'},
150 {'/', 'T', '\254'}, {'/', 't', '\274'}, /* slash */
151 {'.', 'E', '\314'}, {'.', 'e', '\344'}, /* dot above */
152 {';', 'I', '\307'}, {';', 'i', '\347'}, /* ogonek */
153 {';', 'U', '\331'}, {';', 'u', '\371'},
154 /* iso-8859-9 uses this */
155 /* iso-8859-9 has really bad choosen G( S, and I. as they collide
156 * whith the same letters on other iso-8859-x (that is they are on
157 * different places :-( ), if you use turkish uncomment these and
158 * comment out the lines in iso-8859-2 and iso-8859-3 sections
159 * FIXME: should be dynamic according to chosen language
160 * if/when Wine has turkish support.
161 */
162 /* collision whith G( from iso-8859-3 !!! */
163 /* {'(', 'G', '\320'}, {'(', 'g', '\360'}, */ /* breve */
164 /* collision whith S, from iso-8859-2 !!! */
165 /* {',', 'S', '\336'}, {',', 's', '\376'}, */ /* cedilla */
166 /* collision whith I. from iso-8859-3 !!! */
167 /* {'.', 'I', '\335'}, {'.', 'i', '\375'}, */ /* dot above */
168 };
169
170 /* FUNCTIONS *****************************************************************/
171
172 /*** Statics used by TranslateMessage ***/
173
174 static UINT DontDistinguishShifts( UINT ret ) {
175 if( ret == VK_LSHIFT || ret == VK_RSHIFT ) ret = VK_SHIFT;
176 if( ret == VK_LCONTROL || ret == VK_RCONTROL ) ret = VK_CONTROL;
177 if( ret == VK_LMENU || ret == VK_RMENU ) ret = VK_MENU;
178 return ret;
179 }
180
181 static VOID STDCALL SetKeyState(DWORD key, BOOL down) {
182 QueueKeyStateTable[key] = down ? 0x80 : 0;
183 }
184
185 VOID DumpKeyState( PBYTE KeyState ) {
186 int i;
187
188 DbgPrint( "KeyState { " );
189 for( i = 0; i < 0x100; i++ ) {
190 if( KeyState[i] ) DbgPrint( "%02x(%02x) ", i, KeyState[i] );
191 }
192 DbgPrint( "};\n" );
193 }
194
195 static BYTE KeysSet( PKBDTABLES pkKT, PBYTE KeyState,
196 int Mod, int FakeModLeft, int FakeModRight ) {
197 int i;
198
199 if( !KeyState || !pkKT ) return 0;
200
201 for( i = 0; i < pkKT->bMaxVSCtoVK; i++ ) {
202 if( KeyState[i] & 0xC0 &&
203 ((pkKT->pusVSCtoVK[i] & 0xff) == Mod ||
204 (pkKT->pusVSCtoVK[i] & 0xff) == FakeModLeft ||
205 (pkKT->pusVSCtoVK[i] & 0xff) == FakeModRight ) ) {
206 return KeyState[i];
207 }
208 }
209
210 return 0;
211 }
212
213 static DWORD ModBits( PKBDTABLES pkKT, PBYTE KeyState ) {
214 int i;
215 DWORD ModBits = 0;
216 BYTE Mask;
217
218 if( !KeyState ) return 0;
219
220 /* DumpKeyState( KeyState ); */
221
222 for( i = 0; pkKT->pCharModifiers->pVkToBit[i].Vk; i++ ) {
223 int Vk = pkKT->pCharModifiers->pVkToBit[i].Vk;
224 switch(Vk)
225 {
226 case VK_SHIFT:
227 Mask = KeysSet( pkKT, KeyState, Vk, VK_LSHIFT, VK_RSHIFT );
228 if (Mask & 0xc0)
229 ModBits |= pkKT->pCharModifiers->pVkToBit[i].ModBits;
230 break;
231 case VK_CONTROL:
232 Mask = KeysSet( pkKT, KeyState, Vk, VK_LCONTROL, VK_RCONTROL );
233 if (Mask & 0xc0)
234 ModBits |= pkKT->pCharModifiers->pVkToBit[i].ModBits;
235 break;
236 case VK_MENU:
237 Mask = KeysSet( pkKT, KeyState, Vk, VK_LMENU, VK_RMENU );
238 if (Mask & 0xc0)
239 ModBits |= pkKT->pCharModifiers->pVkToBit[i].ModBits;
240 if (Mask & 0x40)
241 ModBits |= 0x02 /* KCTRL */;
242 break;
243 default:
244 Mask = KeysSet( pkKT, KeyState, Vk, 0, 0 );
245 if (Mask & 0x80)
246 ModBits |= pkKT->pCharModifiers->pVkToBit[i].ModBits;
247 break;
248 }
249 }
250
251 DPRINT( "Current Mod Bits: %x\n", ModBits );
252
253 return ModBits;
254 }
255
256 static BOOL TryToTranslateChar(WORD wVirtKey,
257 DWORD ModBits,
258 PBOOL pbDead,
259 PBOOL pbLigature,
260 PWCHAR pwcTranslatedChar,
261 PKBDTABLES keyLayout )
262 {
263 PVK_TO_WCHAR_TABLE vtwTbl;
264 PVK_TO_WCHARS10 vkPtr;
265 size_t size_this_entry;
266 int nMod, shift;
267
268 DPRINT ( "TryToTranslate: %04x %x\n", wVirtKey, ModBits );
269
270 if (ModBits > keyLayout->pCharModifiers->wMaxModBits)
271 {
272 return FALSE;
273 }
274 shift = keyLayout->pCharModifiers->ModNumber[ModBits];
275
276 for (nMod = 0; keyLayout->pVkToWcharTable[nMod].nModifications; nMod++)
277 {
278 if (shift >= keyLayout->pVkToWcharTable[nMod].nModifications)
279 {
280 continue;
281 }
282 vtwTbl = &keyLayout->pVkToWcharTable[nMod];
283 size_this_entry = vtwTbl->cbSize;
284 vkPtr = (PVK_TO_WCHARS10)((BYTE *)vtwTbl->pVkToWchars);
285 while(vkPtr->VirtualKey)
286 {
287 if( wVirtKey == vkPtr->VirtualKey )
288 {
289 *pbDead = vkPtr->wch[shift] == WCH_DEAD;
290 *pbLigature = vkPtr->wch[shift] == WCH_LGTR;
291 *pwcTranslatedChar = vkPtr->wch[shift];
292 if( *pbDead )
293 {
294 vkPtr = (PVK_TO_WCHARS10)(((BYTE *)vkPtr) + size_this_entry);
295 if( vkPtr->VirtualKey != 0xff )
296 {
297 DPRINT( "Found dead key with no trailer in the table.\n" );
298 DPRINT( "VK: %04x, ADDR: %08x\n", wVirtKey, (int)vkPtr );
299 return FALSE;
300 }
301 *pwcTranslatedChar = vkPtr->wch[shift];
302 }
303 return TRUE;
304 }
305 vkPtr = (PVK_TO_WCHARS10)(((BYTE *)vkPtr) + size_this_entry);
306 }
307 }
308 return FALSE;
309 }
310
311 static
312 int STDCALL
313 ToUnicodeInner(UINT wVirtKey,
314 UINT wScanCode,
315 PBYTE lpKeyState,
316 LPWSTR pwszBuff,
317 int cchBuff,
318 UINT wFlags,
319 PKBDTABLES pkKT)
320 {
321 WCHAR wcTranslatedChar;
322 BOOL bDead;
323 BOOL bLigature;
324
325 if( !pkKT ) return 0;
326
327 if( TryToTranslateChar( wVirtKey,
328 ModBits( pkKT, lpKeyState ),
329 &bDead,
330 &bLigature,
331 &wcTranslatedChar,
332 pkKT ) )
333 {
334 if( bLigature )
335 {
336 DPRINT("Not handling ligature (yet)\n" );
337 return 0;
338 }
339
340 /* DbgPrint( "Trans: %04x\n", wcTranslatedChar ); */
341 if( cchBuff > 0 ) pwszBuff[0] = wcTranslatedChar;
342
343 return bDead ? -1 : 1;
344 }
345
346 return 0;
347 }
348
349 DWORD
350 STDCALL
351 NtUserGetKeyState(
352 DWORD key)
353 {
354 DWORD ret;
355
356 if( key < 0x100 ) {
357 ret = ((DWORD)(QueueKeyStateTable[key] & 0x80) << 8 ) |
358 (QueueKeyStateTable[key] & 0x80) |
359 (QueueKeyStateTable[key] & 0x01);
360 return ret;
361 }
362 return 0;
363 }
364
365 int STDCALL ToUnicodeEx( UINT wVirtKey,
366 UINT wScanCode,
367 PBYTE lpKeyState,
368 LPWSTR pwszBuff,
369 int cchBuff,
370 UINT wFlags,
371 HKL dwhkl ) {
372 return ToUnicodeInner( wVirtKey,
373 wScanCode,
374 lpKeyState,
375 pwszBuff,
376 cchBuff,
377 wFlags,
378 PsGetWin32Thread() ?
379 PsGetWin32Thread()->KeyboardLayout : 0 );
380 }
381
382 int STDCALL ToUnicode( UINT wVirtKey,
383 UINT wScanCode,
384 PBYTE lpKeyState,
385 LPWSTR pwszBuff,
386 int cchBuff,
387 UINT wFlags ) {
388 return ToUnicodeEx( wVirtKey,
389 wScanCode,
390 QueueKeyStateTable,
391 pwszBuff,
392 cchBuff,
393 wFlags,
394 0 );
395 }
396
397 /*
398 * Utility to copy and append two unicode strings.
399 *
400 * IN OUT PUNICODE_STRING ResultFirst -> First string and result
401 * IN PUNICODE_STRING Second -> Second string to append
402 * IN BOOL Deallocate -> TRUE: Deallocate First string before
403 * overwriting.
404 *
405 * Returns NTSTATUS.
406 */
407
408 static NTSTATUS ReallyAppendUnicodeString(PUNICODE_STRING ResultFirst,
409 PUNICODE_STRING Second,
410 BOOL Deallocate) {
411 NTSTATUS Status;
412 PWSTR new_string =
413 ExAllocatePool(PagedPool,
414 (ResultFirst->Length + Second->Length + sizeof(WCHAR)));
415 if( !new_string ) {
416 return STATUS_NO_MEMORY;
417 }
418 memcpy( new_string, ResultFirst->Buffer,
419 ResultFirst->Length );
420 memcpy( new_string + ResultFirst->Length / sizeof(WCHAR),
421 Second->Buffer,
422 Second->Length );
423 if( Deallocate ) RtlFreeUnicodeString(ResultFirst);
424 ResultFirst->Length += Second->Length;
425 ResultFirst->MaximumLength = ResultFirst->Length;
426 new_string[ResultFirst->Length / sizeof(WCHAR)] = 0;
427 Status = RtlCreateUnicodeString(ResultFirst,new_string) ?
428 STATUS_SUCCESS : STATUS_NO_MEMORY;
429 ExFreePool(new_string);
430 return Status;
431 }
432
433 /*
434 * Utility function to read a value from the registry more easily.
435 *
436 * IN PUNICODE_STRING KeyName -> Name of key to open
437 * IN PUNICODE_STRING ValueName -> Name of value to open
438 * OUT PUNICODE_STRING ReturnedValue -> String contained in registry
439 *
440 * Returns NTSTATUS
441 */
442
443 static NTSTATUS ReadRegistryValue( PUNICODE_STRING KeyName,
444 PUNICODE_STRING ValueName,
445 PUNICODE_STRING ReturnedValue ) {
446 NTSTATUS Status;
447 HANDLE KeyHandle;
448 OBJECT_ATTRIBUTES KeyAttributes;
449 PKEY_VALUE_PARTIAL_INFORMATION KeyValuePartialInfo;
450 ULONG Length = 0;
451 ULONG ResLength = 0;
452 UNICODE_STRING Temp;
453
454 InitializeObjectAttributes(&KeyAttributes, KeyName, OBJ_CASE_INSENSITIVE,
455 NULL, NULL);
456 Status = ZwOpenKey(&KeyHandle, KEY_ALL_ACCESS, &KeyAttributes);
457 if( !NT_SUCCESS(Status) ) {
458 return Status;
459 }
460
461 Status = ZwQueryValueKey(KeyHandle, ValueName, KeyValuePartialInformation,
462 0,
463 0,
464 &ResLength);
465
466 if( Status != STATUS_BUFFER_TOO_SMALL ) {
467 NtClose(KeyHandle);
468 return Status;
469 }
470
471 ResLength += sizeof( *KeyValuePartialInfo );
472 KeyValuePartialInfo =
473 ExAllocatePool(PagedPool, ResLength);
474 Length = ResLength;
475
476 if( !KeyValuePartialInfo ) {
477 NtClose(KeyHandle);
478 return STATUS_NO_MEMORY;
479 }
480
481 Status = ZwQueryValueKey(KeyHandle, ValueName, KeyValuePartialInformation,
482 (PVOID)KeyValuePartialInfo,
483 Length,
484 &ResLength);
485
486 if( !NT_SUCCESS(Status) ) {
487 NtClose(KeyHandle);
488 ExFreePool(KeyValuePartialInfo);
489 return Status;
490 }
491
492 Temp.Length = Temp.MaximumLength = KeyValuePartialInfo->DataLength;
493 Temp.Buffer = (PWCHAR)KeyValuePartialInfo->Data;
494
495 /* At this point, KeyValuePartialInfo->Data contains the key data */
496 RtlInitUnicodeString(ReturnedValue,L"");
497 ReallyAppendUnicodeString(ReturnedValue,&Temp,FALSE);
498
499 ExFreePool(KeyValuePartialInfo);
500 NtClose(KeyHandle);
501
502 return Status;
503 }
504
505 typedef PVOID (*KbdLayerDescriptor)(VOID);
506 NTSTATUS STDCALL LdrGetProcedureAddress(PVOID module,
507 PANSI_STRING import_name,
508 DWORD flags,
509 PVOID *func_addr);
510
511 void InitKbdLayout( PVOID *pkKeyboardLayout ) {
512 UNICODE_STRING KeyName;
513 UNICODE_STRING ValueName;
514 UNICODE_STRING LayoutKeyName;
515 UNICODE_STRING LayoutValueName;
516 UNICODE_STRING DefaultLocale;
517 UNICODE_STRING LayoutFile;
518 UNICODE_STRING FullLayoutPath;
519 PWCHAR KeyboardLayoutWSTR;
520 HMODULE kbModule = 0;
521 NTSTATUS Status;
522 ANSI_STRING kbdProcedureName;
523 KbdLayerDescriptor layerDescGetFn;
524
525 #define XX_STATUS(x) if (!NT_SUCCESS(Status = (x))) continue;
526
527 do {
528 RtlInitUnicodeString(&KeyName,
529 L"\\REGISTRY\\Machine\\SYSTEM\\CurrentControlSet"
530 L"\\Control\\Nls\\Locale");
531 RtlInitUnicodeString(&ValueName,
532 L"(Default)");
533
534 DPRINT("KeyName = %wZ, ValueName = %wZ\n", &KeyName, &ValueName);
535
536 Status = ReadRegistryValue(&KeyName,&ValueName,&DefaultLocale);
537
538 if( !NT_SUCCESS(Status) ) {
539 DbgPrint( "Could not get default locale (%08x).\n", Status );
540 } else {
541 DPRINT( "DefaultLocale = %wZ\n", &DefaultLocale );
542
543 RtlInitUnicodeString(&LayoutKeyName,
544 L"\\REGISTRY\\Machine\\SYSTEM\\CurrentControlSet"
545 L"\\Control\\KeyboardLayouts\\");
546
547 ReallyAppendUnicodeString(&LayoutKeyName,&DefaultLocale,FALSE);
548
549 RtlFreeUnicodeString(&DefaultLocale);
550 RtlInitUnicodeString(&LayoutValueName,L"Layout File");
551
552 Status = ReadRegistryValue(&LayoutKeyName,&LayoutValueName,&LayoutFile);
553 RtlInitUnicodeString(&FullLayoutPath,SYSTEMROOT_DIR);
554
555 if( !NT_SUCCESS(Status) ) {
556 DbgPrint("Got default locale but not layout file. (%08x)\n",
557 Status);
558 RtlFreeUnicodeString(&LayoutFile);
559 } else {
560 DPRINT("Read registry and got %wZ\n", &LayoutFile);
561
562 RtlFreeUnicodeString(&LayoutKeyName);
563
564 ReallyAppendUnicodeString(&FullLayoutPath,&LayoutFile,FALSE);
565
566 DPRINT("Loading Keyboard DLL %wZ\n", &FullLayoutPath);
567
568 RtlFreeUnicodeString(&LayoutFile);
569
570 KeyboardLayoutWSTR = ExAllocatePool(PagedPool,
571 (FullLayoutPath.Length + 1) *
572 sizeof(WCHAR));
573
574 if( !KeyboardLayoutWSTR ) {
575 DbgPrint("Couldn't allocate a string for the keyboard layout name.\n");
576 RtlFreeUnicodeString(&FullLayoutPath);
577 return;
578 }
579 memcpy(KeyboardLayoutWSTR,FullLayoutPath.Buffer,
580 (FullLayoutPath.Length + 1) * sizeof(WCHAR));
581 KeyboardLayoutWSTR[FullLayoutPath.Length] = 0;
582
583 kbModule = EngLoadImage(KeyboardLayoutWSTR);
584 DPRINT( "Load Keyboard Layout: %S\n", KeyboardLayoutWSTR );
585
586 if( !kbModule )
587 DbgPrint( "Load Keyboard Layout: No %wZ\n", &FullLayoutPath );
588 }
589
590 RtlFreeUnicodeString(&FullLayoutPath);
591 }
592
593 if( !kbModule )
594 {
595 DbgPrint("Trying to load US Keyboard Layout\n");
596 kbModule = EngLoadImage(L"\\SystemRoot\\system32\\kbdus.dll");
597
598 if (!kbModule)
599 {
600 DbgPrint("Failed to load any Keyboard Layout\n");
601 return;
602 }
603 }
604
605 RtlInitAnsiString( &kbdProcedureName, "KbdLayerDescriptor" );
606
607 LdrGetProcedureAddress((PVOID)kbModule,
608 &kbdProcedureName,
609 0,
610 (PVOID*)&layerDescGetFn);
611
612 if( layerDescGetFn ) {
613 *pkKeyboardLayout = layerDescGetFn();
614 }
615 } while (FALSE);
616
617 if( !*pkKeyboardLayout ) {
618 DbgPrint("Failed to load the keyboard layout.\n");
619 }
620
621 #undef XX_STATUS
622 }
623
624 PKBDTABLES W32kGetDefaultKeyLayout() {
625 PKBDTABLES pkKeyboardLayout = 0;
626 InitKbdLayout( (PVOID) &pkKeyboardLayout );
627 return pkKeyboardLayout;
628 }
629
630 BOOL STDCALL
631 NtUserTranslateMessage(LPMSG lpMsg,
632 HKL dwhkl) /* Used to pass the kbd layout */
633 {
634 static INT dead_char = 0;
635 UINT ScanCode = 0;
636 LONG UState = 0;
637 WCHAR wp[2] = { 0 };
638 MSG NewMsg = { 0 };
639 MSG InMsg = { 0 };
640 PUSER_MESSAGE UMsg;
641 PKBDTABLES keyLayout;
642
643 if( !NT_SUCCESS(MmCopyFromCaller(&InMsg, lpMsg, sizeof(InMsg))) ) {
644 return FALSE;
645 }
646
647 keyLayout = PsGetWin32Thread()->KeyboardLayout;
648 if( !keyLayout ) return 0;
649
650 ScanCode = (InMsg.lParam >> 16) & 0xff;
651
652 if (InMsg.message != WM_KEYDOWN && InMsg.message != WM_SYSKEYDOWN)
653 {
654 if (InMsg.message == WM_KEYUP) {
655 SetKeyState( ScanCode, FALSE ); /* Release key */
656 }
657 return(FALSE);
658 }
659
660 SetKeyState( ScanCode, TRUE ); /* Strike key */
661
662 /* Pass 2: Get Unicode Character */
663 UState = ToUnicodeInner(InMsg.wParam, HIWORD(InMsg.lParam) & 0xff,
664 QueueKeyStateTable, wp, 2, 0,
665 keyLayout );
666
667 if (UState == 1)
668 {
669 NewMsg.message = (InMsg.message == WM_KEYDOWN) ? WM_CHAR : WM_SYSCHAR;
670 if (dead_char)
671 {
672 ULONG i;
673
674 if (wp[0] == ' ') wp[0] = dead_char;
675 if (dead_char == 0xa2) dead_char = '(';
676 else if (dead_char == 0xa8) dead_char = '"';
677 else if (dead_char == 0xb2) dead_char = ';';
678 else if (dead_char == 0xb4) dead_char = '\'';
679 else if (dead_char == 0xb7) dead_char = '<';
680 else if (dead_char == 0xb8) dead_char = ',';
681 else if (dead_char == 0xff) dead_char = '.';
682 for (i = 0; i < sizeof(accent_chars)/sizeof(accent_chars[0]); i++)
683 {
684 if ((accent_chars[i].ac_accent == dead_char) &&
685 (accent_chars[i].ac_char == wp[0]))
686 {
687 wp[0] = accent_chars[i].ac_result;
688 break;
689 }
690 }
691 dead_char = 0;
692 }
693 NewMsg.hwnd = InMsg.hwnd;
694 NewMsg.wParam = wp[0];
695 NewMsg.lParam = InMsg.lParam;
696 UMsg = MsqCreateMessage(&NewMsg);
697 DPRINT( "CHAR='%c' %04x %08x\n", wp[0], wp[0], InMsg.lParam );
698 MsqPostMessage(PsGetWin32Thread()->MessageQueue, UMsg);
699 return(TRUE);
700 }
701 else if (UState == -1)
702 {
703 NewMsg.message =
704 (InMsg.message == WM_KEYDOWN) ? WM_DEADCHAR : WM_SYSDEADCHAR;
705 NewMsg.hwnd = InMsg.hwnd;
706 NewMsg.wParam = wp[0];
707 NewMsg.lParam = InMsg.lParam;
708 dead_char = wp[0];
709 UMsg = MsqCreateMessage(&NewMsg);
710 MsqPostMessage(PsGetWin32Thread()->MessageQueue, UMsg);
711 return(TRUE);
712 }
713 return(FALSE);
714 }
715
716 HWND STDCALL
717 NtUserSetFocus(HWND hWnd)
718 {
719 return IntSetFocusWindow(hWnd);
720 }
721
722 DWORD
723 STDCALL
724 NtUserGetKeyboardState(
725 LPBYTE lpKeyState)
726 {
727 if (lpKeyState) {
728 if(!NT_SUCCESS(MmCopyToCaller(lpKeyState, QueueKeyStateTable, 256)))
729 return FALSE;
730 }
731 return TRUE;
732 }
733
734 DWORD
735 STDCALL
736 NtUserSetKeyboardState(
737 LPBYTE lpKeyState)
738 {
739 if (lpKeyState) {
740 if(! NT_SUCCESS(MmCopyFromCaller(QueueKeyStateTable, lpKeyState, 256)))
741 return FALSE;
742 }
743 return TRUE;
744 }
745
746 static UINT VkToScan( UINT Code, BOOL ExtCode, PKBDTABLES pkKT ) {
747 int i;
748
749 for( i = 0; i < pkKT->bMaxVSCtoVK; i++ ) {
750 if( pkKT->pusVSCtoVK[i] == Code ) { return i; }
751 }
752
753 return 0;
754 }
755
756 UINT ScanToVk( UINT Code, BOOL ExtKey, PKBDTABLES pkKT ) {
757 if( ExtKey ) {
758 int i;
759
760 for( i = 0; pkKT->pVSCtoVK_E0[i].Vsc; i++ ) {
761 if( pkKT->pVSCtoVK_E0[i].Vsc == Code )
762 return pkKT->pVSCtoVK_E0[i].Vk & 0xff;
763 }
764 for( i = 0; pkKT->pVSCtoVK_E1[i].Vsc; i++ ) {
765 if( pkKT->pVSCtoVK_E1[i].Vsc == Code )
766 return pkKT->pVSCtoVK_E1[i].Vk & 0xff;
767 }
768
769 return 0;
770 } else {
771 if( Code >= pkKT->bMaxVSCtoVK ) { return 0; }
772 return pkKT->pusVSCtoVK[Code] & 0xff;
773 }
774 }
775
776 /*
777 * Map a virtual key code, or virtual scan code, to a scan code, key code,
778 * or unshifted unicode character.
779 *
780 * Code: See Below
781 * Type:
782 * 0 -- Code is a virtual key code that is converted into a virtual scan code
783 * that does not distinguish between left and right shift keys.
784 * 1 -- Code is a virtual scan code that is converted into a virtual key code
785 * that does not distinguish between left and right shift keys.
786 * 2 -- Code is a virtual key code that is converted into an unshifted unicode
787 * character.
788 * 3 -- Code is a virtual scan code that is converted into a virtual key code
789 * that distinguishes left and right shift keys.
790 * KeyLayout: Keyboard layout handle (currently, unused)
791 *
792 * @implemented
793 */
794
795 UINT
796 STDCALL
797 NtUserMapVirtualKeyEx( UINT Code, UINT Type, DWORD keyboardId, HKL dwhkl ) {
798 UINT ret = 0;
799 PKBDTABLES keyLayout = PsGetWin32Thread()->KeyboardLayout;
800
801 if( !keyLayout ) return 0;
802
803 switch( Type ) {
804 case 0:
805 if( Code == VK_RSHIFT ) Code = VK_LSHIFT;
806 if( Code == VK_RMENU ) Code = VK_LMENU;
807 if( Code == VK_RCONTROL ) Code = VK_LCONTROL;
808 ret = VkToScan( Code, FALSE, keyLayout );
809 break;
810
811 case 1:
812 ret =
813 DontDistinguishShifts
814 (NtUserMapVirtualKeyEx( Code, 3, keyboardId, dwhkl ) );
815 break;
816
817 case 2: {
818 WCHAR wp[2];
819
820 ret = VkToScan( Code, FALSE, keyLayout );
821 ToUnicodeInner( Code, ret, 0, wp, 2, 0, keyLayout );
822 ret = wp[0];
823 } break;
824
825 case 3:
826 ret = ScanToVk( Code, FALSE, keyLayout );
827 break;
828 }
829
830 return ret;
831 }
832
833
834 int
835 STDCALL
836 NtUserToUnicodeEx(
837 UINT wVirtKey,
838 UINT wScanCode,
839 PBYTE lpKeyState,
840 LPWSTR pwszBuff,
841 int cchBuff,
842 UINT wFlags,
843 HKL dwhkl ) {
844 BYTE KeyStateBuf[0x100];
845 PWCHAR OutPwszBuff = 0;
846 int ret = 0;
847
848
849 if( !NT_SUCCESS(MmCopyFromCaller(KeyStateBuf,
850 lpKeyState,
851 sizeof(KeyStateBuf))) ) {
852 DbgPrint( "Couldn't copy key state from caller.\n" );
853 return 0;
854 }
855 OutPwszBuff = ExAllocatePool(NonPagedPool,sizeof(WCHAR) * cchBuff);
856 if( !OutPwszBuff ) {
857 DbgPrint( "ExAllocatePool(%d) failed\n", sizeof(WCHAR) * cchBuff);
858 return 0;
859 }
860 RtlZeroMemory( OutPwszBuff, sizeof( WCHAR ) * cchBuff );
861
862 ret = ToUnicodeEx( wVirtKey,
863 wScanCode,
864 KeyStateBuf,
865 OutPwszBuff,
866 cchBuff,
867 wFlags,
868 dwhkl );
869
870 MmCopyToCaller(pwszBuff,OutPwszBuff,sizeof(WCHAR)*cchBuff);
871 ExFreePool(OutPwszBuff);
872
873 return ret;
874 }
875
876 static int W32kSimpleToupper( int ch ) {
877 if( ch >= 'a' && ch <= 'z' ) ch = ch - 'a' + 'A';
878 return ch;
879 }
880
881 DWORD
882 STDCALL
883 NtUserGetKeyNameText( LONG lParam, LPWSTR lpString, int nSize ) {
884 int i;
885 DWORD ret = 0;
886 UINT CareVk = 0;
887 UINT VkCode = 0;
888 UINT ScanCode = (lParam >> 16) & 0xff;
889 BOOL ExtKey = lParam & (1<<24) ? TRUE : FALSE;
890 PKBDTABLES keyLayout =
891 PsGetWin32Thread() ?
892 PsGetWin32Thread()->KeyboardLayout : 0;
893
894 if( !keyLayout || nSize < 1 ) return 0;
895
896 if( lParam & (1<<25) ) {
897 CareVk = VkCode = ScanToVk( ScanCode, ExtKey, keyLayout );
898 if( VkCode == VK_LSHIFT || VkCode == VK_RSHIFT )
899 VkCode = VK_LSHIFT;
900 if( VkCode == VK_LCONTROL || VkCode == VK_RCONTROL )
901 VkCode = VK_LCONTROL;
902 if( VkCode == VK_LMENU || VkCode == VK_RMENU )
903 VkCode = VK_LMENU;
904 } else {
905 VkCode = ScanToVk( ScanCode, ExtKey, keyLayout );
906 }
907
908 VSC_LPWSTR *KeyNames = 0;
909
910 if( CareVk != VkCode )
911 ScanCode = VkToScan( VkCode, ExtKey, keyLayout );
912
913 if( ExtKey )
914 KeyNames = keyLayout->pKeyNamesExt;
915 else
916 KeyNames = keyLayout->pKeyNames;
917
918 for( i = 0; KeyNames[i].pwsz; i++ ) {
919 if( KeyNames[i].vsc == ScanCode ) {
920 UINT StrLen = wcslen(KeyNames[i].pwsz);
921 UINT StrMax = StrLen > (nSize - 1) ? (nSize - 1) : StrLen;
922 WCHAR null_wc = 0;
923 if( NT_SUCCESS( MmCopyToCaller( lpString,
924 KeyNames[i].pwsz,
925 StrMax * sizeof(WCHAR) ) ) &&
926 NT_SUCCESS( MmCopyToCaller( lpString + StrMax,
927 &null_wc,
928 sizeof( WCHAR ) ) ) ) {
929 ret = StrMax;
930 break;
931 }
932 }
933 }
934
935 if( ret == 0 ) {
936 WCHAR UCName[2];
937
938 UCName[0] = W32kSimpleToupper(NtUserMapVirtualKeyEx( VkCode, 2, 0, 0 ));
939 UCName[1] = 0;
940 ret = 1;
941
942 if( !NT_SUCCESS(MmCopyToCaller( lpString, UCName, 2 * sizeof(WCHAR) )) )
943 return 0;
944 }
945
946 return ret;
947 }
948
949 /*
950 * Filter this message according to the current key layout, setting wParam
951 * appropriately.
952 */
953
954 VOID FASTCALL W32kKeyProcessMessage(LPMSG Msg, PKBDTABLES KeyboardLayout) {
955 if( !KeyboardLayout || !Msg) return;
956 if( Msg->message != WM_KEYDOWN && Msg->message != WM_SYSKEYDOWN &&
957 Msg->message != WM_KEYUP && Msg->message != WM_SYSKEYUP ) {
958 return;
959 }
960 Msg->wParam = NtUserMapVirtualKeyEx( (Msg->lParam >> 16) & 0xff, 1, 0, 0 );
961 }
962
963 /* EOF */