remove library

This commit is contained in:
辉鸭蛋 2024-12-14 01:23:26 +08:00
parent 0c435a9393
commit e00b38eb66
34 changed files with 0 additions and 2627 deletions

View File

@ -1,21 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-windows10.0.22621.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Platforms>x64</Platforms>
</PropertyGroup>
<ItemGroup>
<None Remove="NativeMethods.json" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.3.46-beta">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>

View File

@ -1,10 +0,0 @@
{
"$schema": "https://raw.githubusercontent.com/microsoft/CsWin32/main/src/Microsoft.Windows.CsWin32/settings.schema.json",
"allowMarshaling": true,
"useSafeHandles": false,
"emitSingleFile": true,
"public": true,
"comInterop": {
"useIntPtrForComOutPointers": true
}
}

View File

@ -1,38 +0,0 @@
// D3D11
CreateDirect3D11DeviceFromDXGIDevice
CreateDirect3D11SurfaceFromDXGISurface
// GDI32
BitBlt
CreateCompatibleBitmap
CreateCompatibleDC
DeleteDC
GetDeviceCaps
SelectObject
// User32
GetClientRect
GetDC
GetForegroundWindow
GetSystemMetrics
GetWindowDC
GetWindowRect
GetWindowThreadProcessId
mouse_event
PostMessage
ReleaseDC
EnumWindows
GetWindowText
IsWindowVisible
GetWindowTextLength
// COM & WinRT
D3D11CreateDevice
ID3D11Device3
IDirect3DDxgiInterfaceAccess
// Constants
D3D11_SDK_VERSION
DXGI_ERROR_UNSUPPORTED
WM_LBUTTONDOWN
WM_LBUTTONUP

View File

@ -5,18 +5,10 @@ VisualStudioVersion = 17.6.33815.320
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BetterGenshinImpact", "BetterGenshinImpact\BetterGenshinImpact.csproj", "{75EC89E2-413D-4725-BCEA-AFAC57708F07}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Vision.WindowCapture", "Vision.WindowCapture\Vision.WindowCapture.csproj", "{C9080C1D-1B26-46CB-A494-A5E7FE3FCEBA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BetterGenshinImpact.Win32", "BetterGenshinImpact.Win32\BetterGenshinImpact.Win32.csproj", "{75F4541B-9624-4AFB-BAEA-3EAFD3300EE1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Fischless.GameCapture", "Fischless.GameCapture\Fischless.GameCapture.csproj", "{6B0A3D96-D88D-48DD-8112-4CD5BA5D27CE}"
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
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Deploy", "Deploy", "{458E1106-43A4-47E6-B11B-D243035D4C76}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MicaSetup", "Build\MicaSetup\MicaSetup.csproj", "{AB85DA23-EB8F-4FBF-A7FA-35CE05B23C15}"
@ -43,22 +35,6 @@ Global
{75EC89E2-413D-4725-BCEA-AFAC57708F07}.Release|Any CPU.Build.0 = Release|x64
{75EC89E2-413D-4725-BCEA-AFAC57708F07}.Release|x64.ActiveCfg = Release|x64
{75EC89E2-413D-4725-BCEA-AFAC57708F07}.Release|x64.Build.0 = Release|x64
{C9080C1D-1B26-46CB-A494-A5E7FE3FCEBA}.Debug|Any CPU.ActiveCfg = Debug|x64
{C9080C1D-1B26-46CB-A494-A5E7FE3FCEBA}.Debug|Any CPU.Build.0 = Debug|x64
{C9080C1D-1B26-46CB-A494-A5E7FE3FCEBA}.Debug|x64.ActiveCfg = Debug|x64
{C9080C1D-1B26-46CB-A494-A5E7FE3FCEBA}.Debug|x64.Build.0 = Debug|x64
{C9080C1D-1B26-46CB-A494-A5E7FE3FCEBA}.Release|Any CPU.ActiveCfg = Release|x64
{C9080C1D-1B26-46CB-A494-A5E7FE3FCEBA}.Release|Any CPU.Build.0 = Release|x64
{C9080C1D-1B26-46CB-A494-A5E7FE3FCEBA}.Release|x64.ActiveCfg = Release|x64
{C9080C1D-1B26-46CB-A494-A5E7FE3FCEBA}.Release|x64.Build.0 = Release|x64
{75F4541B-9624-4AFB-BAEA-3EAFD3300EE1}.Debug|Any CPU.ActiveCfg = Debug|x64
{75F4541B-9624-4AFB-BAEA-3EAFD3300EE1}.Debug|Any CPU.Build.0 = Debug|x64
{75F4541B-9624-4AFB-BAEA-3EAFD3300EE1}.Debug|x64.ActiveCfg = Debug|x64
{75F4541B-9624-4AFB-BAEA-3EAFD3300EE1}.Debug|x64.Build.0 = Debug|x64
{75F4541B-9624-4AFB-BAEA-3EAFD3300EE1}.Release|Any CPU.ActiveCfg = Release|x64
{75F4541B-9624-4AFB-BAEA-3EAFD3300EE1}.Release|Any CPU.Build.0 = Release|x64
{75F4541B-9624-4AFB-BAEA-3EAFD3300EE1}.Release|x64.ActiveCfg = Release|x64
{75F4541B-9624-4AFB-BAEA-3EAFD3300EE1}.Release|x64.Build.0 = Release|x64
{6B0A3D96-D88D-48DD-8112-4CD5BA5D27CE}.Debug|Any CPU.ActiveCfg = Debug|x64
{6B0A3D96-D88D-48DD-8112-4CD5BA5D27CE}.Debug|Any CPU.Build.0 = Debug|x64
{6B0A3D96-D88D-48DD-8112-4CD5BA5D27CE}.Debug|x64.ActiveCfg = Debug|x64
@ -67,14 +43,6 @@ Global
{6B0A3D96-D88D-48DD-8112-4CD5BA5D27CE}.Release|Any CPU.Build.0 = Release|x64
{6B0A3D96-D88D-48DD-8112-4CD5BA5D27CE}.Release|x64.ActiveCfg = Release|x64
{6B0A3D96-D88D-48DD-8112-4CD5BA5D27CE}.Release|x64.Build.0 = Release|x64
{D35CB953-C666-4E57-9A9A-3AAE5BF78402}.Debug|Any CPU.ActiveCfg = Debug|x64
{D35CB953-C666-4E57-9A9A-3AAE5BF78402}.Debug|Any CPU.Build.0 = Debug|x64
{D35CB953-C666-4E57-9A9A-3AAE5BF78402}.Debug|x64.ActiveCfg = Debug|x64
{D35CB953-C666-4E57-9A9A-3AAE5BF78402}.Debug|x64.Build.0 = Debug|x64
{D35CB953-C666-4E57-9A9A-3AAE5BF78402}.Release|Any CPU.ActiveCfg = Release|x64
{D35CB953-C666-4E57-9A9A-3AAE5BF78402}.Release|Any CPU.Build.0 = Release|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|Any CPU.ActiveCfg = Debug|x64
{08152E44-2564-46C5-B5B2-54DD43C01A79}.Debug|Any CPU.Build.0 = Debug|x64
{08152E44-2564-46C5-B5B2-54DD43C01A79}.Debug|x64.ActiveCfg = Debug|x64
@ -83,14 +51,6 @@ Global
{08152E44-2564-46C5-B5B2-54DD43C01A79}.Release|Any CPU.Build.0 = Release|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|Any CPU.ActiveCfg = Debug|x64
{10A48327-7E58-4B51-B1FC-55506C703C8F}.Debug|Any CPU.Build.0 = Debug|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|Any CPU.ActiveCfg = Release|x64
{10A48327-7E58-4B51-B1FC-55506C703C8F}.Release|Any CPU.Build.0 = Release|x64
{10A48327-7E58-4B51-B1FC-55506C703C8F}.Release|x64.ActiveCfg = Release|x64
{10A48327-7E58-4B51-B1FC-55506C703C8F}.Release|x64.Build.0 = Release|x64
{AB85DA23-EB8F-4FBF-A7FA-35CE05B23C15}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AB85DA23-EB8F-4FBF-A7FA-35CE05B23C15}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AB85DA23-EB8F-4FBF-A7FA-35CE05B23C15}.Debug|x64.ActiveCfg = Debug|x64

View File

