절전모드 해제시 창 크기 및 위치 자동 복원 프로그램

윈도우10 듀얼 모니터 환경에서 절전모드 해제 시 창이 구석에 처박히거나 이상한 위치로 이동하는 경우를 해결하는 방법 입니다. Mosaico이나 WindowsLayoutSnapshot 프로그램이 있지만, 상용 프로그램이고 무료는 버그가 있어서 채찍피티한테 시켜서 딱 창 위치 기억/복원 이 2가지 기능만 할 수 있도록 스크립트 작성했습니다.

윈도우11 사용자는 해당사항이 없습니다. 방법을 찾는다면 다음 게시글 참고 요망

다음의 파이썬 코드는 Win32 API를 사용하여 창 위치를 JSON 파일으로 저장, 창 위치 복원시 JSON 파일에 저장된 창 ID를 불러와서 자동으로 모든 창의 위치를 복원합니다. 간혹 구석에 창이 처박혀 있어서 빼도 박도 못하는 상황으로부터 문제를 해결합니다.

import json
import pygetwindow as gw
import win32gui
import win32con
import argparse
import time
import sys

# File path for saving window positions
SAVE_FILE = "window_positions.json"

def save_window_positions():
    """Save the positions, sizes, and states of all currently open windows."""
    windows = gw.getAllWindows()
    window_positions = []

    for window in windows:
        if window.title:  # Exclude windows without titles
            hwnd = window._hWnd
            rect = win32gui.GetWindowRect(hwnd)

            # Determine window state (normal, minimized, maximized)
            placement = win32gui.GetWindowPlacement(hwnd)
            state = "normal"
            if placement[1] == win32con.SW_SHOWMINIMIZED:
                state = "minimized"
            elif placement[1] == win32con.SW_SHOWMAXIMIZED:
                state = "maximized"

            window_positions.append({
                "hwnd": hwnd,  # Add window handle
                "title": window.title,
                "x": rect[0],
                "y": rect[1],
                "width": rect[2] - rect[0],
                "height": rect[3] - rect[1],
                "state": state
            })

    with open(SAVE_FILE, "w", encoding="utf-8") as file:
        json.dump(window_positions, file, indent=4)

    print(f"Window positions have been saved to {SAVE_FILE}.")

def restore_window_positions():
    """Restore windows to their saved positions, sizes, and states."""
    try:
        with open(SAVE_FILE, "r", encoding="utf-8") as file:
            window_positions = json.load(file)
    except FileNotFoundError:
        print(f"The file {SAVE_FILE} does not exist. Please save the positions first.")
        return

    for saved_window in window_positions:
        hwnd = saved_window["hwnd"]
        try:
            # Check if the window is valid and visible
            if win32gui.IsWindow(hwnd) and win32gui.IsWindowVisible(hwnd):
                x = saved_window["x"]
                y = saved_window["y"]
                width = saved_window["width"]
                height = saved_window["height"]
                state = saved_window["state"]

                # Restore size and position
                if width > 0 and height > 0:
                    win32gui.SetWindowPos(hwnd, win32con.HWND_TOP, x, y, width, height, 0)

                # Restore state
                if state == "minimized":
                    win32gui.ShowWindow(hwnd, win32con.SW_SHOWMINIMIZED)
                elif state == "maximized":
                    win32gui.ShowWindow(hwnd, win32con.SW_SHOWMAXIMIZED)
                else:
                    win32gui.ShowWindow(hwnd, win32con.SW_SHOWNORMAL)

                print(f"Restored window: title={saved_window['title']}, x={x}, y={y}, width={width}, height={height}, state={state}")
            else:
                print(f"The window is either invalid or not visible: {saved_window['title']}")
        except Exception as e:
            print(f"Error occurred while restoring window: {saved_window['title']} ({e})")

    print("Window positions have been restored.")

def main():
    parser = argparse.ArgumentParser(description="Tool to save and restore window positions")
    parser.add_argument("--save", action="store_true", help="Save current window positions")
    parser.add_argument("--restore", action="store_true", help="Restore windows to saved positions")

    args = parser.parse_args()

    if args.save:
        save_window_positions()
    elif args.restore:
        restore_window_positions()
    else:
        print("Please use either --save or --restore option.")
        
    time.sleep(2)
    sys.exit()

if __name__ == "__main__":
    main()

위 스크립트를 적당한 위치에 저장하고, 파이썬을 설치합니다. 이후 다음의 커맨드로 창 위치 저장과 복원이 정상적으로 작동하는지 확인 할 수 있습니다. Win32 API를 사용하므로 복원 시 관리자 권한이 필요합니다.

> python app.py --save
> python app.py --resotre

이후 대기모드 진입, 해제 시 스크립트가 실행될 수 있도록 윈도우 작업 스케줄러를 사용하여 등록해줍니다. 다음과 같이 두개의 작업을 등록해줄 것입니다.

Save Window Pisition 트리거 및 액션 설정(창 위치 저장)

Restore Window Position 트리거 및 액션 설정(창 위치 복원)

액션 설정 시 다음과 같이 하고, 스크립트 이름, 경로는 적절히 수정합니다.

이제 대기모드 진입/해제(복귀) 시 자동으로 창 위치가 복원되는 것을 확인 할 수 있습니다.


다음은 위 파이썬 스크립트를 pyinstaller 를 사용하여 .EXE 파일로 패키징한 파일입니다.

압축 해제 후 커맨드 라인(CMD)에서 다음과 같이 실행하면 됩니다. 윈도우 창 위치 값을 담고 있는 window_positions.json 파일은 app.exe 와 같은 폴더에 저장됩니다.

PC를 거의 24/7 계속 켜놓지만 간혹 대기 모드에서 복귀할 때 창이 구석에 처박히는 문제를 해결하기 위한 스크립트입니다. 필요하신 분 참고하세요.

Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.