Add HotKeyListener
This commit is contained in:
+32
-76
@@ -22,48 +22,27 @@ public class Cache<TValue>(IComparer<TValue> comparer) :
|
|||||||
public void Clear() =>
|
public void Clear() =>
|
||||||
items.Clear();
|
items.Clear();
|
||||||
|
|
||||||
public bool Contains(TValue item)
|
public bool Contains(TValue item) =>
|
||||||
{
|
items.IndexOf(item) >= 0;
|
||||||
int index = items.IndexOf(item);
|
|
||||||
if (index >= 0)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerator<TValue> GetEnumerator() =>
|
public IEnumerator<TValue> GetEnumerator() =>
|
||||||
items.GetEnumerator();
|
items.GetEnumerator();
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => items.GetEnumerator();
|
IEnumerator IEnumerable.GetEnumerator() =>
|
||||||
|
items.GetEnumerator();
|
||||||
|
|
||||||
public int IndexOf(TValue item) =>
|
public int IndexOf(TValue item) =>
|
||||||
items.IndexOf(item);
|
items.IndexOf(item);
|
||||||
|
|
||||||
public bool Remove(TValue item)
|
public bool Remove(TValue item) =>
|
||||||
|
items.Remove(item);
|
||||||
|
|
||||||
|
public bool TryGetValue(TValue key,
|
||||||
|
out TValue? item)
|
||||||
{
|
{
|
||||||
int index = items.IndexOf(item);
|
var index = items.IndexOf(key);
|
||||||
if (index >= 0)
|
item = index >= 0 ? items[index] : default;
|
||||||
{
|
return index >= 0;
|
||||||
items.RemoveAt(index);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TryGetValue(TValue key, out TValue? item)
|
|
||||||
{
|
|
||||||
int index = items.IndexOf(key);
|
|
||||||
if (index >= 0)
|
|
||||||
{
|
|
||||||
item = items[index];
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
item = default;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int FindInsertIndex(TValue item)
|
private int FindInsertIndex(TValue item)
|
||||||
@@ -94,20 +73,20 @@ public class Cache<TValue>(IComparer<TValue> comparer) :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Cache<TKey, TValue>(IComparer<TKey> comparer) :
|
public class Cache<TKey, TValue>(IComparer<TKey>? comparer = null) :
|
||||||
ICache<TKey, TValue>
|
ICache<TKey, TValue>
|
||||||
where TKey :
|
where TKey : notnull
|
||||||
notnull
|
where TValue : notnull
|
||||||
where TValue :
|
|
||||||
notnull
|
|
||||||
{
|
{
|
||||||
|
private readonly IComparer<TKey> comparer = comparer ?? Comparer<TKey>.Default;
|
||||||
private readonly List<KeyValuePair<TKey, TValue?>> items = [];
|
private readonly List<KeyValuePair<TKey, TValue?>> items = [];
|
||||||
|
|
||||||
public TValue? this[TKey key]
|
public TValue? this[TKey key]
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
int index = items.BinarySearch(new KeyValuePair<TKey, TValue?>(key, default),
|
int index = items.BinarySearch(
|
||||||
|
new KeyValuePair<TKey, TValue?>(key, default),
|
||||||
new KeyValuePairComparer<TKey, TValue?>(comparer));
|
new KeyValuePairComparer<TKey, TValue?>(comparer));
|
||||||
|
|
||||||
if (index >= 0)
|
if (index >= 0)
|
||||||
@@ -119,7 +98,8 @@ public class Cache<TKey, TValue>(IComparer<TKey> comparer) :
|
|||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
int index = items.BinarySearch(new KeyValuePair<TKey, TValue?>(key, default),
|
int index = items.BinarySearch(
|
||||||
|
new KeyValuePair<TKey, TValue?>(key, default),
|
||||||
new KeyValuePairComparer<TKey, TValue?>(comparer));
|
new KeyValuePairComparer<TKey, TValue?>(comparer));
|
||||||
|
|
||||||
if (index >= 0)
|
if (index >= 0)
|
||||||
@@ -135,7 +115,8 @@ public class Cache<TKey, TValue>(IComparer<TKey> comparer) :
|
|||||||
|
|
||||||
public void Add(TKey key, TValue value)
|
public void Add(TKey key, TValue value)
|
||||||
{
|
{
|
||||||
int index = items.BinarySearch(new KeyValuePair<TKey, TValue?>(key, default),
|
int index = items.BinarySearch(
|
||||||
|
new KeyValuePair<TKey, TValue?>(key, default),
|
||||||
new KeyValuePairComparer<TKey, TValue?>(comparer));
|
new KeyValuePairComparer<TKey, TValue?>(comparer));
|
||||||
|
|
||||||
if (index < 0)
|
if (index < 0)
|
||||||
@@ -148,19 +129,11 @@ public class Cache<TKey, TValue>(IComparer<TKey> comparer) :
|
|||||||
|
|
||||||
public void Clear() => items.Clear();
|
public void Clear() => items.Clear();
|
||||||
|
|
||||||
public bool Contains(TKey key)
|
public bool Contains(TKey key) =>
|
||||||
{
|
items.FindIndex(kvp => comparer.Compare(kvp.Key, key) == 0) >= 0;
|
||||||
int index = items.FindIndex(kvp => comparer.Compare(kvp.Key, key) == 0);
|
|
||||||
if (index >= 0)
|
|
||||||
{
|
|
||||||
items.RemoveAt(index);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() =>
|
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() =>
|
||||||
items.GetEnumerator();
|
items.GetEnumerator();
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() =>
|
IEnumerator IEnumerable.GetEnumerator() =>
|
||||||
GetEnumerator();
|
GetEnumerator();
|
||||||
@@ -168,31 +141,14 @@ public class Cache<TKey, TValue>(IComparer<TKey> comparer) :
|
|||||||
public int IndexOf(TKey key) =>
|
public int IndexOf(TKey key) =>
|
||||||
items.FindIndex(kvp => comparer.Compare(kvp.Key, key) == 0);
|
items.FindIndex(kvp => comparer.Compare(kvp.Key, key) == 0);
|
||||||
|
|
||||||
public bool Remove(TKey key)
|
public bool Remove(TKey key) =>
|
||||||
{
|
items.RemoveAll(kvp => comparer.Compare(kvp.Key, key) == 0) > 0;
|
||||||
int index = items.FindIndex(kvp => comparer.Compare(kvp.Key, key) == 0);
|
|
||||||
if (index >= 0)
|
|
||||||
{
|
|
||||||
items.RemoveAt(index);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TryGetValue(TKey key, out TValue? value)
|
public bool TryGetValue(TKey key, out TValue? value) =>
|
||||||
{
|
(items.BinarySearch(new KeyValuePair<TKey, TValue?>(key, default),
|
||||||
int index = items.BinarySearch(new KeyValuePair<TKey, TValue?>(key, default(TValue)),
|
new KeyValuePairComparer<TKey, TValue?>(comparer)) is int index && index >= 0)
|
||||||
new KeyValuePairComparer<TKey, TValue?>(comparer));
|
? (value = items[index].Value, true).Item2
|
||||||
|
: (value = default, false).Item2;
|
||||||
if (index >= 0)
|
|
||||||
{
|
|
||||||
value = items[index].Value;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
value = default;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private class KeyValuePairComparer<TK, TV>(IComparer<TK> comparer) :
|
private class KeyValuePairComparer<TK, TV>(IComparer<TK> comparer) :
|
||||||
IComparer<KeyValuePair<TK, TV>>
|
IComparer<KeyValuePair<TK, TV>>
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using CommunityToolkit.Mvvm.Messaging;
|
using CommunityToolkit.Mvvm.Messaging;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Toolkit.Foundation;
|
namespace Toolkit.Foundation;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
namespace Toolkit.Foundation;
|
||||||
|
|
||||||
|
public enum ModifierKey : uint
|
||||||
|
{
|
||||||
|
Alt = 0x00000001,
|
||||||
|
Ctrl = 0x00000002,
|
||||||
|
Shift = 0x00000004,
|
||||||
|
Win = 0x00000008,
|
||||||
|
}
|
||||||
+177
-171
@@ -1,175 +1,181 @@
|
|||||||
namespace Toolkit.Foundation;
|
namespace Toolkit.Foundation;
|
||||||
|
|
||||||
public enum VirtualKey
|
public enum VirtualKey : uint
|
||||||
{
|
{
|
||||||
None = 0,
|
None = 0x0000,
|
||||||
LeftButton = 1,
|
|
||||||
RightButton = 2,
|
Back = 0x0008,
|
||||||
Cancel = 3,
|
Tab = 0x0009,
|
||||||
MiddleButton = 4,
|
Clear = 0x000C,
|
||||||
XButton1 = 5,
|
Enter = 0x000D,
|
||||||
XButton2 = 6,
|
Shift = 0x0010,
|
||||||
Back = 8,
|
Control = 0x0011,
|
||||||
Tab = 9,
|
Menu = 0x0012,
|
||||||
Clear = 12,
|
Pause = 0x0013,
|
||||||
Enter = 13,
|
CapitalLock = 0x0014,
|
||||||
Shift = 16,
|
Kana = 0x0015,
|
||||||
Control = 17,
|
Hangul = 0x0015,
|
||||||
Menu = 18,
|
Junja = 0x0017,
|
||||||
Pause = 19,
|
Final = 0x0018,
|
||||||
CapitalLock = 20,
|
Hanja = 0x0019,
|
||||||
Kana = 21,
|
Kanji = 0x0019,
|
||||||
Hangul = 21,
|
Escape = 0x001B,
|
||||||
Junja = 23,
|
Convert = 0x001C,
|
||||||
Final = 24,
|
NonConvert = 0x001D,
|
||||||
Hanja = 25,
|
Accept = 0x001E,
|
||||||
Kanji = 25,
|
ModeChange = 0x001F,
|
||||||
Escape = 27,
|
Space = 0x0020,
|
||||||
Convert = 28,
|
PageUp = 0x0021,
|
||||||
NonConvert = 29,
|
PageDown = 0x0022,
|
||||||
Accept = 30,
|
End = 0x0023,
|
||||||
ModeChange = 31,
|
Home = 0x0024,
|
||||||
Space = 32,
|
Left = 0x0025,
|
||||||
PageUp = 33,
|
Up = 0x0026,
|
||||||
PageDown = 34,
|
Right = 0x0027,
|
||||||
End = 35,
|
Down = 0x0028,
|
||||||
Home = 36,
|
Select = 0x0029,
|
||||||
Left = 37,
|
Print = 0x002A,
|
||||||
Up = 38,
|
Execute = 0x002B,
|
||||||
Right = 39,
|
Snapshot = 0x002C,
|
||||||
Down = 40,
|
Insert = 0x002D,
|
||||||
Select = 41,
|
Delete = 0x002E,
|
||||||
Print = 42,
|
Help = 0x002F,
|
||||||
Execute = 43,
|
|
||||||
Snapshot = 44,
|
Number0 = 0x0030,
|
||||||
Insert = 45,
|
Number1 = 0x0031,
|
||||||
Delete = 46,
|
Number2 = 0x0032,
|
||||||
Help = 47,
|
Number3 = 0x0033,
|
||||||
Number0 = 48,
|
Number4 = 0x0034,
|
||||||
Number1 = 49,
|
Number5 = 0x0035,
|
||||||
Number2 = 50,
|
Number6 = 0x0036,
|
||||||
Number3 = 51,
|
Number7 = 0x0037,
|
||||||
Number4 = 52,
|
Number8 = 0x0038,
|
||||||
Number5 = 53,
|
Number9 = 0x0039,
|
||||||
Number6 = 54,
|
|
||||||
Number7 = 55,
|
A = 0x0041,
|
||||||
Number8 = 56,
|
B = 0x0042,
|
||||||
Number9 = 57,
|
C = 0x0043,
|
||||||
A = 65,
|
D = 0x0044,
|
||||||
B = 66,
|
E = 0x0045,
|
||||||
C = 67,
|
F = 0x0046,
|
||||||
D = 68,
|
G = 0x0047,
|
||||||
E = 69,
|
H = 0x0048,
|
||||||
F = 70,
|
I = 0x0049,
|
||||||
G = 71,
|
J = 0x004A,
|
||||||
H = 72,
|
K = 0x004B,
|
||||||
I = 73,
|
L = 0x004C,
|
||||||
J = 74,
|
M = 0x004D,
|
||||||
K = 75,
|
N = 0x004E,
|
||||||
L = 76,
|
O = 0x004F,
|
||||||
M = 77,
|
P = 0x0050,
|
||||||
N = 78,
|
Q = 0x0051,
|
||||||
O = 79,
|
R = 0x0052,
|
||||||
P = 80,
|
S = 0x0053,
|
||||||
Q = 81,
|
T = 0x0054,
|
||||||
R = 82,
|
U = 0x0055,
|
||||||
S = 83,
|
V = 0x0056,
|
||||||
T = 84,
|
W = 0x0057,
|
||||||
U = 85,
|
X = 0x0058,
|
||||||
V = 86,
|
Y = 0x0059,
|
||||||
W = 87,
|
Z = 0x005A,
|
||||||
X = 88,
|
|
||||||
Y = 89,
|
LeftWindows = 0x005B,
|
||||||
Z = 90,
|
RightWindows = 0x005C,
|
||||||
LeftWindows = 91,
|
Application = 0x005D,
|
||||||
RightWindows = 92,
|
Sleep = 0x005F,
|
||||||
Application = 93,
|
|
||||||
Sleep = 95,
|
NumberPad0 = 0x0060,
|
||||||
NumberPad0 = 96,
|
NumberPad1 = 0x0061,
|
||||||
NumberPad1 = 97,
|
NumberPad2 = 0x0062,
|
||||||
NumberPad2 = 98,
|
NumberPad3 = 0x0063,
|
||||||
NumberPad3 = 99,
|
NumberPad4 = 0x0064,
|
||||||
NumberPad4 = 100,
|
NumberPad5 = 0x0065,
|
||||||
NumberPad5 = 101,
|
NumberPad6 = 0x0066,
|
||||||
NumberPad6 = 102,
|
NumberPad7 = 0x0067,
|
||||||
NumberPad7 = 103,
|
NumberPad8 = 0x0068,
|
||||||
NumberPad8 = 104,
|
NumberPad9 = 0x0069,
|
||||||
NumberPad9 = 105,
|
|
||||||
Multiply = 106,
|
Multiply = 0x006A,
|
||||||
Add = 107,
|
Add = 0x006B,
|
||||||
Separator = 108,
|
Separator = 0x006C,
|
||||||
Subtract = 109,
|
Subtract = 0x006D,
|
||||||
Decimal = 110,
|
Decimal = 0x006E,
|
||||||
Divide = 111,
|
Divide = 0x006F,
|
||||||
F1 = 112,
|
|
||||||
F2 = 113,
|
F1 = 0x0070,
|
||||||
F3 = 114,
|
F2 = 0x0071,
|
||||||
F4 = 115,
|
F3 = 0x0072,
|
||||||
F5 = 116,
|
F4 = 0x0073,
|
||||||
F6 = 117,
|
F5 = 0x0074,
|
||||||
F7 = 118,
|
F6 = 0x0075,
|
||||||
F8 = 119,
|
F7 = 0x0076,
|
||||||
F9 = 120,
|
F8 = 0x0077,
|
||||||
F10 = 121,
|
F9 = 0x0078,
|
||||||
F11 = 122,
|
F10 = 0x0079,
|
||||||
F12 = 123,
|
F11 = 0x007A,
|
||||||
F13 = 124,
|
F12 = 0x007B,
|
||||||
F14 = 125,
|
F13 = 0x007C,
|
||||||
F15 = 126,
|
F14 = 0x007D,
|
||||||
F16 = 127,
|
F15 = 0x007E,
|
||||||
F17 = 128,
|
F16 = 0x007F,
|
||||||
F18 = 129,
|
F17 = 0x0080,
|
||||||
F19 = 130,
|
F18 = 0x0081,
|
||||||
F20 = 131,
|
F19 = 0x0082,
|
||||||
F21 = 132,
|
F20 = 0x0083,
|
||||||
F22 = 133,
|
F21 = 0x0084,
|
||||||
F23 = 134,
|
F22 = 0x0085,
|
||||||
F24 = 135,
|
F23 = 0x0086,
|
||||||
NavigationView = 136,
|
F24 = 0x0087,
|
||||||
NavigationMenu = 137,
|
|
||||||
NavigationUp = 138,
|
NavigationView = 0x0088,
|
||||||
NavigationDown = 139,
|
NavigationMenu = 0x0089,
|
||||||
NavigationLeft = 140,
|
NavigationUp = 0x008A,
|
||||||
NavigationRight = 141,
|
NavigationDown = 0x008B,
|
||||||
NavigationAccept = 142,
|
NavigationLeft = 0x008C,
|
||||||
NavigationCancel = 143,
|
NavigationRight = 0x008D,
|
||||||
NumberKeyLock = 144,
|
NavigationAccept = 0x008E,
|
||||||
Scroll = 145,
|
NavigationCancel = 0x008F,
|
||||||
LeftShift = 160,
|
|
||||||
RightShift = 161,
|
NumberKeyLock = 0x0090,
|
||||||
LeftControl = 162,
|
Scroll = 0x0091,
|
||||||
RightControl = 163,
|
|
||||||
LeftMenu = 164,
|
LeftShift = 0x00A0,
|
||||||
RightMenu = 165,
|
RightShift = 0x00A1,
|
||||||
GoBack = 166,
|
LeftControl = 0x00A2,
|
||||||
GoForward = 167,
|
RightControl = 0x00A3,
|
||||||
Refresh = 168,
|
LeftMenu = 0x00A4,
|
||||||
Stop = 169,
|
RightMenu = 0x00A5,
|
||||||
Search = 170,
|
|
||||||
Favorites = 171,
|
GoBack = 0x00A6,
|
||||||
GoHome = 172,
|
GoForward = 0x00A7,
|
||||||
GamepadA = 195,
|
Refresh = 0x00A8,
|
||||||
GamepadB = 196,
|
Stop = 0x00A9,
|
||||||
GamepadX = 197,
|
Search = 0x00AA,
|
||||||
GamepadY = 198,
|
Favorites = 0x00AB,
|
||||||
GamepadRightShoulder = 199,
|
GoHome = 0x00AC,
|
||||||
GamepadLeftShoulder = 200,
|
|
||||||
GamepadLeftTrigger = 201,
|
GamepadA = 0x00C3,
|
||||||
GamepadRightTrigger = 202,
|
GamepadB = 0x00C4,
|
||||||
GamepadDPadUp = 203,
|
GamepadX = 0x00C5,
|
||||||
GamepadDPadDown = 204,
|
GamepadY = 0x00C6,
|
||||||
GamepadDPadLeft = 205,
|
GamepadRightShoulder = 0x00C7,
|
||||||
GamepadDPadRight = 206,
|
GamepadLeftShoulder = 0x00C8,
|
||||||
GamepadMenu = 207,
|
GamepadLeftTrigger = 0x00C9,
|
||||||
GamepadView = 208,
|
GamepadRightTrigger = 0x00CA,
|
||||||
GamepadLeftThumbstickButton = 209,
|
GamepadDPadUp = 0x00CB,
|
||||||
GamepadRightThumbstickButton = 210,
|
GamepadDPadDown = 0x00CC,
|
||||||
GamepadLeftThumbstickUp = 211,
|
GamepadDPadLeft = 0x00CD,
|
||||||
GamepadLeftThumbstickDown = 212,
|
GamepadDPadRight = 0x00CE,
|
||||||
GamepadLeftThumbstickRight = 213,
|
GamepadMenu = 0x00CF,
|
||||||
GamepadLeftThumbstickLeft = 214,
|
GamepadView = 0x00D0,
|
||||||
GamepadRightThumbstickUp = 215,
|
GamepadLeftThumbstickButton = 0x00D1,
|
||||||
GamepadRightThumbstickDown = 216,
|
GamepadRightThumbstickButton = 0x00D2,
|
||||||
GamepadRightThumbstickRight = 217,
|
GamepadLeftThumbstickUp = 0x00D3,
|
||||||
GamepadRightThumbstickLeft = 218
|
GamepadLeftThumbstickDown = 0x00D4,
|
||||||
|
GamepadLeftThumbstickRight = 0x00D5,
|
||||||
|
GamepadLeftThumbstickLeft = 0x00D6,
|
||||||
|
GamepadRightThumbstickUp = 0x00D7,
|
||||||
|
GamepadRightThumbstickDown = 0x00D8,
|
||||||
|
GamepadRightThumbstickRight = 0x00D9,
|
||||||
|
GamepadRightThumbstickLeft = 0x00DA,
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
using Rect = Windows.Foundation.Rect;
|
||||||
|
|
||||||
|
namespace Toolkit.UI.WinUI;
|
||||||
|
|
||||||
|
public static class RectExtensions
|
||||||
|
{
|
||||||
|
public static Rect ToWindowsRect(this Windows.Rect rect) => new(rect.X, rect.Y, rect.Width, rect.Height);
|
||||||
|
}
|
||||||
@@ -8,9 +8,10 @@ using System.Drawing;
|
|||||||
using Windows.Win32.UI.Shell;
|
using Windows.Win32.UI.Shell;
|
||||||
using Windows.Win32.UI.WindowsAndMessaging;
|
using Windows.Win32.UI.WindowsAndMessaging;
|
||||||
using Toolkit.Windows;
|
using Toolkit.Windows;
|
||||||
using Rect = Windows.Foundation.Rect;
|
|
||||||
using WinUIEx;
|
using WinUIEx;
|
||||||
using Windows.Graphics;
|
using Windows.Graphics;
|
||||||
|
using Rect = Windows.Foundation.Rect;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Toolkit.UI.WinUI;
|
namespace Toolkit.UI.WinUI;
|
||||||
|
|
||||||
@@ -18,6 +19,14 @@ public static partial class WindowExtensions
|
|||||||
{
|
{
|
||||||
private static SUBCLASSPROC? SubClassDelegate;
|
private static SUBCLASSPROC? SubClassDelegate;
|
||||||
|
|
||||||
|
public static uint GetDpi(this Window window)
|
||||||
|
{
|
||||||
|
nint handle = WindowNative.GetWindowHandle(window);
|
||||||
|
if (handle == 0) return 0;
|
||||||
|
|
||||||
|
return PInvoke.GetDpiForWindow(new HWND(handle));
|
||||||
|
}
|
||||||
|
|
||||||
public static void Hide(this Window window)
|
public static void Hide(this Window window)
|
||||||
{
|
{
|
||||||
nint handle = WindowNative.GetWindowHandle(window);
|
nint handle = WindowNative.GetWindowHandle(window);
|
||||||
@@ -26,7 +35,7 @@ public static partial class WindowExtensions
|
|||||||
WindowHelper.HideWindow(new HWND(handle));
|
WindowHelper.HideWindow(new HWND(handle));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void IsShownInSwitchers(this Window window,
|
public static void SetIsShownInSwitchers(this Window window,
|
||||||
bool value)
|
bool value)
|
||||||
{
|
{
|
||||||
if (window.AppWindow is AppWindow appWindow)
|
if (window.AppWindow is AppWindow appWindow)
|
||||||
@@ -35,17 +44,6 @@ public static partial class WindowExtensions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SetSize(this Window window,
|
|
||||||
int width,
|
|
||||||
int height)
|
|
||||||
{
|
|
||||||
nint handle = WindowNative.GetWindowHandle(window);
|
|
||||||
if (handle == 0) return;
|
|
||||||
|
|
||||||
float value = PInvoke.GetDpiForWindow(new HWND(handle)) / 96f;
|
|
||||||
window.AppWindow.Resize(new SizeInt32((int)(width * (double)value), (int)(height * (double)value)));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void MoveAndResize(this Window window,
|
public static void MoveAndResize(this Window window,
|
||||||
Rect rect)
|
Rect rect)
|
||||||
{
|
{
|
||||||
@@ -87,19 +85,32 @@ public static partial class WindowExtensions
|
|||||||
nint handle = WindowNative.GetWindowHandle(window);
|
nint handle = WindowNative.GetWindowHandle(window);
|
||||||
if (handle == 0) return;
|
if (handle == 0) return;
|
||||||
|
|
||||||
WindowHelper.SetForegroundWindow(new HWND(handle));
|
PInvoke.SetForegroundWindow(new HWND(handle));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SetTopMost(this Window window,
|
public static void SetIsMaximizable(this Window window, bool value) =>
|
||||||
bool value)
|
window.UpdateOverlappedPresenter(presenter => presenter.IsMaximizable = value);
|
||||||
|
|
||||||
|
public static void SetIsMinimizable(this Window window, bool value) =>
|
||||||
|
window.UpdateOverlappedPresenter(presenter => presenter.IsMinimizable = value);
|
||||||
|
|
||||||
|
public static void SetIsResizable(this Window window, bool value) =>
|
||||||
|
window.UpdateOverlappedPresenter(presenter => presenter.IsResizable = value);
|
||||||
|
|
||||||
|
public static void SetSize(this Window window,
|
||||||
|
int width,
|
||||||
|
int height)
|
||||||
{
|
{
|
||||||
if (window.AppWindow is AppWindow appWindow &&
|
nint handle = WindowNative.GetWindowHandle(window);
|
||||||
appWindow.Presenter is OverlappedPresenter presenter)
|
if (handle == 0) return;
|
||||||
{
|
|
||||||
presenter.IsAlwaysOnTop = value;
|
float value = PInvoke.GetDpiForWindow(new HWND(handle)) / 96f;
|
||||||
}
|
window.AppWindow.Resize(new SizeInt32((int)(width * (double)value), (int)(height * (double)value)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void SetIsTopMost(this Window window, bool value) =>
|
||||||
|
window.UpdateOverlappedPresenter(presenter => presenter.IsAlwaysOnTop = value);
|
||||||
|
|
||||||
public static void SetTransparency(this Window window,
|
public static void SetTransparency(this Window window,
|
||||||
bool value)
|
bool value)
|
||||||
{
|
{
|
||||||
@@ -136,7 +147,6 @@ public static partial class WindowExtensions
|
|||||||
WINDOW_EX_STYLE exStyle = (WINDOW_EX_STYLE)PInvoke.GetWindowLong(hWnd, WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE);
|
WINDOW_EX_STYLE exStyle = (WINDOW_EX_STYLE)PInvoke.GetWindowLong(hWnd, WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE);
|
||||||
_ = PInvoke.SetWindowLong(hWnd, WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE, (int)(exStyle & ~WINDOW_EX_STYLE.WS_EX_LAYERED));
|
_ = PInvoke.SetWindowLong(hWnd, WINDOW_LONG_PTR_INDEX.GWL_EXSTYLE, (int)(exStyle & ~WINDOW_EX_STYLE.WS_EX_LAYERED));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static unsafe void EnableTransparency(HWND hWnd)
|
private static unsafe void EnableTransparency(HWND hWnd)
|
||||||
{
|
{
|
||||||
SubClassDelegate = new SUBCLASSPROC(WindowSubClass);
|
SubClassDelegate = new SUBCLASSPROC(WindowSubClass);
|
||||||
@@ -153,6 +163,15 @@ public static partial class WindowExtensions
|
|||||||
|
|
||||||
private static int ToWin32(Color c) => c.B << 16 | c.G << 8 | c.R;
|
private static int ToWin32(Color c) => c.B << 16 | c.G << 8 | c.R;
|
||||||
|
|
||||||
|
private static void UpdateOverlappedPresenter(this Window window,
|
||||||
|
Action<OverlappedPresenter> action)
|
||||||
|
{
|
||||||
|
if (window.AppWindow.Presenter is OverlappedPresenter presenter)
|
||||||
|
{
|
||||||
|
action(presenter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static unsafe LRESULT WindowSubClass(HWND hWnd,
|
private static unsafe LRESULT WindowSubClass(HWND hWnd,
|
||||||
uint uMsg, WPARAM wParam, LPARAM lParam, nuint uIdSubclass, nuint dwRefData)
|
uint uMsg, WPARAM wParam, LPARAM lParam, nuint uIdSubclass, nuint dwRefData)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
using Toolkit.Foundation;
|
||||||
|
|
||||||
|
namespace Toolkit.Windows;
|
||||||
|
|
||||||
|
public record HotKeyDescriptor(ModifierKey Modifiers, VirtualKey VirtualKey);
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
using CommunityToolkit.Mvvm.Messaging;
|
||||||
|
using Toolkit.Foundation;
|
||||||
|
|
||||||
|
namespace Toolkit.Windows;
|
||||||
|
|
||||||
|
public class HotKeyListener(ICache<int, HotKeyDescriptor> cache,
|
||||||
|
IMessenger messenger) :
|
||||||
|
IHotKeyListener,
|
||||||
|
IRecipient<WndProcEventArgs>
|
||||||
|
{
|
||||||
|
private bool isDisposed;
|
||||||
|
|
||||||
|
~HotKeyListener()
|
||||||
|
{
|
||||||
|
Dispose(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
messenger.RegisterAll(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (!isDisposed)
|
||||||
|
{
|
||||||
|
isDisposed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Receive(WndProcEventArgs message)
|
||||||
|
{
|
||||||
|
const int WM_HOTKEY = 0x0312;
|
||||||
|
if (message.Message == WM_HOTKEY)
|
||||||
|
{
|
||||||
|
int key = (int)message.WParam;
|
||||||
|
if (cache.Contains(key))
|
||||||
|
{
|
||||||
|
messenger.Send(new HotKeyPressedEventArgs(key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
using Toolkit.Foundation;
|
||||||
|
using Windows.Win32;
|
||||||
|
using Windows.Win32.Foundation;
|
||||||
|
using Windows.Win32.UI.Input.KeyboardAndMouse;
|
||||||
|
|
||||||
|
namespace Toolkit.Windows;
|
||||||
|
|
||||||
|
public class HotKeyManager(IWndProc wndProc,
|
||||||
|
ICache<int, HotKeyDescriptor> cache) :
|
||||||
|
IHotKeyManager
|
||||||
|
{
|
||||||
|
public void Add(int key, HotKeyDescriptor descriptor)
|
||||||
|
{
|
||||||
|
HOT_KEY_MODIFIERS modifiers = 0;
|
||||||
|
|
||||||
|
if ((descriptor.Modifiers & ModifierKey.Alt) == ModifierKey.Alt)
|
||||||
|
modifiers |= HOT_KEY_MODIFIERS.MOD_ALT;
|
||||||
|
if ((descriptor.Modifiers & ModifierKey.Ctrl) == ModifierKey.Ctrl)
|
||||||
|
modifiers |= HOT_KEY_MODIFIERS.MOD_CONTROL;
|
||||||
|
if ((descriptor.Modifiers & ModifierKey.Shift) == ModifierKey.Shift)
|
||||||
|
modifiers |= HOT_KEY_MODIFIERS.MOD_SHIFT;
|
||||||
|
if ((descriptor.Modifiers & ModifierKey.Win) == ModifierKey.Win)
|
||||||
|
modifiers |= HOT_KEY_MODIFIERS.MOD_WIN;
|
||||||
|
|
||||||
|
uint vk = (uint)descriptor.VirtualKey;
|
||||||
|
if (PInvoke.RegisterHotKey(new HWND(wndProc.Handle), key, modifiers, vk))
|
||||||
|
{
|
||||||
|
cache.Add(key, descriptor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Contains(int key) =>
|
||||||
|
cache.Contains(key);
|
||||||
|
|
||||||
|
public void Remove(int key)
|
||||||
|
{
|
||||||
|
PInvoke.UnregisterHotKey(new HWND(wndProc.Handle), key);
|
||||||
|
cache.Remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
HWND hwnd = new(wndProc.Handle);
|
||||||
|
foreach (KeyValuePair<int, HotKeyDescriptor> item in cache)
|
||||||
|
{
|
||||||
|
PInvoke.UnregisterHotKey(hwnd, item.Key);
|
||||||
|
}
|
||||||
|
|
||||||
|
cache.Clear();
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
~HotKeyManager()
|
||||||
|
{
|
||||||
|
Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
namespace Toolkit.Windows;
|
||||||
|
|
||||||
|
public record HotKeyPressedEventArgs(int Key);
|
||||||
@@ -2,6 +2,6 @@
|
|||||||
|
|
||||||
namespace Toolkit.Windows;
|
namespace Toolkit.Windows;
|
||||||
|
|
||||||
public interface ITaskbarButtonMonitor :
|
public interface IHotKeyListener :
|
||||||
IInitialization,
|
IInitialization,
|
||||||
IDisposable;
|
IDisposable;
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
namespace Toolkit.Windows;
|
||||||
|
|
||||||
|
public interface IHotKeyManager :
|
||||||
|
IDisposable
|
||||||
|
{
|
||||||
|
void Add(int key, HotKeyDescriptor descriptor);
|
||||||
|
|
||||||
|
bool Contains(int key);
|
||||||
|
|
||||||
|
void Remove(int key);
|
||||||
|
}
|
||||||
@@ -2,6 +2,6 @@
|
|||||||
|
|
||||||
namespace Toolkit.Windows;
|
namespace Toolkit.Windows;
|
||||||
|
|
||||||
public interface IPointer :
|
public interface IPointerListener :
|
||||||
IInitialization,
|
IInitialization,
|
||||||
IDisposable;
|
IDisposable;
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
using Toolkit.Foundation;
|
||||||
|
|
||||||
|
namespace Toolkit.Windows;
|
||||||
|
|
||||||
|
public interface ITaskbarButtonListener :
|
||||||
|
IInitialization,
|
||||||
|
IDisposable;
|
||||||
@@ -49,3 +49,5 @@ DispatchMessage
|
|||||||
PostQuitMessage
|
PostQuitMessage
|
||||||
DestroyWindow
|
DestroyWindow
|
||||||
GetModuleHandle
|
GetModuleHandle
|
||||||
|
RegisterHotKey
|
||||||
|
UnregisterHotKey
|
||||||
@@ -62,7 +62,7 @@ public class NotifyIcon(IWndProc wndProc,
|
|||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsafe PointerLocation GetPointerPosition()
|
public static unsafe PointerLocation GetPointerPosition()
|
||||||
{
|
{
|
||||||
Point point = new();
|
Point point = new();
|
||||||
_ = PInvoke.GetCursorPos(&point);
|
_ = PInvoke.GetCursorPos(&point);
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
using CommunityToolkit.Mvvm.Messaging;
|
using CommunityToolkit.Mvvm.Messaging;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Drawing;
|
|
||||||
using Windows.Win32;
|
using Windows.Win32;
|
||||||
using Windows.Win32.Foundation;
|
using Windows.Win32.Foundation;
|
||||||
using Windows.Win32.UI.WindowsAndMessaging;
|
using Windows.Win32.UI.WindowsAndMessaging;
|
||||||
|
|
||||||
namespace Toolkit.Windows;
|
namespace Toolkit.Windows;
|
||||||
|
|
||||||
public class Pointer(IMessenger messenger) :
|
public class PointerListener(IMessenger messenger) :
|
||||||
IPointer
|
IPointerListener
|
||||||
{
|
{
|
||||||
private bool isDisposed;
|
private bool isDisposed;
|
||||||
private bool isPointerDrag;
|
private bool isPointerDrag;
|
||||||
@@ -16,7 +15,7 @@ public class Pointer(IMessenger messenger) :
|
|||||||
private HOOKPROC? mouseEventDelegate;
|
private HOOKPROC? mouseEventDelegate;
|
||||||
private UnhookWindowsHookExSafeHandle? mouseHandle;
|
private UnhookWindowsHookExSafeHandle? mouseHandle;
|
||||||
|
|
||||||
~Pointer()
|
~PointerListener()
|
||||||
{
|
{
|
||||||
Dispose(false);
|
Dispose(false);
|
||||||
}
|
}
|
||||||
@@ -27,25 +26,22 @@ public class Pointer(IMessenger messenger) :
|
|||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsafe void Initialize() =>
|
public unsafe void Initialize()
|
||||||
InitializeHook();
|
{
|
||||||
|
mouseEventDelegate = new HOOKPROC(MouseProc);
|
||||||
|
mouseHandle = PInvoke.SetWindowsHookEx(WINDOWS_HOOK_ID.WH_MOUSE_LL, mouseEventDelegate,
|
||||||
|
PInvoke.GetModuleHandle("user32.dll"), 0);
|
||||||
|
}
|
||||||
|
|
||||||
protected virtual void Dispose(bool disposing)
|
protected virtual void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
if (!isDisposed)
|
if (!isDisposed)
|
||||||
{
|
{
|
||||||
RemoveHook();
|
Remove();
|
||||||
isDisposed = true;
|
isDisposed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private unsafe void InitializeHook()
|
|
||||||
{
|
|
||||||
mouseEventDelegate = new HOOKPROC(MouseProc);
|
|
||||||
mouseHandle = PInvoke.SetWindowsHookEx(WINDOWS_HOOK_ID.WH_MOUSE_LL, mouseEventDelegate,
|
|
||||||
PInvoke.GetModuleHandle("user32.dll"), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
private LRESULT MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
|
private LRESULT MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
if (nCode >= 0)
|
if (nCode >= 0)
|
||||||
@@ -82,7 +78,7 @@ public class Pointer(IMessenger messenger) :
|
|||||||
return PInvoke.CallNextHookEx(mouseHandle, nCode, wParam, lParam);
|
return PInvoke.CallNextHookEx(mouseHandle, nCode, wParam, lParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
private unsafe void RemoveHook()
|
private unsafe void Remove()
|
||||||
{
|
{
|
||||||
if (mouseHandle is not null && mouseHandle.DangerousGetHandle() != nint.Zero)
|
if (mouseHandle is not null && mouseHandle.DangerousGetHandle() != nint.Zero)
|
||||||
{
|
{
|
||||||
@@ -42,7 +42,7 @@ public class TaskbarButton :
|
|||||||
|
|
||||||
public void Receive(PointerReleasedEventArgs args)
|
public void Receive(PointerReleasedEventArgs args)
|
||||||
{
|
{
|
||||||
if (!isDrag && isWithinBounds)
|
if (args.Button is PointerButton.Left && !isDrag && isWithinBounds)
|
||||||
{
|
{
|
||||||
messenger.Send(new TaskbarButtonInvokedEventArgs(this));
|
messenger.Send(new TaskbarButtonInvokedEventArgs(this));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ using UIAutomationClient;
|
|||||||
|
|
||||||
namespace Toolkit.Windows;
|
namespace Toolkit.Windows;
|
||||||
|
|
||||||
public class TaskbarButtonMonitor :
|
public class TaskbarButtonListener :
|
||||||
ITaskbarButtonMonitor
|
ITaskbarButtonListener
|
||||||
{
|
{
|
||||||
private readonly IDispatcherTimer dispatcherTimer;
|
private readonly IDispatcherTimer dispatcherTimer;
|
||||||
private readonly IDispatcherTimerFactory dispatcherTimerFactory;
|
private readonly IDispatcherTimerFactory dispatcherTimerFactory;
|
||||||
@@ -19,7 +19,7 @@ public class TaskbarButtonMonitor :
|
|||||||
private IUIAutomationElement? taskListElement;
|
private IUIAutomationElement? taskListElement;
|
||||||
private IntPtr taskListHandle;
|
private IntPtr taskListHandle;
|
||||||
|
|
||||||
public TaskbarButtonMonitor(ITaskbarList taskbarList,
|
public TaskbarButtonListener(ITaskbarList taskbarList,
|
||||||
IMessenger messenger,
|
IMessenger messenger,
|
||||||
IDispatcherTimerFactory dispatcherTimerFactory,
|
IDispatcherTimerFactory dispatcherTimerFactory,
|
||||||
IServiceFactory serviceFactory,
|
IServiceFactory serviceFactory,
|
||||||
Reference in New Issue
Block a user