I want to be able to map the Caps Lock Key to Escape if it is not pressed with any other key and Control if it is. How can I do that on Windows 7?


11 Answers 11


This may have appeared on the previously mentioned vim wikia page after Rich's solution above.

; Author: fwompner gmail com
SetCapsLockState, alwaysoff
Send {LControl Down}
KeyWait, CapsLock
Send {LControl Up}
if ( A_PriorKey = "CapsLock" )
    Send {Esc}

This is not my work, but I've started using it and it works exactly as described, no real caveats, and because it doesn't attempt to map any exceptions (because they are unnecessary) it behaves quite nicely in Chrome (I really wanted it for Vimium).

  • I've been using this script and it works for me. I'm using this for rebinding Caps Lock to Control/Escape for vim.
    – Brandon
    Commented Sep 19, 2016 at 15:04
  • 1
    Works! Just to clarify, it's an AutoHotKey script. Start here: autohotkey.com Commented Oct 26, 2017 at 14:20
  • 1
    For the benefit of readers that may not have clicked through and seen the comments on my gist, it seems this solution only works if you press Caps Lock before pressing Shift. Caps+Shift+X works but Shift+Caps+X doesn't.
    – Rich
    Commented Jan 3, 2018 at 10:12
  • ...although fenwar's version works in a similar way and doesn't have that limitation.
    – Rich
    Commented Oct 26, 2022 at 13:49
  • 1
    Here is the same script for autohotkey v2: InstallKeybdHook SetCapsLockState "AlwaysOff" Capslock:: { Send "{LCtrl down}" KeyWait "CapsLock" Send "{LCtrl Up}" If (A_PriorKey == "CapsLock") { Send "{Esc}" } } Commented May 8, 2023 at 18:26

You can remap it to Escape with SharpKeys

However, I don't know of a realistic way to perform conditional remapping, other than writing a keyboard driver.

  • 1
    I already have my Caps Lock key mapped to Escape with SharpKeys. Commented Jan 23, 2012 at 14:24

This is not exactly what you want but very close if you can live with some flaws. Here's an AutoHotKey script:

$CapsLock Up::Send {Escape}

It remaps Caps Lock to Ctrl and sends Escape when you release the key. It took me a while to get used to the Escape key being pressed every time I let go the Caps Lock key. However it's pretty much useless on website textareas because pressing Escape loses the focus on the textarea.

I'm looking for a solution to this though. I might go as far as write some sort of driver/keyboard hook in C if needed, haha.

Vim-specific annoyances: It makes digraphs impossible to type using the Ctrl-K combination and is generally plain annoying before you get used to it. It works well for me though because I'd do anything to avoid Esc and Ctrl keys as much as possible.

  • If you just want to map it to escape, you can simplify this to: $CapsLock::Escape and then immediately return.
    – Kazark
    Commented Apr 14, 2016 at 16:26
  • I'm trying to understand -- so the flaw with the script is that when Caps Lock is pressed and released, both a Ctrl and Escape are sent?
    – Rishi
    Commented Jun 15, 2016 at 16:19
  • Watch out: the AutoHotKey code given here led to all kinds of problems for me. The script given by dragon788, on the other hand, seems to be working well so far.
    – ba_ul
    Commented Feb 11, 2020 at 3:19

Here is a registry entry that maps the caps lock to escape on windows 7.

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,3a,00,46,00,01,00,3a,00,00,00,00,00

