화면 캡처와 녹화 시 마우스 커서 크기가 다르게 찍히는 이유와 완벽한 해결법
Windows 접근성 확대 커서 및 고DPI 설정 시 스크린샷과 동영상에서 커서가 32x32 기본 크기로 작아지는 원인과 Win32 API를 활용한 무손실 커서 합성 기술
- DWM 하드웨어 커서 오버레이 계층 분리로 인한 일반 프레임버퍼 캡처의 커서 누락 원인 규명
- Windows.Graphics.Capture 및 기존 캡처 툴의 접근성 확대 커서 배율 무시 한계 분석
- CursorBaseSize 레지스트리 감지 및 DrawIconEx 핫스팟 보정 기반 무손실 렌더링 파이프라인 구현

Windows 운영체제에서 화면을 캡처하거나 튜토리얼 동영상을 녹화할 때, 분명 내 눈에는 큼직하고 예쁜 커서가 보이는데 결과물을 열어보면 커서가 아주 작게 쪼그라들어 있거나 위치가 어긋나 있는 경험을 해보신 적이 있을 것입니다.
특히 윈도우 접근성 설정에서 마우스 포인터 크기를 1~15단계로 키웠거나 4K 고해상도 모니터에서 DPI 배율을 높여 사용하는 경우, OBS Studio, ScreenToGif, ShareX 같은 유명 캡처 프로그램을 써도 커서 크기가 32x32 기본 크기로 강제 축소되는 현상이 발생합니다.
왜 눈에 보이는 화면과 캡처된 결과물의 커서 크기가 다를까요? 이번 포스트에서는 윈도우 그래픽 렌더링 아키텍처 관점에서 그 원인을 명쾌하게 파헤치고, 실제 사용자가 보는 커서 크기와 위치를 100% 동일하게 캡처·녹화하는 완벽한 기술 파이프라인과 구현 코드를 정리해 드립니다.
📌 목차
- 초보자를 위한 핵심 용어 사전
- 문제 현상: 왜 커서 크기가 축소되어 캡처될까?
- 기술적 원인 분석: 윈도우 커서 렌더링 아키텍처
- 기존 캡처 API 및 오픈소스 도구들의 한계
- 완벽한 해결 메커니즘: 5단계 무손실 합성 파이프라인
- 파이썬 및 Win32 기반 핵심 구현 코드
- 실시간 화면 녹화를 위한 권장 기술 스택
- 마치며: 정밀한 캡처 도구를 위한 체크리스트
초보자를 위한 핵심 용어 사전
아티클을 읽기 전 알아두면 좋은 윈도우 그래픽 및 시스템 핵심 용어들을 정리했습니다.
- DWM (Desktop Window Manager): 윈도우 창, 반투명 효과, 애니메이션을 GPU 하드웨어 가속으로 합성해 화면에 표시하는 윈도우 핵심 그래픽 관리자입니다.
- 하드웨어 커서 플레인 (Hardware Cursor Plane): 그래픽 카드(GPU)가 데스크톱 화면 위에 마우스 커서를 독립된 최상단 레이어로 얹어서 빠르게 그려주는 하드웨어 전용 레이어입니다.
- 커서 핫스팟 (Hotspot): 마우스 클릭 시 실제로 이벤트가 발생하는 커서 내부의 기준 좌표(x, y)입니다. 일반 화살표는 대개 좌측 상단 끝점(0, 0)입니다.
- DPI (Dots Per Inch): 1인치당 들어가는 픽셀 밀도입니다. 고해상도 디스플레이에서 글자나 UI가 너무 작아지지 않도록 125%, 150%, 200% 등으로 화면을 확대합니다.
- DrawIconEx: 윈도우 Win32 API 함수로, 아이콘이나 커서 리소스를 지정된 가로/세로 픽셀 크기에 맞춰 깨짐 없이 고품질로 그려주는 렌더링 함수입니다.
문제 현상: 왜 커서 크기가 축소되어 캡처될까?
윈도우 10 및 윈도우 11의 설정 > 접근성 > 마우스 포인터 및 터치 메뉴에서는 마우스 포인터의 크기를 기본 1부터 최대 15까지 자유롭게 확대할 수 있습니다. 또한 최근 커스텀 아니메 마우스 커서나 고해상도 커서 팩을 사용하는 사용자도 많습니다.
하지만 화면 스크린샷 캡처 툴을 실행하거나 녹화 프로그램을 구동하면 다음과 같은 문제가 반복됩니다:
- 모니터 화면에서는 가로 64px 또는 128px의 큼직한 커서가 보이는데, 캡처된 이미지나 동영상에서는 항상
32x32크기의 작은 화살표로 강제 축소됩니다. - 커서 확대 배율이 반영되지 않은 채 위치만 계산되어 마우스 클릭 지점(핫스팟)과 실제 캡처 화면의 클릭 타깃이 어긋나는 현상이 발생합니다.
- 윈도우 최신 캡처 API인
Windows.Graphics.Capture를 사용해도 동일한 크기 축소 버그가 발생합니다.
이 현상이 발생하는 이유는 단순한 소프트웨어 버그가 아니라, 윈도우 OS의 화면 렌더링 구조 자체에 기인합니다.
기술적 원인 분석: 윈도우 커서 렌더링 아키텍처
윈도우 운영체제에서 화면을 그리는 방식과 커서를 그리는 방식은 서로 완전히 다른 파이프라인을 탑니다.

