Files
marcer-gamedvd-launcher/MarcerGameDvdLauncher/ProgramHelpers.cs
T
2026-08-10 20:20:27 +02:00

116 lines
4.4 KiB
C#

using System;
using System.Runtime.InteropServices;
namespace MarcerGameDvdLauncher
{
// Small helpers refactored into their own file to keep Program.cs focused.
internal static class ProgramHelpers
{
// Flushes the console input buffer to avoid processing leftover key events
// Uses Win32 FlushConsoleInputBuffer on the standard input handle. On non-Windows
// environments this will be a no-op.
public static void FlushInputBuffer()
{
try
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
var handle = GetStdHandle(STD_INPUT_HANDLE);
if (handle != IntPtr.Zero)
{
FlushConsoleInputBuffer(handle);
}
}
}
catch
{
// swallowing is OK here; flushing input is a best-effort UX improvement
}
}
private const int STD_INPUT_HANDLE = -10;
[System.Runtime.InteropServices.DllImport("kernel32.dll")]
private static extern IntPtr GetStdHandle(int nStdHandle);
[System.Runtime.InteropServices.DllImport("kernel32.dll", SetLastError = true)]
[return: System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.Bool)]
private static extern bool FlushConsoleInputBuffer(IntPtr hConsoleInput);
// P/Invoke to query key state (used to detect physical key release)
private const int VK_RETURN = 0x0D;
[DllImport("user32.dll")]
private static extern short GetAsyncKeyState(int vKey);
// Shows a simple modal message on the reserved last console line and
// blocks until the Return key is physically released. The message is
// then removed and the method returns. This is designed to be a
// lightweight modal for the console UI and uses the last console line
// which the application reserves for transient messages.
public static void ShowModalUntilReturnReleased(string message)
{
try
{
int lastRow = Math.Max(0, Console.WindowHeight - 1);
int width = Console.WindowWidth;
string text = message ?? string.Empty;
if (text.Length > width) text = text.Substring(0, Math.Max(0, width - 3)) + "...";
int padding = Math.Max(0, width - text.Length);
string line = text + new string(' ', padding);
Console.BackgroundColor = ConsoleColor.DarkGray;
Console.ForegroundColor = ConsoleColor.White;
try { Console.SetCursorPosition(0, lastRow); } catch { }
try { Console.Write(line); } catch { }
Console.ResetColor();
// Wait until Return key is not pressed
// GetAsyncKeyState returns a short where the high-order bit is set when key is down
while ((GetAsyncKeyState(VK_RETURN) & 0x8000) != 0)
{
Thread.Sleep(10);
}
// Clear the line
try { Console.SetCursorPosition(0, lastRow); } catch { }
try { Console.Write(new string(' ', width)); } catch { }
}
catch
{
// ignore any console errors here
}
finally
{
Console.ResetColor();
}
}
public static string ResolveIfRelative(string? path, string exeDir)
{
if (string.IsNullOrWhiteSpace(path))
return string.Empty;
if (Path.IsPathRooted(path))
return path;
return Path.GetFullPath(Path.Combine(exeDir, path));
}
// Centralized console message printer to avoid duplicated Console.WriteLine/ReadKey blocks.
public static void ShowConsoleMessage(string[] lines, ConsoleColor fg = ConsoleColor.Gray, bool clear = true, bool waitForKey = true)
{
if (clear) Console.Clear();
var prev = Console.ForegroundColor;
try
{
Console.ForegroundColor = fg;
foreach (var l in lines) Console.WriteLine(l);
}
finally
{
Console.ForegroundColor = prev;
}
if (waitForKey) Console.ReadKey(intercept: true);
}
}
}