mirror of
https://github.com/babalae/better-genshin-impact
synced 2025-01-05 10:26:56 +08:00
remove library
This commit is contained in:
parent
0c435a9393
commit
e00b38eb66
@ -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>
|
@ -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
|
||||
}
|
||||
}
|
@ -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
|
@ -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
|
||||
|
@ -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>
|
@ -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);
|
||||
}
|
@ -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; }
|
||||
}
|
@ -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,
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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,
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
@ -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>
|
@ -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
|
||||
{
|
||||
}
|
||||
}
|
@ -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)
|
||||
)]
|
@ -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>
|
@ -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;
|
||||
}
|
||||
}
|
@ -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>
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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>
|
@ -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; }
|
||||
}
|
@ -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>
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
namespace Vision.WindowCapture;
|
||||
|
||||
public enum CaptureModeEnum
|
||||
{
|
||||
BitBlt,
|
||||
WindowsGraphicsCapture
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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;
|
||||
//}
|
||||
}
|
@ -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>();
|
||||
}
|
||||
}
|
@ -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;
|
||||
//}
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
# Vision.WindowCapture
|
||||
|
||||
一个针对窗口截图的库。输入窗口句柄后可以进行捕获,不会捕获覆盖窗体的内容。
|
||||
|
||||
支持以下方案:
|
||||
|
||||
* BitBlt
|
||||
* Windows.Graphics.Capture
|
||||
* DwmSharedSurface (建设中)
|
@ -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>
|
@ -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),
|
||||
};
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user