Skip to content

Instantly share code, notes, and snippets.

@ClassicOldSong
Last active January 6, 2026 21:29
Show Gist options
  • Select an option

  • Save ClassicOldSong/0a088d2a92a06f86e48fe328b67ec995 to your computer and use it in GitHub Desktop.

Select an option

Save ClassicOldSong/0a088d2a92a06f86e48fe328b67ec995 to your computer and use it in GitHub Desktop.
Auto Pause/Resume script for providing console grade experience with Apollo
#Requires AutoHotkey v2.0
#SingleInstance Force
DetectHiddenWindows true
; Globals to manage the suspend/resume state
global IsProcessSuspended := false
global IsProcessResumed := false
LockFile := A_Temp "\AutoPauseResume.lock"
; Ensure we clean up on script exit:
OnExit(Cleanup)
; Check if the lock file exists before deleting it
if FileExist(LockFile)
FileDelete(LockFile)
; --------------------------------------------------------------------------
; 1) Define excluded processes as a map (key-value)
; - The key is the process name in lowercase, mapped to `true`.
; --------------------------------------------------------------------------
excludedProcesses := Map()
excludedProcesses["explorer.exe"] := true
excludedProcesses["csrss.exe"] := true
excludedProcesses["winlogon.exe"] := true
excludedProcesses["svchost.exe"] := true
excludedProcesses["dwm.exe"] := true
excludedProcesses["cmd.exe"] := true
excludedProcesses["chrome.exe"] := true
excludedProcesses["powershell.exe"] := true
excludedProcesses["sublime_text.exe"] := true
excludedProcesses["sublime_merge.exe"] := true
excludedProcesses["steamwebhelper.exe"] := true
excludedProcesses["openconsole.exe"] := true
excludedProcesses["windowsterminal.exe"] := true
excludedProcesses["playnite.desktopapp.exe"] := true
excludedProcesses["playnite.fullscreenapp.exe"] := true
; --------------------------------------------------------------------------
; 2) Get the active window's PID & Process Name, confirm it's not excluded
; --------------------------------------------------------------------------
if !WinExist("A")
{
MsgBox "No active window detected. Please focus a window to suspend."
ExitApp
}
pid := WinGetPID("A")
if !pid
{
MsgBox "Failed to get the active window's PID."
ExitApp
}
processName := WinGetProcessName()
if !processName
{
MsgBox "Failed to retrieve the active window's process name."
ExitApp
}
; Convert the process name to lowercase for case-insensitive matching
procLower := StrLower(processName)
; Check if `excludedProcesses` has this process in its keys, and if the value is true
if excludedProcesses.Has(procLower) && excludedProcesses[procLower]
{
; Excluded process, so do nothing and exit.
ExitApp
}
; --------------------------------------------------------------------------
; 3) Suspend the process & start checking for the lock file in a timer
; --------------------------------------------------------------------------
SuspendProcess(pid)
IsProcessSuspended := true ; Mark that we have indeed suspended a process
; Optional: show a short tooltip or do a quick beep instead of a MsgBox
; MsgBox "Process '" processName "' (PID: " pid ") suspended. Waiting for lock file..."
SetTimer(CheckLockFile, 500) ; check the lock file every 500 ms
return
; --------------------------------------------------------------------------
CheckLockFile(*)
{
global LockFile, pid, processName, IsProcessResumed
if FileExist(LockFile)
{
ResumeProcess(pid)
IsProcessResumed := true
; MsgBox "Process '" processName "' (PID: " pid ") resumed. Exiting."
FileDelete(LockFile)
ExitApp
}
}
; --------------------------------------------------------------------------
SuspendProcess(pid)
{
PROCESS_ALL_ACCESS := 0x1F0FFF
hProc := DllCall("OpenProcess", "UInt", PROCESS_ALL_ACCESS, "Int", 0, "UInt", pid, "Ptr")
if !hProc
{
MsgBox "Failed to open process (PID: " pid ")."
ExitApp
}
hNtdll := DllCall("GetModuleHandle", "Str", "ntdll.dll", "Ptr")
if !hNtdll
{
MsgBox "Failed to get module handle for ntdll.dll."
ExitApp
}
NtSuspendProcess := DllCall("GetProcAddress", "Ptr", hNtdll, "AStr", "NtSuspendProcess", "Ptr")
if !NtSuspendProcess
{
MsgBox "Failed to locate NtSuspendProcess in ntdll.dll."
ExitApp
}
DllCall(NtSuspendProcess, "Ptr", hProc)
DllCall("CloseHandle", "Ptr", hProc)
}
; --------------------------------------------------------------------------
ResumeProcess(pid)
{
PROCESS_ALL_ACCESS := 0x1F0FFF
hProc := DllCall("OpenProcess", "UInt", PROCESS_ALL_ACCESS, "Int", 0, "UInt", pid, "Ptr")
if !hProc
{
; Process may no longer exist, don't do anything.
; MsgBox "Failed to open process (PID: " pid ")."
ExitApp
}
hNtdll := DllCall("GetModuleHandle", "Str", "ntdll.dll", "Ptr")
if !hNtdll
{
MsgBox "Failed to get module handle for ntdll.dll."
ExitApp
}
NtResumeProcess := DllCall("GetProcAddress", "Ptr", hNtdll, "AStr", "NtResumeProcess", "Ptr")
if !NtResumeProcess
{
MsgBox "Failed to locate NtResumeProcess in ntdll.dll."
ExitApp
}
DllCall(NtResumeProcess, "Ptr", hProc)
DllCall("CloseHandle", "Ptr", hProc)
}
; --------------------------------------------------------------------------
; Automatically resume the process if the user manually exits the script
; or the script ends unexpectedly.
; --------------------------------------------------------------------------
Cleanup(exitReason, exitCode)
{
global pid, IsProcessSuspended, IsProcessResumed
; If the process was suspended and hasn't been resumed via the lock file,
; auto-resume it here.
if IsProcessSuspended && !IsProcessResumed
{
ResumeProcess(pid)
}
}
#Requires AutoHotkey v2.0
#SingleInstance Force
LockFile := A_Temp "\AutoPauseResume.lock"
; Simply create the lock file and exit
FileAppend("", LockFile)
ExitApp
@RJNY
Copy link

RJNY commented Jan 5, 2026

this script has been amazing! I appreciate how simple it is.
Perhaps you know better than me, is there a way to tell the host machine to allow sleep/hibernate while the game is suspended?

edit: I played with this for a few hours to see if I can get the host machine to suspend. I initially thought it it had to do with the timer in the script. I tried rewriting it to not rely on the timer, but it still won't permit sleep/hybernate. now I think it has to do with the steam audio driver Steam Streaming Microphone, but I'm not sure what to do about that.

edit #2:
during gameplay the audio driver is Steam Streaming Speaker, but on suspend, it is replaced by Steam Streaming Microphone. I still strongly suspect this is the reason it prevents host PC from sleep/hibernate. I still have no clue how to disable this on session pause.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment