mirror of
https://github.com/babalae/better-genshin-impact
synced 2025-01-07 03:17:16 +08:00
use new hotkey module
This commit is contained in:
parent
9fe2a75db2
commit
cef6f6a9e0
@ -13,6 +13,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Fischless.GameCapture", "Fi
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Vision.WindowCapture.Test", "Vision.WindowCapture.Test\Vision.WindowCapture.Test.csproj", "{D35CB953-C666-4E57-9A9A-3AAE5BF78402}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Fischless.HotkeyCapture", "Fischless.HotkeyCapture\Fischless.HotkeyCapture.csproj", "{08152E44-2564-46C5-B5B2-54DD43C01A79}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Fischless.KeyboardCapture", "Fischless.KeyboardCapture\Fischless.KeyboardCapture.csproj", "{10A48327-7E58-4B51-B1FC-55506C703C8F}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
@ -39,6 +43,14 @@ Global
|
||||
{D35CB953-C666-4E57-9A9A-3AAE5BF78402}.Debug|x64.Build.0 = Debug|x64
|
||||
{D35CB953-C666-4E57-9A9A-3AAE5BF78402}.Release|x64.ActiveCfg = Release|x64
|
||||
{D35CB953-C666-4E57-9A9A-3AAE5BF78402}.Release|x64.Build.0 = Release|x64
|
||||
{08152E44-2564-46C5-B5B2-54DD43C01A79}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{08152E44-2564-46C5-B5B2-54DD43C01A79}.Debug|x64.Build.0 = Debug|x64
|
||||
{08152E44-2564-46C5-B5B2-54DD43C01A79}.Release|x64.ActiveCfg = Release|x64
|
||||
{08152E44-2564-46C5-B5B2-54DD43C01A79}.Release|x64.Build.0 = Release|x64
|
||||
{10A48327-7E58-4B51-B1FC-55506C703C8F}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{10A48327-7E58-4B51-B1FC-55506C703C8F}.Debug|x64.Build.0 = Debug|x64
|
||||
{10A48327-7E58-4B51-B1FC-55506C703C8F}.Release|x64.ActiveCfg = Release|x64
|
||||
{10A48327-7E58-4B51-B1FC-55506C703C8F}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
@ -26,7 +26,6 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" />
|
||||
<PackageReference Include="GlobalHotkeys" Version="1.0.0.6" />
|
||||
<PackageReference Include="H.InputSimulator" Version="1.4.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="7.0.1" />
|
||||
@ -52,6 +51,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Fischless.GameCapture\Fischless.GameCapture.csproj" />
|
||||
<ProjectReference Include="..\Fischless.HotkeyCapture\Fischless.HotkeyCapture.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -15,7 +15,7 @@ public class QuickEnhanceArtifactMacro
|
||||
return;
|
||||
}
|
||||
|
||||
SystemControl.ActivateWindow(TaskContext.Instance().GameHandle);
|
||||
// SystemControl.ActivateWindow(TaskContext.Instance().GameHandle);
|
||||
|
||||
var captureArea = TaskContext.Instance().SystemInfo.CaptureAreaRect;
|
||||
var assetScale = TaskContext.Instance().SystemInfo.AssetScale;
|
||||
|
@ -4,6 +4,8 @@ using System.Text.Json.Serialization;
|
||||
using System.Windows;
|
||||
using BetterGenshinImpact.Helpers;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Fischless.HotkeyCapture;
|
||||
using Gma.System.MouseKeyHook.HotKeys;
|
||||
|
||||
namespace BetterGenshinImpact.Model;
|
||||
|
||||
@ -18,11 +20,11 @@ public partial class HotKeySettingModel : ObservableObject
|
||||
|
||||
public string ConfigPropertyName { get; set; }
|
||||
|
||||
public Action<mrousavy.HotKey> OnKeyAction { get; set; }
|
||||
public Action<object?, KeyPressedEventArgs> OnKeyAction { get; set; }
|
||||
|
||||
public mrousavy.HotKey? KeyBindInfo { get; set; }
|
||||
public HotkeyHook? KeyBindInfo { get; set; }
|
||||
|
||||
public HotKeySettingModel(string functionName, string configPropertyName, string hotkey, Action<mrousavy.HotKey> onKeyAction)
|
||||
public HotKeySettingModel(string functionName, string configPropertyName, string hotkey, Action<object?, KeyPressedEventArgs> onKeyAction)
|
||||
{
|
||||
FunctionName = functionName;
|
||||
ConfigPropertyName = configPropertyName;
|
||||
@ -39,12 +41,14 @@ public partial class HotKeySettingModel : ObservableObject
|
||||
|
||||
try
|
||||
{
|
||||
KeyBindInfo = new mrousavy.HotKey(
|
||||
HotKey.Modifiers,
|
||||
HotKey.Key,
|
||||
UIDispatcherHelper.MainWindow,
|
||||
OnKeyAction
|
||||
);
|
||||
Fischless.HotkeyCapture.Hotkey hotkey = new(HotKey.ToString());
|
||||
|
||||
KeyBindInfo?.Dispose();
|
||||
KeyBindInfo = new HotkeyHook();
|
||||
KeyBindInfo.KeyPressed -= OnKeyPressed;
|
||||
KeyBindInfo.KeyPressed += OnKeyPressed;
|
||||
KeyBindInfo.RegisterHotKey(hotkey.ModifierKey, hotkey.Key);
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@ -54,6 +58,11 @@ public partial class HotKeySettingModel : ObservableObject
|
||||
|
||||
}
|
||||
|
||||
private void OnKeyPressed(object? sender, KeyPressedEventArgs e)
|
||||
{
|
||||
OnKeyAction.Invoke(sender, e);
|
||||
}
|
||||
|
||||
public void UnRegisterHotKey()
|
||||
{
|
||||
KeyBindInfo?.Dispose();
|
||||
|
@ -64,7 +64,7 @@ public partial class HotKeyPageViewModel : ObservableObject
|
||||
"自动拾取开关",
|
||||
nameof(Config.HotKeyConfig.AutoPickEnabledHotkey),
|
||||
Config.HotKeyConfig.AutoPickEnabledHotkey,
|
||||
hotKey =>
|
||||
(_, _) =>
|
||||
{
|
||||
TaskContext.Instance().Config.AutoPickConfig.Enabled = !TaskContext.Instance().Config.AutoPickConfig.Enabled;
|
||||
_logger.LogInformation("切换{Name}状态为[{Enabled}]", "自动拾取", ToChinese(TaskContext.Instance().Config.AutoPickConfig.Enabled));
|
||||
@ -76,7 +76,7 @@ public partial class HotKeyPageViewModel : ObservableObject
|
||||
"自动剧情开关",
|
||||
nameof(Config.HotKeyConfig.AutoSkipEnabledHotkey),
|
||||
Config.HotKeyConfig.AutoSkipEnabledHotkey,
|
||||
hotKey =>
|
||||
(_, _) =>
|
||||
{
|
||||
TaskContext.Instance().Config.AutoSkipConfig.Enabled = !TaskContext.Instance().Config.AutoSkipConfig.Enabled;
|
||||
_logger.LogInformation("切换{Name}状态为[{Enabled}]", "自动剧情", ToChinese(TaskContext.Instance().Config.AutoSkipConfig.Enabled));
|
||||
@ -88,7 +88,7 @@ public partial class HotKeyPageViewModel : ObservableObject
|
||||
"自动钓鱼开关",
|
||||
nameof(Config.HotKeyConfig.AutoFishingEnabledHotkey),
|
||||
Config.HotKeyConfig.AutoFishingEnabledHotkey,
|
||||
hotKey =>
|
||||
(_, _) =>
|
||||
{
|
||||
TaskContext.Instance().Config.AutoFishingConfig.Enabled = !TaskContext.Instance().Config.AutoFishingConfig.Enabled;
|
||||
_logger.LogInformation("切换{Name}状态为[{Enabled}]", "自动钓鱼", ToChinese(TaskContext.Instance().Config.AutoFishingConfig.Enabled));
|
||||
@ -100,7 +100,7 @@ public partial class HotKeyPageViewModel : ObservableObject
|
||||
"长按旋转视角 - 那维莱特转圈",
|
||||
nameof(Config.HotKeyConfig.TurnAroundHotkey),
|
||||
Config.HotKeyConfig.TurnAroundHotkey,
|
||||
hotKey => { TurnAroundMacro.Done(); }
|
||||
(_, _) => { TurnAroundMacro.Done(); }
|
||||
);
|
||||
HotKeySettingModels.Add(turnAroundHotKeySettingModel);
|
||||
|
||||
@ -108,7 +108,7 @@ public partial class HotKeyPageViewModel : ObservableObject
|
||||
"按下快速强化圣遗物",
|
||||
nameof(Config.HotKeyConfig.EnhanceArtifactHotkey),
|
||||
Config.HotKeyConfig.EnhanceArtifactHotkey,
|
||||
hotKey => { QuickEnhanceArtifactMacro.Done(); }
|
||||
(_, _) => { QuickEnhanceArtifactMacro.Done(); }
|
||||
);
|
||||
HotKeySettingModels.Add(enhanceArtifactHotKeySettingModel);
|
||||
|
||||
@ -116,7 +116,7 @@ public partial class HotKeyPageViewModel : ObservableObject
|
||||
"启动/停止自动七圣召唤",
|
||||
nameof(Config.HotKeyConfig.AutoGeniusInvokation),
|
||||
Config.HotKeyConfig.AutoGeniusInvokation,
|
||||
hotKey => { _taskSettingsPageViewModel.OnSwitchAutoGeniusInvokation(); }
|
||||
(_, _) => { _taskSettingsPageViewModel.OnSwitchAutoGeniusInvokation(); }
|
||||
));
|
||||
}
|
||||
|
||||
|
17
Fischless.HotkeyCapture/Fischless.HotkeyCapture.csproj
Normal file
17
Fischless.HotkeyCapture/Fischless.HotkeyCapture.csproj
Normal file
@ -0,0 +1,17 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0-windows10.0.22621.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Platforms>x64</Platforms>
|
||||
<LangVersion>12.0</LangVersion>
|
||||
<UseWindowsForms>True</UseWindowsForms>
|
||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Vanara.PInvoke.User32" Version="3.4.17" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
100
Fischless.HotkeyCapture/Hotkey.cs
Normal file
100
Fischless.HotkeyCapture/Hotkey.cs
Normal file
@ -0,0 +1,100 @@
|
||||
using Vanara.PInvoke;
|
||||
|
||||
namespace Fischless.HotkeyCapture;
|
||||
|
||||
public sealed class Hotkey
|
||||
{
|
||||
public bool Alt { get; set; }
|
||||
public bool Control { get; set; }
|
||||
public bool Shift { get; set; }
|
||||
public bool Windows { get; set; }
|
||||
|
||||
private Keys key;
|
||||
|
||||
public Keys Key
|
||||
{
|
||||
get => key;
|
||||
set
|
||||
{
|
||||
if (value != Keys.ControlKey && value != Keys.Alt && value != Keys.Menu && value != Keys.ShiftKey)
|
||||
{
|
||||
key = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
key = Keys.None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public User32.HotKeyModifiers ModifierKey =>
|
||||
(Windows ? User32.HotKeyModifiers.MOD_WIN : User32.HotKeyModifiers.MOD_NONE) |
|
||||
(Control ? User32.HotKeyModifiers.MOD_CONTROL : User32.HotKeyModifiers.MOD_NONE) |
|
||||
(Shift ? User32.HotKeyModifiers.MOD_SHIFT : User32.HotKeyModifiers.MOD_NONE) |
|
||||
(Alt ? User32.HotKeyModifiers.MOD_ALT : User32.HotKeyModifiers.MOD_NONE);
|
||||
|
||||
public Hotkey()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
public Hotkey(string hotkeyStr)
|
||||
{
|
||||
try
|
||||
{
|
||||
string[] keyStrs = hotkeyStr.Replace(" ", string.Empty).Split('+');
|
||||
|
||||
foreach (string keyStr in keyStrs)
|
||||
{
|
||||
if (keyStr.Equals("Win", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
Windows = true;
|
||||
}
|
||||
else if (keyStr.Equals("Ctrl", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
Control = true;
|
||||
}
|
||||
else if (keyStr.Equals("Shift", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
Shift = true;
|
||||
}
|
||||
else if (keyStr.Equals("Alt", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
Alt = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Key = (Keys)Enum.Parse(typeof(Keys), keyStr);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw new ArgumentException("Invalid Hotkey");
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
string str = string.Empty;
|
||||
if (Key != Keys.None)
|
||||
{
|
||||
str = string.Format("{0}{1}{2}{3}{4}",
|
||||
Windows ? "Win + " : string.Empty,
|
||||
Control ? "Ctrl + " : string.Empty,
|
||||
Shift ? "Shift + " : string.Empty,
|
||||
Alt ? "Alt + " : string.Empty,
|
||||
Key);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
Alt = false;
|
||||
Control = false;
|
||||
Shift = false;
|
||||
Windows = false;
|
||||
Key = Keys.None;
|
||||
}
|
||||
}
|
41
Fischless.HotkeyCapture/HotkeyHolder.cs
Normal file
41
Fischless.HotkeyCapture/HotkeyHolder.cs
Normal file
@ -0,0 +1,41 @@
|
||||
namespace Fischless.HotkeyCapture;
|
||||
|
||||
public sealed class HotkeyHolder
|
||||
{
|
||||
private static Hotkey? hotkey;
|
||||
private static HotkeyHook? hotkeyHook;
|
||||
private static Action<object?, KeyPressedEventArgs>? keyPressed;
|
||||
|
||||
public static void RegisterHotKey(string hotkeyStr, Action<object?, KeyPressedEventArgs> keyPressed = null!)
|
||||
{
|
||||
if (string.IsNullOrEmpty(hotkeyStr))
|
||||
{
|
||||
UnregisterHotKey();
|
||||
return;
|
||||
}
|
||||
|
||||
hotkey = new Hotkey(hotkeyStr);
|
||||
|
||||
hotkeyHook?.Dispose();
|
||||
hotkeyHook = new HotkeyHook();
|
||||
hotkeyHook.KeyPressed -= OnKeyPressed;
|
||||
hotkeyHook.KeyPressed += OnKeyPressed;
|
||||
HotkeyHolder.keyPressed = keyPressed;
|
||||
hotkeyHook.RegisterHotKey(hotkey.ModifierKey, hotkey.Key);
|
||||
}
|
||||
|
||||
public static void UnregisterHotKey()
|
||||
{
|
||||
if (hotkeyHook != null)
|
||||
{
|
||||
hotkeyHook.KeyPressed -= OnKeyPressed;
|
||||
hotkeyHook.UnregisterHotKey();
|
||||
hotkeyHook.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnKeyPressed(object? sender, KeyPressedEventArgs e)
|
||||
{
|
||||
keyPressed?.Invoke(sender, e);
|
||||
}
|
||||
}
|
78
Fischless.HotkeyCapture/HotkeyHook.cs
Normal file
78
Fischless.HotkeyCapture/HotkeyHook.cs
Normal file
@ -0,0 +1,78 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using Vanara.PInvoke;
|
||||
|
||||
namespace Fischless.HotkeyCapture;
|
||||
|
||||
public sealed class HotkeyHook : IDisposable
|
||||
{
|
||||
public event EventHandler<KeyPressedEventArgs>? KeyPressed = null;
|
||||
|
||||
private readonly Window window = new();
|
||||
private int currentId;
|
||||
|
||||
private class Window : NativeWindow, IDisposable
|
||||
{
|
||||
public event EventHandler<KeyPressedEventArgs>? KeyPressed = null;
|
||||
|
||||
public Window()
|
||||
{
|
||||
CreateHandle(new CreateParams());
|
||||
}
|
||||
|
||||
protected override void WndProc(ref Message m)
|
||||
{
|
||||
base.WndProc(ref m);
|
||||
|
||||
if (m.Msg == (int)User32.WindowMessage.WM_HOTKEY)
|
||||
{
|
||||
Keys key = (Keys)(((int)m.LParam >> 16) & 0xFFFF);
|
||||
User32.HotKeyModifiers modifier = (User32.HotKeyModifiers)((int)m.LParam & 0xFFFF);
|
||||
|
||||
KeyPressed?.Invoke(this, new KeyPressedEventArgs(modifier, key));
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
DestroyHandle();
|
||||
}
|
||||
}
|
||||
|
||||
public HotkeyHook()
|
||||
{
|
||||
window.KeyPressed += (sender, args) =>
|
||||
{
|
||||
KeyPressed?.Invoke(this, args);
|
||||
};
|
||||
}
|
||||
|
||||
public void RegisterHotKey(User32.HotKeyModifiers modifier, Keys key)
|
||||
{
|
||||
currentId += 1;
|
||||
if (!User32.RegisterHotKey(window!.Handle, currentId, modifier, (uint)key))
|
||||
{
|
||||
if (Marshal.GetLastWin32Error() == SystemErrorCodes.ERROR_HOTKEY_ALREADY_REGISTERED)
|
||||
{
|
||||
throw new InvalidOperationException("Hotkey already registered");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException("Hotkey registration failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void UnregisterHotKey()
|
||||
{
|
||||
for (int i = currentId; i > 0; i--)
|
||||
{
|
||||
User32.UnregisterHotKey(window!.Handle, i);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
UnregisterHotKey();
|
||||
window?.Dispose();
|
||||
}
|
||||
}
|
15
Fischless.HotkeyCapture/KeyPressedEventArgs.cs
Normal file
15
Fischless.HotkeyCapture/KeyPressedEventArgs.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using Vanara.PInvoke;
|
||||
|
||||
namespace Fischless.HotkeyCapture;
|
||||
|
||||
public class KeyPressedEventArgs : EventArgs
|
||||
{
|
||||
public User32.HotKeyModifiers Modifier { get; }
|
||||
public Keys Key { get; }
|
||||
|
||||
internal KeyPressedEventArgs(User32.HotKeyModifiers modifier, Keys key)
|
||||
{
|
||||
Modifier = modifier;
|
||||
Key = key;
|
||||
}
|
||||
}
|
7
Fischless.HotkeyCapture/SystemErrorCodes.cs
Normal file
7
Fischless.HotkeyCapture/SystemErrorCodes.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace Fischless.HotkeyCapture;
|
||||
|
||||
internal sealed class SystemErrorCodes
|
||||
{
|
||||
public const int ERROR_HOTKEY_ALREADY_REGISTERED = 0x581;
|
||||
public const int ERROR_HOTKEY_NOT_REGISTERED = 0x58B;
|
||||
}
|
18
Fischless.KeyboardCapture/Fischless.KeyboardCapture.csproj
Normal file
18
Fischless.KeyboardCapture/Fischless.KeyboardCapture.csproj
Normal file
@ -0,0 +1,18 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0-windows10.0.22621.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Platforms>x64</Platforms>
|
||||
<LangVersion>12.0</LangVersion>
|
||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Vanara.PInvoke.Kernel32" Version="3.4.17" />
|
||||
<PackageReference Include="Vanara.PInvoke.User32" Version="3.4.17" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
98
Fischless.KeyboardCapture/KeyboardHook.cs
Normal file
98
Fischless.KeyboardCapture/KeyboardHook.cs
Normal file
@ -0,0 +1,98 @@
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using Vanara.PInvoke;
|
||||
|
||||
namespace Fischless.KeyboardCapture;
|
||||
|
||||
public sealed class KeyboardHook : IDisposable
|
||||
{
|
||||
public event KeyEventHandler KeyDown = null!;
|
||||
|
||||
public event KeyPressEventHandler KeyPress = null!;
|
||||
|
||||
public event KeyEventHandler KeyUp = null!;
|
||||
|
||||
private User32.SafeHHOOK hook = new(IntPtr.Zero);
|
||||
private User32.HookProc? hookProc;
|
||||
|
||||
~KeyboardHook()
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
if (hook.IsNull)
|
||||
{
|
||||
hookProc = KeyboardHookProc;
|
||||
hook = User32.SetWindowsHookEx(User32.HookType.WH_KEYBOARD_LL, hookProc, Kernel32.GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName), 0);
|
||||
|
||||
User32.SetWindowsHookEx(User32.HookType.WH_KEYBOARD_LL, hookProc, IntPtr.Zero, (int)Kernel32.GetCurrentThreadId());
|
||||
|
||||
if (hook.IsNull)
|
||||
{
|
||||
Stop();
|
||||
throw new SystemException("Failed to install keyboard hook");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
bool retKeyboard = true;
|
||||
|
||||
if (!hook.IsNull)
|
||||
{
|
||||
retKeyboard = User32.UnhookWindowsHookEx(hook);
|
||||
hook = new(IntPtr.Zero);
|
||||
}
|
||||
|
||||
if (!retKeyboard)
|
||||
{
|
||||
throw new SystemException("Failed to uninstall hook");
|
||||
}
|
||||
}
|
||||
|
||||
private nint KeyboardHookProc(int nCode, nint wParam, nint lParam)
|
||||
{
|
||||
if (nCode >= 0)
|
||||
{
|
||||
if (KeyDown != null || KeyUp != null || KeyPress != null)
|
||||
{
|
||||
User32.KBDLLHOOKSTRUCT hookStruct = (User32.KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(User32.KBDLLHOOKSTRUCT))!;
|
||||
|
||||
if (KeyDown != null && (wParam == (nint)User32.WindowMessage.WM_KEYDOWN || wParam == (nint)User32.WindowMessage.WM_SYSKEYDOWN))
|
||||
{
|
||||
Keys keyData = (Keys)hookStruct.vkCode;
|
||||
KeyEventArgs e = new(keyData);
|
||||
KeyDown(this, e);
|
||||
}
|
||||
|
||||
if (KeyPress != null && wParam == (nint)User32.WindowMessage.WM_KEYDOWN)
|
||||
{
|
||||
byte[] keyState = new byte[256];
|
||||
_ = User32.GetKeyboardState(keyState);
|
||||
|
||||
if (User32.ToAscii(hookStruct.vkCode, hookStruct.scanCode, keyState, out ushort lpChar, hookStruct.flags) == 1)
|
||||
{
|
||||
KeyPressEventArgs e = new((char)lpChar);
|
||||
KeyPress(this, e);
|
||||
}
|
||||
}
|
||||
|
||||
if (KeyUp != null && (wParam == (nint)User32.WindowMessage.WM_KEYUP || wParam == (nint)User32.WindowMessage.WM_SYSKEYUP))
|
||||
{
|
||||
Keys keyData = (Keys)hookStruct.vkCode;
|
||||
KeyEventArgs e = new(keyData);
|
||||
KeyUp(this, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return User32.CallNextHookEx(hook, nCode, wParam, lParam);
|
||||
}
|
||||
}
|
15
Fischless.KeyboardCapture/KeyboardItem.cs
Normal file
15
Fischless.KeyboardCapture/KeyboardItem.cs
Normal file
@ -0,0 +1,15 @@
|
||||
namespace Fischless.KeyboardCapture;
|
||||
|
||||
public record struct KeyboardItem
|
||||
{
|
||||
public DateTime DateTime;
|
||||
public Keys KeyCode;
|
||||
public string Key;
|
||||
|
||||
public KeyboardItem(DateTime dateTime, Keys keyCode, string? key = null)
|
||||
{
|
||||
DateTime = dateTime;
|
||||
KeyCode = keyCode;
|
||||
Key = key;
|
||||
}
|
||||
}
|
167
Fischless.KeyboardCapture/KeyboardReader.cs
Normal file
167
Fischless.KeyboardCapture/KeyboardReader.cs
Normal file
@ -0,0 +1,167 @@
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Fischless.KeyboardCapture;
|
||||
|
||||
[DebuggerDisplay("{result.ToString()}")]
|
||||
public class KeyboardReader : IDisposable
|
||||
{
|
||||
public static KeyboardReader Default { get; } = new();
|
||||
|
||||
public event EventHandler<KeyboardResult> Received = null!;
|
||||
|
||||
public bool IsCombinationOnly = false;
|
||||
public bool IsCaseSensitived = false;
|
||||
protected KeyboardHook KeyboardHook = new();
|
||||
protected bool IsShift = false;
|
||||
protected bool IsCtrl = false;
|
||||
protected bool IsAlt = false;
|
||||
protected bool IsWin = false;
|
||||
|
||||
public KeyboardReader()
|
||||
{
|
||||
Start();
|
||||
}
|
||||
|
||||
~KeyboardReader()
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
KeyboardHook.KeyDown -= OnKeyDown;
|
||||
KeyboardHook.KeyDown += OnKeyDown;
|
||||
KeyboardHook.KeyUp -= OnKeyUp;
|
||||
KeyboardHook.KeyUp += OnKeyUp;
|
||||
KeyboardHook.Start();
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
KeyboardHook.Stop();
|
||||
KeyboardHook.KeyDown -= OnKeyDown;
|
||||
KeyboardHook.KeyUp -= OnKeyUp;
|
||||
}
|
||||
|
||||
private void OnKeyDown(object? sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.KeyCode == Keys.Shift
|
||||
|| e.KeyCode == Keys.ShiftKey
|
||||
|| e.KeyCode == Keys.LShiftKey
|
||||
|| e.KeyCode == Keys.RShiftKey)
|
||||
{
|
||||
IsShift = true;
|
||||
if (IsCombinationOnly)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (e.KeyCode == Keys.Control
|
||||
|| e.KeyCode == Keys.ControlKey
|
||||
|| e.KeyCode == Keys.LControlKey
|
||||
|| e.KeyCode == Keys.RControlKey)
|
||||
{
|
||||
IsCtrl = true;
|
||||
if (IsCombinationOnly)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (e.KeyCode == Keys.LWin
|
||||
|| e.KeyCode == Keys.RWin)
|
||||
{
|
||||
IsWin = true;
|
||||
if (IsCombinationOnly)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (e.KeyCode == Keys.Alt
|
||||
|| e.KeyCode == Keys.LMenu
|
||||
|| e.KeyCode == Keys.RMenu)
|
||||
{
|
||||
IsAlt = true;
|
||||
if (IsCombinationOnly)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var now = DateTime.Now;
|
||||
|
||||
#if FALSE
|
||||
Debug.WriteLine(e.KeyCode);
|
||||
#endif
|
||||
|
||||
KeyboardItem item;
|
||||
|
||||
if (IsCaseSensitived)
|
||||
{
|
||||
bool isUpper = Control.IsKeyLocked(Keys.CapsLock) ? !IsShift : IsShift;
|
||||
|
||||
if (isUpper)
|
||||
{
|
||||
item = new(now, e.KeyCode, char.ToUpper((char)e.KeyCode).ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
item = new(now, e.KeyCode, char.ToLower((char)e.KeyCode).ToString());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
item = new(now, e.KeyCode);
|
||||
}
|
||||
|
||||
KeyboardResult result = new(item)
|
||||
{
|
||||
IsShift = IsShift,
|
||||
IsCtrl = IsCtrl,
|
||||
IsAlt = IsAlt,
|
||||
IsWin = IsWin,
|
||||
};
|
||||
|
||||
Received?.Invoke(this, result);
|
||||
#if FALSE
|
||||
Debug.WriteLine(result.ToString());
|
||||
#endif
|
||||
}
|
||||
|
||||
private void OnKeyUp(object? sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.KeyCode == Keys.Shift
|
||||
|| e.KeyCode == Keys.ShiftKey
|
||||
|| e.KeyCode == Keys.LShiftKey
|
||||
|| e.KeyCode == Keys.RShiftKey)
|
||||
{
|
||||
IsShift = false;
|
||||
return;
|
||||
}
|
||||
else if (e.KeyCode == Keys.Control
|
||||
|| e.KeyCode == Keys.ControlKey
|
||||
|| e.KeyCode == Keys.LControlKey
|
||||
|| e.KeyCode == Keys.RControlKey)
|
||||
{
|
||||
IsCtrl = false;
|
||||
return;
|
||||
}
|
||||
else if (e.KeyCode == Keys.LWin
|
||||
|| e.KeyCode == Keys.RWin)
|
||||
{
|
||||
IsWin = false;
|
||||
return;
|
||||
}
|
||||
else if (e.KeyCode == Keys.Alt
|
||||
|| e.KeyCode == Keys.LMenu
|
||||
|| e.KeyCode == Keys.RMenu)
|
||||
{
|
||||
IsAlt = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
49
Fischless.KeyboardCapture/KeyboardResult.cs
Normal file
49
Fischless.KeyboardCapture/KeyboardResult.cs
Normal file
@ -0,0 +1,49 @@
|
||||
namespace Fischless.KeyboardCapture;
|
||||
|
||||
public sealed class KeyboardResult
|
||||
{
|
||||
public KeyboardItem KeyboardItem { get; init; } = default;
|
||||
public string Key => KeyboardItem.Key ?? KeyboardItem.KeyCode.ToString();
|
||||
public bool IsShift { get; set; } = false;
|
||||
public bool IsCtrl { get; set; } = false;
|
||||
public bool IsAlt { get; set; } = false;
|
||||
public bool IsWin { get; set; } = false;
|
||||
|
||||
public KeyboardResult(KeyboardItem keyboardItem)
|
||||
{
|
||||
KeyboardItem = keyboardItem;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
List<string> keyModifiers = new();
|
||||
|
||||
if (IsCtrl)
|
||||
{
|
||||
keyModifiers.Add("Ctrl");
|
||||
}
|
||||
|
||||
if (IsShift)
|
||||
{
|
||||
keyModifiers.Add("Shift");
|
||||
}
|
||||
|
||||
if (IsAlt)
|
||||
{
|
||||
keyModifiers.Add("Alt");
|
||||
}
|
||||
|
||||
string keyModifiersStr = string.Join("+", keyModifiers);
|
||||
|
||||
if (!string.IsNullOrEmpty(keyModifiersStr) && !string.IsNullOrEmpty(Key))
|
||||
{
|
||||
return $"{keyModifiersStr}+{Key}";
|
||||
}
|
||||
else
|
||||
{
|
||||
return Key;
|
||||
}
|
||||
}
|
||||
|
||||
public static implicit operator string(KeyboardResult result) => result?.ToString();
|
||||
}
|
Loading…
Reference in New Issue
Block a user