@ -1,17 +0,0 @@
<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>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Vanara.PInvoke.Kernel32" Version="4.0.2" />
<PackageReference Include="Vanara.PInvoke.User32" Version="4.0.2" />
</ItemGroup>
</Project>

View File

@ -1,52 +0,0 @@
namespace Fischless.KeyboardCapture;
public static class KeyboardConst
{
public const string Ctrl = nameof(Ctrl);
public const string LCtrl = nameof(LCtrl);
public const string RCtrl = nameof(RCtrl);
public const string Shift = nameof(Shift);
public const string Lhift = nameof(Lhift);
public const string RShift = nameof(RShift);
public const string Alt = nameof(Alt);
public const string LAlt = nameof(LAlt);
public const string RAlt = nameof(RAlt);
public const string Win = nameof(Win);
public const string LWin = nameof(LWin);
public const string RWin = nameof(RWin);
public const string Esc = nameof(Esc);
public const string Del = nameof(Del);
public const string Enter = nameof(Enter);
public const string NumEnter = nameof(NumEnter);
public const string Num = nameof(Num);
public const string NumpadDot = nameof(Num) + ".";
public const string NumpadSlash = nameof(Num) + "/";
public const string NumpadAsterisk = nameof(Num) + "*";
public const string NumpadMinus = nameof(Num) + "-";
public const string NumpadPlus = nameof(Num) + "+";
public const string Equal = "=";
public const string Apostrophe = "'";
public const string Comma = ",";
public const string Minus = "-";
public const string Period = ".";
public const string Question = "?";
public const string Pipe = "|";
public const string Slash = "/";
public const string Semicolon = ";";
public const string LeftSquareBracket = "[";
public const string Backslash = @"\";
public const string RightSquareBracket = "]";
public const string Tilde = "`";
public const string PgUp = nameof(PgUp);
public const string PgDn = nameof(PgDn);
public const string CapsLock = nameof(CapsLock);
public const string ScrollLock = nameof(ScrollLock);
}

View File

@ -1,66 +0,0 @@
namespace Fischless.KeyboardCapture;
public delegate void KeyboardEventHandler(object? sender, KeyboardEventArgs e);
public delegate void KeyboardPressEventHandler(object? sender, KeyboardPressEventArgs e);
public class KeyboardEventArgs
{
private bool _suppressKeyPress;
public KeyboardEventArgs(KeyboardKeys keyData)
{
KeyData = keyData;
}
public virtual bool Alt => (KeyData & KeyboardKeys.Alt) == KeyboardKeys.Alt;
public bool Control => (KeyData & KeyboardKeys.Control) == KeyboardKeys.Control;
public bool Handled { get; set; }
public KeyboardKeys KeyCode
{
get
{
KeyboardKeys keyGenerated = KeyData & KeyboardKeys.KeyCode;
// since Keys can be discontiguous, keeping Enum.IsDefined.
if (!Enum.IsDefined(typeof(KeyboardKeys), (int)keyGenerated))
{
return KeyboardKeys.None;
}
return keyGenerated;
}
}
public int KeyValue => (int)(KeyData & KeyboardKeys.KeyCode);
public KeyboardKeys KeyData { get; }
public KeyboardKeys Modifiers => KeyData & KeyboardKeys.Modifiers;
public virtual bool Shift => (KeyData & KeyboardKeys.Shift) == KeyboardKeys.Shift;
public bool SuppressKeyPress
{
get => _suppressKeyPress;
set
{
_suppressKeyPress = value;
Handled = value;
}
}
}
public class KeyboardPressEventArgs : EventArgs
{
public KeyboardPressEventArgs(char keyChar)
{
KeyChar = keyChar;
}
public char KeyChar { get; set; }
public bool Handled { get; set; }
}

View File

@ -1,139 +0,0 @@
using Vanara.PInvoke;
namespace Fischless.KeyboardCapture;
public static class KeyboardExtension
{
public static bool IsKeyLocked(this KeyboardKeys keyVal)
{
if (keyVal == KeyboardKeys.Insert || keyVal == KeyboardKeys.NumLock || keyVal == KeyboardKeys.CapsLock || keyVal == KeyboardKeys.Scroll)
{
int result = User32.GetKeyState((int)keyVal);
// If the high-order bit is 1, the key is down; otherwise, it is up.
// If the low-order bit is 1, the key is toggled. A key, such as the CAPS LOCK key,
// is toggled if it is turned on. The key is off and untoggled if the low-order bit is 0.
// A toggle key's indicator light (if any) on the keyboard will be on when the key is toggled,
// and off when the key is untoggled.
// Toggle keys (only low bit is of interest).
if (keyVal == KeyboardKeys.Insert || keyVal == KeyboardKeys.CapsLock)
{
return (result & 0x1) != 0x0;
}
return (result & 0x8001) != 0x0;
}
// else - it's an un-lockable key.
// Actually get the exception string from the system resource.
throw new NotSupportedException("Specified key is not supported.");
}
public static bool IsExtendedKey(this KeyboardKeys keyVal)
{
switch (keyVal)
{
case KeyboardKeys.Return:
short state = User32.GetKeyState((int)KeyboardKeys.Return);
return state == 0x01 || state == -128;
}
return false;
}
public static bool IsCombinationKey(this KeyboardKeys keyVal)
{
return keyVal switch
{
KeyboardKeys.Shift
or KeyboardKeys.ShiftKey
or KeyboardKeys.LShiftKey
or KeyboardKeys.RShiftKey
or KeyboardKeys.Control
or KeyboardKeys.ControlKey
or KeyboardKeys.LControlKey
or KeyboardKeys.RControlKey
or KeyboardKeys.LWin
or KeyboardKeys.RWin
or KeyboardKeys.Alt
or KeyboardKeys.LMenu
or KeyboardKeys.RMenu => true,
_ => false,
};
}
public static string ToName(this KeyboardKeys keyVal, bool useStrict = false)
{
if (useStrict)
{
throw new NotImplementedException(nameof(useStrict));
}
return keyVal switch
{
KeyboardKeys.Control => KeyboardConst.Ctrl,
KeyboardKeys.Return => KeyboardConst.Enter,
KeyboardKeys.NumEnter => KeyboardConst.NumEnter,
KeyboardKeys.ShiftKey => KeyboardConst.Shift,
KeyboardKeys.ControlKey => KeyboardConst.Ctrl,
KeyboardKeys.Menu => KeyboardConst.Alt,
KeyboardKeys.Capital => KeyboardConst.CapsLock,
KeyboardKeys.Escape => KeyboardConst.Esc,
KeyboardKeys.PageUp => KeyboardConst.PgUp,
KeyboardKeys.PageDown => KeyboardConst.PgDn,
KeyboardKeys.Delete => KeyboardConst.Del,
KeyboardKeys.D0 => 0.ToString(),
KeyboardKeys.D1 => 1.ToString(),
KeyboardKeys.D2 => 2.ToString(),
KeyboardKeys.D3 => 3.ToString(),
KeyboardKeys.D4 => 4.ToString(),
KeyboardKeys.D5 => 5.ToString(),
KeyboardKeys.D6 => 6.ToString(),
KeyboardKeys.D7 => 7.ToString(),
KeyboardKeys.D8 => 8.ToString(),
KeyboardKeys.D9 => 9.ToString(),
KeyboardKeys.LWin => KeyboardConst.Win,
KeyboardKeys.RWin => KeyboardConst.Win,
KeyboardKeys.NumPad0 => KeyboardConst.Num + 0,
KeyboardKeys.NumPad1 => KeyboardConst.Num + 1,
KeyboardKeys.NumPad2 => KeyboardConst.Num + 2,
KeyboardKeys.NumPad3 => KeyboardConst.Num + 3,
KeyboardKeys.NumPad4 => KeyboardConst.Num + 4,
KeyboardKeys.NumPad5 => KeyboardConst.Num + 5,
KeyboardKeys.NumPad6 => KeyboardConst.Num + 6,
KeyboardKeys.NumPad7 => KeyboardConst.Num + 7,
KeyboardKeys.NumPad8 => KeyboardConst.Num + 8,
KeyboardKeys.NumPad9 => KeyboardConst.Num + 9,
KeyboardKeys.Multiply => KeyboardConst.NumpadAsterisk,
KeyboardKeys.Add => KeyboardConst.NumpadPlus,
KeyboardKeys.Subtract => KeyboardConst.NumpadMinus,
KeyboardKeys.Decimal => KeyboardConst.NumpadDot,
KeyboardKeys.Divide => KeyboardConst.NumpadDot,
KeyboardKeys.Scroll => KeyboardConst.ScrollLock,
KeyboardKeys.LShiftKey or KeyboardKeys.RShiftKey => KeyboardConst.Shift,
KeyboardKeys.LControlKey or KeyboardKeys.RControlKey => KeyboardConst.Ctrl,
KeyboardKeys.LMenu or KeyboardKeys.RMenu => KeyboardConst.Alt,
KeyboardKeys.OemSemicolon => KeyboardConst.Semicolon,
KeyboardKeys.Oemplus => KeyboardConst.Equal,
KeyboardKeys.Oemcomma => KeyboardConst.Comma,
KeyboardKeys.OemMinus => KeyboardConst.Minus,
KeyboardKeys.OemPeriod => KeyboardConst.Period,
KeyboardKeys.OemQuestion => KeyboardConst.Question,
KeyboardKeys.Oemtilde => KeyboardConst.Tilde,
KeyboardKeys.OemOpenBrackets => KeyboardConst.LeftSquareBracket,
KeyboardKeys.OemPipe => KeyboardConst.Pipe,
KeyboardKeys.OemCloseBrackets => KeyboardConst.RightSquareBracket,
KeyboardKeys.OemQuotes => KeyboardConst.Apostrophe,
KeyboardKeys.OemBackslash => KeyboardConst.Backslash,
KeyboardKeys.Shift => KeyboardConst.Shift,
KeyboardKeys.Alt => KeyboardConst.Alt,
_ => keyVal.ToString(),
};
}
}
public enum KeyboardNameType
{
Default,
Strict,
}

