127

In Windows 8 I used to remap my capslock key to control using the registry script

REGEDIT4

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout]
"Scancode Map"=hex:00,00,00,00,00,00,00,00,02,00,00,00,1d,00,3a,00,00,00,00,00

After having upgraded to Window 10, this does not work anymore.

How can it be done?

1
  • Note this only remaps Caps Lock to another Ctrl key. I want them swapped, so I used the instructions here to tweak the script above: superuser.com/a/1202601/315584
    – jia103
    Sep 20, 2017 at 15:00

12 Answers 12

107

Did you remember to reboot? It works fine for me, just like in Windows 7 and 8.

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout]
"Scancode Map"=hex:00,00,00,00,00,00,00,00,02,00,00,00,1d,00,3a,00,00,00,00,00
5
  • 9
    The issue for me was that the Windows 10 upgrade reset my caps lock mapping. But doing it again the same way worked after another restart. Dec 1, 2015 at 2:48
  • 50
    If anyone else like me needs the final piece of the puzzle: paste the above into a new text file, save it with the .reg extension, double click the file to apply the changes to the registry, then reboot. Sep 6, 2016 at 0:00
  • 6
    How do you map it back to Caps Lock afterwards? Dec 1, 2016 at 1:36
  • 7
    @EhteshChoudhury you can delete the "Scancode Map" entry under the registry key, reboot, and default behavior will be restored.
    – bojolais
    Apr 11, 2017 at 19:16
  • 2
    I only had to logout and login again, didn't have to reboot (win 10)
    – piec
    Feb 7, 2020 at 15:10
140

In case anyone needed this done via PowerShell:

$hexified = "00,00,00,00,00,00,00,00,02,00,00,00,1d,00,3a,00,00,00,00,00".Split(',') | % { "0x$_"};

$kbLayout = 'HKLM:\System\CurrentControlSet\Control\Keyboard Layout';

New-ItemProperty -Path $kbLayout -Name "Scancode Map" -PropertyType Binary -Value ([byte[]]$hexified);

Run it as Administrator and reboot.

3
  • 3
    Apparently logging out and an in again is sufficient
    – piec
    Feb 7, 2020 at 15:10
  • @binarymason it has gotten a lot better over the years. PowerShell was a pretty poor scripting language until they open sourced it and came out with PowerShell Core. Oct 23, 2021 at 15:33
  • Can anyone explain these scancodes and how to manipulate them? Oct 23, 2021 at 17:03
69

There is now a solution directly from Microsoft for mapping caps lock to the control key called PowerToys. PowerToys does not involve using a third party tool or modifying the registry by hand (which has the potential for causing serious problems if done incorrectly). The tool in PowerToys that handles this is installed by default and called Keyboard Manager. It works exactly as expected - here is an image of the Caps Lock key mapped to the Ctrl key.

enter image description here

8
  • 1
    I used the registry "Scancode Map" key for years, including on Windows 10, but one day it stopped working for Ctrl-X. Caps Lock acted as Ctrl most of the time, but not when used with the X key. Keyboard Manager seems to work correctly and also handles Ctrl-Alt-backslash, another key combination which can defeat remapping.
    – Ed Avis
    Dec 29, 2020 at 10:22
  • 2
    ...However, the PowerToys remapping does not work over remote desktop. You can remap on your local PC but the remote desktop session does not get the remapping. And running the same PowerToys on the remote PC doesn't work either. (It seems that somehow, both Ctrl and Caps Lock keypresses are being sent to the remote computer.)
    – Ed Avis
    Dec 31, 2020 at 13:01
  • 2
    Here's the Microsoft Docs page and install link
    – karmakaze
    May 11, 2021 at 1:56
  • The tool is a bit OP but it works better than the Registry key, because the Num Lock idicator on my keyboard still gets activated, when I use the Registry key., but stays off with this tool. All functions, which are not usefull can be disabled. I have installed from Github. Works fine.
    – ceving
    Sep 25, 2021 at 12:53
  • This isn't working for me. It doesn't persist across restarts. Feb 3 at 19:48
30

You can use SharpKeys to map any key to any other key in Windows 7, 8, or 10. It's much easier and cleaner to do than to modify the registry yourself.

Hope this helps.

