Skip to content

Commit c3c7276

Browse files
committed
Always stay on top if game is fullscreen
1 parent 7bb45ea commit c3c7276

File tree

1 file changed

+27
-6
lines changed

1 file changed

+27
-6
lines changed

BepInEx.SplashScreen.GUI/Program.cs

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -245,21 +245,26 @@ private static void SnapPositionToGameWindowThread(object processArg)
245245
if (!_mainForm.Visible && !temporarilyHidden)
246246
continue;
247247

248-
if (gameProcess.MainWindowHandle == IntPtr.Zero ||
248+
var gameWindowHandle = gameProcess.MainWindowHandle;
249+
var gameWindowTitle = gameProcess.MainWindowTitle;
250+
251+
if (gameWindowHandle == IntPtr.Zero ||
249252
// Ignore console window
250-
gameProcess.MainWindowTitle.StartsWith("BepInEx") ||
251-
gameProcess.MainWindowTitle.StartsWith("Select BepInEx"))
253+
gameWindowTitle.StartsWith("BepInEx") ||
254+
gameWindowTitle.StartsWith("Select BepInEx"))
252255
{
253256
// Need to refresh the process if the window handle is not yet valid or it will keep grabbing the old one
257+
_mainForm.TopMost = false;
254258
gameProcess.Refresh();
255259
continue;
256260
}
257261

258262
// Detect Unity's pre-launch resoultion and hotkey configuration window and hide the splash until it is closed
259263
// It seems like it's not possible to localize this window so the title check should be fine? Hopefully?
260-
if (gameProcess.MainWindowTitle.EndsWith(" Configuration"))
264+
if (gameWindowTitle.EndsWith(" Configuration"))
261265
{
262266
_mainForm.Visible = false;
267+
_mainForm.TopMost = false;
263268
temporarilyHidden = true;
264269
gameProcess.Refresh();
265270
continue;
@@ -271,13 +276,13 @@ private static void SnapPositionToGameWindowThread(object processArg)
271276
_mainForm.Visible = true;
272277
}
273278

274-
if (!NativeMethods.GetWindowRect(new HandleRef(_mainForm, gameProcess.MainWindowHandle), out var rct))
279+
if (!NativeMethods.GetWindowRect(new HandleRef(_mainForm, gameWindowHandle), out var rct))
275280
throw new InvalidOperationException("GetWindowRect failed :(");
276281

277282
var foregroundWindow = NativeMethods.GetForegroundWindow();
278283
// The main game window is not responding most of the time, which prevents it from being recognized as the foreground window
279284
// To work around this, check if the currently focused window is the splash window, as it will most likely be the last focused window after user clicks on the game window
280-
_mainForm.TopMost = gameProcess.MainWindowHandle == foregroundWindow || _mainForm.Handle == foregroundWindow;
285+
_mainForm.TopMost = gameWindowHandle == foregroundWindow || NativeMethods.IsBorderless(gameWindowHandle);
281286

282287
// Just in case, don't want to mangle the splash
283288
if (default(NativeMethods.RECT).Equals(rct))
@@ -327,6 +332,22 @@ public struct RECT
327332

328333
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
329334
public static extern IntPtr GetForegroundWindow();
335+
336+
[DllImport("user32.dll")]
337+
private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
338+
339+
private static int GWL_STYLE = -16;
340+
private static int WS_BORDER = 0x00800000; //window with border
341+
private static int WS_DLGFRAME = 0x00400000; //window with double border but no title
342+
private static int WS_CAPTION = WS_BORDER | WS_DLGFRAME; //window with a title bar
343+
private static int WS_SYSMENU = 0x00080000; //window menu
344+
345+
public static bool IsBorderless(IntPtr windowPtr)
346+
{
347+
int style = GetWindowLong(windowPtr, GWL_STYLE);
348+
349+
return (style & WS_CAPTION) == 0 && (style & WS_SYSMENU) == 0;
350+
}
330351
}
331352

332353
#endregion

0 commit comments

Comments
 (0)