View File

@ -1,98 +0,0 @@
using System.Diagnostics;
using System.Runtime.InteropServices;
using Vanara.PInvoke;
namespace Fischless.KeyboardCapture;
public sealed class KeyboardHook : IDisposable
{
public event KeyboardEventHandler KeyDown = null!;
public event KeyboardPressEventHandler KeyPress = null!;
public event KeyboardEventHandler 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))
{
KeyboardKeys keyData = (KeyboardKeys)hookStruct.vkCode;
KeyboardEventArgs 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)
{
KeyboardPressEventArgs e = new((char)lpChar);
KeyPress(this, e);
}
}
if (KeyUp != null && (wParam == (nint)User32.WindowMessage.WM_KEYUP || wParam == (nint)User32.WindowMessage.WM_SYSKEYUP))
{
KeyboardKeys keyData = (KeyboardKeys)hookStruct.vkCode;
KeyboardEventArgs e = new(keyData);
KeyUp(this, e);
}
}
}
return User32.CallNextHookEx(hook, nCode, wParam, lParam);
}
}

View File

@ -1,15 +0,0 @@
namespace Fischless.KeyboardCapture;
public record struct KeyboardItem
{
public DateTime DateTime;
public KeyboardKeys KeyCode;
public string? Key;
public KeyboardItem(DateTime dateTime, KeyboardKeys keyCode, string? key = default)
{
DateTime = dateTime;
KeyCode = keyCode;
Key = key;
}
}

View File

