I recently bought a Filco Majestouch Ninja mechanical keyboard. It doesn’t come with all the fancy function keys, therefore I decided to create some function keys myself. I installed the AutoHotKey (AHK) tool and wrote an AHK script. I use the Windows key as a replacement for the Function (Fn) key typically found on laptop keyboards. Here is a list of my function key mappings.

ShortcutFunctions
Win+EscPut computer to sleep
Win+F6Toggle volume mute
Win+F7Turn master volume down
Win+F8Turn master volume up
Win+F9Skip to previous song
Win+F10Play or pause song
Win+F11Skip to next song
Win+F12Open Network And Sharing Center

I use a Windows 7 on my desktop, but I found the Power User Menu shortcuts in Windows 8 come in handy, so I created them too. The Power User Menu is the pop-up menu which is displayed on the bottom left corner when you press Win+X on a Windows 8 computer. The script will not display the menu, so you need to remember the shortcut keys.

ShortcutFunctions
Win+X, FProgram and Features
Win+X, BMobility Center
Win+X, OPower Pptions
Win+X, VEvent Viewer
Win+X, YSystem
Win+X, MDevice Manager
Win+X, KDisk Management
Win+X, GComputer Management
Win+X, CCommand Prompt
Win+X, ACommand Prompt (Admin)
Win+X, TTask Manager
Win+X, PControl Panel
Win+X, EExplorer
Win+X, SSearch
Win+X, RRun
Win+X, DDesktop

Here goes the script.

