Keyboard Layouts in Windows: How they work and how to create your own

Welcome to another programming adventure! Today, we're going to explore the fascinating world of Windows keyboard layouts. Surprisingly, a Windows keyboard layout is essentially a compiled C++ program. So, let's embark on this journey and learn something new together.

Understanding the KLC File Format and other tools

Before we discuss how to create your own custom keyboard layout, let's first understand the KLC file format. A KLC file is a text file that describes a keyboard layout in Windows and is used to generate a C++ source file that is compiled into a Dynamic Link Library (DLL). Microsoft Keyboard Layout Creator (MSKLC) is a tool that can generate both the KLC file and the C++ source code for the layout. However, the KLC file format is specific to MSKLC and not a universal format. Although MSKLC is a powerful tool, there are other tools and approaches available for creating custom layouts. For example, kbdutool.exe is a command-line utility that can translate KLC files to C++ source code and compile them using the Microsoft Visual C++ Compiler. If you want to learn more about kbdutool.exe and the layout compilation process, you can refer to this 2006 article by Michael S. Kaplan.

Unfortunately, there isn't a comprehensive specification for the KLC file format readily available online. However, I can provide you with a brief overview of the main fields and an example of a simple KLC file.

Here's an example of a simple .klc file:

KBD  "My Custom Layout" 0x00000809
Copyright  "© 2023 John Doe"
COMPANY "John Doe"
LOCALENAME  "en-US"
LOCALEID  "00000809"
VERSION 1.0

SHIFTSTATE 0 // Base state
SHIFTSTATE 1 // Shift state
SHIFTSTATE 2 // Control state
SHIFTSTATE 6 // AltGr state

// VK  SC  Base    Shift   Control AltGr
0x31  2   '1'     '!'     -       -       // 1 key
0x32  3   '2'     '@'     -       -       // 2 key
...
0x41  30  'a'     'A'     -       -       // A key
0x42  48  'b'     'B'     -       -       // B key
...

KEYNAME
02  "1"
03  "2"
...
1e  "a"
1f  "b"
...

Keep in mind that this is just a brief overview of the .klc file format, and a more complex layout would involve additional fields and sections. If you want to explore more about the format, you can study the .klc files generated by Microsoft Keyboard Layout Creator (MSKLC) for different languages and layout variations.

The C++ Connection

When thinking about keyboard layouts, we usually imagine a simple mapping of physical keys to characters or functions. But in the Windows universe, it's much more complex. A Windows keyboard layout is a C or C++ program that's compiled into a Dynamic Link Library (DLL) file. The primary function of this program is KbdLayerDescriptor, which returns a pointer to a KBDTABLES structure containing various tables defining the layout.

#include <windows.h>
#include "kbd.h"

extern "C" PKBDTABLES WINAPI KbdLayerDescriptor(VOID) {
    // Fill in the KBDTABLES structure here
    static KBDTABLES kbdTables = { ... };
    return &kbdTables;
}

Why would Windows use a compiled program for something that appears to be a simple mapping? The answer lies in the flexibility and abstraction that a DLL provides. By using a DLL, Windows can dynamically load and unload different keyboard layouts as needed. It also creates a layer of abstraction between the physical keyboard hardware and the software interpreting key presses.

Crafting Your Own Layout

So, how do you create a custom keyboard layout for Windows? Here's a brief outline of the process:

  1. Create a new C/C++ project in your preferred development environment. environment.
  2. Add the necessary Windows headers and define the KbdLayerDescriptor function:
#include <windows.h>
#include "kbd.h"

extern "C" PKBDTABLES WINAPI KbdLayerDescriptor(VOID) {
    // Fill in the KBDTABLES structure here
    static KBDTABLES kbdTables = { ... };
    return &kbdTables;
}
  1. Define the KBDTABLES structure, which contains various tables defining the layout:
typedef struct _KBDTABLES {
    PMODIFIERS pCharModifiers;
    PVK_TO_WCHARS1 pVkToWcharTable;
    PDEADKEY pDeadKey;
    PWSTR *pKeyNames;
    PWSTR *pKeyNamesExt;
    PWSTR *pKeyNamesDead;
    PVK_TO_PFNS pVkToF;
    PVK_TO_PFN paSpecialKeys;
} KBDTABLES, *PKBDTABLES;
  1. Create the required tables based on your custom layout.
  2. Compile the project to create a DLL.
  3. Modify the Windows registry to install your custom layout by adding a new entry under the HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layouts key. The value of the entry should be the layout ID in hexadecimal format, followed by a semicolon and the path to the compiled DLL. For example:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layouts
    00000809 "Layout Name"="<path to DLL>"

