using System.Runtime.InteropServices; using System.Windows.Input; using System.Windows.Interop; using Microsoft.Win32; namespace DeskCore; /// Systemweites Tastenkürzel (RegisterHotKey). public sealed class Hotkey : IDisposable { public const int ModAlt = 0x1, ModCtrl = 0x2, ModShift = 0x4, ModWin = 0x8; private const int ModNoRepeat = 0x4000, WmHotkey = 0x0312, Id = 0xB001; private readonly IntPtr _hwnd; private readonly HwndSource _source; private bool _registered; public event Action? Pressed; public Hotkey(IntPtr hwnd) { _hwnd = hwnd; _source = HwndSource.FromHwnd(hwnd); _source.AddHook(Hook); } /// Registriert das Kürzel. false = schon von einem anderen Programm belegt. public bool Register(int modifiers, int vk) { Unregister(); if (vk == 0) return false; _registered = RegisterHotKey(_hwnd, Id, modifiers | ModNoRepeat, vk); return _registered; } public void Unregister() { if (_registered) UnregisterHotKey(_hwnd, Id); _registered = false; } private IntPtr Hook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { if (msg == WmHotkey && wParam.ToInt32() == Id) { Pressed?.Invoke(); handled = true; } return IntPtr.Zero; } public static string Describe(int modifiers, int vk) { if (vk == 0) return "–"; var parts = new List(); if ((modifiers & ModWin) != 0) parts.Add("Win"); if ((modifiers & ModCtrl) != 0) parts.Add("Strg"); if ((modifiers & ModAlt) != 0) parts.Add("Alt"); if ((modifiers & ModShift) != 0) parts.Add("Umschalt"); var key = KeyInterop.KeyFromVirtualKey(vk); parts.Add(key switch { >= Key.D0 and <= Key.D9 => ((char)('0' + (key - Key.D0))).ToString(), Key.Space => "Leertaste", _ => key.ToString(), }); return string.Join(" + ", parts); } public void Dispose() { Unregister(); _source.RemoveHook(Hook); } [DllImport("user32.dll")] private static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vk); [DllImport("user32.dll")] private static extern bool UnregisterHotKey(IntPtr hWnd, int id); } /// Start mit Windows über HKCU\...\Run. public static class Autostart { private const string Key = @"Software\Microsoft\Windows\CurrentVersion\Run"; private const string Name = "DeskCore"; // Frühere Namen dieser App. "DeskHub" heißt auch ein anderes Programm → nur übernehmen, wenn der Eintrag eindeutig von uns ist. private static readonly string[] OldNames = ["DesktopSortierer", "DeskHub"]; public static bool Enabled { get { try { using var k = Registry.CurrentUser.OpenSubKey(Key); return k?.GetValue(Name) is string; } catch { return false; } } set { try { using var k = Registry.CurrentUser.OpenSubKey(Key, writable: true) ?? Registry.CurrentUser.CreateSubKey(Key); if (value) k.SetValue(Name, $"\"{Environment.ProcessPath}\" --minimized"); else k.DeleteValue(Name, throwOnMissingValue: false); } catch { } } } /// Alten Autostart-Eintrag ("DesktopSortierer") auf den neuen Namen umstellen. public static void Migrate() { try { using var k = Registry.CurrentUser.OpenSubKey(Key, writable: true); if (k is null) return; bool wasEnabled = false; foreach (var old in OldNames) { if (k.GetValue(old) is not string cmd) continue; bool ours = old == "DesktopSortierer" || (cmd.Contains($"{old}.exe", StringComparison.OrdinalIgnoreCase) && cmd.Contains("--minimized")); if (!ours) continue; k.DeleteValue(old, throwOnMissingValue: false); wasEnabled = true; } if (wasEnabled) Enabled = true; } catch { } } /// Falls die exe verschoben wurde: Pfad im Autostart aktualisieren. public static void RefreshPath() { if (Enabled) Enabled = true; } }