Last active
January 18, 2021 15:24
-
-
Save andyneff/dff921fd01214809820f4f4035ed7360 to your computer and use it in GitHub Desktop.
A script to forceable put your computer to sleep
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Basic windows GUI that will persistently try and put your computer to sleep. | |
# WARNING: This ignores Alt+F4 and commands to kill the app. This is on purpose. | |
# The only way to kill is with a force kill, which defeats the purpose of the | |
# script | |
import signal | |
import time | |
import os | |
import threading | |
import win32api | |
import win32con | |
import win32gui | |
os.environ['PYGAME_HIDE_SUPPORT_PROMPT'] = '1' | |
from pygame import mixer | |
INITIAL_MESSAGE = "Bedtime" | |
class ShutdownGui(): | |
def __init__(self): | |
self.message = INITIAL_MESSAGE | |
self.repeat_rate = 30*60 | |
self.done = False | |
self.stage_delays = [60, 15] | |
self.stage_filenames = ["dustyroom_sound_design_digital_descend_shutdown.mp3", | |
"zapsplat_science_fiction_machine_power_down_just_low_freq_44823.mp3"] | |
self.stage_repeats = [5, 1] | |
#get instance handle | |
hInstance = win32api.GetModuleHandle() | |
# the class name | |
className = 'SimpleWin32' | |
# create and initialize window class | |
wndClass = win32gui.WNDCLASS() | |
wndClass.style = win32con.CS_HREDRAW | win32con.CS_VREDRAW | |
wndClass.lpfnWndProc = self.wndProc | |
wndClass.hInstance = hInstance | |
wndClass.hIcon = win32gui.LoadIcon(0, win32con.IDI_APPLICATION) | |
wndClass.hCursor = win32gui.LoadCursor(0, win32con.IDC_ARROW) | |
wndClass.hbrBackground = win32gui.GetStockObject(win32con.WHITE_BRUSH) | |
wndClass.lpszClassName = className | |
wndClassAtom = win32gui.RegisterClass(wndClass) | |
self.window = win32gui.CreateWindow( | |
wndClassAtom, #it seems message dispatching only works with the atom, not the class name | |
'Night Night ' + os.environ['USERNAME'].title(), | |
win32con.WS_OVERLAPPEDWINDOW, | |
win32con.CW_USEDEFAULT, | |
win32con.CW_USEDEFAULT, | |
300, 100, | |
0, | |
0, | |
hInstance, | |
None) | |
# Show & update the window | |
win32gui.ShowWindow(self.window, win32con.SW_SHOWMINNOACTIVE) | |
win32gui.UpdateWindow(self.window) | |
def run(self): | |
win32gui.PumpMessages() | |
def wndProc(self, hWnd, message, wParam, lParam): | |
if message == win32con.WM_PAINT: | |
hDC, paintStruct = win32gui.BeginPaint(hWnd) | |
rect = win32gui.GetClientRect(hWnd) | |
win32gui.DrawText(hDC, self.message, -1, rect, | |
win32con.DT_SINGLELINE | win32con.DT_CENTER | win32con.DT_VCENTER) | |
win32gui.EndPaint(hWnd, paintStruct) | |
return 0 | |
elif message == win32con.WM_LBUTTONUP: | |
self.running = False | |
try: | |
self.sleep_timer.cancel() | |
except: | |
pass | |
elif message == win32con.WM_CLOSE: | |
if self.done: | |
return win32gui.DefWindowProc(hWnd, message, wParam, lParam) | |
print('No closing!') | |
elif message == win32con.WM_DESTROY: | |
win32gui.PostQuitMessage(0) | |
return 0 | |
elif message == win32con.WM_POWERBROADCAST: | |
if wParam == win32con.PBT_APMSUSPEND: # Going to sleep | |
# If the user preemptively sleeps, then kill this script | |
self.done = True | |
win32gui.PostMessage(self.window, win32con.WM_CLOSE, 0, 0) | |
else: | |
return win32gui.DefWindowProc(hWnd, message, wParam, lParam) | |
def sleep(self, secs): | |
self.sleep_timer = threading.Timer(secs, lambda: None) | |
self.sleep_timer.start() | |
self.sleep_timer.join() | |
def redraw(self): | |
win32gui.RedrawWindow(self.window, None, None, | |
win32con.RDW_ERASE | win32con.RDW_INVALIDATE) | |
def shutdown_timer(self): | |
mixer.init() | |
mixer.music.set_volume(0.3) | |
while 1: | |
self.running = True | |
self.shutdown() | |
self.message = "Resume at " + \ | |
time.strftime('%H:%M.%S', | |
time.localtime(time.time() + self.repeat_rate)) | |
self.redraw() | |
self.sleep(self.repeat_rate) | |
def shutdown(self): | |
# for stage in range(len(self.stage_delays)): | |
for stage in range(len(self.stage_delays)): | |
mixer.music.load(self.stage_filenames[stage]) | |
for x in range(self.stage_repeats[stage]): | |
self.message = f'Stage {stage+1} of {len(self.stage_delays)} ({x+1}/{self.stage_repeats[stage]})' | |
self.redraw() | |
mixer.music.play() | |
self.sleep(self.stage_delays[stage]) | |
if not self.running: | |
return | |
if self.running: | |
self.done = True | |
os.system('shutdown /h') | |
win32gui.PostMessage(self.window, win32con.WM_CLOSE, 0, 0) | |
def main(): | |
gui = ShutdownGui() | |
threading.Thread(target=gui.shutdown_timer, daemon=True).start() | |
gui.run() | |
# Only works if ShowWindow is called | |
def exit_app(signum, frame): | |
win32gui.PostQuitMessage(0) | |
if __name__ == '__main__': | |
signal.signal(signal.SIGINT, exit_app) | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment