F.R.I.D.A.Y.

다중 모니터 위치 파악하기 본문

DEV/C C++

다중 모니터 위치 파악하기

F.R.I.D.A.Y. 2021. 7. 16. 20:02
반응형


Index

  • 모니터 위치 지정
  • EnumDisplayMonitors
    • lpfnEnum
  • 바탕화면에 그리기
    • WorkerW
    • 좌표 계산하기
  • 결과 확인

Script from F.R.I.D.A.Y


모니터 위치 지정copy^

 Windows에서는 여러 개의 모니터를 사용할 때 각 모니터의 위치를 정할 수 있다.

 

 나의 경우에는 1번 모니터를 메인으로 위에 2번 모니터가 존재하는 방식으로 사용한다. 이런 상황에서, 멀티 모니터 프로그래밍을 하려면 각 모니터의 위치를 찾아야하는 문제가 있다.

 

 그러나 바탕화면을 담당하는 WorkerW 프로세스의 영역을 구하면 다음과 같다.

 각 모니터 모두 FHD 해상도에 세로로 이어 붙인 상황이기 때문에 크기는 1920×2160이 맞다. 그러나 이를 Windows 좌표로 분석하면 다른 값이 노출된다.

 

 위 두 장의 사진은 생성한 윈도우위 좌표를 윈도우 안에 출력해주는 코드이다. 메인으로 사용하고 있는 1번[1] 모니터의 좌-상 위치는 (0, 0)이지만, 서브 모니터로 연결한 좌-상 위치는(0, -1080)이다.

 

 이 출력으로 Windows 좌표계에선 무조건 메인 모니터의 좌-상 위치가 (0, 0)으로 고정됨을 확인 했다.

 

 때문에 단순히 GetClientRect나 GetWindowRect 함수로 좌표계 범위를 구하기엔 한계가 있다. 그러면 어떤 방식으로 찾아야 하는가?

 

 이미 관련 함수를 WIN API에서 제공하고 있다.

 

 

EnumDisplayMonitorscopy^

 다음 함수는 아래의 원형을 가진다.

EnumDisplayMonitors(HDC hdc, LPCRECT lprcClip, MONITORENUMPROC lpfnEnum, LPARAM dwData);

 모든 모니터[2]를 순회한다. 모니터의 범위를 구하기 위함이므로 우리는 첫 번째와 두 번째 값에 nullptr을 전달하고 때에 따라서 마지막 값에도 nullptr을 넣어도 된다.

 각 모니터를 순회하면서 세 번째 인자로 넘긴 함수를 실행하는데, 그 함수 원형은 다음과 같다.

 

lpfnEnumcopy^

BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdc, LPRECT monitorRect, LPARAM data);

bool 타입 아니고 BOOL 타입

 C99 이상 및 C++에서 제공하는 bool 타입이 아니라 int 타입이 typedef로 BOOL로 선언되었다. 때문에 원론적으로 가면 bool !== BOOL이기 때문에 함수를 BOOL로 사용하지 않으면 함수 원형이 다르다는 문제가 발생할 것이다.

 각 인자는 앞에서부터 현재 접근한 모니터의 핸들, DC 핸들, 현재 모니터의 좌표값, <EnumDisplayMonitors>에서 전달한 네 번째 인자가 들어간다.

 

 여기에서 중요한 점은, 세번째 인자인 LPRECT monitorRect, 혹은 모니터 핸들로 GetMonitorInfo 함수로 불러들이 데이터는 기준 모니터[3]가 아니라면 값이 음수를 가질 수 있다. 즉, 기준 모니터 좌측이나 상부에 위치하도록 설정을 한 경우에는 음수를 가지게 된다는 말이다.

 


바탕화면에 그리기copy^

 원래 계획인 바탕화면에 (아이콘 뒤에) 그리기 작업은 WorkerW 프로세스에 그리는 것으로 한다. WorkerW 프로세스 영역은 디스플레이가 연결 될 때마다 업데이트가 이루어진다.[4]

 

WorkerWcopy^

 WorkerW는 각 방향에서 가장 값이 큰 모니터의 값을 기반으로 구역이 생성된다. 만일 아래와 같은 방식으로 모니터를 구현하면

 

 WorkerW는 3번 모니터의 Left 값, 4번 모니터의 Top값, 2번 모니터의 Right 및 Bottom 값을 기반으로 크기가 정해진다.

 Windows상의 기준 좌표는 1번 모니터(Left, Top)를 (0, 0)으로 구성해 처리한다. 그러나 WorkerW 내부의 좌표는 3번 모니터의 Left값, 4번 모니터의 Top값이 (0, 0)으로 동작한다.

 

좌표 계산하기copy^

 그럼 이렇게 차이가 나는 부분을 그릴 때마다 직접 다 계산을 해서 넣어주어야 하는가 하면, 그건 또 아니다. 다행스럽게도 이런 문제는 MS팀에서 이미 파악을 하고 있으니, ScreenToClient 라는 함수를 제공한다. Screen은 Windows 좌표계를 따르고, Client는 Window 좌표계를 따르는데, 이 함수가 Windows 좌표계를 윈도우 좌표계로 전환해준다. 따라서 이 함수를 이용하면 원하는 모니터에 바탕화면에 이미지를 그리는 등의 행위를 할 수 있다.

 

 

결과 확인copy^

 다음 이미지를 통해 잘 동작함을 확인했다.

 주 모니터에는 0, 부 모니터에는 1이 적혀 있다.

 

728x90
반응형
Comments