diff --git a/src/MarcerGameDvdLauncher/FavoritesService.cs b/src/MarcerGameDvdLauncher/FavoritesService.cs index e825881..90a964c 100644 --- a/src/MarcerGameDvdLauncher/FavoritesService.cs +++ b/src/MarcerGameDvdLauncher/FavoritesService.cs @@ -4,7 +4,7 @@ namespace MarcerGameDvdLauncher { // Manages loading, saving and querying favorite ZIP paths. - public class FavoritesService + public class FavoritesService(string filePath) { // Virtual folder name displayed at the root when favorites exist. // Not configurable — fixed UI element. @@ -14,15 +14,10 @@ namespace MarcerGameDvdLauncher // Not configurable — fixed persistence file. public const string DefaultFileName = "favorites.txt"; - private readonly string _filePath; + private readonly string _filePath = filePath ?? throw new ArgumentNullException(nameof(filePath)); // Use a SortedSet so favorites are kept in sorted order in memory. private SortedSet _favorites = new(StringComparer.OrdinalIgnoreCase); - public FavoritesService(string filePath) - { - _filePath = filePath ?? throw new ArgumentNullException(nameof(filePath)); - } - // Load favorites from disk (no-op if file missing) public void Load() { @@ -31,7 +26,7 @@ namespace MarcerGameDvdLauncher var lines = File.ReadAllLines(_filePath, System.Text.Encoding.UTF8); foreach (var l in lines) { - var t = l?.Trim(); + var t = l.Trim(); if (string.IsNullOrEmpty(t)) continue; try { @@ -71,14 +66,13 @@ namespace MarcerGameDvdLauncher if (string.IsNullOrWhiteSpace(path)) throw new ArgumentNullException(nameof(path)); var full = Path.GetFullPath(path); bool added; - if (_favorites.Contains(full)) + if (!_favorites.Add(full)) { _favorites.Remove(full); added = false; } else { - _favorites.Add(full); added = true; } Save(); diff --git a/src/MarcerGameDvdLauncher/HatariLauncher.cs b/src/MarcerGameDvdLauncher/HatariLauncher.cs index 60898fa..8e3a416 100644 --- a/src/MarcerGameDvdLauncher/HatariLauncher.cs +++ b/src/MarcerGameDvdLauncher/HatariLauncher.cs @@ -44,15 +44,8 @@ namespace MarcerGameDvdLauncher throw new ArgumentException("ZIP archive path must not be empty.", nameof(zipFilePath)); try { - string args = _argsTemplate; - if (!string.IsNullOrWhiteSpace(_cfgPath)) - { - args = args.Replace("{cfg}", _cfgPath); - } - else - { - args = args.Replace("{cfg}", Path.Combine(Directory.GetCurrentDirectory(),DEFAULT_CONFIG_FILE)); - } + var args = _argsTemplate; + args = args.Replace("{cfg}", !string.IsNullOrWhiteSpace(_cfgPath) ? _cfgPath : Path.Combine(Directory.GetCurrentDirectory(),DEFAULT_CONFIG_FILE)); args = args.Replace("{zip}", zipFilePath); var psi = new System.Diagnostics.ProcessStartInfo diff --git a/src/MarcerGameDvdLauncher/InputController.cs b/src/MarcerGameDvdLauncher/InputController.cs index 123c4de..5287648 100644 --- a/src/MarcerGameDvdLauncher/InputController.cs +++ b/src/MarcerGameDvdLauncher/InputController.cs @@ -1,11 +1,6 @@ // Copyright (c) 2026 Stefan Koelle (https://stefankoelle.de) // Licensed under the MIT License. See LICENSE file in project root for details. -using System; -using System.Collections.Generic; -using System.IO; -using System.Threading; - namespace MarcerGameDvdLauncher { /// @@ -13,42 +8,25 @@ namespace MarcerGameDvdLauncher /// Extracted from AppHost so that LauncherApp stays focused on lifecycle management. /// No functional change - all key-handling behaviour is preserved exactly. /// - internal class InputController + internal class InputController( + OverlayDirectoryBrowser directoryBrowser, + MenuRenderer menuRenderer, + NavigationController navigationController, + HatariLauncher hatariLauncher, + FavoritesService favoritesService, + UIErrorService errorService) { - private readonly OverlayDirectoryBrowser _directoryBrowser; - private readonly MenuRenderer _menuRenderer; - private readonly NavigationController _navigationController; - private readonly HatariLauncher _hatariLauncher; - private readonly FavoritesService _favoritesService; - private readonly UIErrorService _errorService; - private List _gameEntries = new(); - public IReadOnlyList GameEntries => _gameEntries; - - public InputController(OverlayDirectoryBrowser directoryBrowser, MenuRenderer menuRenderer, - NavigationController navigationController, HatariLauncher hatariLauncher, - FavoritesService favoritesService, UIErrorService errorService) - { - _directoryBrowser = directoryBrowser; - _menuRenderer = menuRenderer; - _navigationController = navigationController; - _hatariLauncher = hatariLauncher; - _favoritesService = favoritesService; - _errorService = errorService; - } - private bool IsFavorite(GameEntry e) { - return e.Kind == EntryKind.Zip - ? _favoritesService.IsFavorite(e.InPatch ? e.PatchPath : e.RootPath) - : false; + return e.Kind == EntryKind.Zip && favoritesService.IsFavorite(e.InPatch ? e.PatchPath : e.RootPath); } private void DrawMenu(int availableLines) { - _menuRenderer.DrawMenu(_gameEntries, _navigationController.ScrollOffset, - _navigationController.SelectedIndex, availableLines, IsFavorite); + menuRenderer.DrawMenu(_gameEntries, navigationController.ScrollOffset, + navigationController.SelectedIndex, availableLines, IsFavorite); } /// @@ -56,7 +34,7 @@ namespace MarcerGameDvdLauncher /// public void RefreshView(int availableLines) { - _navigationController.UpdateScrollOffset(_gameEntries.Count, availableLines); + navigationController.UpdateScrollOffset(_gameEntries.Count, availableLines); DrawMenu(availableLines); } @@ -68,9 +46,9 @@ namespace MarcerGameDvdLauncher try { // If we are at the virtual Favorites folder, produce the flat list from the favorites service - if (string.Equals(_navigationController.CurrentRelativePath, FavoritesService.FavoritesRootName, StringComparison.OrdinalIgnoreCase)) + if (string.Equals(navigationController.CurrentRelativePath, FavoritesService.FavoritesRootName, StringComparison.OrdinalIgnoreCase)) { - var favs = _favoritesService.GetAll(); + var favs = favoritesService.GetAll(); _gameEntries = new List(); foreach (var p in favs) { @@ -85,15 +63,15 @@ namespace MarcerGameDvdLauncher IsVirtual = false }); } - _navigationController.SetEntriesCount(_gameEntries.Count); + navigationController.SetEntriesCount(_gameEntries.Count); return; } // Otherwise use the overlay directory browser for normal folders - _gameEntries = _directoryBrowser.GetEntries(_navigationController.CurrentRelativePath); + _gameEntries = directoryBrowser.GetEntries(navigationController.CurrentRelativePath); // If we are at the root and there are favorites, prepend a virtual Favorites folder - if (string.IsNullOrEmpty(_navigationController.CurrentRelativePath) && _favoritesService.HasFavorites()) + if (string.IsNullOrEmpty(navigationController.CurrentRelativePath) && favoritesService.HasFavorites()) { var virtualEntry = new GameEntry { @@ -108,14 +86,14 @@ namespace MarcerGameDvdLauncher _gameEntries.Insert(0, virtualEntry); } - _navigationController.SetEntriesCount(_gameEntries.Count); + navigationController.SetEntriesCount(_gameEntries.Count); } catch (Exception ex) { // Show the error to the user and continue with an empty list - _errorService.ShowError(ex.Message); + errorService.ShowError(ex.Message); _gameEntries = new List(); - _navigationController.SetEntriesCount(0); + navigationController.SetEntriesCount(0); } } @@ -126,9 +104,9 @@ namespace MarcerGameDvdLauncher { if (key.KeyChar == '?') { - _menuRenderer.ShowHelpBox(availableLines); + menuRenderer.ShowHelpBox(availableLines); Console.ReadKey(intercept: true); - _menuRenderer.InvalidateCache(); + menuRenderer.InvalidateCache(); DrawMenu(availableLines); ProgramHelpers.FlushInputBuffer(); return false; @@ -138,16 +116,16 @@ namespace MarcerGameDvdLauncher { case ConsoleKey.UpArrow: { - int previousSelectedIndex = _navigationController.SelectedIndex; - bool didScroll = _navigationController.MoveUp(_gameEntries, availableLines); + int previousSelectedIndex = navigationController.SelectedIndex; + bool didScroll = navigationController.MoveUp(_gameEntries, availableLines); if (didScroll) { DrawMenu(availableLines); } else { - _menuRenderer.RedrawEntry(_gameEntries, previousSelectedIndex, previousSelectedIndex - _navigationController.ScrollOffset, false, availableLines, IsFavorite); - _menuRenderer.RedrawEntry(_gameEntries, _navigationController.SelectedIndex, _navigationController.SelectedIndex - _navigationController.ScrollOffset, true, availableLines, IsFavorite); + menuRenderer.RedrawEntry(_gameEntries, previousSelectedIndex, previousSelectedIndex - navigationController.ScrollOffset, false, availableLines, IsFavorite); + menuRenderer.RedrawEntry(_gameEntries, navigationController.SelectedIndex, navigationController.SelectedIndex - navigationController.ScrollOffset, true, availableLines, IsFavorite); } // flush input to avoid key repeat ProgramHelpers.FlushInputBuffer(); @@ -155,16 +133,16 @@ namespace MarcerGameDvdLauncher break; case ConsoleKey.DownArrow: { - int previousSelectedIndex = _navigationController.SelectedIndex; - bool didScroll = _navigationController.MoveDown(_gameEntries, availableLines); + int previousSelectedIndex = navigationController.SelectedIndex; + bool didScroll = navigationController.MoveDown(_gameEntries, availableLines); if (didScroll) { DrawMenu(availableLines); } else { - _menuRenderer.RedrawEntry(_gameEntries, previousSelectedIndex, previousSelectedIndex - _navigationController.ScrollOffset, false, availableLines, IsFavorite); - _menuRenderer.RedrawEntry(_gameEntries, _navigationController.SelectedIndex, _navigationController.SelectedIndex - _navigationController.ScrollOffset, true, availableLines, IsFavorite); + menuRenderer.RedrawEntry(_gameEntries, previousSelectedIndex, previousSelectedIndex - navigationController.ScrollOffset, false, availableLines, IsFavorite); + menuRenderer.RedrawEntry(_gameEntries, navigationController.SelectedIndex, navigationController.SelectedIndex - navigationController.ScrollOffset, true, availableLines, IsFavorite); } ProgramHelpers.FlushInputBuffer(); } @@ -172,26 +150,26 @@ namespace MarcerGameDvdLauncher case ConsoleKey.Enter: case ConsoleKey.RightArrow: { - var oldRelativePath = _navigationController.CurrentRelativePath; - var isDirectory = _gameEntries.Count > 0 && _gameEntries[_navigationController.SelectedIndex].Kind == EntryKind.Directory; - _navigationController.HandleEnter(_gameEntries); - if (isDirectory && oldRelativePath != _navigationController.CurrentRelativePath) + var oldRelativePath = navigationController.CurrentRelativePath; + var isDirectory = _gameEntries.Count > 0 && _gameEntries[navigationController.SelectedIndex].Kind == EntryKind.Directory; + navigationController.HandleEnter(_gameEntries); + if (isDirectory && oldRelativePath != navigationController.CurrentRelativePath) { ReloadGameEntries(); - _navigationController.UpdateScrollOffset(_gameEntries.Count, availableLines); + navigationController.UpdateScrollOffset(_gameEntries.Count, availableLines); } DrawMenu(availableLines); // Only start a ZIP if NOT switching to a directory - if (!isDirectory && _gameEntries.Count > 0 && _gameEntries[_navigationController.SelectedIndex].Kind == EntryKind.Zip) + if (!isDirectory && _gameEntries.Count > 0 && _gameEntries[navigationController.SelectedIndex].Kind == EntryKind.Zip) { - string zipToLaunch = _gameEntries[_navigationController.SelectedIndex].InPatch ? _gameEntries[_navigationController.SelectedIndex].PatchPath : _gameEntries[_navigationController.SelectedIndex].RootPath; + string zipToLaunch = _gameEntries[navigationController.SelectedIndex].InPatch ? _gameEntries[navigationController.SelectedIndex].PatchPath : _gameEntries[navigationController.SelectedIndex].RootPath; try { - _hatariLauncher.Launch(zipToLaunch); + hatariLauncher.Launch(zipToLaunch); } catch (Exception ex) { - _errorService.ShowError(ex.Message); + errorService.ShowError(ex.Message); } } // flush input to avoid leftover key events after an enter/navigation @@ -201,23 +179,23 @@ namespace MarcerGameDvdLauncher case ConsoleKey.Backspace: case ConsoleKey.LeftArrow: { - _navigationController.GoUpDirectory(); + navigationController.GoUpDirectory(); ReloadGameEntries(); - _navigationController.UpdateScrollOffset(_gameEntries.Count, availableLines); + navigationController.UpdateScrollOffset(_gameEntries.Count, availableLines); DrawMenu(availableLines); ProgramHelpers.FlushInputBuffer(); } break; case ConsoleKey.PageDown: { - _navigationController.PageDown(_gameEntries, availableLines); + navigationController.PageDown(_gameEntries, availableLines); DrawMenu(availableLines); ProgramHelpers.FlushInputBuffer(); } break; case ConsoleKey.PageUp: { - _navigationController.PageUp(_gameEntries, availableLines); + navigationController.PageUp(_gameEntries, availableLines); DrawMenu(availableLines); ProgramHelpers.FlushInputBuffer(); } @@ -226,17 +204,17 @@ namespace MarcerGameDvdLauncher case ConsoleKey.Oem8: { // Toggle favorite for selected ZIP (handles numpad * and some layouts) - if (_gameEntries.Count > 0 && _gameEntries[_navigationController.SelectedIndex].Kind == EntryKind.Zip) + if (_gameEntries.Count > 0 && _gameEntries[navigationController.SelectedIndex].Kind == EntryKind.Zip) { - var ge = _gameEntries[_navigationController.SelectedIndex]; + var ge = _gameEntries[navigationController.SelectedIndex]; string path = ge.InPatch ? ge.PatchPath : ge.RootPath; try { - _favoritesService.Toggle(path); + favoritesService.Toggle(path); } catch (Exception ex) { - _errorService.ShowError("Failed to toggle favorite: " + ex.Message); + errorService.ShowError("Failed to toggle favorite: " + ex.Message); } // Redraw the whole menu so the '*' marker updates immediately DrawMenu(availableLines); diff --git a/src/MarcerGameDvdLauncher/MenuRenderer.cs b/src/MarcerGameDvdLauncher/MenuRenderer.cs index 21b08d8..45634d2 100644 --- a/src/MarcerGameDvdLauncher/MenuRenderer.cs +++ b/src/MarcerGameDvdLauncher/MenuRenderer.cs @@ -3,7 +3,7 @@ namespace MarcerGameDvdLauncher { - public class MenuRenderer + public class MenuRenderer(AppColorConfig? colors = null) { // Simple line-based double buffer to avoid full Clear() flicker. // cachedBuffer holds the last rendered text and colors for each visible row. @@ -12,12 +12,7 @@ namespace MarcerGameDvdLauncher private int _cachedWidth = -1; // Color configuration (injected; defaults to built-in scheme if null) - private readonly AppColorConfig _colors; - - public MenuRenderer(AppColorConfig? colors = null) - { - _colors = colors ?? new AppColorConfig(); - } + private readonly AppColorConfig _colors = colors ?? new AppColorConfig(); // availableLines is provided per-draw so the renderer adapts to console resizes public void DrawMenu(List entries, int scrollOffset, int selectedIndex, int availableLines, Func? isFavorite = null) @@ -140,53 +135,40 @@ namespace MarcerGameDvdLauncher // Renders a centered, bordered help box with key bindings inside the // available console area. The caller is responsible for waiting on a - // key and redrawing the menu afterwards. + // key and redrawing the menu afterward. public void ShowHelpBox(int availableLines) { - try + var width = Console.WindowWidth; + var helpLines = GetHelpLines(); + var boxHeight = Math.Min(helpLines.Length + 2, Math.Max(3, availableLines)); + var boxWidth = Math.Max(1, width); + var topRow = Math.Max(0, (availableLines - boxHeight) / 2); + + Console.BackgroundColor = ConsoleColor.DarkGray; + Console.ForegroundColor = ConsoleColor.White; + + var topBorder = "+" + new string('-', Math.Max(0, boxWidth - 2)) + "+"; + Console.SetCursorPosition(0, topRow); + Console.Write(topBorder); + + for (var i = 0; i < boxHeight - 2; i++) { - int width = Console.WindowWidth; - string[] helpLines = GetHelpLines(); - int boxHeight = Math.Min(helpLines.Length + 2, Math.Max(3, availableLines)); - int boxWidth = Math.Max(1, width); - int topRow = Math.Max(0, (availableLines - boxHeight) / 2); - - Console.BackgroundColor = ConsoleColor.DarkGray; - Console.ForegroundColor = ConsoleColor.White; - - string topBorder = "+" + new string('-', Math.Max(0, boxWidth - 2)) + "+"; - Console.SetCursorPosition(0, topRow); - Console.Write(topBorder); - - for (int i = 0; i < boxHeight - 2; i++) - { - int row = topRow + 1 + i; - string content; - if (i < helpLines.Length) - { - content = PadToWidth(helpLines[i], boxWidth - 2); - } - else - { - content = new string(' ', Math.Max(0, boxWidth - 2)); - } - Console.SetCursorPosition(0, row); - Console.Write("|" + content + "|"); - } - - int bottomRow = topRow + boxHeight - 1; - if (bottomRow < Console.WindowHeight) - { - string bottomBorder = "+" + new string('-', Math.Max(0, boxWidth - 2)) + "+"; - Console.SetCursorPosition(0, bottomRow); - Console.Write(bottomBorder); - } - - Console.ResetColor(); + var row = topRow + 1 + i; + var content = i < helpLines.Length + ? PadToWidth(helpLines[i], boxWidth - 2) + : new string(' ', Math.Max(0, boxWidth - 2)); + Console.SetCursorPosition(0, row); + Console.Write("|" + content + "|"); } - catch + + var bottomRow = topRow + boxHeight - 1; + if (bottomRow < Console.WindowHeight) { + var bottomBorder = "+" + new string('-', Math.Max(0, boxWidth - 2)) + "+"; + Console.SetCursorPosition(0, bottomRow); + Console.Write(bottomBorder); } + Console.ResetColor(); } private static string[] GetHelpLines() @@ -235,7 +217,7 @@ namespace MarcerGameDvdLauncher { if (width <= 0) return string.Empty; - string label = GetLabel(e, isFavorite); + var label = GetLabel(e, isFavorite); // If the console width is smaller than the label, truncate the label if (width <= label.Length) @@ -243,7 +225,7 @@ namespace MarcerGameDvdLauncher return label.Substring(0, width); } - int maxNameLen = width - label.Length; // space left for name + var maxNameLen = width - label.Length; // space left for name string displayName; if (e.Name.Length <= maxNameLen) { @@ -257,7 +239,7 @@ namespace MarcerGameDvdLauncher displayName = e.Name.Substring(0, Math.Max(0, maxNameLen)); } - int padding = Math.Max(0, width - label.Length - displayName.Length); + var padding = Math.Max(0, width - label.Length - displayName.Length); var result = label + displayName + new string(' ', padding); // Ensure exact width (defensive): truncate or pad if needed if (result.Length > width) return result.Substring(0, width); @@ -273,7 +255,7 @@ namespace MarcerGameDvdLauncher { // Layer label (7 chars) string layer; - if (e.InRoot && e.InPatch) layer = "[BOTH] "; + if (e is {InRoot: true, InPatch: true}) layer = "[BOTH] "; else if (e.InPatch) layer = "[PTCH] "; else if (e.InRoot) layer = "[ROOT] "; else layer = " "; @@ -299,15 +281,15 @@ namespace MarcerGameDvdLauncher if (e.Kind == EntryKind.Directory) { - if (e.InRoot && e.InPatch) return _colors.FolderBoth; // Both layers - if (e.InPatch && !e.InRoot) return _colors.FolderPatchOnly; // Only patch - if (e.InRoot && !e.InPatch) return _colors.FolderRootOnly; // Only root + if (e is {InRoot: true, InPatch: true}) return _colors.FolderBoth; // Both layers + if (e is {InPatch: true, InRoot: false}) return _colors.FolderPatchOnly; // Only patch + if (e is {InRoot: true, InPatch: false}) return _colors.FolderRootOnly; // Only root } else if (e.Kind == EntryKind.Zip) { - if (e.InRoot && e.InPatch) return _colors.ZipBoth; // Both layers - if (e.InRoot && !e.InPatch) return _colors.ZipRootOnly; // Only root - if (e.InPatch && !e.InRoot) return _colors.ZipPatchOnly; // Only patch + if (e is {InRoot: true, InPatch: true}) return _colors.ZipBoth; // Both layers + if (e is { InRoot: true, InPatch: false }) return _colors.ZipRootOnly; // Only root + if (e is {InPatch: true, InRoot: false}) return _colors.ZipPatchOnly; // Only patch } return ConsoleColor.DarkGray; } diff --git a/src/MarcerGameDvdLauncher/NavigationController.cs b/src/MarcerGameDvdLauncher/NavigationController.cs index f464bf2..6523452 100644 --- a/src/MarcerGameDvdLauncher/NavigationController.cs +++ b/src/MarcerGameDvdLauncher/NavigationController.cs @@ -8,11 +8,11 @@ namespace MarcerGameDvdLauncher // Scroll fractions: when the selection cursor reaches 2/3 of the visible window // height from the top, the list scrolls down; when it reaches 1/3, it scrolls up. // Not configurable — these ratios are the established navigation behaviour. - private const double BottomScrollFraction = 2.0 / 3.0; - private const double TopScrollFraction = 1.0 / 3.0; + private const double BOTTOM_SCROLL_FRACTION = 2.0 / 3.0; + private const double TOP_SCROLL_FRACTION = 1.0 / 3.0; - public int SelectedIndex { get; private set; } = 0; - public int ScrollOffset { get; private set; } = 0; + public int SelectedIndex { get; private set; } + public int ScrollOffset { get; private set; } public string CurrentRelativePath { get; private set; } = ""; // Stores the last selection & scroll position for each directory private readonly Dictionary _lastSelections = new(); @@ -105,12 +105,12 @@ namespace MarcerGameDvdLauncher if (availableLines < 1) availableLines = 1; if (entryCount <= availableLines) { ScrollOffset = 0; return; } if (SelectedIndex == 0) { ScrollOffset = 0; return; } - int bottomScrollTrigger = ScrollOffset + (int)(availableLines * BottomScrollFraction); - int topScrollTrigger = ScrollOffset + (int)(availableLines * TopScrollFraction); + int bottomScrollTrigger = ScrollOffset + (int)(availableLines * BOTTOM_SCROLL_FRACTION); + int topScrollTrigger = ScrollOffset + (int)(availableLines * TOP_SCROLL_FRACTION); if (SelectedIndex >= bottomScrollTrigger && (ScrollOffset + availableLines) < entryCount) - ScrollOffset = SelectedIndex - (int)(availableLines * BottomScrollFraction); + ScrollOffset = SelectedIndex - (int)(availableLines * BOTTOM_SCROLL_FRACTION); else if (SelectedIndex < topScrollTrigger && ScrollOffset > 0) - ScrollOffset = SelectedIndex - (int)(availableLines * TopScrollFraction); + ScrollOffset = SelectedIndex - (int)(availableLines * TOP_SCROLL_FRACTION); if (ScrollOffset < 0) ScrollOffset = 0; if (ScrollOffset > entryCount - availableLines) ScrollOffset = entryCount - availableLines; diff --git a/src/MarcerGameDvdLauncher/OverlayDirectoryBrowser.cs b/src/MarcerGameDvdLauncher/OverlayDirectoryBrowser.cs index a22ae4a..928e0a3 100644 --- a/src/MarcerGameDvdLauncher/OverlayDirectoryBrowser.cs +++ b/src/MarcerGameDvdLauncher/OverlayDirectoryBrowser.cs @@ -19,16 +19,16 @@ namespace MarcerGameDvdLauncher public class OverlayDirectoryBrowser(string root, string patch) { - public List GetEntries(string currentRelativePath) + public List GetEntries(string? currentRelativePath) { try { // Normalize and protect against path traversal or absolute paths in the relative path - string rel = currentRelativePath ?? string.Empty; + var rel = currentRelativePath ?? string.Empty; // Remove any leading directory separators rel = rel.TrimStart(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); // If the relative path is rooted or contains parent directory segments, reset to root - if (Path.IsPathRooted(rel) || rel.Split(new[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries).Any(p => p == "..")) + if (Path.IsPathRooted(rel) || rel.Split([Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar], StringSplitOptions.RemoveEmptyEntries).Any(p => p == "..")) { rel = string.Empty; } diff --git a/src/MarcerGameDvdLauncher/Program.cs b/src/MarcerGameDvdLauncher/Program.cs index 8a72cf2..d507317 100644 --- a/src/MarcerGameDvdLauncher/Program.cs +++ b/src/MarcerGameDvdLauncher/Program.cs @@ -6,11 +6,11 @@ namespace MarcerGameDvdLauncher class Program { // Console window title. Not configurable — fixed application display name. - private const string DefaultTitle = "Marcer GameDVD Launcher"; + private const string DEFAULT_TITLE = "Marcer GameDVD Launcher"; static void Main(string[] args) { - Console.Title = DefaultTitle; + Console.Title = DEFAULT_TITLE; var app = new LauncherApp(); app.Run(); } diff --git a/src/MarcerGameDvdLauncher/ProgramHelpers.cs b/src/MarcerGameDvdLauncher/ProgramHelpers.cs index d0e0e38..046c80a 100644 --- a/src/MarcerGameDvdLauncher/ProgramHelpers.cs +++ b/src/MarcerGameDvdLauncher/ProgramHelpers.cs @@ -1,7 +1,6 @@ // Copyright (c) 2026 Stefan Koelle (https://stefankoelle.de) // Licensed under the MIT License. See LICENSE file in project root for details. -using System; using System.Runtime.InteropServices; namespace MarcerGameDvdLauncher @@ -40,11 +39,11 @@ namespace MarcerGameDvdLauncher // These are defined by the Windows API and do not change. private const int STD_INPUT_HANDLE = -10; - [System.Runtime.InteropServices.DllImport("kernel32.dll")] + [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)] + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] private static extern bool FlushConsoleInputBuffer(IntPtr hConsoleInput); // P/Invoke to query key state (used to detect physical key release) @@ -59,16 +58,16 @@ namespace MarcerGameDvdLauncher // 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) + public static void ShowModalUntilReturnReleased(string? message) { try { - int lastRow = AvailableLines; - int width = Console.WindowWidth; - string text = message ?? string.Empty; + var lastRow = AvailableLines; + var width = Console.WindowWidth; + var 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); + var padding = Math.Max(0, width - text.Length); + var line = text + new string(' ', padding); Console.BackgroundColor = ConsoleColor.DarkGray; Console.ForegroundColor = ConsoleColor.White;