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

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

DEV/C C++

다중 모니터 위치 파악하기

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


모니터 위치 지정

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

 

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

 

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

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

 

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

 

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

 

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

 

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

 

 

EnumDisplayMonitors

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

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

 모든 모니터[# 미러링용 드라이버 및 현재 보이지 않는 모니터를 포함한다.]를 순회한다. 모니터의 범위를 구하기 위함이므로 우리는 첫 번째와 두 번째 값에 nullptr을 전달하고 때에 따라서 마지막 값에도 nullptr을 넣어도 된다.

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

 

lpfnEnum

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 함수로 불러들이 데이터는 기준 모니터[# 시스템 설정에서 보면 모니터를 주 모니터로 설정한 것이 기준 모니터가 된다.]가 아니라면 값이 음수를 가질 수 있다. 즉, 기준 모니터 좌측이나 상부에 위치하도록 설정을 한 경우에는 음수를 가지게 된다는 말이다.

 


바탕화면에 그리기

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

 

WorkerW

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

 

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

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

 

좌표 계산하기

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

 

 

결과 확인

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

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

 

# index

728x90
반응형
Comments