@ -1,984 +0,0 @@
namespace Fischless.KeyboardCapture;
/// <summary>
/// https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
/// But cutmized 0x0E as NumEnter.
/// </summary>
[Flags]
public enum KeyboardKeys
{
/// <summary>
/// The bit mask to extract a key code from a key value.
/// </summary>
KeyCode = 0x0000FFFF,
/// <summary>
/// The bit mask to extract modifiers from a key value.
/// </summary>
Modifiers = unchecked((int)0xFFFF0000),
/// <summary>
/// No key pressed.
/// </summary>
None = 0x00,
/// <summary>
/// The left mouse button.
/// </summary>
LButton = 0x01,
/// <summary>
/// The right mouse button.
/// </summary>
RButton = 0x02,
/// <summary>
/// The CANCEL key.
/// </summary>
Cancel = 0x03,
/// <summary>
/// The middle mouse button (three-button mouse).
/// </summary>
MButton = 0x04,
/// <summary>
/// The first x mouse button (five-button mouse).
/// </summary>
XButton1 = 0x05,
/// <summary>
/// The second x mouse button (five-button mouse).
/// </summary>
XButton2 = 0x06,
/// <summary>
/// The BACKSPACE key.
/// </summary>
Back = 0x08,
/// <summary>
/// The TAB key.
/// </summary>
Tab = 0x09,
/// <summary>
/// The CLEAR key.
/// </summary>
LineFeed = 0x0A,
/// <summary>
/// The CLEAR key.
/// </summary>
Clear = 0x0C,
/// <summary>
/// The RETURN key.
/// </summary>
Return = 0x0D,
/// <summary>
/// The ENTER key.
/// </summary>
Enter = Return,
/// <summary>
/// The Unassigned code: The Num ENTER key.
/// </summary>
NumEnter = 0x0E,
/// <summary>
/// The SHIFT key.
/// </summary>
ShiftKey = 0x10,
/// <summary>
/// The CTRL key.
/// </summary>
ControlKey = 0x11,
/// <summary>
/// The ALT key.
/// </summary>
Menu = 0x12,
/// <summary>
/// The PAUSE key.
/// </summary>
Pause = 0x13,
/// <summary>
/// The CAPS LOCK key.
/// </summary>
Capital = 0x14,
/// <summary>
/// The CAPS LOCK key.
/// </summary>
CapsLock = 0x14,
/// <summary>
/// The IME Kana mode key.
/// </summary>
KanaMode = 0x15,
/// <summary>
/// The IME Hanguel mode key.
/// </summary>
HanguelMode = 0x15,
/// <summary>
/// The IME Hangul mode key.
/// </summary>
HangulMode = 0x15,
/// <summary>
/// The IME Junja mode key.
/// </summary>
JunjaMode = 0x17,
/// <summary>
/// The IME Final mode key.
/// </summary>
FinalMode = 0x18,
/// <summary>
/// The IME Hanja mode key.
/// </summary>
HanjaMode = 0x19,
/// <summary>
/// The IME Kanji mode key.
/// </summary>
KanjiMode = 0x19,
/// <summary>
/// The ESC key.
/// </summary>
Escape = 0x1B,
/// <summary>
/// The IME Convert key.
/// </summary>
IMEConvert = 0x1C,
/// <summary>
/// The IME NonConvert key.
/// </summary>
IMENonconvert = 0x1D,
/// <summary>
/// The IME Accept key.
/// </summary>
IMEAccept = 0x1E,
/// <summary>
/// The IME Accept key.
/// </summary>
IMEAceept = IMEAccept,
/// <summary>
/// The IME Mode change request.
/// </summary>
IMEModeChange = 0x1F,
/// <summary>
/// The SPACEBAR key.
/// </summary>
Space = 0x20,
/// <summary>
/// The PAGE UP key.
/// </summary>
Prior = 0x21,
/// <summary>
/// The PAGE UP key.
/// </summary>
PageUp = Prior,
/// <summary>
/// The PAGE DOWN key.
/// </summary>
Next = 0x22,
/// <summary>
/// The PAGE DOWN key.
/// </summary>
PageDown = Next,
/// <summary>
/// The END key.
/// </summary>
End = 0x23,
/// <summary>
/// The HOME key.
/// </summary>
Home = 0x24,
/// <summary>
/// The LEFT ARROW key.
/// </summary>
Left = 0x25,
/// <summary>
/// The UP ARROW key.
/// </summary>
Up = 0x26,
/// <summary>
/// The RIGHT ARROW key.
/// </summary>
Right = 0x27,
/// <summary>
/// The DOWN ARROW key.
/// </summary>
Down = 0x28,
/// <summary>
/// The SELECT key.
/// </summary>
Select = 0x29,
/// <summary>
/// The PRINT key.
/// </summary>
Print = 0x2A,
/// <summary>
/// The EXECUTE key.
/// </summary>
Execute = 0x2B,
/// <summary>
/// The PRINT SCREEN key.
/// </summary>
Snapshot = 0x2C,
/// <summary>
/// The PRINT SCREEN key.
/// </summary>
PrintScreen = Snapshot,
/// <summary>
/// The INS key.
/// </summary>
Insert = 0x2D,
/// <summary>
/// The DEL key.
/// </summary>
Delete = 0x2E,
/// <summary>
/// The HELP key.
/// </summary>
Help = 0x2F,
/// <summary>
/// The 0 key.
/// </summary>
D0 = 0x30, // 0
/// <summary>
/// The 1 key.
/// </summary>
D1 = 0x31, // 1
/// <summary>
/// The 2 key.
/// </summary>
D2 = 0x32, // 2
/// <summary>
/// The 3 key.
/// </summary>
D3 = 0x33, // 3
/// <summary>
/// The 4 key.
/// </summary>
D4 = 0x34, // 4
/// <summary>
/// The 5 key.
/// </summary>
D5 = 0x35, // 5
/// <summary>
/// The 6 key.
/// </summary>
D6 = 0x36, // 6
/// <summary>
/// The 7 key.
/// </summary>
D7 = 0x37, // 7
/// <summary>
/// The 8 key.
/// </summary>
D8 = 0x38, // 8
/// <summary>
/// The 9 key.
/// </summary>
D9 = 0x39, // 9
/// <summary>
/// The A key.
/// </summary>
A = 0x41,
/// <summary>
/// The B key.
/// </summary>
B = 0x42,
/// <summary>
/// The C key.
/// </summary>
C = 0x43,
/// <summary>
/// The D key.
/// </summary>
D = 0x44,
/// <summary>
/// The E key.
/// </summary>
E = 0x45,
/// <summary>
/// The F key.
/// </summary>
F = 0x46,
/// <summary>
/// The G key.
/// </summary>
G = 0x47,
/// <summary>
/// The H key.
/// </summary>
H = 0x48,
/// <summary>
/// The I key.
/// </summary>
I = 0x49,
/// <summary>
/// The J key.
/// </summary>
J = 0x4A,
/// <summary>
/// The K key.
/// </summary>
K = 0x4B,
/// <summary>
/// The L key.
/// </summary>
L = 0x4C,
/// <summary>
/// The M key.
/// </summary>
M = 0x4D,
/// <summary>
/// The N key.
/// </summary>
N = 0x4E,
/// <summary>
/// The O key.
/// </summary>
O = 0x4F,
/// <summary>
/// The P key.
/// </summary>
P = 0x50,
/// <summary>
/// The Q key.
/// </summary>
Q = 0x51,
/// <summary>
/// The R key.
/// </summary>
R = 0x52,
/// <summary>
/// The S key.
/// </summary>
S = 0x53,
/// <summary>
/// The T key.
/// </summary>
T = 0x54,
/// <summary>
/// The U key.
/// </summary>
U = 0x55,
/// <summary>
/// The V key.
/// </summary>
V = 0x56,
/// <summary>
/// The W key.
/// </summary>
W = 0x57,
/// <summary>
/// The X key.
/// </summary>
X = 0x58,
/// <summary>
/// The Y key.
/// </summary>
Y = 0x59,
/// <summary>
/// The Z key.
/// </summary>
Z = 0x5A,
/// <summary>
/// The left Windows logo key (Microsoft Natural Keyboard).
/// </summary>
LWin = 0x5B,
/// <summary>
/// The right Windows logo key (Microsoft Natural Keyboard).
/// </summary>
RWin = 0x5C,
/// <summary>
/// The Application key (Microsoft Natural Keyboard).
/// </summary>
Apps = 0x5D,
/// <summary>
/// The Computer Sleep key.
/// </summary>
Sleep = 0x5F,
/// <summary>
/// The 0 key on the numeric keypad.
/// </summary>
NumPad0 = 0x60,
/// <summary>
/// The 1 key on the numeric keypad.
/// </summary>
NumPad1 = 0x61,
/// <summary>
/// The 2 key on the numeric keypad.
/// </summary>
NumPad2 = 0x62,
/// <summary>
/// The 3 key on the numeric keypad.
/// </summary>
NumPad3 = 0x63,
/// <summary>
/// The 4 key on the numeric keypad.
/// </summary>
NumPad4 = 0x64,
/// <summary>
/// The 5 key on the numeric keypad.
/// </summary>
NumPad5 = 0x65,
/// <summary>
/// The 6 key on the numeric keypad.
/// </summary>
NumPad6 = 0x66,
/// <summary>
/// The 7 key on the numeric keypad.
/// </summary>
NumPad7 = 0x67,
/// <summary>
/// The 8 key on the numeric keypad.
/// </summary>
NumPad8 = 0x68,
/// <summary>
/// The 9 key on the numeric keypad.
/// </summary>
NumPad9 = 0x69,
/// <summary>
/// The Multiply key.
/// </summary>
Multiply = 0x6A,
/// <summary>
/// The Add key.
/// </summary>
Add = 0x6B,
/// <summary>
/// The Separator key.
/// </summary>
Separator = 0x6C,
/// <summary>
/// The Subtract key.
/// </summary>
Subtract = 0x6D,
/// <summary>
/// The Decimal key.
/// </summary>
Decimal = 0x6E,
/// <summary>
/// The Divide key.
/// </summary>
Divide = 0x6F,
/// <summary>
/// The F1 key.
/// </summary>
F1 = 0x70,
/// <summary>
/// The F2 key.
/// </summary>
F2 = 0x71,
/// <summary>
/// The F3 key.
/// </summary>
F3 = 0x72,
/// <summary>
/// The F4 key.
/// </summary>
F4 = 0x73,
/// <summary>
/// The F5 key.
/// </summary>
F5 = 0x74,
/// <summary>
/// The F6 key.
/// </summary>
F6 = 0x75,
/// <summary>
/// The F7 key.
/// </summary>
F7 = 0x76,
/// <summary>
/// The F8 key.
/// </summary>
F8 = 0x77,
/// <summary>
/// The F9 key.
/// </summary>
F9 = 0x78,
/// <summary>
/// The F10 key.
/// </summary>
F10 = 0x79,
/// <summary>
/// The F11 key.
/// </summary>
F11 = 0x7A,
/// <summary>
/// The F12 key.
/// </summary>
F12 = 0x7B,
/// <summary>
/// The F13 key.
/// </summary>
F13 = 0x7C,
/// <summary>
/// The F14 key.
/// </summary>
F14 = 0x7D,
/// <summary>
/// The F15 key.
/// </summary>
F15 = 0x7E,
/// <summary>
/// The F16 key.
/// </summary>
F16 = 0x7F,
/// <summary>
/// The F17 key.
/// </summary>
F17 = 0x80,
/// <summary>
/// The F18 key.
/// </summary>
F18 = 0x81,
/// <summary>
/// The F19 key.
/// </summary>
F19 = 0x82,
/// <summary>
/// The F20 key.
/// </summary>
F20 = 0x83,
/// <summary>
/// The F21 key.
/// </summary>
F21 = 0x84,
/// <summary>
/// The F22 key.
/// </summary>
F22 = 0x85,
/// <summary>
/// The F23 key.
/// </summary>
F23 = 0x86,
/// <summary>
/// The F24 key.
/// </summary>
F24 = 0x87,
/// <summary>
/// The NUM LOCK key.
/// </summary>
NumLock = 0x90,
/// <summary>
/// The SCROLL LOCK key.
/// </summary>
Scroll = 0x91,
/// <summary>
/// The left SHIFT key.
/// </summary>
LShiftKey = 0xA0,
/// <summary>
/// The right SHIFT key.
/// </summary>
RShiftKey = 0xA1,
/// <summary>
/// The left CTRL key.
/// </summary>
LControlKey = 0xA2,
/// <summary>
/// The right CTRL key.
/// </summary>
RControlKey = 0xA3,
/// <summary>
/// The left ALT key.
/// </summary>
LMenu = 0xA4,
/// <summary>
/// The right ALT key.
/// </summary>
RMenu = 0xA5,
/// <summary>
/// The Browser Back key.
/// </summary>
BrowserBack = 0xA6,
/// <summary>
/// The Browser Forward key.
/// </summary>
BrowserForward = 0xA7,
/// <summary>
/// The Browser Refresh key.
/// </summary>
BrowserRefresh = 0xA8,
/// <summary>
/// The Browser Stop key.
/// </summary>
BrowserStop = 0xA9,
/// <summary>
/// The Browser Search key.
/// </summary>
BrowserSearch = 0xAA,
/// <summary>
/// The Browser Favorites key.
/// </summary>
BrowserFavorites = 0xAB,
/// <summary>
/// The Browser Home key.
/// </summary>
BrowserHome = 0xAC,
/// <summary>
/// The Volume Mute key.
/// </summary>
VolumeMute = 0xAD,
/// <summary>
/// The Volume Down key.
/// </summary>
VolumeDown = 0xAE,
/// <summary>
/// The Volume Up key.
/// </summary>
VolumeUp = 0xAF,
/// <summary>
/// The Media Next Track key.
/// </summary>
MediaNextTrack = 0xB0,
/// <summary>
/// The Media Previous Track key.
/// </summary>
MediaPreviousTrack = 0xB1,
/// <summary>
/// The Media Stop key.
/// </summary>
MediaStop = 0xB2,
/// <summary>
/// The Media Play Pause key.
/// </summary>
MediaPlayPause = 0xB3,
/// <summary>
/// The Launch Mail key.
/// </summary>
LaunchMail = 0xB4,
/// <summary>
/// The Select Media key.
/// </summary>
SelectMedia = 0xB5,
/// <summary>
/// The Launch Application1 key.
/// </summary>
LaunchApplication1 = 0xB6,
/// <summary>
/// The Launch Application2 key.
/// </summary>
LaunchApplication2 = 0xB7,
/// <summary>
/// The Oem Semicolon key.
/// </summary>
OemSemicolon = 0xBA,
/// <summary>
/// The Oem 1 key.
/// </summary>
Oem1 = OemSemicolon,
/// <summary>
/// The Oem plus key.
/// </summary>
Oemplus = 0xBB,
/// <summary>
/// The Oem comma key.
/// </summary>
Oemcomma = 0xBC,
/// <summary>
/// The Oem Minus key.
/// </summary>
OemMinus = 0xBD,
/// <summary>
/// The Oem Period key.
/// </summary>
OemPeriod = 0xBE,
/// <summary>
/// The Oem Question key.
/// </summary>
OemQuestion = 0xBF,
/// <summary>
/// The Oem 2 key.
/// </summary>
Oem2 = OemQuestion,
/// <summary>
/// The Oem tilde key.
/// </summary>
Oemtilde = 0xC0,
/// <summary>
/// The Oem 3 key.
/// </summary>
Oem3 = Oemtilde,
/// <summary>
/// The Oem Open Brackets key.
/// </summary>
OemOpenBrackets = 0xDB,
/// <summary>
/// The Oem 4 key.
/// </summary>
Oem4 = OemOpenBrackets,
/// <summary>
/// The Oem Pipe key.
/// </summary>
OemPipe = 0xDC,
/// <summary>
/// The Oem 5 key.
/// </summary>
Oem5 = OemPipe,
/// <summary>
/// The Oem Close Brackets key.
/// </summary>
OemCloseBrackets = 0xDD,
/// <summary>
/// The Oem 6 key.
/// </summary>
Oem6 = OemCloseBrackets,
/// <summary>
/// The Oem Quotes key.
/// </summary>
OemQuotes = 0xDE,
/// <summary>
/// The Oem 7 key.
/// </summary>
Oem7 = OemQuotes,
/// <summary>
/// The Oem8 key.
/// </summary>
Oem8 = 0xDF,
/// <summary>
/// The Oem Backslash key.
/// </summary>
OemBackslash = 0xE2,
/// <summary>
/// The Oem 102 key.
/// </summary>
Oem102 = OemBackslash,
/// <summary>
/// The PROCESS KEY key.
/// </summary>
ProcessKey = 0xE5,
/// <summary>
/// The Packet KEY key.
/// </summary>
Packet = 0xE7,
/// <summary>
/// The ATTN key.
/// </summary>
Attn = 0xF6,
/// <summary>
/// The CRSEL key.
/// </summary>
Crsel = 0xF7,
/// <summary>
/// The EXSEL key.
/// </summary>
Exsel = 0xF8,
/// <summary>
/// The ERASE EOF key.
/// </summary>
EraseEof = 0xF9,
/// <summary>
/// The PLAY key.
/// </summary>
Play = 0xFA,
/// <summary>
/// The ZOOM key.
/// </summary>
Zoom = 0xFB,
/// <summary>
/// A constant reserved for future use.
/// </summary>
NoName = 0xFC,
/// <summary>
/// The PA1 key.
/// </summary>
Pa1 = 0xFD,
/// <summary>
/// The CLEAR key.
/// </summary>
OemClear = 0xFE,
/// <summary>
/// The SHIFT modifier key.
/// </summary>
Shift = 0x00010000,
/// <summary>
/// The CTRL modifier key.
/// </summary>
Control = 0x00020000,
/// <summary>
/// The ALT modifier key.
/// </summary>
Alt = 0x00040000,
}