2
  • 2
    Can I use this to switch languages by pressing caps lock ?
    – thanos.a
    Jan 5, 2019 at 17:34
  • Just wanted to note that this program just modifies your registry, so it's not something that has to be running all the time or anything. Great utility!
    – xaxxon
    Jan 4, 2021 at 18:29
24

I use the following to send CTRL for the CAPS LOCK key, send ALT for the CTRL key, and send CAPS LOCK for the ALT key. CTRL is to the left of "A" where God intended it, ALT is below SHIFT, and the utterly useless CAPS LOCK key is safely tucked away where I have to break my wrist to hit it.

Windows Registry Editor Version 5.00

; The hex data is in five groups of four bytes:
;   00,00,00,00,\    header version (always 00000000)
;   00,00,00,00,\    header flags (always 00000000)
;   04,00,00,00,\    # of entries (3 in this case) plus a NULL terminator line.
;                    Entries are in 2-byte pairs: Key code to send & keyboard key to send it.
;                    Each entry is in "least significant byte, most significant byte" order,
;                    e.g. 0x1234 becomes `34,12`
;   1d,00,3a,00,\    Send LEFT CTRL (0x001d) code when user presses the CAPS LOCK key (0x003a) 
;   38,00,1d,00,\    Send LEFT ALT (0x0038) code when user presses the LEFT CTRL key (0x001d) 
;   3a,00,38,00,\    Send CAPS LOCK (0x003a) code when user presses the LEFT ALT key (0x0038) 
;   00,00,00,00      NULL terminator

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout]
"Scancode Map"=hex:00,00,00,00,\
                   00,00,00,00,\
                   04,00,00,00,\
                   1d,00,3a,00,\
                   38,00,1d,00,\
                   3a,00,38,00,\
                   00,00,00,00
4
  • 6
    I really appreciate the comments. I always wondered what the codes meant. Very helpful.
    – zaphodtx
    Aug 8, 2018 at 22:01
  • What a nice explanation ! Do you know by any chance the kye code of the Windows key ? I need to remap the CapsLock to act as Windows Key Jul 2, 2020 at 17:12
  • 1
    @AndreiBoyanov that would be 0xE05B, so instead of 1d,00,3a,00 you should use 5b,e0,3a,00.
    – selurvedu
    Jan 17, 2021 at 16:15
  • Thanks for this answer! I spent a while to find an explanation for the data structure. Other answers and sources suggest a working solution without explaining how it works and how to alter it. SharpKeys, however, does the same with a user-friendly UI.
    – selurvedu
    Jan 17, 2021 at 16:24
8

I used to use AutoHotKey to do this.

I'd have a link in the startup directory to run a very basic ahk script:

Capslock::Ctrl

The thing is, Autohotkey isn't run as Administrator so it won't affect privileged windows, unless you use the task scheduler instead of the startup directory to run the script at login with higher privileges. The second problem is that sometimes, the script hangs when resuming sleep, so you may need to reload it, which is annoying.

AutoHotKey is better suited for more complex tasks, like writing macros.

3
  • I tried the autohotkey solution and i do not recommend it. It doesn't work well if you have your autorepeat speed high, delay low. It also doesn't mix well with xkeymacs, which makes emacs keys work almost everywhere in Windows.
    – Reb.Cabin
    Mar 30, 2019 at 4:32
  • I don't use emacs, open a .ahk file automatically at login, and find this solution to be the most simple and portable by far
    – 3pitt
    Aug 7, 2019 at 10:51
  • I use emacs and this is a very feasible solution for me. I just execute the script at login every time on the desktop. I don't have admin rights. May 12, 2021 at 10:01
8

The inexhaustible sysinternals toolbox also provides a little program just for switching capslock with control -- Ctrl2Cap

Ctrl2cap is a kernel-mode device driver that filters the system's keyboard class driver in order to convert caps-lock characters into control characters.

It has a long history, but does work on Windows 10, including 64-bit. You run it once to install the driver.

1
  • 1
    For me, Ctrl2Cap is currently the most reliable solution. The registry key "Scancode Map" does work in Windows 10, but strangely stopped working for the Ctrl-X keystroke in particular. The PowerToys Keyboard Manager works, including Ctrl-X, but doesn't work over remote desktop (and running it on the remote PC as well as the local one doesn't seem to let you remap successfully). Ctrl2Cap is remapping in all applications including remote desktop.
    – Ed Avis
    Dec 31, 2020 at 9:09