Save the above to a file with a .reg extension (like mapCapLocks.reg) and import/execute it on your machine. This can be done by clicking that file in the File Explorer, and then signing out and signing in again.

  • Please quote the essential parts of the answer from the reference link(s), as the answer can become invalid if the linked page(s) change. Currently 404 so this answer is useless.
    – DavidPostill
    Commented Feb 12, 2017 at 14:26
  • Excellent points. I will update the answer
    – Stryker
    Commented Feb 12, 2017 at 16:11
  • 4
    This will also map the ScrollLock key to CapsLock. If that's not what you want, use the value hex:00,00,00,00,00,00,00,00,02,00,00,00,01,00,3a,00,00,00,00,00. Useful editor for this map is ScancodeMapping from PlexData.
    – Appleshell
    Commented Jun 22, 2019 at 14:05
  • Thanks @Appleshell. Was looking into this and realised it was also doing that additional remapping. Useful introduction for newbies. And if you want to swap escape with caps lock, use this: hex:00,00,00,00,00,00,00,00,03,00,00,00,01,00,3a,00,3a,00,01,00,00,00,00,00
    – Cloud
    Commented Feb 16, 2022 at 22:16
  • Useful site for testing keyboard presses after signing back in
    – Cloud
    Commented Feb 16, 2022 at 22:27

I use the following AutoHotkey script for this, adapted from one I found on the Vim Tips Wiki. The implementation is a bit hacky, but it "works for me." (And unlike the other answers on this page as of 2016-09-19, it fully solves the issue without any caveats that I am aware of.)

The original coder noted:

The script also tries to detect and avoid "false positives" where you press Control and another key and release both too quickly, i.e. before the timeout period.

Be sure to tweak the 250ms value depending on how good or bad your keyboard is, and your own reaction time. This is probably something to tweak experimentally to your own liking.

CapsLockCtrlEscape.ahk gist:

g_LastCtrlKeyDownTime := 0
g_AbortSendEsc := false
g_ControlRepeatDetected := false

    if (g_ControlRepeatDetected)

    send,{Ctrl down}
    g_LastCtrlKeyDownTime := A_TickCount
    g_AbortSendEsc := false
    g_ControlRepeatDetected := true


*CapsLock Up::
    send,{Ctrl up}
    g_ControlRepeatDetected := false
    if (g_AbortSendEsc)
    current_time := A_TickCount
    time_elapsed := current_time - g_LastCtrlKeyDownTime
    if (time_elapsed <= 250)
        SendInput {Esc}

    g_AbortSendEsc := true

Actually I think I've built the perfect solution here:

As a Vim user, this is a must for me, and I've been using it with success on Windows for a long time. I just create an entry on HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run with regedit to point to the executable and it simply works.

To compile and install dependencies please check the repository README and main website for Interception.

I've also created a Linux version of the same here:


I was looking for something as similar to this, but unfortunately the AHK scripts from the answers here didn't work well for me.

However, I found a solution that solved this for me on the vim wiki.

  • First, download the following app called dual-key-remap.
  • Extract the zip in a location of your choosing (I store utilities like these in C:\Users\%username%\util\)
  • Open the following directory: C:\Users\%username%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\ and drag the dual-key-remap.exe file there, while holding ALT to create a shortcut. (Or right click and select 'create shortcut', and move the shortcut to your startup directory).
  • Log in and out. A few seconds after you're logged in the keys will be rebound.

If you don't mind compiling short source code yourself, then you can use the code below. You need to compile it as Windows console application. E.g., in Visual C++ command prompt you can compile it with

cl /D_WIN32_WINNT=0x0401 remap_capslock.cpp /EHsc /link user32.lib

The key remapping works while the application is running. No need for reboot, log out/in, etc. If you need remapping to work for applications run with admin rights, then you need to run the remapper application as admin also. Have been using it for couple of days already (on Windows 10), so far so good.

// The app allows to remap CapsLock key to Esc (if pressed separately) or to Ctrl (if pressed with other keys).
// This may be useful for Vim.
// To compile from Visual C++ command prompt: 
//    cl /D_WIN32_WINNT=0x0401 remap_capslock.cpp /EHsc /link user32.lib
// Original source (which supported only Caps-Ctrl remapping): https://superuser.com/a/1490007/22750

#include <windows.h>
#include <iostream>
#include <set>

HHOOK hook;
std::set<WORD> keys_down;
bool caps_down = false;
bool caps_was_down_with_another_key = false;

