Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / MFC

Loading keyboard layout (KbdLayerDescriptor) in 32/64-bit environment

4.75/5 (12 votes)
13 Aug 2012Ms-PL3 min read 46.6K   2.2K  
When loading a keyboard dll as a 32-bit application on a 64-bit system, the keyboard-dll-files does not work as expected, this class fixes that problem

Image 1

Introduction

Windows uses kbd**.dll files to load keyboards. When loading a keyboard on a 32-bit application on a 64-bit system you'll get a corrupted array.

This little hack will handle keyboard-DLL loads for a 32-bit application, running on a 64-bit system.

Background  

The problem was found during my creation of a on-screen keyboard that I wanted to be multilingual.

After searching several forums I didn't find any good solution for the problem. The DLL-import is the same on either systems, but after running init using KbdLayerDescriptor(), the array is actual corrupted. An element called pVkToWcharTable is always NULL. This array shows the connection between Virtual Keys (VK) and characters, pretty essential for presenting a keyboard.

In the kbd.h header-file, from Microsoft DDK, this pointer is defined:

C++
#if defined(BUILD_WOW6432)
    #define KBD_LONG_POINTER __ptr64
#else
     #define KBD_LONG_POINTER
#endif

This works great on a 32-bit application running a 32-bit system, but not on a 64-bit system. 

If you define BUILD_WOW6432 and compile the application as 64-bit, the program works as expected.

What caused this strange behavior? After doing a little research of the topic I found the probably cause in MSDN. A pointer defined as __ptr32 is coerced on a 64-bit system. If the KbdLayerDescriptor() actually uses sizeof() and other functions to get the length, it probably goes out of range, in the array.

My solution is to create "my own" 64-bit variables using this define

C++
#define KBD_LONG_POINTER64 __ptr64

Checkout the kbd64.h file for all variables/functions renamed around this 64-bit define. Kbd64.h is just a renamed kbd.h to ensure own defines for the 64-bit pointer.

The demo  

The included demonstration shows how to get the DLL initiated and array filled correctly. It does not show how to handle modifiers and dead-keys, that is not essential part of the subject.

If you are looking into handling dead-keys or wondering anything about these "strange" kbd**.dll files, check out Michael Kaplan Sorting it all Out and search for the KbdLayerDescriptor.

Using the code   

The CKLL class has four public functions + one helper (from KLL.h).  

C++
//Loads the DLL into the handler
BOOL	LoadDLL(CString sKeyboardDll);
	
//Get the counts of virtual keys (VK)
USHORT	GetVKCount();
 
//Get the char(s) linked to that VK
CString	GetChar(USHORT iVK);
 
//Get the scan code(s) linked to that VK
CString GetSC(USHORT iVK);
 
//Helper: Return TRUE if 64-bit, false if 32-bit
BOOL	Is64BitWindows();

If you have already have written you're own functions based on the kbd.h header from Microsoft, then you can use the kbd64.h header and replace the variables and add 64 in the end; for example PKBDTABLES -> PKBDTABLES64. Then you use the Is64BitWindows() to check what type of system the application is running on. 

Check out the Fill32() and Fill64() function in the CKLL class to get an idea on how it works.

Points of Interest

The keyboard-DLLs are created using the Microsoft Keyboard Layout Creator and by using the built-in functions you can easily create custom DLLs without any hassle. 

The connection between Scan Codes (SC) and physical layout is pretty interesting

Image 2

Source - Compare the Scan Code value from the picture above, with the result from KeyboardLayout

With this knowledge it is much easier to create an on-screen keyboard, and present a keyboard language you never used before. 

The qwerty-range seems match every time, and you can also match it to Microsoft's own Keyboard Layouts, to ensure that it is right.

Feedback  

If you have solved this problem differently, I would like to hear from you in the comment field!

History

v1.0 Init release to the public.

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)