Files
DeskCore/Hotkey.cs
T
M_ViperandClaude Opus 5.5 77bb3e6b9d DeskCore 1.0.0
Desktop-Icons in eigene Kategorien sortieren: Windows-11-Design (hell/dunkel),
Desktop-Boxen, automatisches Einsortieren nach Regeln, Rückgängig, Suche,
Infobereich mit Tastenkürzel, Sicherung als ZIP und Installer ohne Adminrechte.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-01 20:19:32 +02:00

139 lines
4.4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Runtime.InteropServices;
using System.Windows.Input;
using System.Windows.Interop;
using Microsoft.Win32;
namespace DeskCore;
/// <summary>Systemweites Tastenkürzel (RegisterHotKey).</summary>
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);
}
/// <summary>Registriert das Kürzel. false = schon von einem anderen Programm belegt.</summary>
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<string>();
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);
}
/// <summary>Start mit Windows über HKCU\...\Run.</summary>
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 { }
}
}
/// <summary>Alten Autostart-Eintrag ("DesktopSortierer") auf den neuen Namen umstellen.</summary>
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 { }
}
/// <summary>Falls die exe verschoben wurde: Pfad im Autostart aktualisieren.</summary>
public static void RefreshPath()
{
if (Enabled) Enabled = true;
}
}