View File

@ -1,198 +0,0 @@
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 { get; set; } = false;
public bool IsCaseSensitived { get; set; } = false;
public bool IsShift { get; private set; } = false;
public bool IsCtrl { get; private set; } = false;
public bool IsAlt { get; private set; } = false;
public bool IsWin { get; private set; } = false;
public bool IsExtendedKey { get; private set; } = false;
protected KeyboardHook KeyboardHook = new();
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, KeyboardEventArgs e)
{
if (e.KeyCode == KeyboardKeys.Shift
|| e.KeyCode == KeyboardKeys.ShiftKey
|| e.KeyCode == KeyboardKeys.LShiftKey
|| e.KeyCode == KeyboardKeys.RShiftKey)
{
if (!IsShift)
{
IsShift = true;
IsExtendedKey = e.KeyCode == KeyboardKeys.RShiftKey;
if (IsCombinationOnly)
{
return;
}
}
}
else if (e.KeyCode == KeyboardKeys.Control
|| e.KeyCode == KeyboardKeys.ControlKey
|| e.KeyCode == KeyboardKeys.LControlKey
|| e.KeyCode == KeyboardKeys.RControlKey)
{
if (!IsCtrl)
{
IsCtrl = true;
IsExtendedKey = e.KeyCode == KeyboardKeys.RControlKey;
if (IsCombinationOnly)
{
return;
}
}
}
else if (e.KeyCode == KeyboardKeys.LWin
|| e.KeyCode == KeyboardKeys.RWin)
{
if (!IsWin)
{
IsWin = true;
IsExtendedKey = e.KeyCode == KeyboardKeys.RWin;
if (IsCombinationOnly)
{
return;
}
}
}
else if (e.KeyCode == KeyboardKeys.Alt
|| e.KeyCode == KeyboardKeys.LMenu
|| e.KeyCode == KeyboardKeys.RMenu)
{
if (!IsAlt)
{
IsAlt = true;
IsExtendedKey = e.KeyCode == KeyboardKeys.RMenu;
if (IsCombinationOnly)
{
return;
}
}
}
else if (e.KeyCode == KeyboardKeys.Return)
{
IsExtendedKey = KeyboardKeys.Return.IsExtendedKey();
}
DateTime now = DateTime.Now;
#if false
Debug.WriteLine(e.KeyCode);
#endif
KeyboardItem item;
if (IsCaseSensitived)
{
bool isUpper = KeyboardKeys.CapsLock.IsKeyLocked() ? !IsShift : IsShift;
if (isUpper)
{
item = new KeyboardItem(now, e.KeyCode, char.ToUpper((char)e.KeyCode).ToString());
}
else
{
item = new KeyboardItem(now, e.KeyCode, char.ToLower((char)e.KeyCode).ToString());
}
}
else
{
item = new KeyboardItem(now, e.KeyCode);
}
KeyboardResult result = new(item)
{
IsShift = IsShift,
IsCtrl = IsCtrl,
IsAlt = IsAlt,
IsWin = IsWin,
IsExtendedKey = IsExtendedKey,
};
Received?.Invoke(this, result);
#if true
Debug.WriteLine(result.ToString());
#endif
}
private void OnKeyUp(object? sender, KeyboardEventArgs e)
{
if (e.KeyCode == KeyboardKeys.Shift
|| e.KeyCode == KeyboardKeys.ShiftKey
|| e.KeyCode == KeyboardKeys.LShiftKey
|| e.KeyCode == KeyboardKeys.RShiftKey)
{
IsShift = false;
IsExtendedKey = e.KeyCode == KeyboardKeys.RShiftKey;
return;
}
else if (e.KeyCode == KeyboardKeys.Control
|| e.KeyCode == KeyboardKeys.ControlKey
|| e.KeyCode == KeyboardKeys.LControlKey
|| e.KeyCode == KeyboardKeys.RControlKey)
{
IsExtendedKey = e.KeyCode == KeyboardKeys.RControlKey;
IsCtrl = false;
return;
}
else if (e.KeyCode == KeyboardKeys.LWin
|| e.KeyCode == KeyboardKeys.RWin)
{
IsExtendedKey = e.KeyCode == KeyboardKeys.RWin;
IsWin = false;
return;
}
else if (e.KeyCode == KeyboardKeys.Alt
|| e.KeyCode == KeyboardKeys.LMenu
|| e.KeyCode == KeyboardKeys.RMenu)
{
IsExtendedKey = e.KeyCode == KeyboardKeys.RMenu;
IsAlt = false;
return;
}
else if (e.KeyCode == KeyboardKeys.Return)
{
IsExtendedKey = KeyboardKeys.Return.IsExtendedKey();
}
}
}

