瀏覽代碼

win-capture: Use DPI context for game capture

Fixes cursor position for windows unaware of DPI.

Only works on Windows 10 1607 and above.
jpark37 4 年之前
父節點
當前提交
6a288b255a
共有 1 個文件被更改,包括 64 次插入0 次删除
  1. 64 0
      plugins/win-capture/game-capture.c

+ 64 - 0
plugins/win-capture/game-capture.c

@@ -109,6 +109,11 @@ struct game_capture_config {
 	enum hook_rate hook_rate;
 };
 
+typedef DPI_AWARENESS_CONTEXT(WINAPI *PFN_SetThreadDpiAwarenessContext)(
+	DPI_AWARENESS_CONTEXT);
+typedef DPI_AWARENESS_CONTEXT(WINAPI *PFN_GetThreadDpiAwarenessContext)(VOID);
+typedef DPI_AWARENESS_CONTEXT(WINAPI *PFN_GetWindowDpiAwarenessContext)(HWND);
+
 struct game_capture {
 	obs_source_t *source;
 
@@ -178,6 +183,10 @@ struct game_capture {
 	};
 
 	void (*copy_texture)(struct game_capture *);
+
+	PFN_SetThreadDpiAwarenessContext set_thread_dpi_awareness_context;
+	PFN_GetThreadDpiAwarenessContext get_thread_dpi_awareness_context;
+	PFN_GetWindowDpiAwarenessContext get_window_dpi_awareness_context;
 };
 
 struct graphics_offsets offsets32 = {0};
@@ -557,6 +566,35 @@ static void *game_capture_create(obs_data_t *settings, obs_source_t *source)
 		gc->source, HOTKEY_START, TEXT_HOTKEY_START, HOTKEY_STOP,
 		TEXT_HOTKEY_STOP, hotkey_start, hotkey_stop, gc, gc);
 
+	const HMODULE hModuleUser32 = GetModuleHandle(L"User32.dll");
+	if (hModuleUser32) {
+		PFN_SetThreadDpiAwarenessContext
+			set_thread_dpi_awareness_context =
+				(PFN_SetThreadDpiAwarenessContext)GetProcAddress(
+					hModuleUser32,
+					"SetThreadDpiAwarenessContext");
+		PFN_GetThreadDpiAwarenessContext
+			get_thread_dpi_awareness_context =
+				(PFN_GetThreadDpiAwarenessContext)GetProcAddress(
+					hModuleUser32,
+					"GetThreadDpiAwarenessContext");
+		PFN_GetWindowDpiAwarenessContext
+			get_window_dpi_awareness_context =
+				(PFN_GetWindowDpiAwarenessContext)GetProcAddress(
+					hModuleUser32,
+					"GetWindowDpiAwarenessContext");
+		if (set_thread_dpi_awareness_context &&
+		    get_thread_dpi_awareness_context &&
+		    get_window_dpi_awareness_context) {
+			gc->set_thread_dpi_awareness_context =
+				set_thread_dpi_awareness_context;
+			gc->get_thread_dpi_awareness_context =
+				get_thread_dpi_awareness_context;
+			gc->get_window_dpi_awareness_context =
+				get_window_dpi_awareness_context;
+		}
+	}
+
 	game_capture_update(gc, settings);
 	return gc;
 }
@@ -1831,10 +1869,26 @@ static void game_capture_tick(void *data, float seconds)
 			}
 
 			if (gc->config.cursor) {
+				DPI_AWARENESS_CONTEXT previous = NULL;
+				if (gc->get_window_dpi_awareness_context !=
+				    NULL) {
+					const DPI_AWARENESS_CONTEXT context =
+						gc->get_window_dpi_awareness_context(
+							gc->window);
+					previous =
+						gc->set_thread_dpi_awareness_context(
+							context);
+				}
+
 				check_foreground_window(gc, seconds);
 				obs_enter_graphics();
 				cursor_capture(&gc->cursor_data);
 				obs_leave_graphics();
+
+				if (previous) {
+					gc->set_thread_dpi_awareness_context(
+						previous);
+				}
 			}
 
 			gc->fps_reset_time += seconds;
@@ -1861,8 +1915,18 @@ static inline void game_capture_render_cursor(struct game_capture *gc)
 			 ? (HWND)(uintptr_t)gc->global_hook_info->window
 			 : gc->window;
 
+	DPI_AWARENESS_CONTEXT previous = NULL;
+	if (gc->get_window_dpi_awareness_context != NULL) {
+		const DPI_AWARENESS_CONTEXT context =
+			gc->get_window_dpi_awareness_context(gc->window);
+		previous = gc->set_thread_dpi_awareness_context(context);
+	}
+
 	ClientToScreen(window, &p);
 
+	if (previous)
+		gc->set_thread_dpi_awareness_context(previous);
+
 	cursor_draw(&gc->cursor_data, -p.x, -p.y, gc->global_hook_info->cx,
 		    gc->global_hook_info->cy);
 }