Search notes:

swap_keys.c

This small C program swaps the Esc and the Caps Lock keys and assigns the right ctrl key to the right alt key on the keyboard.
//
//   http://stackoverflow.com/a/27644207/180275
//
#include <stdio.h>

#ifdef __CYGWIN__ // 2017-07-18 (tsettgchabe)
// #define _WIN32_WINNT 0x0404
#define _WIN32_WINNT 0x0500
#endif
#include <windows.h>

HHOOK hook;

#ifdef AS_DLL

int i = 0;

BOOL WINAPI DllMain (
    HINSTANCE hInstDLL,
    DWORD     fdwReason,
    LPVOID    lpvReserved

) {

//  Oh, wy are such things even necessary and what can
//  be done to change it.
  if (! i++) {
    MessageBox(0, "DllMain", "Swap keys", 0);
  }
}

#endif

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

    KBDLLHOOKSTRUCT *p = (KBDLLHOOKSTRUCT *) lParam;

    DWORD newVkCode;
    INPUT inputs[1];
    UINT ret;

    char wParamStr[11];
    char vkStr    [10] = "";

    if (nCode < 0) {
     //
     // nCode: A code the hook procedure uses to determine how to process the message.
     // If nCode is less than zero, the hook procedure must pass the message to
     // the CallNextHookEx function without further processing and should return
     // the value returned by CallNextHookEx.
     //
        return CallNextHookEx(hook, nCode, wParam, lParam);
    }

#ifdef SHOW_INFO

    if      (wParam == WM_KEYDOWN)    strcpy(wParamStr, "KEYDOWN");
    else if (wParam == WM_KEYUP)      strcpy(wParamStr, "KEYUP");
    else if (wParam == WM_SYSKEYDOWN) strcpy(wParamStr, "SYSKEYDOWN");
    else if (wParam == WM_SYSKEYUP)   strcpy(wParamStr, "SYSKEYUP");
    else                              strcpy(wParamStr, "UNKNOWN");

    if      (p->vkCode ==   9) strcpy(vkStr, "<TAB>"    );
    else if (p->vkCode ==  10) strcpy(vkStr, "<LF>"     );
    else if (p->vkCode ==  13) strcpy(vkStr, "<CR>"     );
    else if (p->vkCode ==  20) strcpy(vkStr, "<CAPSLCK>");
    else if (p->vkCode ==  27) strcpy(vkStr, "<ESC>"    );
    else if (p->vkCode == 161) strcpy(vkStr, "<L-SHIFT>");
    else if (p->vkCode == 162) strcpy(vkStr, "<L-CTRL>" );
    else if (p->vkCode == 163) strcpy(vkStr, "<R-CTRL>" );
    else if (p->vkCode == 164) strcpy(vkStr, "<L-ALT>"  );
    else if (p->vkCode == 165) strcpy(vkStr, "<R-ALT>"  );
    else if (p->vkCode == 226) strcpy(vkStr, "<R-SHIFT>");
    else vkStr[0] = p->vkCode;

    char wndTitle[256];
    HWND hwnd=GetForegroundWindow();
    GetWindowText(hwnd, wndTitle, sizeof(wndTitle));

    WINDOWPLACEMENT wp;
    wp.length = sizeof(wp);

    GetWindowPlacement(hwnd, &wp);
    char* showCmd;
    if (wp.showCmd == SW_MAXIMIZE) { showCmd = "    SW_MAXIMIZE"; }
    else                           { showCmd = "not SW_MAXIMIZE"; }

    printf(" %-10s - %3lu | %9s | %3d - %lu | %-30s %s\n", wParamStr, p->vkCode, vkStr, p->scanCode, p->time, wndTitle, showCmd);

#endif

    inputs[0].type           = INPUT_KEYBOARD;
    inputs[0].ki.wScan       = 0;
    inputs[0].ki.dwFlags     = 0;
    inputs[0].ki.time        = 0;
    inputs[0].ki.dwExtraInfo = 0;

    if (wParam == WM_KEYUP || wParam == WM_SYSKEYUP) {
        inputs[0].ki.dwFlags = KEYEVENTF_KEYUP;
    }

    if ((p->flags & LLKHF_INJECTED) == 0) {
     //
     // If the LLKHF_INJECTED (= 0x10) bit is set, the event was injected.
     //
     // With the previous test, we skip over injected events and only
     // change «original» events.
     //
        if (p->vkCode == VK_ESCAPE) {                    // ESC (27) -> CAPS LOCK (20)
            inputs[0].ki.wVk = VK_CAPITAL;
            ret = SendInput(1, inputs, sizeof (INPUT));
            return 1;
        }
        if (p->vkCode == VK_CAPITAL) {                   // CAPS LOCK (20) -> ESC (27)
            inputs[0].ki.wVk = VK_ESCAPE;
            ret = SendInput(1, inputs, sizeof (INPUT));
            return 1;
        }
        if (p->vkCode == VK_RMENU) {                     // Right Alt (165) -> Right Ctrl (163)
            inputs[0].ki.wVk = VK_RCONTROL;
            ret = SendInput(1, inputs, sizeof (INPUT));
            return 1;
        }
    }


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

#ifdef AS_DLL
extern // 2017-07-21 - tsettchabe / CYGWIN
__declspec(dllexport)
#endif
int
#ifdef AS_DLL
__stdcall
#endif
startSwapKeys() {

    MSG messages;

    hook = SetWindowsHookEx(WH_KEYBOARD_LL, keyboardHook, NULL, 0);

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

#ifndef AS_DLL

    printf("Waiting for messages ...\n");

    while (GetMessage (&messages, NULL, 0, 0)) {
        TranslateMessage(&messages);
        DispatchMessage(&messages);
    }

#endif
    return 0;

}

#ifndef AS_DLL
int main(int argc, char **argv) {
    return startSwapKeys();
}
#endif
Github repository swap-keys, path: /swap_keys.c

Compiling

With Visual Studio on the command line:
cl swap_keys.c user32.lib

Compiling as DLL

With MinGW:
$ gcc -DAS_DLL -c swap_keys.c
$ gcc -shared -o swap_keys.dll swap_keys.o

See also

Configuring the keyboard layout
A similar program is SwapKeys.cs, but written in C# and this program, written in VBA.
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout
Examples for Visual Basic for Application accessing the Windows API: SetWindowsHookEx
The Sysinternals tool Ctrl2Cap.
https://github.com/susam/uncap
The source code on github.

Index