LRESULT CALLBACK keyboardHook(int nCode, WPARAM wParam, LPARAM lParam) {

    if ((p->flags & LLKHF_INJECTED) == 0) {
        std::cout << "nCode=" << nCode << "\twParam=" << wParam << "\tvkCode=" << p->vkCode << "\tscanCode=" << p->scanCode << std::endl;
        bool keyup = wParam == WM_KEYUP || wParam == WM_SYSKEYUP;
        if (p->vkCode == VK_CAPITAL) {
            if (keyup) {
                if (caps_was_down_with_another_key) {
                    std::cout << "Remapping CAPSLOCK UP to CTRL UP" << std::endl;
                    input[0].ki.dwFlags = KEYEVENTF_KEYUP;
                    input[0].ki.wVk = VK_LCONTROL;
                    SendInput(1, input, sizeof (INPUT));
                } else {
                    std::cout << "Remapping CAPSLOCK UP to ESCAPE DOWN&UP" << std::endl;
                    input[0].ki.dwFlags = KEYEVENTF_KEYUP;
                    input[0].ki.wVk = VK_LCONTROL;
                    input[1].ki.dwFlags = 0;
                    input[1].ki.wVk = VK_ESCAPE;
                    input[2].ki.dwFlags = KEYEVENTF_KEYUP;
                    input[2].ki.wVk = VK_ESCAPE;
                    SendInput(3, input, sizeof (INPUT));
                caps_down = false;
                caps_was_down_with_another_key = false;
            } else {
                std::cout << "Remapping CAPSLOCK DOWN to CTRL DOWN" << std::endl;
                caps_down = true;
                input[0].ki.dwFlags = 0;
                input[0].ki.wVk = VK_LCONTROL;
                SendInput(1, input, sizeof (INPUT));
            return 1;
        } else {
            if (keyup) {
            } else {
            std::cout << keys_down.size() << " keys down" << std::endl;
        if (caps_down && !keys_down.empty()) {
            caps_was_down_with_another_key = true;
    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) {
        std::cout << "Error " << GetLastError() << std::endl;
        return 1;
    std::cout << "Mapping ??? CAPSLOCK=>LCTRL and LCTRL=>CAPSLOCK..." << std::endl;
    while (GetMessage (&messages, NULL, 0, 0)) {
    return 0;

I don't have enough reputation to comment on the answer that worked for me. I still upvoted it though.

pepper-chico's answer worked for me.

Caps Lock key behaves as Escape key if pressed on its own. And behaves like Ctrl key if combined with others. I also have the same use case for this. Vim.

The instruction in the link he provided is simple enough to follow.


I got sick of time-dependent solutions using AutoHotKey, but once in a blue moon, I do want to type a lot of caps; so I didn't want to disable it. I finally came up with a script that seems to work pretty well. No script I made would prevent it from turning on with some mysterious accidental combination (on an early M$ ergo kb), so I decided to map it to a keystroke I never use. The following remaps it to <Ctrl-Pause/Break>. That key chord does nothing normally, but turns on with the following script. You can change the key to trigger CapsLock to anything you like.

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn  ; Enable warnings to assist with detecting common errors.
SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

; Disable CapsLock and Shift-CapsLock combinations

; Uncomment the following lines to also disable the Left Windows Key

; Define the Ctrl-Pause/Break shortcut
SetCapsLockState % !GetKeyState("CapsLock", "T")

I don't expect it to interfere with the normal use of the Pause/Break key (which is just about nothing in Windows). You can compile it into a compact .exe with AutoHotKey too. I quickly found that other combinations of Shift, Ctrl and CapsLock would also trigger CapsLock, but after fixing it in the code, and using it a few days, it's functioning flawlessly. I wasn't sure if disabling the CapsLock key in AHK entirely would also disable the CapsLock state when triggered by another key chord, so I just trapped for these CapsLock-triggering combinations. I have stopped having false CapsLock triggers, and yet CAPS LOCK is still easy go get ;}


PowerToys switch esc and caps lock solution for Windows 10/11 (no conditional)

This answer covers only the switch esc and caps lock without considering other keys being pressed or not:

Selling points:

enter image description here

enter image description here

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .