I put together a cmd batch file, install-keyboard.bat
(latest version in https://gitlab.com/0mid/dotfiles/-/blob/master/install-keyboard.bat), to map the CapsLock and the right "Windows key" both to Left Ctrl (LCtrl).
Hopefully, the variable names for the key codes and clarifying comments (incorporating those from @mnemotronic here and the 'official' docs, in addition to mine) make this script useful for (and extensible by) others who are forced to use this proprietary operating system (Windows).
This batch file needs to be run in an Admin cmd, and a sign-out sign-in (NOT a restart) is needed for the new mappings to take effect. There doesn't seem to be an equivalent key per user (HKCU), so this mapping affects the whole local machine (HKLM).
I'm having to do this because AutoHotKey is working unreliably (otherwise it is great, free software, https://www.gnu.org/philosophy/free-sw.html, and doesn't need Admin to 'install', use or take effect either). In particular, although, in AutoHotKey, I mapped the "Windows key" to Ctrl, Windows+d (expected to be Ctrl-d) keeps being 'intercepted' by Windows first instead, causing its multiple desktop to be displayed (which I couldn't find a way to disable), or worse a broken keyboard state to happen in which most keys won't even function.
@echo off
setlocal
net session >nul 2>&1 || (echo This script requires Admin.&goto :eof)
rem Unfortunately, as the key "Keyboard Layout" HAS TO be written
rem under HKEY_LOCAL_MACHINE\..., this needs Admin.
rem Also unfortunately, as the mappings are apparently read by the
rem keyboard driver at session start-up, once the mapping is stored in
rem the registry, a log out/log in was needed for the mapping to take
rem effect. Restarting explorer.exe did NOT do it. Microsoft docs
rem below says a restart is needed, which wasn't.
rem From
rem https://docs.microsoft.com/en-us/windows-hardware/drivers/hid/keyboard-and-mouse-class-drivers#scan-code-mapper-for-keyboards:
rem ---
rem Windows 2000 and Windows XP include a new Scan Code Mapper, which
rem provides a method that allows for mapping of scan codes. The scan
rem code mappings for Windows are stored in the following registry
rem key: syntax
rem HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout
rem Note There is also a Keyboard Layouts key (notice the plural form)
rem under the Control key, but that key should not be modified.
rem In the Keyboard Layout key, the Scancode Map value must be added.
rem This value is of type REG_BINARY (little Endian format) and has
rem the data format specified in the following table.
rem |Start offset (in bytes) | Size (in bytes) | Data |
rem |0 | 4 | Header: Version Information |
rem |4 | 4 | Header: Flags |
rem |8 | 4 | Header: Number of Mappings |
rem |12 | 4 | Individual Mapping |
rem |... | ... | ... |
rem |Last 4 bytes | 4 | Null Terminator (0x00000000) |
rem The first and second DWORDS store header information and should be
rem set to all zeroes for the current version of the Scan Code Mapper.
rem The third DWORD entry holds a count of the total number of
rem mappings that follow, including the null terminating mapping. The
rem minimum count would therefore be 1 (no mappings specified). The
rem individual mappings follow the header. Each mapping is one DWORD
rem in length and is divided into two WORD length fields. Each WORD
rem field stores the scan code for a key to be mapped.
rem Note that if the mapping of a scan code is necessary on a
rem keypress, the step is performed in user mode just before the scan
rem code is converted to a virtual key. Doing this conversion in user
rem mode can present certain limitations, such as mapping not working
rem correctly when running under Terminal Services.
rem To remove these mappings, remove the Scancode Map registry value
rem and reboot.
rem ---
rem The hex data is in five groups of four bytes:
rem 00,00,00,00,\ header version (always 00000000)
rem 00,00,00,00,\ header flags (always 00000000)
rem 03,00,00,00,\ # of entries (2 in this case) plus a NULL terminator line.
rem Entries are in 2-byte pairs: Key code to send & keyboard key to send it.
rem Each entry is in "least significant byte, most significant byte" order,
rem e.g. 0x1234 becomes `34,12`
rem 1d,00,3a,00,\ Send LEFT CTRL (0x001d) code when user presses the CAPS LOCK key (0x003a)
rem 1d,00,5c,e0,\ Send LEFT CTRL (0x001d) code when user presses the right Windows key (0xe05c)
rem 00,00,00,00 NULL terminator
set "CapsLock=3a,00"
set "LCtrl=1d,00"
set "RCtrl=1d,e0"
set "LAlt=38,00"
set "RAlt=38,e0"
set "LWin=5b,e0"
set "RWin=5c,e0"
set "Menu=5d,e0"
set "headerVersion=00,00,00,00"
set "headerFlags=00,00,00,00"
set "numEntries=03,00,00,00"
set "mapping1=%LCtrl%,%CapsLock%"
set "mapping2=%LCtrl%,%RWin%"
set "nullTerminator=00,00,00,00"
set "data=%headerVersion%%headerFlags%%numEntries%%mapping1%%mapping2%%nullTerminator%"
set "dataNoComma=%data:,=%"
set "key=HKLM\SYSTEM\CurrentControlSet\Control\Keyboard Layout"
reg add "%key%" /f /v "Scancode Map" /t REG_BINARY /d %dataNoComma%
echo Sign out and sign in for the new key mappings to take effect.
Uncap
which does not require rebooting or admin privilege)dual-key-remap
which doesn't require reboot/admin either