View File

@ -1,75 +0,0 @@
namespace Fischless.KeyboardCapture;
public sealed class KeyboardResult
{
public KeyboardItem KeyboardItem { get; init; } = default;
public string Key => KeyboardItem.Key ?? KeyboardItem.KeyCode.ToName();
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 bool IsExtendedKey { get; set; } = false;
public KeyboardResult(KeyboardItem keyboardItem)
{
KeyboardItem = keyboardItem;
}
public override string ToString()
{
List<string> keyModifiers = [];
if (IsCtrl)
{
return KeyboardConst.Ctrl;
}
if (IsShift)
{
return KeyboardConst.Shift;
}
if (IsAlt)
{
return KeyboardConst.Alt;
}
if (IsWin)
{
return KeyboardConst.Win;
}
if (keyModifiers.Count > 0)
{
if (KeyboardItem.KeyCode.IsCombinationKey())
{
if (IsCtrl)
{
return KeyboardConst.Ctrl;
}
if (IsShift)
{
return KeyboardConst.Shift;
}
if (IsAlt)
{
return KeyboardConst.Alt;
}
if (IsWin)
{
return KeyboardConst.Win;
}
}
else
{
return $"{string.Join('+', keyModifiers)}+{Key}";
}
}
return Key;
}
public static implicit operator string(KeyboardResult result) => result.ToString();
}

View File

@ -1,8 +0,0 @@
<Application
x:Class="Vision.WindowCapture.Test.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Vision.WindowCapture.Test"
StartupUri="MainWindow.xaml">
<Application.Resources/>
</Application>

View File

@ -1,17 +0,0 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
namespace Vision.WindowCapture.Test
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
}
}

View File

@ -1,10 +0,0 @@
using System.Windows;
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]

View File

@ -1,12 +0,0 @@
<Window x:Class="Vision.WindowCapture.Test.CaptureTestWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="CaptureTestWindow" Height="450" Width="800">
<Grid>
<Image x:Name="DisplayCaptureResultImage" Height="Auto" Width="Auto" />
</Grid>
</Window>

View File

@ -1,85 +0,0 @@
using System;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Windows.Win32.Foundation;
namespace Vision.WindowCapture.Test;
public partial class CaptureTestWindow : Window
{
private IWindowCapture? _capture;
private long _captureTime;
private long _transferTime;
private long _captureCount;
public CaptureTestWindow()
{
_captureTime = 0;
_captureCount = 0;
InitializeComponent();
Closed += (sender, args) =>
{
CompositionTarget.Rendering -= Loop;
_capture?.StopAsync();
Debug.WriteLine("平均截图耗时:" + _captureTime * 1.0 / _captureCount);
Debug.WriteLine("平均转换耗时:" + _transferTime * 1.0 / _captureCount);
Debug.WriteLine("平均总耗时:" + (_captureTime + _transferTime) * 1.0 / _captureCount);
};
}
public async void StartCapture(IntPtr hWnd, CaptureModeEnum captureMode)
{
if (hWnd == IntPtr.Zero)
{
MessageBox.Show("请选择窗口");
return;
}
_capture = WindowCaptureFactory.Create(captureMode);
await _capture.StartAsync((HWND)hWnd);
CompositionTarget.Rendering += Loop;
}
private void Loop(object? sender, EventArgs e)
{
var sw = new Stopwatch();
sw.Start();
var bitmap = _capture?.Capture();
sw.Stop();
Debug.WriteLine("截图耗时:" + sw.ElapsedMilliseconds);
_captureTime += sw.ElapsedMilliseconds;
if (bitmap != null)
{
_captureCount++;
sw.Reset();
sw.Start();
DisplayCaptureResultImage.Source = ToBitmapImage(bitmap);
sw.Stop();
Debug.WriteLine("转换耗时:" + sw.ElapsedMilliseconds);
_transferTime += sw.ElapsedMilliseconds;
}
else
{
Debug.WriteLine("截图失败");
}
}
public static BitmapImage ToBitmapImage(Bitmap bitmap)
{
var ms = new MemoryStream();
bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
var image = new BitmapImage();
image.BeginInit();
ms.Seek(0, SeekOrigin.Begin);
image.StreamSource = ms;
image.EndInit();
return image;
}
}

View File

@ -1,12 +0,0 @@
<Window x:Class="Vision.WindowCapture.Test.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Vision.WindowCapture.Test"
mc:Ignorable="d"
Title="MainWindow" Height="400" Width="400">
<Canvas>
<Button x:Name="CaptureBtn" Content="Capture" Canvas.Left="30" Canvas.Top="98" Width="75" Click="CaptureBtn_OnClick"/>
</Canvas>
</Window>

View File

@ -1,41 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Vision.WindowCapture.Test
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void CaptureBtn_OnClick(object sender, RoutedEventArgs e)
{
var picker = new PickerWindow();
var hWnd = picker.PickCaptureTarget(new WindowInteropHelper(this).Handle);
if (hWnd != IntPtr.Zero)
{
var captureWindow = new CaptureTestWindow();
captureWindow.StartCapture(hWnd, CaptureModeEnum.WindowsGraphicsCapture);
captureWindow.Show();
}
}
}
}

View File

@ -1,36 +0,0 @@
<Window x:Class="Vision.WindowCapture.Test.PickerWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Vision.WindowCapture.Test"
mc:Ignorable="d"
Title="选择捕获窗口" Height="450" Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel
Grid.Row="0"
Margin="5,0"
Orientation="Horizontal">
<TextBlock FontSize="20" Text="双击选中要捕获的窗口" />
</StackPanel>
<ListBox
x:Name="WindowList"
Grid.Row="1"
Padding="0,10"
BorderThickness="0">
<ListBox.ItemTemplate>
<DataTemplate>
<ContentControl MouseDoubleClick="WindowsOnMouseDoubleClick">
<TextBlock FontSize="14" Text="{Binding Name}" />
</ContentControl>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>

View File

@ -1,98 +0,0 @@
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Input;
using System.Windows.Interop;
using static Windows.Win32.PInvoke;
namespace Vision.WindowCapture.Test;
public partial class PickerWindow : Window
{
private readonly string[] _ignoreProcesses = { "applicationframehost", "shellexperiencehost", "systemsettings", "winstore.app", "searchui" };
public PickerWindow()
{
InitializeComponent();
Loaded += OnLoaded;
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
FindWindows();
}
public IntPtr PickCaptureTarget(IntPtr hWnd)
{
new WindowInteropHelper(this).Owner = hWnd;
ShowDialog();
return ((CapturableWindow?)WindowList.SelectedItem)?.Handle ?? IntPtr.Zero;
}
private unsafe void FindWindows()
{
var wih = new WindowInteropHelper(this);
EnumWindows((hWnd, lParam) =>
{
// ignore invisible windows
if (!IsWindowVisible(hWnd))
return true;
// ignore untitled windows
string title;
int bufferSize = GetWindowTextLength(hWnd) + 1;
fixed (char* windowNameChars = new char[bufferSize])
{
if (GetWindowText(hWnd, windowNameChars, bufferSize) == 0)
{
int errorCode = Marshal.GetLastWin32Error();
if (errorCode != 0)
{
throw new Win32Exception(errorCode);
}
return true;
}
title = new string(windowNameChars);
if (string.IsNullOrWhiteSpace(title))
return true;
}
// ignore me
if (wih.Handle == hWnd)
return true;
uint processId;
GetWindowThreadProcessId(hWnd, &processId);
// ignore by process name
var process = Process.GetProcessById((int)processId);
if (_ignoreProcesses.Contains(process.ProcessName.ToLower()))
return true;
WindowList.Items.Add(new CapturableWindow
{
Handle = hWnd,
Name = $"{title} ({process.ProcessName}.exe)"
});
return true;
}, IntPtr.Zero);
}
private void WindowsOnMouseDoubleClick(object sender, MouseButtonEventArgs e)
{
Close();
}
}
public struct CapturableWindow
{
public string Name { get; set; }
public IntPtr Handle { get; set; }
}