6

This is the script to swap CTRL and CAPS LOCK keys:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout]
"Scancode Map"=hex:00,00,00,00,00,00,00,00,03,00,00,00,1d,00,3a,00,3a,00,1d,00,00,00,00,00
2

If, for some reason, you don't want to run third-party tools, it's possible to do this yourself with a bit of C. Thanks to Susam Pal's brilliant answer, I put the snippet below together.

It's practically a key-logger. It listens for key presses, captures them, and constructs keyboard input with the mapping in mind. The below console app need to be running for it to work.

You will need to compile this somehow. I used msys2.org with pacman -S mingw-w64-x86_64-gcc and compiled with /mingw64/bin/gcc nocaps.c -o nocaps.exe.

#include <stdio.h>
#include <windows.h>

HHOOK hook;

#define KEYCODE_CAPSLOCK 20
#define KEYCODE_LCTRL 162

LRESULT CALLBACK keyboardHook(int nCode, WPARAM wParam, LPARAM lParam)
{
    KBDLLHOOKSTRUCT *p = (KBDLLHOOKSTRUCT *) lParam;
    INPUT input = {.type = INPUT_KEYBOARD };

    printf("nCode=%d\t wParam=%d\t p->vkCode=%lu \t p->scanCode=%d\t\n", nCode, wParam, p->vkCode, p->scanCode);


    if (wParam == WM_KEYUP || wParam == WM_SYSKEYUP) {
        input.ki.dwFlags = KEYEVENTF_KEYUP;
    }

    if (p->vkCode == KEYCODE_CAPSLOCK && (p->flags & LLKHF_INJECTED) == 0) {
        input.ki.wVk = KEYCODE_LCTRL;
        SendInput(1, &input, sizeof (INPUT));
        return 1;
    } else if (p->vkCode == KEYCODE_LCTRL && (p->flags & LLKHF_INJECTED) == 0) {
        input.ki.wVk = KEYCODE_CAPSLOCK;
        SendInput(1, &input, sizeof (INPUT));
        return 1;
    }

    return CallNextHookEx(hook, nCode, wParam, lParam);
}

int main(int argc, char **argv)
{
    MSG messages;

    hook = SetWindowsHookEx(WH_KEYBOARD_LL, keyboardHook, NULL, 0);
    if (hook == NULL) {
        printf("Error %d\n", GetLastError());
        return 1;
    }

    printf("Mapping CAPSLOCK=>LCTRL and LCTRL=>CAPSLOCK..\n");
    while (GetMessage (&messages, NULL, 0, 0))
    {
        TranslateMessage(&messages);
        DispatchMessage(&messages);
    }
    return 0;
}
2

You can use lswitch to remap language input to CapsLock.

Use any key to switch input languages, usage: lswitch [keycode]. Keycode is optional and defaults to context menu key. Another good candidate is a CapsLock key with a keycode of 20.

lswitch 20

Add it to autoload.

1
  • this works, however the caps lock functionality is lost. any idea on how to define the caps lock functionality to shift+caps lock combination?
    – thanos.a
    Jan 5, 2019 at 17:51
0

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.
-1

I would like to share my AutoHotKey solution on Windows 10:

Loop, %0%  ; For each parameter:
  {
    param := %A_Index%  ; Fetch the contents of the variable whose name is contained in A_Index.
    params .= A_Space . param
  }
ShellExecute := A_IsUnicode ? "shell32\ShellExecute":"shell32\ShellExecuteA"

if not A_IsAdmin
{
    If A_IsCompiled
       DllCall(ShellExecute, uint, 0, str, "RunAs", str, A_ScriptFullPath, str, params , str, A_WorkingDir, int, 1)
    Else
       DllCall(ShellExecute, uint, 0, str, "RunAs", str, A_AhkPath, str, """" . A_ScriptFullPath . """" . A_Space . params, str, A_WorkingDir, int, 1)
    ExitApp
}

+Capslock::Capslock ; make shift+Caps-Lock the Caps Lock toggle
Capslock::Control   ; make Caps Lock the control button
1
  • 2
    Could you go into a detail on how your answer differs from the others posted?
    – Burgi
    May 28, 2021 at 11:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.