카테고리 없음

python 다중 모니터 창 이동

zoomer75 2021. 10. 15. 09:58

다중모니터 사용시 프로그램을 창 이동하는 프로그램입니다. 기존 스트림덱에서 사용할려고 만들었습니다.

모니터 구분 및 창 이동을 위해서는 win32api , win32gui 가 필요합니다.

일단 pip 로 설치합니다.

pip install pywin32

윈도우의 경우 설치가 안되시는 분들은 https://www.lfd.uci.edu/~gohlke/pythonlibs/#pywin32 사이트에서 python 버전과 비트에 맞는 whl 파일을 다운받아 설치하시면 됩니다.

pip C:\경로\xxx.whl

전체 소스입니다.


from win32 import win32api, win32gui
from operator import itemgetter

class MoveMonitor():

    def __init__(self, parent = None):
        monitor = win32api.EnumDisplayMonitors()
        self.monitorMap = list()

        for info in monitor:
            # 주 모니터와 서브 모니터 구분
            if info[2][0] == 0 and info[2][1] == 0:
                monitorType = "P"
            else :
                monitorType = "S"

            self.monitorMap.append({'type': monitorType, 'handle' : info[0], 'left' : info[2][0], 'top' : info[2][1]})

    '''
    @ 현재 선택된 창의 타이틀과 핸들을 돌려준다.
    @ list : title, handle, left, top, width, height 
    '''
    def getActiveWindowHandle(self):
        def callback(hwnd, hwnd_list: list):
            activeTitle = win32gui.GetWindowText(win32gui.GetForegroundWindow())
            title = win32gui.GetWindowText(hwnd)
            if win32gui.IsWindowEnabled(hwnd) and win32gui.IsWindowVisible(hwnd) and title:
                if title == activeTitle:
                    rect = win32gui.GetWindowRect(hwnd)
                    hwnd_list.append((title, hwnd, rect[0], rect[1], rect[2] - rect[0], rect[3] - rect[1]))
        output = []
        win32gui.EnumWindows(callback, output)
        return output[0]

    def moveWindow(self, direction):
        self.direction = direction
        tmpMonitorMap = self.monitorMap

        # 선택된 프로그램의 핸들값
        hwnd = self.getActiveWindowHandle()

        # 선택된 프로그램의 현재 모니터 위치
        thisMonitorHandle = win32api.MonitorFromWindow(hwnd[1])

        # 방향에 따라 list 를 정렬하여 값을 추출
        if direction == 'left':
            # left 내림차순 정렬
            sortedData = sorted(self.monitorMap, key=itemgetter('left'), reverse=False)
        elif direction == 'right':
            sortedData = sorted(self.monitorMap, key=itemgetter('left'), reverse=True)
        elif direction == 'up':
            sortedData = sorted(self.monitorMap, key=itemgetter('top'), reverse=False)
        elif direction == 'down':
            sortedData = sorted(self.monitorMap, key=itemgetter('top'), reverse=True)

        # 창 이동
        win32gui.MoveWindow(hwnd[1], sortedData[0]['left'], sortedData[0]['top'], hwnd[4], hwnd[5], 1)

test = MoveMonitor()
test.moveWindow('down')

win32 함수에 대한 설명은 http://timgolden.me.uk/pywin32-docs 사이트를 참고하시면 됩니다.

win32api.EnumDisplayMonitors() 함수를 이용하여 현재 시스템의 모니터 갯수와 정보(해상도, 위치) 를 확인합니다.

결과값은 다음과 같습니다.
[(PyHANDLE:65537, PyHANDLE:0, (0, 0, 1920, 1080)), (PyHANDLE:65539, PyHANDLE:0, (-1920, 1, 0, 1081))]

1 : 모니터에 대한 핸들값입니다.
2 : unknown
3 : 위치와 해상도에 관한 값입니다. 앞의 2개 값만 사용합니다. ( left, top, width, height )
0, 0 이 주모니터입니다. left 가 - 일 경우 주 모니터 왼쪽에 위치 한다고 보면 됩니다.
모니터가 상하로 위치할 경우 top 의 +- 값을 보고 판단합니다.

그리고 이동 할려고 하는 창의 정보를 가져옵니다.

getActiveWindowHandle 함수를 이용하여 현재 포커싱된 창의 핸들값과 크기 정보를 가져옵니다.

마지막으로 win32gui.MoveWindow 함수를 이용하여 해당 모니터의 좌측 상단을 기준으로 이동합니다.

전 이 class 를 스트림덱에 적용하여 사용하고 있습니다.

다음에는 큰 모니터 사용자를 위한 창 분할 기능을 만들도록 하겠습니다.

감사합니다.

반응형