Using AutoHotKey to streamline workflow with custom modifier keys

I was tired of typing some of the generic code in Unreal and came up with a solution that I think works fairly well. I’ve seen some videos utilizing crazy amounts of macro keys but that ends up with you burning a lot of desk real-estate to get as many buttons as you can, while with custom modifier keys a simple keyboard with few extra macro buttons can give you practically infinite macros within your finger’s reach.

Modifier keys are keys like CTRL, SHIFT and ALT. They tend to be used in combination with some other keys to achieve non-standard functionality. For example, pressing “c” types out the letter c, but pressing “ctrl + c” copies highlighted content to the clipboard.

Most generic gaming software doesn’t allow you to bind standard keys or create custom macros for combinations of keys. The only one I saw doing that to some extent was Roccat but it seems they limited the set of keys you could reprogram. With AutoHotkey you can do that no problem though.

What you need:

AutoHotKey is a button remapping software allowing for creation of complex macros (sequences of inputs or other functionality). It’s a free / open source project.

A keyboard or a mouse with extra buttons you can bind to F13-F24.

One way to do it:

I ended up creating my own modifier keys, using F13-F24. These keys were present on some very old keyboards, but almost no new keyboards has them - but they are still recognized by Windows, and, AutoHotkey. Most brand-name keyboards can also bind F13-F24 to their macro keys or, if a mouse, extra mouse buttons. In my setup, “F13+Q” types out “UPROPERTY()” and “F13+W” types out “UFUNCTION()”, as an example. Meanwhile, “F14+Q” is for “DECLARE_DELEGATE()” and so on. It is also possible to detect which program is currently active, and choose the functionality based on that.

AutoHotkey uses its own language to create the bindings. An example of the main script file:

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.

#SingleInstance, Ignore ; If you make changes and AHK script is already running, remove warning and run new

; #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.

#include UE4 Editor.ahk
#include UE4 VS.ahk

SendCommand(CommandInput)

;Detect Which program we are running

{
    WinGet, ActiveProgram, ProcessName, A
 
   if (ActiveProgram == "devenv.exe")
    PressVS(CommandInput)
    else if (ActiveProgram == "UE4Editor.exe")
    PressUE(CommandInput)
    return
}

;Bindings generated by another script!

F13 & A::SendCommand("F13A") return
F13 & B::SendCommand("F13B") return

...

An example of the Visual Studio Keybinds (UE4 VS.ahk):

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.

#SingleInstance, Force ; If you make changes and AHK script is already running, remove warning and run new

; #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.

PressVS(PressedButton)

{
    switch PressedButton
    {    
        case "F13Q": Send, UPROPERTY()
        case "F13W": Send, UFUNCTION()
        ...
    }
    return
}

An example of the Unreal Editor keybinds (UE4 Editor.ahk). The F13 + CapsLock will use the default hotkey for the play mode (Alt + P) and also move the cursor to the middle of the screen and click it to automatically put the game in focus:

PressUE(PressedButton)
{
    switch PressedButton
    {
        case "F13Q": Send, RerouteNode{Enter}
        case "F13W": Send, {RButton}Lerp Vector{Enter}

        ; Play - moves mouse the middle of the screen and presses left click to gain control

        case "F13CapsLock":    
        x := A_screenWidth/2
        y := A_screenHeight/2      
        Send, !p
        sleep 100
        Send, {Click %x%, %y%}

        ...
    }
    return
}

For the primary bindings I created a C++ script to write them for me :

#include <iostream>
#include <string>
#include <fstream>

int main()
{
	std::string CustomModifierKeys[12] = { "F13", "F14", "F15", "F16", "F17", "F18", "F19", "F20", "F21", "F22", "F23", "F24" };
	std::string SecondHotkeys[] = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "CapsLock", "Space", "Tab", "Enter", "Esc", "Backspace", "Shift" };
	std::string FileName = "Hotkeys.txt";
	std::string FileName2 = "Bindings.txt";
	std::ofstream Output(FileName);

	for (auto CustomModifierKey : CustomModifierKeys)
	{
		for (auto SecondHotkey : SecondHotkeys)
		{
			Output << CustomModifierKey << " & " << SecondHotkey << "::" << "SendCommand(" << "\"" << CustomModifierKey << SecondHotkey << "\"" << ") " << "return" << std::endl;
		}
		Output << std::endl;
	}
	Output.close();

	Output.open(FileName2);

	Output << "{" << std::endl << "    switch PressedButton" << std::endl << "    {" << std::endl;
	for (auto CustomModifierKey : CustomModifierKeys)
	{
		for (auto SecondHotkey : SecondHotkeys)
		{
			Output << "        case " << "\"" << CustomModifierKey << SecondHotkey << "\"" << ": Send, " << SecondHotkey << std::endl;
		}
		Output << std::endl;
	}
	Output << "    }" << std::endl << "    return" << std::endl << "}";
}

For the bindings the script is rather rudimentary because frankly I saw it relatively unnecessary; I typically make the bindings as I go.

I have some bindings set up and so far I have not experienced any slowdowns, the performance of the script if “really abused to its full extent” is unknown to me.

1 Like