Here, 00000809 is the layout ID for English (United States), and <path to DLL> is the path to the compiled DLL file.

  1. Restart your computer and select your custom layout in Windows keyboard settings.

For a more detailed guide, check out this resource from 2006:

Getting all you can out of a keyboard layout, Part #8

Limitations and Considerations

While creating a custom keyboard layout can be a powerful way to tailor your typing experience, there are some limitations to be aware of. For example, in recent versions of Windows (10 and 11), the spacebar cannot be modified anymore. This means that certain custom layouts that relied on modified spacebar behavior, such as using Shift+Space for a non-breaking space or AltGr+Space for an underscore, are no longer possible.

Additionally, it's important to be cautious when modifying the Windows registry and working with system DLLs. Always make sure to back up your registry before making changes, and consider storing your custom layout DLL in a separate folder rather than the default Windows system folder. This will help avoid potential conflicts with existing Windows keyboard layouts.

Using the Custom Layout DLL

Once your custom layout is installed and configured in the Windows registry, the system will load your DLL whenever your layout is selected in the keyboard settings. The KbdLayerDescriptor function in your DLL provides Windows with the necessary information to translate key presses according to your custom layout, ensuring a seamless typing experience.

Expanding the Possibilities: Custom Logic in KbdLayerDescriptor

While the primary purpose of the KbdLayerDescriptor function is to provide the necessary keyboard mapping tables to Windows, you can technically add custom logic within the function or in other functions that you define in your DLL. This opens up a wide range of potential use cases, but keep in mind that doing so might introduce additional complexity and potential compatibility issues. Let's take a look at a few interesting possibilities that could be achieved with custom logic:

Virtual Keyboards

Imagine implementing a virtual keyboard that interacts with the physical keyboard and provides additional features such as on-screen key previews, customizable key arrangements, or even the ability to switch between different layouts on-the-fly. You could achieve this by adding logic to the KbdLayerDescriptor function to handle virtual key events and manage the state of the virtual keyboard.

Keyboard Macros

Custom logic within the KbdLayerDescriptor function could enable the creation of keyboard macros or shortcuts. By intercepting specific key combinations, you can trigger predefined actions or sequences of keystrokes, streamlining repetitive tasks and improving productivity for users who frequently perform certain actions in their daily workflow.

Special Input Modes

How about using custom logic to implement special input modes? You could create a "gaming mode" that temporarily disables certain keys (e.g., the Windows key) or remaps them to avoid accidental key presses during gameplay. Another example could be a "typing tutor" mode that provides real-time feedback and assistance for users learning how to touch-type or improving their typing skills.

Accessibility Features

Custom logic can help improve the accessibility of keyboard input for users with special needs. For example, you could implement features such as sticky keys (which allow modifier keys like Shift or Ctrl to be pressed and released before pressing the key they modify), key filtering (which can help prevent accidental key presses), or key repeat delays (which adjust the time it takes for a key to start repeating when held down).

Keep in mind that these examples are just a few possibilities, and adding custom logic to the KbdLayerDescriptor function can open up a wide range of potential use cases. However, it's important to carefully consider the implications of adding custom logic to your keyboard layout, as it might affect overall system stability and compatibility with future Windows updates. Always test your custom layout thoroughly to ensure that it works as expected and does not introduce any unintended side effects.

Note: For many of the mentioned use cases, it might be more suitable to use a dedicated keyboard input management library or tool, rather than implementing the custom logic directly within the KbdLayerDescriptor function. Such libraries and tools can provide a more flexible, maintainable, and compatible approach to handling advanced keyboard input scenarios.

Wrapping Up

As we conclude this adventure, we hope you gained valuable insights into the world of Windows keyboard layouts and the intricate C++ programs behind them. So, next time you find yourself working with your keyboard, remember the ingenuity and complexity that lies beneath the surface.

Creating a custom layout can be an engaging journey, allowing you to dive deeper into the inner workings of your operating system and uncover unexpected technical details. Embrace the fun of hacking around and taking control of your own typing experience. With the information provided here, you're all set to embark on your own keyboard layout project.

Until our next adventure, happy coding!