topmostfriend/TopMostFriend/HotKeyWindow.cs
2022-08-26 01:54:01 +02:00

110 lines
3.5 KiB
C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace TopMostFriend {
public sealed class HotKeyWindow : Form {
public class HotKeyInfo {
public string Name { get; }
public int Atom { get; }
public int Key { get; }
public Action Action { get; }
public HotKeyInfo(string name, int atom, int key, Action action) {
Name = name ?? throw new ArgumentNullException(nameof(name));
Atom = atom;
Key = key;
Action = action ?? throw new ArgumentNullException(nameof(action));
}
}
private readonly List<HotKeyInfo> RegisteredHotKeys = new List<HotKeyInfo>();
public HotKeyWindow() {
ShowInTaskbar = false;
Text = string.Empty;
FormBorderStyle = FormBorderStyle.None;
StartPosition = FormStartPosition.Manual;
Size = new Size(1, 1);
Location = new Point(-9999, -9999);
CreateHandle();
Hide();
}
protected override void OnFormClosing(FormClosingEventArgs e) {
e.Cancel = e.CloseReason == CloseReason.UserClosing;
}
protected override void WndProc(ref Message m) {
base.WndProc(ref m);
if(m.Msg == Win32.WM_HOTKEY) {
int keyCode = m.LParam.ToInt32();
lock (RegisteredHotKeys)
RegisteredHotKeys.FirstOrDefault(x => x.Key == keyCode)?.Action.Invoke();
}
}
protected override void Dispose(bool disposing) {
lock (RegisteredHotKeys) {
HotKeyInfo[] hotKeys = RegisteredHotKeys.ToArray();
foreach(HotKeyInfo hotKey in hotKeys)
Unregister(hotKey.Atom);
}
base.Dispose(disposing);
}
public int Register(string name, Win32ModKeys modifiers, Keys key, Action action) {
if (action == null)
throw new ArgumentNullException(nameof(action));
if(string.IsNullOrEmpty(name))
name = Guid.NewGuid().ToString();
int atom = Win32.GlobalAddAtom(name);
int keyCode = ((ushort)key << 16) | (ushort)modifiers;
if (atom == 0)
throw new Win32Exception(Marshal.GetLastWin32Error(), @"Atom creation failed.");
if (!Win32.RegisterHotKey(Handle, atom, modifiers, key)) {
Win32.GlobalDeleteAtom((ushort)atom);
throw new Win32Exception(Marshal.GetLastWin32Error(), @"Hotkey registration failed.");
}
lock(RegisteredHotKeys)
RegisteredHotKeys.Add(new HotKeyInfo(name, atom, keyCode, action));
return atom;
}
public void Unregister(int id) {
if (id < 1)
return;
lock (RegisteredHotKeys) {
if (!RegisteredHotKeys.Any(x => x.Atom == id))
return;
RegisteredHotKeys.RemoveAll(x => x.Atom == id);
}
Win32.UnregisterHotKey(Handle, id);
Win32.GlobalDeleteAtom((ushort)id);
}
public void Unregister(string name) {
int atom = 0;
lock (RegisteredHotKeys)
atom = RegisteredHotKeys.FirstOrDefault(x => x.Name == name)?.Atom ?? 0;
Unregister(atom);
}
}
}