View File

@ -1,23 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows10.0.22621.0</TargetFramework>
<Nullable>enable</Nullable>
<UseWPF>true</UseWPF>
<LangVersion>12.0</LangVersion>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Platforms>x64</Platforms>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Vision.WindowCapture\Vision.WindowCapture.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Update="CaptureTestWindow.xaml.cs">
<SubType>Code</SubType>
</Compile>
</ItemGroup>
</Project>

View File

@ -1,62 +0,0 @@
using System.Diagnostics;
using System.Drawing;
using Windows.Win32.Foundation;
using Windows.Win32.Graphics.Gdi;
using static Windows.Win32.PInvoke;
namespace Vision.WindowCapture.BitBlt
{
public class BitBltCapture : IWindowCapture
{
private HWND _hWnd;
public bool IsCapturing { get; private set; }
public Task StartAsync(HWND hWnd)
{
_hWnd = hWnd;
IsCapturing = true;
return Task.CompletedTask;
}
public Bitmap? Capture()
{
if (_hWnd == IntPtr.Zero)
{
return null;
}
try
{
GetWindowRect(_hWnd, out var windowRect);
var width = windowRect.Width;
var height = windowRect.Height;
var hdcSrc = GetWindowDC(_hWnd);
var hdcDest = CreateCompatibleDC(hdcSrc);
var hBitmap = CreateCompatibleBitmap(hdcSrc, width, height);
var hOld = SelectObject(hdcDest, hBitmap);
Windows.Win32.PInvoke.BitBlt(hdcDest, 0, 0, width, height, hdcSrc, 0, 0, ROP_CODE.SRCCOPY);
SelectObject(hdcDest, hOld);
DeleteDC(hdcDest);
_ = ReleaseDC(_hWnd, hdcSrc);
var bitmap = Image.FromHbitmap(hBitmap);
DeleteObject(hBitmap);
return bitmap;
}
catch (Exception e)
{
Debug.WriteLine(e);
return null;
}
}
public Task StopAsync()
{
_hWnd = HWND.Null;
IsCapturing = false;
return Task.CompletedTask;
}
}
}

View File

@ -1,7 +0,0 @@
namespace Vision.WindowCapture;
public enum CaptureModeEnum
{
BitBlt,
WindowsGraphicsCapture
}

View File

@ -1,9 +0,0 @@
namespace Vision.WindowCapture;
public static class CaptureModeExtensions
{
public static CaptureModeEnum ToCaptureMode(this string modeName)
{
return (CaptureModeEnum)Enum.Parse(typeof(CaptureModeEnum), modeName);
}
}

View File

@ -1,84 +0,0 @@
using System.Drawing;
using Vision.WindowCapture.GraphicsCapture.Helpers;
using Windows.Foundation.Metadata;
using Windows.Graphics.Capture;
using Windows.Graphics.DirectX;
using Windows.Win32.Foundation;
namespace Vision.WindowCapture.GraphicsCapture;
public class GraphicsCapture : IWindowCapture
{
private HWND _hWnd;
private Direct3D11CaptureFramePool? _captureFramePool;
private GraphicsCaptureItem? _captureItem;
private GraphicsCaptureSession? _captureSession;
public bool IsCapturing { get; private set; }
public async Task StartAsync(HWND hWnd)
{
_hWnd = hWnd;
/*
// if use GraphicsCapturePicker, need to set this window handle
// new WindowInteropHelper(this).Handle
var picker = new GraphicsCapturePicker();
picker.SetWindow(hWnd);
_captureItem = picker.PickSingleItemAsync().AsTask().Result;
*/
var device = Direct3D11Helper.CreateDevice();
_captureItem = CaptureHelper.CreateItemForWindow(_hWnd) ?? throw new InvalidOperationException("Failed to create capture item.");
var size = _captureItem.Size;
if (size.Width < 480 || size.Height < 360)
{
throw new InvalidOperationException("窗口画面大小小于480x360无法使用");
}
_captureItem.Closed += OnCaptureItemClosed;
_captureFramePool = Direct3D11CaptureFramePool.Create(device, DirectXPixelFormat.B8G8R8A8UIntNormalized, 2, size);
_captureSession = _captureFramePool.CreateCaptureSession(_captureItem);
if (ApiInformation.IsWriteablePropertyPresent("Windows.Graphics.Capture.GraphicsCaptureSession", "IsBorderRequired"))
{
await GraphicsCaptureAccess.RequestAccessAsync(GraphicsCaptureAccessKind.Borderless);
_captureSession.IsBorderRequired = false;
_captureSession.IsCursorCaptureEnabled = false;
}
_captureSession.StartCapture();
IsCapturing = true;
}
/// <summary>
/// How to handle window size changes?
/// </summary>
/// <returns></returns>
public Bitmap? Capture()
{
using var frame = _captureFramePool?.TryGetNextFrame();
return frame?.ToBitmap();
}
public Task StopAsync()
{
_captureSession?.Dispose();
_captureFramePool?.Dispose();
_captureSession = default;
_captureFramePool = default;
_captureItem = default;
_hWnd = HWND.Null;
IsCapturing = false;
return Task.CompletedTask;
}
private void OnCaptureItemClosed(GraphicsCaptureItem sender, object args)
{
StopAsync();
}
}

View File

@ -1,57 +0,0 @@
// ---------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// ---------------------------------------------------------------------------------
using System.Diagnostics.CodeAnalysis;
using Windows.Graphics.Capture;
using Windows.UI;
using Windows.Win32.Foundation;
using WinRT.Interop;
namespace Vision.WindowCapture.GraphicsCapture.Helpers;
public static class CaptureHelper
{
public static void SetWindow(this GraphicsCapturePicker picker, IntPtr hwnd)
{
InitializeWithWindow.Initialize(picker, hwnd);
}
[return: MaybeNull]
public static unsafe GraphicsCaptureItem CreateItemForWindow(HWND hwnd)
{
return GraphicsCaptureItem.TryCreateFromWindowId(*(WindowId*)&hwnd);
}
//public static GraphicsCaptureItem CreateItemForMonitor(IntPtr hmon)
//{
// var factory = WindowsRuntimeMarshal.GetActivationFactory(typeof(GraphicsCaptureItem));
// var interop = (IGraphicsCaptureItemInterop)factory;
// var temp = typeof(GraphicsCaptureItem);
// var itemPointer = interop.CreateForMonitor(hmon, GraphicsCaptureItemGuid);
// var item = Marshal.GetObjectForIUnknown(itemPointer) as GraphicsCaptureItem;
// Marshal.Release(itemPointer);
// return item;
//}
}

View File

