summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-10-27 18:09:19 +0100
committersalmonik <salmonik@tuta.io>2026-10-27 18:09:19 +0100
commit3fae02c7d342981c9910db7715305bc57b261a8b (patch)
treef221907effb1f84dfa3e639e3c2966e432e15c10 /src
parentGUI: add F2 preview shell with dummy controls (diff)
downloadhl2h-3fae02c7d342981c9910db7715305bc57b261a8b.tar.gz
hl2h-3fae02c7d342981c9910db7715305bc57b261a8b.zip
GUI: allow movement while open; freeze look and block bind capture
Feedback pass on the preview shell: - Freeze the rendered view explicitly in CreateMove and again at FRAME_RENDER_START; CInput was still letting mouse look move the camera. - Allow normal WASD/jump/duck movement while the GUI is open; strip attack/use/impulse/weapon selection so GUI clicks do not fire. - While bind capture is active, block all game input. - Esc no longer closes the GUI; it only cancels bind capture. F2 or the title-bar X close the preview. - Interpose SDL_ShowCursor / SDL_SetRelativeMouseMode / warp / window grab so the game cannot re-capture or hide the native cursor while the GUI is open.
Diffstat (limited to '')
-rw-r--r--src/gui.cpp96
-rw-r--r--src/hl2h.cpp38
-rw-r--r--src/hl2h.h1
3 files changed, 120 insertions, 15 deletions
diff --git a/src/gui.cpp b/src/gui.cpp
index 74dd537..923cd4d 100644
--- a/src/gui.cpp
+++ b/src/gui.cpp
@@ -879,12 +879,8 @@ void gui_handle_input() {
879 return; 879 return;
880 } 880 }
881 881
882 if (esc_edge) { 882 if (esc_edge && g_capture_card >= 0)
883 if (g_capture_card >= 0) 883 g_capture_card = -1;
884 g_capture_card = -1;
885 else
886 close_gui();
887 }
888 884
889 // Keep the native cursor free even if the game re-grabs it. 885 // Keep the native cursor free even if the game re-grabs it.
890 if (sd_set_relative) 886 if (sd_set_relative)
@@ -1196,4 +1192,92 @@ void gui_draw() {
1196} 1192}
1197 1193
1198bool gui_is_open() { return g_open; } 1194bool gui_is_open() { return g_open; }
1195bool gui_bind_capture_active() { return g_open && g_capture_card >= 0; }
1199QAngle gui_frozen_view() { return g_frozen; } 1196QAngle gui_frozen_view() { return g_frozen; }
1197
1198// ---------------------------------------------------------------------------
1199// SDL cursor interposition
1200// ---------------------------------------------------------------------------
1201// The game re-asserts relative mouse mode / hides the cursor every frame. While
1202// the GUI is open, force the opposite so the native cursor stays usable.
1203
1204static int (*real_show_cursor)(int) = nullptr;
1205static int (*real_set_relative)(int) = nullptr;
1206static void (*real_warp_mouse)(void *, int, int) = nullptr;
1207static void (*real_set_grab)(void *, int) = nullptr;
1208
1209extern "C" __attribute__((visibility("default"))) int SDL_ShowCursor(int toggle) {
1210 if (!real_show_cursor)
1211 real_show_cursor = (int (*)(int))dlsym(RTLD_NEXT, "SDL_ShowCursor");
1212 if (g_open && toggle != -1) {
1213 if (real_show_cursor)
1214 real_show_cursor(1);
1215 return 1;
1216 }
1217 return real_show_cursor ? real_show_cursor(toggle) : 0;
1218}
1219
1220extern "C" __attribute__((visibility("default"))) int
1221SDL_SetRelativeMouseMode(int enabled) {
1222 if (!real_set_relative)
1223 real_set_relative =
1224 (int (*)(int))dlsym(RTLD_NEXT, "SDL_SetRelativeMouseMode");
1225 if (g_open) {
1226 if (real_set_relative)
1227 real_set_relative(0);
1228 return 0;
1229 }
1230 return real_set_relative ? real_set_relative(enabled) : 0;
1231}
1232
1233extern "C" __attribute__((visibility("default"))) void
1234SDL_WarpMouseInWindow(void *window, int x, int y) {
1235 if (!real_warp_mouse)
1236 real_warp_mouse =
1237 (void (*)(void *, int, int))dlsym(RTLD_NEXT, "SDL_WarpMouseInWindow");
1238 if (g_open)
1239 return;
1240 if (real_warp_mouse)
1241 real_warp_mouse(window, x, y);
1242}
1243
1244extern "C" __attribute__((visibility("default"))) void
1245SDL_SetWindowGrab(void *window, int grabbed) {
1246 if (!real_set_grab)
1247 real_set_grab =
1248 (void (*)(void *, int))dlsym(RTLD_NEXT, "SDL_SetWindowGrab");
1249 if (g_open) {
1250 if (real_set_grab)
1251 real_set_grab(window, 0);
1252 return;
1253 }
1254 if (real_set_grab)
1255 real_set_grab(window, grabbed);
1256}
1257
1258static void (*real_set_mouse_grab)(void *, int) = nullptr;
1259static void (*real_warp_global)(int, int) = nullptr;
1260
1261extern "C" __attribute__((visibility("default"))) void
1262SDL_SetWindowMouseGrab(void *window, int grabbed) {
1263 if (!real_set_mouse_grab)
1264 real_set_mouse_grab =
1265 (void (*)(void *, int))dlsym(RTLD_NEXT, "SDL_SetWindowMouseGrab");
1266 if (g_open) {
1267 if (real_set_mouse_grab)
1268 real_set_mouse_grab(window, 0);
1269 return;
1270 }
1271 if (real_set_mouse_grab)
1272 real_set_mouse_grab(window, grabbed);
1273}
1274
1275extern "C" __attribute__((visibility("default"))) void
1276SDL_WarpMouseGlobal(int x, int y) {
1277 if (!real_warp_global)
1278 real_warp_global = (void (*)(int, int))dlsym(RTLD_NEXT, "SDL_WarpMouseGlobal");
1279 if (g_open)
1280 return;
1281 if (real_warp_global)
1282 real_warp_global(x, y);
1283}
diff --git a/src/hl2h.cpp b/src/hl2h.cpp
index c0c27af..a0e6b53 100644
--- a/src/hl2h.cpp
+++ b/src/hl2h.cpp
@@ -546,10 +546,23 @@ static void do_move(int seq, float frametime) {
546 cmd->viewangles[0] = f.x; 546 cmd->viewangles[0] = f.x;
547 cmd->viewangles[1] = f.y; 547 cmd->viewangles[1] = f.y;
548 cmd->viewangles[2] = f.z; 548 cmd->viewangles[2] = f.z;
549 cmd->forwardmove = 0.0f; 549 // Freeze the rendered view explicitly: CInput may not push the modified
550 cmd->sidemove = 0.0f; 550 // command view back to the engine if the client mode returns false.
551 cmd->upmove = 0.0f; 551 if (g_iface.engine) {
552 cmd->buttons = 0; 552 QAngle set = f;
553 using SetViewFn = void (*)(void *, QAngle *);
554 vfunc<SetViewFn>(g_iface.engine, 20)(g_iface.engine, &set);
555 }
556 if (gui_bind_capture_active()) {
557 // Bind capture must not move/act in the game while keys are sampled.
558 cmd->forwardmove = 0.0f;
559 cmd->sidemove = 0.0f;
560 cmd->upmove = 0.0f;
561 cmd->buttons = 0;
562 } else {
563 // Movement is allowed while the GUI is open, but not look/attack/use.
564 cmd->buttons &= (IN_JUMP | IN_DUCK);
565 }
553 cmd->impulse = 0; 566 cmd->impulse = 0;
554 cmd->weaponselect = 0; 567 cmd->weaponselect = 0;
555 cmd->weaponsubtype = 0; 568 cmd->weaponsubtype = 0;
@@ -670,12 +683,19 @@ void set_silent_restore(const QAngle &angles) {
670static void hkdFrameStageNotify(void *self, int stage) { 683static void hkdFrameStageNotify(void *self, int stage) {
671 if (oFrameStageNotify) 684 if (oFrameStageNotify)
672 oFrameStageNotify(self, stage); 685 oFrameStageNotify(self, stage);
673 if (stage == 5 && g_silent_restore_pending) { 686 if (stage == 5) {
674 g_silent_restore_pending = false; 687 if (g_silent_restore_pending) {
675 if (g_iface.engine) { 688 g_silent_restore_pending = false;
676 QAngle a = g_silent_restore_angles; 689 if (g_iface.engine) {
690 QAngle a = g_silent_restore_angles;
691 using SetViewFn = void (*)(void *, QAngle *);
692 vfunc<SetViewFn>(g_iface.engine, 20)(g_iface.engine, &a);
693 }
694 }
695 if (gui_is_open() && g_iface.engine) {
696 QAngle f = gui_frozen_view();
677 using SetViewFn = void (*)(void *, QAngle *); 697 using SetViewFn = void (*)(void *, QAngle *);
678 vfunc<SetViewFn>(g_iface.engine, 20)(g_iface.engine, &a); 698 vfunc<SetViewFn>(g_iface.engine, 20)(g_iface.engine, &f);
679 } 699 }
680 } 700 }
681} 701}
diff --git a/src/hl2h.h b/src/hl2h.h
index 11b9014..8a81439 100644
--- a/src/hl2h.h
+++ b/src/hl2h.h
@@ -234,6 +234,7 @@ void menu_force_close();
234void gui_handle_input(); 234void gui_handle_input();
235void gui_draw(); 235void gui_draw();
236bool gui_is_open(); 236bool gui_is_open();
237bool gui_bind_capture_active();
237QAngle gui_frozen_view(); 238QAngle gui_frozen_view();
238// ISurface pointer (defined in menu.cpp, used for drawing tests) 239// ISurface pointer (defined in menu.cpp, used for drawing tests)
239struct ISurface; 240struct ISurface;