#SingleInstance Force
global g_StartupMemoryPendingActions := {}
global g_StartupMemoryDoublePressWindowMs := 350
; Put computer to sleep (Win + Esc)
#Esc::
; Sleep/Suspend:
DllCall("PowrProf\SetSuspendState", "int", 0, "int", 0, "int", 0)
; Hibernate:
;DllCall("PowrProf\SetSuspendState", "int", 1, "int", 0, "int", 0)
Return
;; Volume control
; Toggle mute (Win + F6)
#F6::Send {Volume_Mute}
; Turn master volume down (Win + F7)
#F7::Send {Volume_Down}
; Turn master volume up (Win + F8)
#F8::Send {Volume_Up}
;; Media control
; Prev song (Win + F9)
#F9::Send {Media_Prev}
; Play or pause (Win + F10)
#F10::Send {Media_Play_Pause}
; Next song (Win + F11)
#F11::Send {Media_Next}
; Show Network control panel (Win + F12)
#F12::Run, %windir%\system32\control.exe /name Microsoft.NetworkandSharingCenter
; Shutdown (Win + Ctrl + F12)
#^F12::Run, shutdown /s /t 0
; Set Hyper-V focal VM StartupBytes to 8 GB, or 3 GB on double press (Win + Ctrl + F9, F9)
#^F9::
HandleStartupMemoryHotkey("focal", 8, 3, "F9")
Return
; Show assigned memory for Hyper-V focal VM (Win + Ctrl + F10)
#^F10::
vmName := "focal"
assignedMemory := GetHyperVAssignedMemory(vmName, errText, !A_IsAdmin)
if (errText != "")
{
TrayTip, Hyper-V Memory, Failed to read %vmName% memory.`n%errText%, 5, 17
Return
}
if (assignedMemory = "")
assignedMemory := "Unknown"
TrayTip, Hyper-V Memory, %vmName% assigned memory: %assignedMemory%, 5, 1
Return
; Set Hyper-V focal VM StartupBytes to 16 GB, or 22 GB on double press (Win + Ctrl + F11, F11)
#^F11::
HandleStartupMemoryHotkey("focal", 16, 22, "F11")
Return
HandleStartupMemoryHotkey(vmName, singlePressTargetGb, doublePressTargetGb, keyName)
{
global g_StartupMemoryPendingActions
global g_StartupMemoryDoublePressWindowMs
actionKey := vmName . "|" . keyName
if (g_StartupMemoryPendingActions.HasKey(actionKey) && (A_TickCount - g_StartupMemoryPendingActions[actionKey].startTick) <= g_StartupMemoryDoublePressWindowMs && AreWinCtrlModifiersHeld())
{
g_StartupMemoryPendingActions.Delete(actionKey)
RunStartupMemoryHotkeyAction(vmName, doublePressTargetGb)
if (g_StartupMemoryPendingActions.Count() = 0)
SetTimer, __HandleStartupMemoryHotkeySinglePress, Off
Return
}
g_StartupMemoryPendingActions[actionKey] := { vmName: vmName, targetGb: singlePressTargetGb, startTick: A_TickCount }
SetTimer, __HandleStartupMemoryHotkeySinglePress, 50
}
__HandleStartupMemoryHotkeySinglePress:
for actionKey, action in g_StartupMemoryPendingActions
{
if ((A_TickCount - action.startTick) >= g_StartupMemoryDoublePressWindowMs)
{
g_StartupMemoryPendingActions.Delete(actionKey)
RunStartupMemoryHotkeyAction(action.vmName, action.targetGb)
}
}
if (g_StartupMemoryPendingActions.Count() = 0)
SetTimer, __HandleStartupMemoryHotkeySinglePress, Off
Return
RunStartupMemoryHotkeyAction(vmName, targetGb)
{
resultText := SetHyperVStartupMemoryGb(vmName, targetGb, errText, !A_IsAdmin)
if (errText != "")
{
TrayTip, Hyper-V Memory, Failed to set %vmName% StartupBytes.`n%errText%, 5, 17
Return
}
TrayTip, Hyper-V Memory, %resultText%, 5, 1
}
AreWinCtrlModifiersHeld()
{
return (GetKeyState("LWin", "P") || GetKeyState("RWin", "P")) && (GetKeyState("LCtrl", "P") || GetKeyState("RCtrl", "P"))
}
GetHyperVAssignedMemory(vmName, ByRef errorText, elevateAndRelaunch := false)
{
escapedVmName := StrReplace(vmName, "'", "''")
psAction := "$vm = Get-VM -Name '" . escapedVmName . "'`n"
. "if ($vm.MemoryAssigned -gt 0) {`n"
. " $result = [math]::Round($vm.MemoryAssigned / 1GB, 2).ToString('0.##') + ' GB'`n"
. "} else {`n"
. " $result = '0 GB (VM may be off)'`n"
. "}"
return RunHyperVPowerShellAction(psAction, errorText, elevateAndRelaunch, "mem_read")
}
SetHyperVStartupMemoryGb(vmName, targetGb, ByRef errorText, elevateAndRelaunch := false)
{
escapedVmName := StrReplace(vmName, "'", "''")
psAction := "$vm = Get-VM -Name '" . escapedVmName . "'`n"
. "$current = [int64]$vm.MemoryStartup`n"
. "$new = " . targetGb . "GB`n"
. "if ($new -ne $current) { Set-VM -Name '" . escapedVmName . "' -MemoryStartupBytes $new }`n"
. "$result = 'Startup memory: ' + ([math]::Round($current / 1GB, 2).ToString('0.##')) + ' GB -> ' + ([math]::Round($new / 1GB, 2).ToString('0.##')) + ' GB'"
return RunHyperVPowerShellAction(psAction, errorText, elevateAndRelaunch, "startup_set")
}
RunHyperVPowerShellAction(psAction, ByRef errorText, elevateAndRelaunch := false, filePrefix := "hyperv")
{
escapedAhkPath := StrReplace(A_AhkPath, "'", "''")
escapedScriptPath := StrReplace(Chr(34) . A_ScriptFullPath . Chr(34), "'", "''")
stamp := A_Now . "_" . A_TickCount
prefix := "ahk_hyperv_" . filePrefix . "_"
scriptFile := A_Temp . "\" . prefix . stamp . ".ps1"
outFile := A_Temp . "\" . prefix . stamp . ".out"
errFile := A_Temp . "\" . prefix . stamp . ".err"
escapedOutFile := StrReplace(outFile, "'", "''")
escapedErrFile := StrReplace(errFile, "'", "''")
psScript := "$ErrorActionPreference = 'Stop'`n"
. "try {`n"
. psAction . "`n"
. " Set-Content -Path '" . escapedOutFile . "' -Value $result -Encoding UTF8`n"
. "} catch {`n"
. " Set-Content -Path '" . escapedErrFile . "' -Value $_.Exception.Message -Encoding UTF8`n"
. "}`n"
if (elevateAndRelaunch)
{
psScript .= "Start-Sleep -Milliseconds 1500`n"
. "Start-Process -FilePath '" . escapedAhkPath . "' -ArgumentList @('/restart', '" . escapedScriptPath . "') -WindowStyle Hidden`n"
}
FileAppend, %psScript%, %scriptFile%, UTF-8
output := ""
errorText := ""
if (elevateAndRelaunch)
{
cmd := "*RunAs """ . ComSpec . """ /c powershell -NoProfile -ExecutionPolicy Bypass -File """ . scriptFile . """"
Run, %cmd%,, Hide UseErrorLevel
launchResult := ErrorLevel
if (launchResult = "ERROR")
{
errorText := "UAC was cancelled or elevation failed."
}
else
{
; Wait for elevated helper to write either output or error.
Loop, 80
{
if (FileExist(outFile) || FileExist(errFile))
break
Sleep, 100
}
}
}
else
{
cmd := ComSpec . " /c powershell -NoProfile -ExecutionPolicy Bypass -File """ . scriptFile . """"
RunWait, %cmd%,, Hide UseErrorLevel
exitCode := ErrorLevel
if (exitCode = "ERROR" && errorText = "")
errorText := "Failed to run PowerShell."
else if (exitCode != "ERROR" && exitCode != 0 && errorText = "")
errorText := "PowerShell exited with code " . exitCode . "."
}
if (FileExist(outFile))
FileRead, output, %outFile%
if (FileExist(errFile))
FileRead, errorText, %errFile%
output := Trim(output)
errorText := Trim(errorText)
if (elevateAndRelaunch && output = "" && errorText = "")
errorText := "Timed out waiting for elevated Hyper-V query."
FileDelete, %scriptFile%
FileDelete, %outFile%
FileDelete, %errFile%
return output
}
view raw fkeys.ahk hosted with ❤ by GitHub