Search notes:

Registry: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout

Configuring the layout with PowerShell

The keyboard layout, or more accurately, the mapping of scancodes can be configured in the registry with a simple PowerShell script.
The following, arguably useless mapping, demonstratres how an environment can be created where 6 is mapped to 5, A is mapped to 6 and 5 to A.
The script uses + to concatenate the scan codes arrays in order to unpack them within an array:
#
#  Scan codes:
#
$s_5 = 0x06, 0x00
$s_6 = 0x07, 0x00
$s_A = 0x1e, 0x00

$mapping = [byte[]] (
  0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00,
# ----------------------
  0x04, 0x00, 0x00, 0x00 +  # 3 mappings + 1 ending  = 0x04
  $s_5      + $s_6       +  # 1st mapping: 6 -> 5
  $s_6      + $s_A       +  # 2nd mapping: A -> 6
  $s_A      + $s_5       +  # 3rd mapping: 5 -> A
# ----------------------
  0x00, 0x00, 0x00, 0x00   # final four bytes
)

$null = new-itemProperty -path "HKLM:\SYSTEM\CurrentControlSet\Control\Keyboard Layout" -name "Scancode Map" -value $mapping -force

Swapping ESC and Caps Lock

The following script is (at least for my purposes) more useful:
$s_ESC  = 0x01, 0x00
$s_CAPS = 0x3a, 0x00
$s_RWIN = 0x5c, 0xe0
$s_RCTR = 0x1d, 0xe0

$mapping = [byte[]] (
  0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00,
  0x04, 0x00, 0x00, 0x00+  # 3 mapping + 1 ending = 0x04
  $s_ESC    + $s_CAPS   +  # 1st mapping: caps lock -> escape
  $s_CAPS   + $s_ESC    +  # 2nd mapping: escape -> caps lock
  $s_RCTR   + $s_RWIN   +  # 3rd mapping: right windows -> right control
  0x00, 0x00, 0x00, 0x00   # final four bytes
)

$null = new-itemProperty -path "HKLM:\SYSTEM\CurrentControlSet\Control\Keyboard Layout" -name "Scancode Map" -value $mapping -force
After changing the scan map, the computer needs to be restarted.
Update 2022-07-23: I used this script in a Oracle VirtualBox guest. It turns out it modifies the keys only if the guest OS is runnning in full screen mode.
The following ascii-art tries to show the Scancode map more graphically:
"Scancode Map"=hex:00,00,00,00,00,00,00,00,04,00,00,00,01,00,3a,00,3a,00,01,00,1d,e0,5c,e0,00,00,00,00
;                 | DWORD 1   | DWORD 2   | 3 Maps    | Map 1     | Map 2     | Map 3:    | Final
;                                         +-----------+-----------+-----------+-----------+-------------
;                                         |           |           |           |           | Final 4 bytes
;                                         | + 1 0000  |           |           | Map 3: Right Windows to Right Ctrl
;                                         | Ending    |           | Map 2: Escape to Caps Lock
;                                         |           | Map 1: Caps Lock to Escape

Changing the keybaord layout programatically

In order to change values under this registry key, administrator privileges are needed. Sometimes, they are not granted, effectively making it impossible to change the keyboard layout in the registry.
However, it's possible to programmatically create a keyboard hook to change scan codes on the fly.
Such programs are:

IgnoreRemoteKeyboardLayout

Apparently, setting the value of IgnoreRemoteKeyboardLayout to 1 prevents a Remote Desktop from using English (or the language of the Remote Client?) as default input language. (as per Neno Loje's Blog)

See also

keyboard
The kbfltr example from the Win2K DDK.
The default value of the registry key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\IniFileMapping\KeyboardLayout.ini\Keyboard Layout.
HKEY_CURRENT_USER\Keyboard Layout
Compare with HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layouts

Links

Keyboard and mouse class drivers (docs.microsoft.com)
The Microsoft Keyboard Layout Creator (msklc.exe) create and modify keyboard layouts (.klc files). It can be downloaded from here.

Index