@ -1,120 +0,0 @@
// ---------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// The MIT License (MIT)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
// ---------------------------------------------------------------------------------
using System.Runtime.InteropServices;
using Windows.Graphics.DirectX.Direct3D11;
using Windows.Win32;
using Windows.Win32.Foundation;
using Windows.Win32.Graphics.Direct3D;
using Windows.Win32.Graphics.Direct3D11;
using Windows.Win32.Graphics.Dxgi;
using Windows.Win32.System.WinRT.Direct3D11;
using WinRT;
using static Windows.Win32.PInvoke;
namespace Vision.WindowCapture.GraphicsCapture.Helpers;
public static class Direct3D11Helper
{
public static IDirect3DDevice? CreateDevice()
{
return CreateDirect3DDevice();
}
public static unsafe IDirect3DDevice? CreateDirect3DDevice()
{
HRESULT hr = D3D11CreateDevice(
default,
D3D_DRIVER_TYPE.D3D_DRIVER_TYPE_HARDWARE,
default,
D3D11_CREATE_DEVICE_FLAG.D3D11_CREATE_DEVICE_BGRA_SUPPORT,
default,
0,
D3D11_SDK_VERSION,
out ID3D11Device? d3d11Device,
default,
out _);
if (hr == HRESULT.DXGI_ERROR_UNSUPPORTED)
{
D3D11CreateDevice(
default,
D3D_DRIVER_TYPE.D3D_DRIVER_TYPE_SOFTWARE,
default,
D3D11_CREATE_DEVICE_FLAG.D3D11_CREATE_DEVICE_BGRA_SUPPORT,
default,
0,
D3D11_SDK_VERSION,
out d3d11Device,
default,
out _);
}
return CreateDirect3DDeviceFromD3D11Device(d3d11Device);
}
public static IDirect3DDevice? CreateDirect3DDeviceFromD3D11Device(ID3D11Device d3d11Device)
{
// Acquire the DXGI interface for the Direct3D device.
// Wrap the native device using a WinRT interop object.
if (CreateDirect3D11DeviceFromDXGIDevice(d3d11Device.As<IDXGIDevice>(), out var iInspectable).Succeeded)
{
nint thisPtr = Marshal.GetIUnknownForObject(iInspectable);
return MarshalInterface<IDirect3DDevice>.FromAbi(thisPtr);
}
return default;
}
public static IDirect3DSurface? CreateDirect3DSurfaceFromSharpDXTexture(ID3D11Texture2D texture)
{
// Acquire the DXGI interface for the Direct3D surface.
// Wrap the native device using a WinRT interop object.
if (CreateDirect3D11SurfaceFromDXGISurface(texture.As<IDXGISurface>(), out var iInspectable).Succeeded)
{
nint thisPtr = Marshal.GetIUnknownForObject(iInspectable);
return MarshalInterface<IDirect3DSurface>.FromAbi(thisPtr);
}
return default;
}
public static ID3D11Device CreateD3D11Device(IDirect3DDevice device)
{
device
.As<IDirect3DDxgiInterfaceAccess>()
.GetInterface(typeof(ID3D11Device).GUID, out var d3dDevice);
object obj = Marshal.GetObjectForIUnknown(d3dDevice);
return obj.As<ID3D11Device>();
}
public static ID3D11Texture2D CreateD3D11Texture2D(IDirect3DSurface surface)
{
surface
.As<IDirect3DDxgiInterfaceAccess>()
.GetInterface(typeof(ID3D11Texture2D).GUID, out var d3dSurface);
object obj = Marshal.GetObjectForIUnknown(d3dSurface);
return obj.As<ID3D11Texture2D>();
}
}

View File

@ -1,125 +0,0 @@
using System.Drawing;
using System.Drawing.Imaging;
using Windows.Graphics.Capture;
using Windows.Win32;
using Windows.Win32.Graphics.Direct3D11;
using Windows.Win32.Graphics.Dxgi.Common;
namespace Vision.WindowCapture.GraphicsCapture.Helpers
{
public static class Texture2DExtensions
{
public static unsafe Bitmap ToBitmap(this Direct3D11CaptureFrame frame)
{
var d3d11Texture2d = Direct3D11Helper.CreateD3D11Texture2D(frame.Surface);
d3d11Texture2d.GetDevice(out var d3dDevice);
d3d11Texture2d.GetDesc(out D3D11_TEXTURE2D_DESC desc);
D3D11_TEXTURE2D_DESC newDesc = new()
{
Width = (uint)frame.ContentSize.Width,
Height = (uint)frame.ContentSize.Height,
MipLevels = 1U,
ArraySize = 1U,
Format = desc.Format,
Usage = D3D11_USAGE.D3D11_USAGE_STAGING,
SampleDesc = new DXGI_SAMPLE_DESC() { Count = 1 },
CPUAccessFlags = D3D11_CPU_ACCESS_FLAG.D3D11_CPU_ACCESS_READ,
};
// Create texture copy
d3dDevice.CreateTexture2D(newDesc, default, out ID3D11Texture2D buffer);
d3dDevice.GetImmediateContext(out ID3D11DeviceContext context);
// Copy data
context.CopyResource(buffer, d3d11Texture2d);
D3D11_MAPPED_SUBRESOURCE subResource = default;
context.Map(buffer, default, D3D11_MAP.D3D11_MAP_READ, default, &subResource);
buffer.GetDesc(out var stagingDesc);
var bitmap = new Bitmap(
(int)stagingDesc.Width,
(int)stagingDesc.Height,
(int)subResource.RowPitch,
PixelFormat.Format32bppArgb,
(nint)subResource.pData);
return bitmap;
}
//public static Stream ToBitmapStream(this Direct3D11CaptureFrame frame)
//{
// var bitmap = frame.ToBitmap();
// Stream memoryStream = new MemoryStream();
// bitmap.Save(memoryStream, ImageFormat.Png);
// return memoryStream;
//}
//public static async Task<SoftwareBitmap> ToSoftwareBitmapAsync(this Direct3D11CaptureFrame frame)
//{
// var result = await SoftwareBitmap.CreateCopyFromSurfaceAsync(frame.Surface, BitmapAlphaMode.Premultiplied);
// return result;
//}
//public static async Task<Bitmap> ToBitmapAsync(this SoftwareBitmap sbitmap)
//{
// using var stream = new Windows.Storage.Streams.InMemoryRandomAccessStream();
// var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, stream);
// encoder.SetSoftwareBitmap(sbitmap);
// await encoder.FlushAsync();
// var bmp = new System.Drawing.Bitmap(stream.AsStream());
// return bmp;
//}
//public static Bitmap Resize(this Bitmap source, int newWidth, int newHeight)
//{
// float wScale = (float)newWidth / source.Width;
// float hScale = (float)newHeight / source.Height;
// float minScale = Math.Min(wScale, hScale);
// var nw = (int)(source.Width * minScale);
// var nh = (int)(source.Height * minScale);
// var padDimsW = (newWidth - nw) / 2;
// var padDimsH = (newHeight - nh) / 2;
// var newBitmap = new Bitmap(newWidth, newHeight, PixelFormat.Format24bppRgb);
// using var g = Graphics.FromImage(newBitmap);
// g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighSpeed;
// g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;
// g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Low;
// g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighSpeed;
// g.DrawImage(source, new Rectangle(padDimsW, padDimsH, nw, nh),
// 0, 0, source.Width, source.Height, GraphicsUnit.Pixel);
// return newBitmap;
//}
//public static Bitmap ResizeWithoutPadding(this Bitmap source, int new_width, int new_height)
//{
// var newBitmap = new Bitmap(new_width, new_height, PixelFormat.Format24bppRgb);
// using var g = Graphics.FromImage(newBitmap);
// g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighSpeed;
// g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;
// g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Low;
// g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighSpeed;
// g.DrawImage(source, new Rectangle(0, 0, new_width, new_height),
// 0, 0, source.Width, source.Height, GraphicsUnit.Pixel);
// return newBitmap;
//}
}
}

View File

@ -1,15 +0,0 @@
using System.Drawing;
using Windows.Win32.Foundation;
namespace Vision.WindowCapture;
public interface IWindowCapture
{
bool IsCapturing { get; }
Task StartAsync(HWND hWnd);
Bitmap? Capture();
Task StopAsync();
}

View File

@ -1,9 +0,0 @@
# Vision.WindowCapture
一个针对窗口截图的库。输入窗口句柄后可以进行捕获,不会捕获覆盖窗体的内容。
支持以下方案:
* BitBlt
* Windows.Graphics.Capture
* DwmSharedSurface (建设中)

View File

@ -1,24 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-windows10.0.22621.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<LangVersion>12.0</LangVersion>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Platforms>x64</Platforms>
</PropertyGroup>
<ItemGroup>
<None Remove="README.md" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.Drawing.Common" Version="8.0.6" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\BetterGenshinImpact.Win32\BetterGenshinImpact.Win32.csproj" />
</ItemGroup>
</Project>

View File

@ -1,20 +0,0 @@
namespace Vision.WindowCapture;
public class WindowCaptureFactory
{
public static string[] ModeNames()
{
return Enum.GetNames(typeof(CaptureModeEnum));
}
public static IWindowCapture Create(CaptureModeEnum mode)
{
return mode switch
{
CaptureModeEnum.BitBlt => new BitBlt.BitBltCapture(),
CaptureModeEnum.WindowsGraphicsCapture => new GraphicsCapture.GraphicsCapture(),
_ => throw new ArgumentOutOfRangeException(nameof(mode), mode, null),
};
}
}