1. 하드웨어/DWM 독립 오버레이 계층
윈도우 OS는 마우스 조작의 즉각적인 반응성(Low-Latency)을 보장하기 위해, 마우스 커서를 일반 데스크톱 창들이 그려지는 프레임버퍼(Frame Buffer)에 직접 그리지 않습니다.
대신 GPU의 하드웨어 커서 플레인(Hardware Cursor Plane) 또는 DWM(Desktop Window Manager)의 최상단 독립 오버레이 계층에서 커서를 실시간 합성합니다. 따라서 시스템이 화면 버퍼를 읽어오는 일반적인 캡처 방식(BitBlt, DXGI Desktop Duplication 등)을 실행하면 커서는 프레임버퍼에 아예 존재하지 않으므로 캡처 대상에서 완전히 누락됩니다.
2. 비트맵 추출 시 확대 배율 유실
커서가 누락되는 것을 막기 위해 대부분의 캡처 툴은 현재 마우스 좌표를 가져와서 커서 비트맵을 위에 덧그리는 방식을 사용합니다.
그러나 Win32의 GetCursorInfo()로 커서 핸들(HCURSOR)을 얻은 후 GetIconInfo()로 비트맵을 직접 추출하면, 윈도우 접근성 서비스가 적용해 둔 확대 배율 정보가 증발하고 원본 파일에 정의된 기본 크기(32x32)의 비트맵만 추출되는 한계가 있습니다.
기존 캡처 API 및 오픈소스 도구들의 한계
현재 널리 사용되는 주요 캡처 API와 도구들의 커서 처리 한계를 비교해 보면 다음과 같습니다:
| API 및 도구 | 동작 방식 | 문제점 및 한계 |
|---|---|---|
Windows.Graphics.Capture (WGC) |
IsCursorCaptureEnabled = true |
최신 윈도우 표준 API임에도 접근성 확대 커서 배율을 무시하고 기본 크기(32x32)로 강제 렌더링 (OBS Studio 이슈 다수 보고) |
Win32 GetCursorInfo() 기본 호출 |
커서 핸들(HCURSOR) 획득 |
비트맵 직접 추출 시 접근성 배율이 적용되지 않은 기본 크기 비트맵 반환 |
| OBS Studio / ScreenToGif / ShareX | WGC / DXGI / GDI 혼용 | 고DPI 및 접근성 대형 커서 설정 시 커서 크기 축소 또는 오프셋 불일치 지속 발생 |
결국 시스템이 자동으로 커서를 넣어주길 기대해서는 안 되며, 사용자의 실제 설정값을 역추적하여 직접 스케일링 후 합성하는 전용 파이프라인이 필요합니다.
완벽한 해결 메커니즘: 5단계 무손실 합성 파이프라인
사용자가 화면에서 보고 있는 커서의 크기, 형태, 위치를 100% 동일하게 캡처하고 녹화하기 위해서는 다음 5단계 아키텍처를 구현해야 합니다.
[1. 레지스트리 & DPI 감지] ─┐
├─► [4. DrawIconEx 무손실 렌더링] ─► [5. 최종 합성 및 출력]
[2. 커서 핸들 & 상태 획득] ─┤ ▲ ├─► PNG/JPG 스크린샷
│ │ └─► MP4 비디오 스트림
[3. 핫스팟 오프셋 좌표 보정] ─┘ │
[화면 캡처 (DXGI Desktop Duplication)] ──┘
1단계: 사용자 커서 크기 및 DPI 배율 동적 감지
윈도우 레지스트리에 저장된 사용자의 실제 커서 기본 크기와 모니터의 DPI 배율을 조회합니다.
- 레지스트리 경로 1:
HKEY_CURRENT_USER\Control Panel\Cursors의CursorBaseSize(기본값:32, 확대 설정 시48,64,96,128등) - 레지스트리 경로 2:
HKEY_CURRENT_USER\Software\Microsoft\Accessibility의CursorSize(접근성 1~15단계) - 모니터 DPI 확인: Per-Monitor DPI Awareness V2 적용 후
DPI / 96.0배율 계산 - 최종 렌더링 픽셀 크기 산출 공식:
최종 렌더 크기 = CursorBaseSize * (모니터 DPI / 96.0)
2단계: 커서 상태 및 핸들 획득
Win32 GetCursorInfo()를 호출하여 커서가 화면에 표시 중인지(CURSOR_SHOWING) 확인하고, 현재 커서의 화면 절대 좌표 (cx, cy)와 HCURSOR 핸들을 가져옵니다.
3단계: 커서 핫스팟(Hotspot) 오프셋 보정
커서 크기를 확대했을 때 마우스 클릭 기준점(Hotspot)도 크기에 비례하여 이동해야 합니다. 그렇지 않으면 화살표 끝이 아닌 엉뚱한 위치가 클릭된 것처럼 녹화됩니다.
GetIconInfoEx()를 호출하여 원본 핫스팟 좌표 (x_hot, y_hot)와 원본 비트맵 크기 (W_orig, H_orig)를 구한 뒤, 확대 비율에 맞추어 보정 오프셋을 계산합니다:
DrawX = CursorX - (x_hot * 최종렌더폭 / W_orig)DrawY = CursorY - (y_hot * 최종렌더높이 / H_orig)
4단계: 무손실 스케일링 렌더링 (DrawIconEx)
커서 비트맵을 강제로 리사이징하면 계단 현상이나 블러가 발생합니다. Win32의 DrawIconEx() 함수에 앞서 산출한 타깃 크기 cxWidth, cyWidth 및 DI_NORMAL 플래그를 전달하면, 윈도우 내부의 고해상도 커서 리소스에서 최적의 비트맵을 선명하게 합성해 줍니다.
5단계: 프레임 합성 및 출력
DXGI Desktop Duplication으로 캡처한 순수 데스크톱 화면 프레임 위에 보정된 좌표와 크기로 커서를 알파 블렌딩 합성한 뒤, 정지화면(PNG/JPG)으로 저장하거나 FFmpeg H.264 파이프라인으로 전송하여 무손실 MP4 영상을 완성합니다.
파이썬 및 Win32 기반 핵심 구현 코드
실제 캡처 프로그램이나 녹화 파이프라인에 즉시 통합할 수 있는 파이썬 참조 코드입니다.
import winreg
import ctypes
from ctypes import wintypes
import win32gui
import win32con
def get_actual_cursor_size() -> int:
"""사용자가 설정한 실제 윈도우 커서 픽셀 크기를 레지스트리에서 반환합니다."""
try:
key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, r"Control Panel\Cursors")
base_size, _ = winreg.QueryValueEx(key, "CursorBaseSize")
winreg.CloseKey(key)
return int(base_size)
except Exception:
# 레지스트리 키가 없는 경우 기본값 32px 반환
return 32
def get_system_dpi_scale() -> float:
"""Per-Monitor Aware V2를 적용하여 시스템의 정확한 DPI 배율을 반환합니다."""
try:
user32 = ctypes.windll.user32
user32.SetProcessDpiAwarenessContext(-4) # Per-Monitor Aware V2 설정
dpi = user32.GetDpiForSystem()
return dpi / 96.0
except Exception:
return 1.0
def capture_cursor_info():
"""현재 커서 핸들, 화면 좌표 및 스케일이 적용된 타깃 렌더 크기를 반환합니다."""
flags, hcursor, (cx, cy) = win32gui.GetCursorInfo()
if not (flags & win32con.CURSOR_SHOWING):
return None # 마우스 커서가 숨겨진 상태
base_size = get_actual_cursor_size()
dpi_scale = get_system_dpi_scale()
target_size = int(base_size * dpi_scale)
return {
"hcursor": hcursor,
"pos": (cx, cy),
"render_size": (target_size, target_size),
"base_size": base_size,
"dpi_scale": dpi_scale
}
# 실행 테스트
if __name__ == "__main__":
cursor_data = capture_cursor_info()
if cursor_data:
print(f"커서 핸들: {cursor_data['hcursor']}")
print(f"화면 좌표: {cursor_data['pos']}")
print(f"최종 렌더 크기: {cursor_data['render_size'][0]}x{cursor_data['render_size'][1]} px")
print(f"(기본 크기: {cursor_data['base_size']}px, DPI 배율: {cursor_data['dpi_scale']:.2f}x)")
else:
print("현재 커서가 숨김 상태입니다.")
이 코드를 사용하면 접근성 배율 15단계(최대 128px~192px)나 4K 모니터(150%~200% 스케일링) 환경에서도 사용자의 실제 마우스 커서 크기를 정확하게 계산할 수 있습니다.
실시간 화면 녹화를 위한 권장 기술 스택
고해상도 화면 캡처 및 60FPS 이상의 부드러운 동영상 녹화 파이프라인을 구축할 때 권장하는 최적의 조합은 다음과 같습니다:
| 파이프라인 영역 | 추천 기술 및 라이브러리 | 대안 기술 | 선정 사유 |
|---|---|---|---|
| 화면 캡처 (Capture) | DXGI Desktop Duplication (D3D11 / BetterCam) | mss, GDI BitBlt |
60FPS 실시간 고성능 화면 캡처 및 1% 미만의 낮은 CPU 점유율 |
| 커서 렌더링 (Overlay) | Win32 DrawIconEx / OpenCV Alpha Blend |
PIL Image.alpha_composite | 윈도우 원본 커서 리소스의 고품질 벡터/비트맵 스케일링 지원 |
| 비디오 인코딩 (Encoding) | FFmpeg (libx264 / h264_nvenc 파이프라인) | OpenCV VideoWriter |
하드웨어 GPU 가속 인코딩 및 고효율 무손실 압축 지원 |
마치며: 정밀한 캡처 도구를 위한 체크리스트
윈도우 화면 캡처와 커서 크기 보존은 단순해 보이지만 운영체제의 DWM 아키텍처, DPI 인식 정책, 레지스트리 구조, Win32 그래픽 API의 동작 원리가 유기적으로 얽혀 있는 정밀한 기술 영역입니다.
직접 캡처 도구나 비디오 레코더를 개발하거나 기존 도구의 커서 크기 문제를 해결하고자 한다면 다음 세 가지를 반드시 기억하십시오:
- 프레임버퍼 캡처만으로는 커서가 누락되므로 반드시 독립 커서 오버레이 파이프라인을 구축해야 합니다.
- 고정된
32x32크기를 가정하지 말고CursorBaseSize레지스트리와 모니터 DPI를 곱해 동적 렌더 크기를 계산해야 합니다. - 커서 크기를 키웠다면
GetIconInfoEx로 핫스팟 오프셋을 재계산하여 클릭 위치의 시각적 일치성을 보장해야 합니다.
화면 캡처와 녹화 프로그램 개발에 이번 가이드가 든든한 기술적 길잡이가 되기를 바랍니다.