diff --git a/Directory.Packages.props b/Directory.Packages.props
index 3479ca4..d955bc6 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -3,8 +3,8 @@
true
-
-
-
+
+
+
\ No newline at end of file
diff --git a/src/ScreenGrab/Extensions/DapploExtensions.cs b/src/ScreenGrab/Extensions/DapploExtensions.cs
index 39c6d1c..a3681fc 100644
--- a/src/ScreenGrab/Extensions/DapploExtensions.cs
+++ b/src/ScreenGrab/Extensions/DapploExtensions.cs
@@ -8,9 +8,9 @@ public static class DapploExtensions
public static Point ScaledCenterPoint(this DisplayInfo displayInfo)
{
Rect displayRect = displayInfo.Bounds;
- NativeMethods.GetScaleFactorForMonitor(displayInfo.MonitorHandle, out uint scaleFactor);
- double scaleFraction = scaleFactor / 100.0;
- Point rawCenter = displayRect.CenterPoint();
+ NativeMethods.GetScaleFactorForMonitor(displayInfo.MonitorHandle, out var scaleFactor);
+ var scaleFraction = scaleFactor / 100.0;
+ var rawCenter = displayRect.CenterPoint();
Point displayScaledCenterPoint = new(rawCenter.X / scaleFraction, rawCenter.Y / scaleFraction);
return displayScaledCenterPoint;
}
@@ -18,8 +18,8 @@ public static Point ScaledCenterPoint(this DisplayInfo displayInfo)
public static Rect ScaledBounds(this DisplayInfo displayInfo)
{
Rect displayRect = displayInfo.Bounds;
- NativeMethods.GetScaleFactorForMonitor(displayInfo.MonitorHandle, out uint scaleFactor);
- double scaleFraction = scaleFactor / 100.0;
+ NativeMethods.GetScaleFactorForMonitor(displayInfo.MonitorHandle, out var scaleFactor);
+ var scaleFraction = scaleFactor / 100.0;
// Scale size and position
Rect scaledBounds = new(
diff --git a/src/ScreenGrab/Extensions/ShapeExtensions.cs b/src/ScreenGrab/Extensions/ShapeExtensions.cs
index 51b40aa..3f9af4b 100644
--- a/src/ScreenGrab/Extensions/ShapeExtensions.cs
+++ b/src/ScreenGrab/Extensions/ShapeExtensions.cs
@@ -1,5 +1,6 @@
using System.Drawing;
using System.Windows;
+using Point = System.Windows.Point;
namespace ScreenGrab.Extensions;
@@ -18,43 +19,43 @@ public static Rectangle AsRectangle(this Rect rect)
public static Rect GetScaledDownByDpi(this Rect rect, DpiScale dpi)
{
return new Rect(rect.X / dpi.DpiScaleX,
- rect.Y / dpi.DpiScaleY,
- rect.Width / dpi.DpiScaleX,
- rect.Height / dpi.DpiScaleY);
+ rect.Y / dpi.DpiScaleY,
+ rect.Width / dpi.DpiScaleX,
+ rect.Height / dpi.DpiScaleY);
}
public static Rect GetScaledUpByDpi(this Rect rect, DpiScale dpi)
{
return new Rect(rect.X * dpi.DpiScaleX,
- rect.Y * dpi.DpiScaleY,
- rect.Width * dpi.DpiScaleX,
- rect.Height * dpi.DpiScaleY);
+ rect.Y * dpi.DpiScaleY,
+ rect.Width * dpi.DpiScaleX,
+ rect.Height * dpi.DpiScaleY);
}
- public static Rect GetScaledUpByFraction(this Rect rect, Double scaleFactor)
+ public static Rect GetScaledUpByFraction(this Rect rect, double scaleFactor)
{
return new Rect(rect.X * scaleFactor,
- rect.Y * scaleFactor,
- rect.Width * scaleFactor,
- rect.Height * scaleFactor);
+ rect.Y * scaleFactor,
+ rect.Width * scaleFactor,
+ rect.Height * scaleFactor);
}
- public static Rect GetScaleSizeByFraction(this Rect rect, Double scaleFactor)
+ public static Rect GetScaleSizeByFraction(this Rect rect, double scaleFactor)
{
return new Rect(rect.X,
- rect.Y,
- rect.Width * scaleFactor,
- rect.Height * scaleFactor);
+ rect.Y,
+ rect.Width * scaleFactor,
+ rect.Height * scaleFactor);
}
public static bool IsGood(this Rect rect)
{
- if (double.IsNaN(rect.X)
+ if (double.IsNaN(rect.X)
|| double.IsNegativeInfinity(rect.X)
|| double.IsPositiveInfinity(rect.X))
return false;
-
- if (double.IsNaN(rect.Y)
+
+ if (double.IsNaN(rect.Y)
|| double.IsNegativeInfinity(rect.Y)
|| double.IsPositiveInfinity(rect.Y))
return false;
@@ -74,10 +75,10 @@ public static bool IsGood(this Rect rect)
return true;
}
- public static System.Windows.Point CenterPoint(this Rect rect)
+ public static Point CenterPoint(this Rect rect)
{
- double x = rect.Left + (rect.Width / 2);
- double y = rect.Top + (rect.Height / 2);
- return new(x, y);
+ var x = rect.Left + rect.Width / 2;
+ var y = rect.Top + rect.Height / 2;
+ return new Point(x, y);
}
}
\ No newline at end of file
diff --git a/src/ScreenGrab/Extensions/WpfExtensions.cs b/src/ScreenGrab/Extensions/WpfExtensions.cs
index 8d00659..aed32a6 100644
--- a/src/ScreenGrab/Extensions/WpfExtensions.cs
+++ b/src/ScreenGrab/Extensions/WpfExtensions.cs
@@ -1,7 +1,6 @@
-using System;
+using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
-using System.Runtime.InteropServices;
namespace ScreenGrab.Extensions;
@@ -13,21 +12,22 @@ public static Point GetAbsolutePosition(this Window w)
return new Point(w.Left, w.Top);
Int32Rect r;
- bool multimonSupported = OSInterop.GetSystemMetrics(OSInterop.SM_CMONITORS) != 0;
+ var multimonSupported = OSInterop.GetSystemMetrics(OSInterop.SM_CMONITORS) != 0;
if (!multimonSupported)
{
- OSInterop.RECT rc = new OSInterop.RECT();
+ var rc = new OSInterop.RECT();
OSInterop.SystemParametersInfo(48, 0, ref rc, 0);
r = new Int32Rect(rc.left, rc.top, rc.width, rc.height);
}
else
{
- WindowInteropHelper helper = new WindowInteropHelper(w);
- IntPtr hmonitor = OSInterop.MonitorFromWindow(new HandleRef(null, helper.EnsureHandle()), 2);
- OSInterop.MONITORINFOEX info = new OSInterop.MONITORINFOEX();
+ var helper = new WindowInteropHelper(w);
+ var hmonitor = OSInterop.MonitorFromWindow(new HandleRef(null, helper.EnsureHandle()), 2);
+ var info = new OSInterop.MONITORINFOEX();
OSInterop.GetMonitorInfo(new HandleRef(null, hmonitor), info);
r = new Int32Rect(info.rcMonitor.left, info.rcMonitor.top, info.rcMonitor.width, info.rcMonitor.height);
}
+
return new Point(r.X, r.Y);
}
}
\ No newline at end of file
diff --git a/src/ScreenGrab/Grab.cs b/src/ScreenGrab/Grab.cs
new file mode 100644
index 0000000..8929a2f
--- /dev/null
+++ b/src/ScreenGrab/Grab.cs
@@ -0,0 +1,39 @@
+using System.Drawing;
+using System.Windows;
+using Dapplo.Windows.User32;
+using ScreenGrab.Extensions;
+
+namespace ScreenGrab;
+
+public class Grab
+{
+ public Action? OnImageCaptured { get; set; }
+
+ public void Capture()
+ {
+ var allDisplayInfos = DisplayInfo.AllDisplayInfos;
+ var allScreenGrab = Application.Current.Windows.OfType().ToList();
+ var numberOfScreenGrabWindowsToCreate = allDisplayInfos.Length - allScreenGrab.Count;
+
+ for (var i = 0; i < numberOfScreenGrabWindowsToCreate; i++)
+ allScreenGrab.Add(new ScreenGrabView(OnImageCaptured));
+
+ const double sideLength = 40;
+
+ foreach (var (displayInfo, screenGrab) in allDisplayInfos.Zip(allScreenGrab,
+ (displayInfo, screenGrab) => (displayInfo, screenGrab)))
+ {
+ screenGrab.WindowStartupLocation = WindowStartupLocation.Manual;
+ screenGrab.Width = sideLength;
+ screenGrab.Height = sideLength;
+ screenGrab.WindowState = WindowState.Normal;
+
+ var screenCenterPoint = displayInfo.ScaledCenterPoint();
+ screenGrab.Left = screenCenterPoint.X - sideLength / 2;
+ screenGrab.Top = screenCenterPoint.Y - sideLength / 2;
+
+ screenGrab.Show();
+ screenGrab.Activate();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ScreenGrab/Grab.xaml b/src/ScreenGrab/Grab.xaml
deleted file mode 100644
index 5c3e7c0..0000000
--- a/src/ScreenGrab/Grab.xaml
+++ /dev/null
@@ -1,240 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/ScreenGrab/Grab.xaml.cs b/src/ScreenGrab/Grab.xaml.cs
deleted file mode 100644
index d8d8c90..0000000
--- a/src/ScreenGrab/Grab.xaml.cs
+++ /dev/null
@@ -1,302 +0,0 @@
-using System.Drawing;
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Input;
-using System.Windows.Media;
-using Dapplo.Windows.User32;
-using ScreenGrab.Extensions;
-using ScreenGrab.Utilities;
-using Point = System.Windows.Point;
-
-namespace ScreenGrab;
-
-public partial class Grab
-{
- #region Fields
-
- private Point clickedPoint = new();
- private TextBox? destinationTextBox;
- private DpiScale? dpiScale;
- private bool isSelecting = false;
- private bool isShiftDown = false;
- private Border selectBorder = new();
- private double selectLeft;
- private double selectTop;
- private Point shiftPoint = new();
- private double xShiftDelta;
- private double yShiftDelta;
- private bool _isFreeze = true;
-
- #endregion Fields
-
- #region Constructors
-
- public Grab()
- {
- InitializeComponent();
- }
-
- #endregion Constructors
-
- #region Properties
- private DisplayInfo? CurrentScreen { get; set; }
-
- public Bitmap Image { get; set; }
-
- #endregion Properties
-
- #region Window Events
-
- public void SetImageToBackground()
- {
- BackgroundImage.Source = null;
- BackgroundImage.Source = ImageMethods.GetWindowBoundsImage(this);
- BackgroundBrush.Opacity = 0.2;
- }
-
- private async void FreezeUnfreeze(bool isActivate)
- {
- if (isActivate)
- {
- BackgroundBrush.Opacity = 0;
- await Task.Delay(150);
- SetImageToBackground();
- }
- else
- {
- BackgroundImage.Source = null;
- }
- }
-
- private void FullscreenGrab_KeyDown(object sender, KeyEventArgs e)
- {
- switch (e.Key)
- {
- case Key.Escape:
- DialogResult = false;
- Close();
- break;
- case Key.F:
- //TODO: 添加全局变量控制显隐
- _isFreeze = !_isFreeze;
- FreezeUnfreeze(_isFreeze);
- break;
- default:
- break;
- }
- }
-
- private void FullscreenGrab_KeyUp(object sender, KeyEventArgs e)
- {
- switch (e.Key)
- {
- case Key.LeftShift:
- case Key.RightShift:
- isShiftDown = false;
- clickedPoint = new Point(clickedPoint.X + xShiftDelta, clickedPoint.Y + yShiftDelta);
- break;
- default:
- break;
- }
- }
-
- private void Window_Closed(object? sender, EventArgs e)
- {
- Close();
-
- GC.Collect();
- }
-
- private void Window_Loaded(object sender, RoutedEventArgs e)
- {
- WindowState = WindowState.Maximized;
- FullWindow.Rect = new System.Windows.Rect(0, 0, Width, Height);
- KeyDown += FullscreenGrab_KeyDown;
- KeyUp += FullscreenGrab_KeyUp;
-
- SetImageToBackground();
-
-#if DEBUG
- Topmost = false;
-#endif
- }
-
- private void Window_Unloaded(object sender, RoutedEventArgs e)
- {
- BackgroundImage.Source = null;
- BackgroundImage.UpdateLayout();
- CurrentScreen = null;
- dpiScale = null;
-
- Loaded -= Window_Loaded;
- Unloaded -= Window_Unloaded;
-
- RegionClickCanvas.MouseDown -= RegionClickCanvas_MouseDown;
- RegionClickCanvas.MouseMove -= RegionClickCanvas_MouseMove;
- RegionClickCanvas.MouseUp -= RegionClickCanvas_MouseUp;
-
- KeyDown -= FullscreenGrab_KeyDown;
- KeyUp -= FullscreenGrab_KeyUp;
- }
-
- #endregion
-
- #region Mouse Events
-
- private void RegionClickCanvas_MouseDown(object sender, MouseButtonEventArgs e)
- {
- if (e.RightButton == MouseButtonState.Pressed)
- return;
-
- isSelecting = true;
- RegionClickCanvas.CaptureMouse();
- CursorClipper.ClipCursor(this);
- clickedPoint = e.GetPosition(this);
- selectBorder.Height = 1;
- selectBorder.Width = 1;
-
- dpiScale = VisualTreeHelper.GetDpi(this);
-
- try
- {
- RegionClickCanvas.Children.Remove(selectBorder);
- }
- catch (Exception)
- {
- // ignored
- }
-
- selectBorder.BorderThickness = new Thickness(2);
- System.Windows.Media.Color borderColor = System.Windows.Media.Color.FromArgb(255, 40, 118, 126);
- selectBorder.BorderBrush = new SolidColorBrush(borderColor);
- _ = RegionClickCanvas.Children.Add(selectBorder);
- Canvas.SetLeft(selectBorder, clickedPoint.X);
- Canvas.SetTop(selectBorder, clickedPoint.Y);
-
- DisplayInfo[] screens = DisplayInfo.AllDisplayInfos;
- System.Windows.Point formsPoint = new((int)clickedPoint.X, (int)clickedPoint.Y);
- foreach (DisplayInfo scr in screens)
- {
- Rect bound = scr.ScaledBounds();
- if (bound.Contains(formsPoint))
- CurrentScreen = scr;
- }
- }
-
- private void RegionClickCanvas_MouseMove(object sender, MouseEventArgs e)
- {
- if (!isSelecting)
- return;
-
- Point movingPoint = e.GetPosition(this);
-
- if (Keyboard.Modifiers == ModifierKeys.Shift)
- {
- PanSelection(movingPoint);
- return;
- }
-
- isShiftDown = false;
-
- double left = Math.Min(clickedPoint.X, movingPoint.X);
- double top = Math.Min(clickedPoint.Y, movingPoint.Y);
-
- selectBorder.Height = Math.Max(clickedPoint.Y, movingPoint.Y) - top;
- selectBorder.Width = Math.Max(clickedPoint.X, movingPoint.X) - left;
- selectBorder.Height += 2;
- selectBorder.Width += 2;
-
- clippingGeometry.Rect = new Rect(
- new System.Windows.Point(left, top),
- new System.Windows.Size(selectBorder.Width - 2, selectBorder.Height - 2));
- Canvas.SetLeft(selectBorder, left - 1);
- Canvas.SetTop(selectBorder, top - 1);
- }
-
- private void RegionClickCanvas_MouseUp(object sender, MouseButtonEventArgs e)
- {
- if (!isSelecting)
- return;
-
- isSelecting = false;
- CurrentScreen = null;
- CursorClipper.UnClipCursor();
- RegionClickCanvas.ReleaseMouseCapture();
- clippingGeometry.Rect = new Rect(
- new System.Windows.Point(0, 0),
- new System.Windows.Size(0, 0));
-
- System.Windows.Point movingPoint = e.GetPosition(this);
- Matrix m = PresentationSource.FromVisual(this).CompositionTarget.TransformToDevice;
- movingPoint.X *= m.M11;
- movingPoint.Y *= m.M22;
-
- movingPoint.X = Math.Round(movingPoint.X);
- movingPoint.Y = Math.Round(movingPoint.Y);
-
- double xDimScaled = Canvas.GetLeft(selectBorder) * m.M11;
- double yDimScaled = Canvas.GetTop(selectBorder) * m.M22;
-
- Rectangle regionScaled = new(
- (int)xDimScaled,
- (int)yDimScaled,
- (int)(selectBorder.Width * m.M11),
- (int)(selectBorder.Height * m.M22));
-
- try
- {
- RegionClickCanvas.Children.Remove(selectBorder);
- }
- catch
- {
- // ignored
- }
-
- //FIXME: ZGGSONG
- Point absPosPoint = this.GetAbsolutePosition();
-
- int thisCorrectedLeft = (int)absPosPoint.X + regionScaled.Left;
- int thisCorrectedTop = (int)absPosPoint.Y + regionScaled.Top;
-
- Rectangle correctedRegion = new(thisCorrectedLeft, thisCorrectedTop, regionScaled.Width, regionScaled.Height);
- Image = ImageMethods.GetRegionOfScreenAsBitmap(correctedRegion);
-
- DialogResult = true;
- }
-
- private void PanSelection(Point movingPoint)
- {
- if (!isShiftDown)
- {
- shiftPoint = movingPoint;
- selectLeft = Canvas.GetLeft(selectBorder);
- selectTop = Canvas.GetTop(selectBorder);
- }
-
- isShiftDown = true;
- xShiftDelta = (movingPoint.X - shiftPoint.X);
- yShiftDelta = (movingPoint.Y - shiftPoint.Y);
-
- double leftValue = selectLeft + xShiftDelta;
- double topValue = selectTop + yShiftDelta;
-
- if (CurrentScreen is not null && dpiScale is not null)
- {
- double currentScreenLeft = CurrentScreen.Bounds.Left; // Should always be 0
- double currentScreenRight = CurrentScreen.Bounds.Right / dpiScale.Value.DpiScaleX;
- double currentScreenTop = CurrentScreen.Bounds.Top; // Should always be 0
- double currentScreenBottom = CurrentScreen.Bounds.Bottom / dpiScale.Value.DpiScaleY;
-
- leftValue = Math.Clamp(leftValue, currentScreenLeft, (currentScreenRight - selectBorder.Width));
- topValue = Math.Clamp(topValue, currentScreenTop, (currentScreenBottom - selectBorder.Height));
- }
-
- clippingGeometry.Rect = new Rect(
- new System.Windows.Point(leftValue, topValue),
- new System.Windows.Size(selectBorder.Width - 2, selectBorder.Height - 2));
- Canvas.SetLeft(selectBorder, leftValue - 1);
- Canvas.SetTop(selectBorder, topValue - 1);
- }
-
- #endregion
-}
\ No newline at end of file
diff --git a/src/ScreenGrab/Models/NullAsyncResult.cs b/src/ScreenGrab/Models/NullAsyncResult.cs
index 7f9f137..9ec7054 100644
--- a/src/ScreenGrab/Models/NullAsyncResult.cs
+++ b/src/ScreenGrab/Models/NullAsyncResult.cs
@@ -13,5 +13,4 @@ public class NullAsyncResult : IAsyncResult
public class NullWaitHandle : WaitHandle
{
-
}
\ No newline at end of file
diff --git a/src/ScreenGrab/NativeMethods.cs b/src/ScreenGrab/NativeMethods.cs
index 6bb243b..666a4de 100644
--- a/src/ScreenGrab/NativeMethods.cs
+++ b/src/ScreenGrab/NativeMethods.cs
@@ -1,11 +1,10 @@
-using System;
-using System.Runtime.InteropServices;
+using System.Runtime.InteropServices;
internal static partial class NativeMethods
{
// See http://msdn.microsoft.com/en-us/library/ms649021%28v=vs.85%29.aspx
public const int WM_CLIPBOARDUPDATE = 0x031D;
- public static IntPtr HWND_MESSAGE = new IntPtr(-3);
+ public static IntPtr HWND_MESSAGE = new(-3);
// See http://msdn.microsoft.com/en-us/library/ms632599%28VS.85%29.aspx#message_only
[LibraryImport("user32.dll", SetLastError = true)]
diff --git a/src/ScreenGrab/OSInterop.cs b/src/ScreenGrab/OSInterop.cs
index da4dc13..cd9aa76 100644
--- a/src/ScreenGrab/OSInterop.cs
+++ b/src/ScreenGrab/OSInterop.cs
@@ -1,18 +1,40 @@
-using System;
+using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
+using System.Windows.Forms;
-static partial class OSInterop
+internal static partial class OSInterop
{
+ public delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam);
+
+ public enum InputType : uint
+ {
+ INPUT_MOUSE,
+ INPUT_KEYBOARD,
+ INPUT_HARDWARE
+ }
+
+ public const int SM_CMONITORS = 80;
+
+ public const int WH_KEYBOARD_LL = 13;
+ public const int VK_SHIFT = 0x10;
+ public const int VK_CONTROL = 0x11;
+ public const int VK_MENU = 0x12;
+ public const int VK_LWIN = 0x5B;
+ public const int VK_RWIN = 0x5C;
+ public const int VK_ESCAPE = 0x1B;
+ public const int WM_HOTKEY = 0x0312;
+ public const int WM_KEYDOWN = 0x0100;
+ public const int WM_KEYUP = 0x0101;
+
[LibraryImport("user32.dll")]
public static partial int GetSystemMetrics(int smIndex);
- public const int SM_CMONITORS = 80;
[LibraryImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static partial bool SystemParametersInfo(int nAction, int nParam, ref RECT rc, int nUpdate);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
- public static extern bool GetMonitorInfo(HandleRef hmonitor, [In, Out] MONITORINFOEX info);
+ public static extern bool GetMonitorInfo(HandleRef hmonitor, [In] [Out] MONITORINFOEX info);
[DllImport("user32.dll")]
public static extern IntPtr MonitorFromWindow(HandleRef handle, int flags);
@@ -22,46 +44,14 @@ static partial class OSInterop
public static partial bool ClipCursor(ref RECT lpRect);
[DllImport("user32.dll")]
- public static extern bool ClipCursor([In()] IntPtr lpRect);
-
- public struct RECT
- {
- public int left;
- public int top;
- public int right;
- public int bottom;
- public int width { get { return right - left; } }
- public int height { get { return bottom - top; } }
- }
-
- [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Auto)]
- public class MONITORINFOEX
- {
- public int cbSize = Marshal.SizeOf(typeof(MONITORINFOEX));
- public RECT rcMonitor = new RECT();
- public RECT rcWork = new RECT();
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
- public char[] szDevice = new char[32];
- public int dwFlags;
- }
-
- public const int WH_KEYBOARD_LL = 13;
- public const int VK_SHIFT = 0x10;
- public const int VK_CONTROL = 0x11;
- public const int VK_MENU = 0x12;
- public const int VK_LWIN = 0x5B;
- public const int VK_RWIN = 0x5C;
- public const int VK_ESCAPE = 0x1B;
- public const int WM_HOTKEY = 0x0312;
- public const int WM_KEYDOWN = 0x0100;
- public const int WM_KEYUP = 0x0101;
+ public static extern bool ClipCursor([In] IntPtr lpRect);
[LibraryImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static partial bool FreeLibrary(IntPtr hModule);
[LibraryImport("user32.dll", SetLastError = true)]
- [UnmanagedCallConv(CallConvs = new Type[] { typeof(System.Runtime.CompilerServices.CallConvStdcall) })]
+ [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvStdcall) })]
[return: MarshalAs(UnmanagedType.Bool)]
internal static partial bool UnhookWindowsHookEx(IntPtr idHook);
@@ -69,53 +59,61 @@ public class MONITORINFOEX
internal static partial IntPtr LoadLibrary(string lpFileName);
[LibraryImport("user32.dll", SetLastError = true)]
- [UnmanagedCallConv(CallConvs = new Type[] { typeof(System.Runtime.CompilerServices.CallConvStdcall) })]
+ [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvStdcall) })]
internal static partial IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hMod, int dwThreadId);
[LibraryImport("user32.dll", SetLastError = true)]
- [UnmanagedCallConv(CallConvs = new Type[] { typeof(System.Runtime.CompilerServices.CallConvStdcall) })]
+ [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvStdcall) })]
internal static partial IntPtr CallNextHookEx(IntPtr idHook, int nCode, IntPtr wParam, IntPtr lParam);
[LibraryImport("user32.dll", SetLastError = true)]
- [UnmanagedCallConv(CallConvs = new Type[] { typeof(System.Runtime.CompilerServices.CallConvStdcall) })]
+ [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvStdcall) })]
internal static partial short GetAsyncKeyState(int vKey);
- public delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam);
-
[LibraryImport("user32.dll")]
- public static partial short GetAsyncKeyState(System.Windows.Forms.Keys vKey);
+ public static partial short GetAsyncKeyState(Keys vKey);
[LibraryImport("user32.dll")]
public static partial uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize);
+ public struct RECT
+ {
+ public int left;
+ public int top;
+ public int right;
+ public int bottom;
+ public int width => right - left;
+ public int height => bottom - top;
+ }
+
+ [StructLayout(LayoutKind.Sequential, Pack = 4, CharSet = CharSet.Auto)]
+ public class MONITORINFOEX
+ {
+ public int cbSize = Marshal.SizeOf(typeof(MONITORINFOEX));
+ public RECT rcMonitor = new();
+ public RECT rcWork = new();
+
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
+ public char[] szDevice = new char[32];
+
+ public int dwFlags;
+ }
+
[StructLayout(LayoutKind.Sequential)]
public struct INPUT
{
public InputType Type;
public InputUnion U;
- public static int Size
- {
- get { return Marshal.SizeOf(typeof(INPUT)); }
- }
- }
-
- public enum InputType : uint
- {
- INPUT_MOUSE,
- INPUT_KEYBOARD,
- INPUT_HARDWARE,
+ public static int Size => Marshal.SizeOf(typeof(INPUT));
}
[StructLayout(LayoutKind.Explicit)]
public struct InputUnion
{
- [FieldOffset(0)]
- internal MOUSEINPUT Mi;
- [FieldOffset(0)]
- internal KEYBDINPUT Ki;
- [FieldOffset(0)]
- internal HARDWAREINPUT Hi;
+ [FieldOffset(0)] internal MOUSEINPUT Mi;
+ [FieldOffset(0)] internal KEYBDINPUT Ki;
+ [FieldOffset(0)] internal HARDWAREINPUT Hi;
}
[StructLayout(LayoutKind.Sequential)]
@@ -145,7 +143,7 @@ internal enum MOUSEEVENTF : uint
VIRTUALDESK = 0x4000,
WHEEL = 0x0800,
XDOWN = 0x0080,
- XUP = 0x0100,
+ XUP = 0x0100
}
[StructLayout(LayoutKind.Sequential)]
@@ -164,872 +162,873 @@ internal enum KEYEVENTF : uint
EXTENDEDKEY = 0x0001,
KEYUP = 0x0002,
SCANCODE = 0x0008,
- UNICODE = 0x0004,
+ UNICODE = 0x0004
}
internal enum VirtualKeyShort : short
{
///
- /// Left mouse button
+ /// Left mouse button
///
LBUTTON = 0x01,
///
- /// Right mouse button
+ /// Right mouse button
///
RBUTTON = 0x02,
///
- /// Control-break processing
+ /// Control-break processing
///
CANCEL = 0x03,
///
- /// Middle mouse button (three-button mouse)
+ /// Middle mouse button (three-button mouse)
///
MBUTTON = 0x04,
///
- /// Windows 2000/XP: X1 mouse button
+ /// Windows 2000/XP: X1 mouse button
///
XBUTTON1 = 0x05,
///
- /// Windows 2000/XP: X2 mouse button
+ /// Windows 2000/XP: X2 mouse button
///
XBUTTON2 = 0x06,
///
- /// BACKSPACE key
+ /// BACKSPACE key
///
BACK = 0x08,
///
- /// TAB key
+ /// TAB key
///
TAB = 0x09,
///
- /// CLEAR key
+ /// CLEAR key
///
CLEAR = 0x0C,
///
- /// ENTER key
+ /// ENTER key
///
RETURN = 0x0D,
///
- /// SHIFT key
+ /// SHIFT key
///
SHIFT = 0x10,
///
- /// CTRL key
+ /// CTRL key
///
CONTROL = 0x11,
///
- /// ALT key
+ /// ALT key
///
MENU = 0x12,
///
- /// PAUSE key
+ /// PAUSE key
///
PAUSE = 0x13,
///
- /// CAPS LOCK key
+ /// CAPS LOCK key
///
CAPITAL = 0x14,
///
- /// Input Method Editor (IME) Kana mode
+ /// Input Method Editor (IME) Kana mode
///
KANA = 0x15,
///
- /// IME Hangul mode
+ /// IME Hangul mode
///
HANGUL = 0x15,
///
- /// IME Junja mode
+ /// IME Junja mode
///
JUNJA = 0x17,
///
- /// IME final mode
+ /// IME final mode
///
FINAL = 0x18,
///
- /// IME Hanja mode
+ /// IME Hanja mode
///
HANJA = 0x19,
///
- /// IME Kanji mode
+ /// IME Kanji mode
///
KANJI = 0x19,
///
- /// ESC key
+ /// ESC key
///
ESCAPE = 0x1B,
///
- /// IME convert
+ /// IME convert
///
CONVERT = 0x1C,
///
- /// IME nonconvert
+ /// IME nonconvert
///
NONCONVERT = 0x1D,
///
- /// IME accept
+ /// IME accept
///
ACCEPT = 0x1E,
///
- /// IME mode change request
+ /// IME mode change request
///
MODECHANGE = 0x1F,
///
- /// SPACEBAR
+ /// SPACEBAR
///
SPACE = 0x20,
///
- /// PAGE UP key
+ /// PAGE UP key
///
PRIOR = 0x21,
///
- /// PAGE DOWN key
+ /// PAGE DOWN key
///
NEXT = 0x22,
///
- /// END key
+ /// END key
///
END = 0x23,
///
- /// HOME key
+ /// HOME key
///
HOME = 0x24,
///
- /// LEFT ARROW key
+ /// LEFT ARROW key
///
LEFT = 0x25,
///
- /// UP ARROW key
+ /// UP ARROW key
///
UP = 0x26,
///
- /// RIGHT ARROW key
+ /// RIGHT ARROW key
///
RIGHT = 0x27,
///
- /// DOWN ARROW key
+ /// DOWN ARROW key
///
DOWN = 0x28,
///
- /// SELECT key
+ /// SELECT key
///
SELECT = 0x29,
///
- /// PRINT key
+ /// PRINT key
///
PRINT = 0x2A,
///
- /// EXECUTE key
+ /// EXECUTE key
///
EXECUTE = 0x2B,
///
- /// PRINT SCREEN key
+ /// PRINT SCREEN key
///
SNAPSHOT = 0x2C,
///
- /// INS key
+ /// INS key
///
INSERT = 0x2D,
///
- /// DEL key
+ /// DEL key
///
DELETE = 0x2E,
///
- /// HELP key
+ /// HELP key
///
HELP = 0x2F,
///
- /// 0 key
+ /// 0 key
///
KEY_0 = 0x30,
///
- /// 1 key
+ /// 1 key
///
KEY_1 = 0x31,
///
- /// 2 key
+ /// 2 key
///
KEY_2 = 0x32,
///
- /// 3 key
+ /// 3 key
///
KEY_3 = 0x33,
///
- /// 4 key
+ /// 4 key
///
KEY_4 = 0x34,
///
- /// 5 key
+ /// 5 key
///
KEY_5 = 0x35,
///
- /// 6 key
+ /// 6 key
///
KEY_6 = 0x36,
///
- /// 7 key
+ /// 7 key
///
KEY_7 = 0x37,
///
- /// 8 key
+ /// 8 key
///
KEY_8 = 0x38,
///
- /// 9 key
+ /// 9 key
///
KEY_9 = 0x39,
///
- /// A key
+ /// A key
///
KEY_A = 0x41,
///
- /// B key
+ /// B key
///
KEY_B = 0x42,
///
- /// C key
+ /// C key
///
KEY_C = 0x43,
///
- /// D key
+ /// D key
///
KEY_D = 0x44,
///
- /// E key
+ /// E key
///
KEY_E = 0x45,
///
- /// F key
+ /// F key
///
KEY_F = 0x46,
///
- /// G key
+ /// G key
///
KEY_G = 0x47,
///
- /// H key
+ /// H key
///
KEY_H = 0x48,
///
- /// I key
+ /// I key
///
KEY_I = 0x49,
///
- /// J key
+ /// J key
///
KEY_J = 0x4A,
///
- /// K key
+ /// K key
///
KEY_K = 0x4B,
///
- /// L key
+ /// L key
///
KEY_L = 0x4C,
///
- /// M key
+ /// M key
///
KEY_M = 0x4D,
///
- /// N key
+ /// N key
///
KEY_N = 0x4E,
///
- /// O key
+ /// O key
///
KEY_O = 0x4F,
///
- /// P key
+ /// P key
///
KEY_P = 0x50,
///
- /// Q key
+ /// Q key
///
KEY_Q = 0x51,
///
- /// R key
+ /// R key
///
KEY_R = 0x52,
///
- /// S key
+ /// S key
///
KEY_S = 0x53,
///
- /// T key
+ /// T key
///
KEY_T = 0x54,
///
- /// U key
+ /// U key
///
KEY_U = 0x55,
///
- /// V key
+ /// V key
///
KEY_V = 0x56,
///
- /// W key
+ /// W key
///
KEY_W = 0x57,
///
- /// X key
+ /// X key
///
KEY_X = 0x58,
///
- /// Y key
+ /// Y key
///
KEY_Y = 0x59,
///
- /// Z key
+ /// Z key
///
KEY_Z = 0x5A,
///
- /// Left Windows key (Microsoft Natural keyboard)
+ /// Left Windows key (Microsoft Natural keyboard)
///
LWIN = 0x5B,
///
- /// Right Windows key (Natural keyboard)
+ /// Right Windows key (Natural keyboard)
///
RWIN = 0x5C,
///
- /// Applications key (Natural keyboard)
+ /// Applications key (Natural keyboard)
///
APPS = 0x5D,
///
- /// Computer Sleep key
+ /// Computer Sleep key
///
SLEEP = 0x5F,
///
- /// Numeric keypad 0 key
+ /// Numeric keypad 0 key
///
NUMPAD0 = 0x60,
///
- /// Numeric keypad 1 key
+ /// Numeric keypad 1 key
///
NUMPAD1 = 0x61,
///
- /// Numeric keypad 2 key
+ /// Numeric keypad 2 key
///
NUMPAD2 = 0x62,
///
- /// Numeric keypad 3 key
+ /// Numeric keypad 3 key
///
NUMPAD3 = 0x63,
///
- /// Numeric keypad 4 key
+ /// Numeric keypad 4 key
///
NUMPAD4 = 0x64,
///
- /// Numeric keypad 5 key
+ /// Numeric keypad 5 key
///
NUMPAD5 = 0x65,
///
- /// Numeric keypad 6 key
+ /// Numeric keypad 6 key
///
NUMPAD6 = 0x66,
///
- /// Numeric keypad 7 key
+ /// Numeric keypad 7 key
///
NUMPAD7 = 0x67,
///
- /// Numeric keypad 8 key
+ /// Numeric keypad 8 key
///
NUMPAD8 = 0x68,
///
- /// Numeric keypad 9 key
+ /// Numeric keypad 9 key
///
NUMPAD9 = 0x69,
///
- /// Multiply key
+ /// Multiply key
///
MULTIPLY = 0x6A,
///
- /// Add key
+ /// Add key
///
ADD = 0x6B,
///
- /// Separator key
+ /// Separator key
///
SEPARATOR = 0x6C,
///
- /// Subtract key
+ /// Subtract key
///
SUBTRACT = 0x6D,
///
- /// Decimal key
+ /// Decimal key
///
DECIMAL = 0x6E,
///
- /// Divide key
+ /// Divide key
///
DIVIDE = 0x6F,
///
- /// F1 key
+ /// F1 key
///
F1 = 0x70,
///
- /// F2 key
+ /// F2 key
///
F2 = 0x71,
///
- /// F3 key
+ /// F3 key
///
F3 = 0x72,
///
- /// F4 key
+ /// F4 key
///
F4 = 0x73,
///
- /// F5 key
+ /// F5 key
///
F5 = 0x74,
///
- /// F6 key
+ /// F6 key
///
F6 = 0x75,
///
- /// F7 key
+ /// F7 key
///
F7 = 0x76,
///
- /// F8 key
+ /// F8 key
///
F8 = 0x77,
///
- /// F9 key
+ /// F9 key
///
F9 = 0x78,
///
- /// F10 key
+ /// F10 key
///
F10 = 0x79,
///
- /// F11 key
+ /// F11 key
///
F11 = 0x7A,
///
- /// F12 key
+ /// F12 key
///
F12 = 0x7B,
///
- /// F13 key
+ /// F13 key
///
F13 = 0x7C,
///
- /// F14 key
+ /// F14 key
///
F14 = 0x7D,
///
- /// F15 key
+ /// F15 key
///
F15 = 0x7E,
///
- /// F16 key
+ /// F16 key
///
F16 = 0x7F,
///
- /// F17 key
+ /// F17 key
///
F17 = 0x80,
///
- /// F18 key
+ /// F18 key
///
F18 = 0x81,
///
- /// F19 key
+ /// F19 key
///
F19 = 0x82,
///
- /// F20 key
+ /// F20 key
///
F20 = 0x83,
///
- /// F21 key
+ /// F21 key
///
F21 = 0x84,
///
- /// F22 key, (PPC only) Key used to lock device.
+ /// F22 key, (PPC only) Key used to lock device.
///
F22 = 0x85,
///
- /// F23 key
+ /// F23 key
///
F23 = 0x86,
///
- /// F24 key
+ /// F24 key
///
F24 = 0x87,
///
- /// NUM LOCK key
+ /// NUM LOCK key
///
NUMLOCK = 0x90,
///
- /// SCROLL LOCK key
+ /// SCROLL LOCK key
///
SCROLL = 0x91,
///
- /// Left SHIFT key
+ /// Left SHIFT key
///
LSHIFT = 0xA0,
///
- /// Right SHIFT key
+ /// Right SHIFT key
///
RSHIFT = 0xA1,
///
- /// Left CONTROL key
+ /// Left CONTROL key
///
LCONTROL = 0xA2,
///
- /// Right CONTROL key
+ /// Right CONTROL key
///
RCONTROL = 0xA3,
///
- /// Left MENU key
+ /// Left MENU key
///
LMENU = 0xA4,
///
- /// Right MENU key
+ /// Right MENU key
///
RMENU = 0xA5,
///
- /// Windows 2000/XP: Browser Back key
+ /// Windows 2000/XP: Browser Back key
///
BROWSER_BACK = 0xA6,
///
- /// Windows 2000/XP: Browser Forward key
+ /// Windows 2000/XP: Browser Forward key
///
BROWSER_FORWARD = 0xA7,
///
- /// Windows 2000/XP: Browser Refresh key
+ /// Windows 2000/XP: Browser Refresh key
///
BROWSER_REFRESH = 0xA8,
///
- /// Windows 2000/XP: Browser Stop key
+ /// Windows 2000/XP: Browser Stop key
///
BROWSER_STOP = 0xA9,
///
- /// Windows 2000/XP: Browser Search key
+ /// Windows 2000/XP: Browser Search key
///
BROWSER_SEARCH = 0xAA,
///
- /// Windows 2000/XP: Browser Favorites key
+ /// Windows 2000/XP: Browser Favorites key
///
BROWSER_FAVORITES = 0xAB,
///
- /// Windows 2000/XP: Browser Start and Home key
+ /// Windows 2000/XP: Browser Start and Home key
///
BROWSER_HOME = 0xAC,
///
- /// Windows 2000/XP: Volume Mute key
+ /// Windows 2000/XP: Volume Mute key
///
VOLUME_MUTE = 0xAD,
///
- /// Windows 2000/XP: Volume Down key
+ /// Windows 2000/XP: Volume Down key
///
VOLUME_DOWN = 0xAE,
///
- /// Windows 2000/XP: Volume Up key
+ /// Windows 2000/XP: Volume Up key
///
VOLUME_UP = 0xAF,
///
- /// Windows 2000/XP: Next Track key
+ /// Windows 2000/XP: Next Track key
///
MEDIA_NEXT_TRACK = 0xB0,
///
- /// Windows 2000/XP: Previous Track key
+ /// Windows 2000/XP: Previous Track key
///
MEDIA_PREV_TRACK = 0xB1,
///
- /// Windows 2000/XP: Stop Media key
+ /// Windows 2000/XP: Stop Media key
///
MEDIA_STOP = 0xB2,
///
- /// Windows 2000/XP: Play/Pause Media key
+ /// Windows 2000/XP: Play/Pause Media key
///
MEDIA_PLAY_PAUSE = 0xB3,
///
- /// Windows 2000/XP: Start Mail key
+ /// Windows 2000/XP: Start Mail key
///
LAUNCH_MAIL = 0xB4,
///
- /// Windows 2000/XP: Select Media key
+ /// Windows 2000/XP: Select Media key
///
LAUNCH_MEDIA_SELECT = 0xB5,
///
- /// Windows 2000/XP: Start Application 1 key
+ /// Windows 2000/XP: Start Application 1 key
///
LAUNCH_APP1 = 0xB6,
///
- /// Windows 2000/XP: Start Application 2 key
+ /// Windows 2000/XP: Start Application 2 key
///
LAUNCH_APP2 = 0xB7,
///
- /// Used for miscellaneous characters; it can vary by keyboard.
+ /// Used for miscellaneous characters; it can vary by keyboard.
///
OEM_1 = 0xBA,
///
- /// Windows 2000/XP: For any country/region, the '+' key
+ /// Windows 2000/XP: For any country/region, the '+' key
///
OEM_PLUS = 0xBB,
///
- /// Windows 2000/XP: For any country/region, the ',' key
+ /// Windows 2000/XP: For any country/region, the ',' key
///
OEM_COMMA = 0xBC,
///
- /// Windows 2000/XP: For any country/region, the '-' key
+ /// Windows 2000/XP: For any country/region, the '-' key
///
OEM_MINUS = 0xBD,
///
- /// Windows 2000/XP: For any country/region, the '.' key
+ /// Windows 2000/XP: For any country/region, the '.' key
///
OEM_PERIOD = 0xBE,
///
- /// Used for miscellaneous characters; it can vary by keyboard.
+ /// Used for miscellaneous characters; it can vary by keyboard.
///
OEM_2 = 0xBF,
///
- /// Used for miscellaneous characters; it can vary by keyboard.
+ /// Used for miscellaneous characters; it can vary by keyboard.
///
OEM_3 = 0xC0,
///
- /// Used for miscellaneous characters; it can vary by keyboard.
+ /// Used for miscellaneous characters; it can vary by keyboard.
///
OEM_4 = 0xDB,
///
- /// Used for miscellaneous characters; it can vary by keyboard.
+ /// Used for miscellaneous characters; it can vary by keyboard.
///
OEM_5 = 0xDC,
///
- /// Used for miscellaneous characters; it can vary by keyboard.
+ /// Used for miscellaneous characters; it can vary by keyboard.
///
OEM_6 = 0xDD,
///
- /// Used for miscellaneous characters; it can vary by keyboard.
+ /// Used for miscellaneous characters; it can vary by keyboard.
///
OEM_7 = 0xDE,
///
- /// Used for miscellaneous characters; it can vary by keyboard.
+ /// Used for miscellaneous characters; it can vary by keyboard.
///
OEM_8 = 0xDF,
///
- /// Windows 2000/XP: Either the angle bracket key or the backslash key on the RT 102-key keyboard
+ /// Windows 2000/XP: Either the angle bracket key or the backslash key on the RT 102-key keyboard
///
OEM_102 = 0xE2,
///
- /// Windows 95/98/Me, Windows NT 4.0, Windows 2000/XP: IME PROCESS key
+ /// Windows 95/98/Me, Windows NT 4.0, Windows 2000/XP: IME PROCESS key
///
PROCESSKEY = 0xE5,
///
- /// Windows 2000/XP: Used to pass Unicode characters as if they were keystrokes.
- /// The VK_PACKET key is the low word of a 32-bit Virtual Key value used for non-keyboard input methods. For more information,
- /// see Remark in KEYBDINPUT, SendInput, WM_KEYDOWN, and WM_KEYUP
+ /// Windows 2000/XP: Used to pass Unicode characters as if they were keystrokes.
+ /// The VK_PACKET key is the low word of a 32-bit Virtual Key value used for non-keyboard input methods. For more
+ /// information,
+ /// see Remark in KEYBDINPUT, SendInput, WM_KEYDOWN, and WM_KEYUP
///
PACKET = 0xE7,
///
- /// Attn key
+ /// Attn key
///
ATTN = 0xF6,
///
- /// CrSel key
+ /// CrSel key
///
CRSEL = 0xF7,
///
- /// ExSel key
+ /// ExSel key
///
EXSEL = 0xF8,
///
- /// Erase EOF key
+ /// Erase EOF key
///
EREOF = 0xF9,
///
- /// Play key
+ /// Play key
///
PLAY = 0xFA,
///
- /// Zoom key
+ /// Zoom key
///
ZOOM = 0xFB,
///
- /// Reserved
+ /// Reserved
///
NONAME = 0xFC,
///
- /// PA1 key
+ /// PA1 key
///
PA1 = 0xFD,
///
- /// Clear key
+ /// Clear key
///
- OEM_CLEAR = 0xFE,
+ OEM_CLEAR = 0xFE
}
internal enum ScanCodeShort : short
@@ -1205,7 +1204,7 @@ internal enum ScanCodeShort : short
ZOOM = 98,
NONAME = 0,
PA1 = 0,
- OEM_CLEAR = 0,
+ OEM_CLEAR = 0
}
[StructLayout(LayoutKind.Sequential)]
@@ -1220,27 +1219,30 @@ internal struct HARDWAREINPUT
internal struct LowLevelKeyboardInputEvent
{
///
- /// A virtual-key code. The code must be a value in the range 1 to 254.
+ /// A virtual-key code. The code must be a value in the range 1 to 254.
///
public int VirtualCode;
///
- /// A hardware scan code for the key.
+ /// A hardware scan code for the key.
///
public int HardwareScanCode;
///
- /// The extended-key flag, event-injected Flags, context code, and transition-state flag. This member is specified as follows. An application can use the following values to test the keystroke Flags. Testing LLKHF_INJECTED (bit 4) will tell you whether the event was injected. If it was, then testing LLKHF_LOWER_IL_INJECTED (bit 1) will tell you whether or not the event was injected from a process running at lower integrity level.
+ /// The extended-key flag, event-injected Flags, context code, and transition-state flag. This member is specified as
+ /// follows. An application can use the following values to test the keystroke Flags. Testing LLKHF_INJECTED (bit 4)
+ /// will tell you whether the event was injected. If it was, then testing LLKHF_LOWER_IL_INJECTED (bit 1) will tell you
+ /// whether or not the event was injected from a process running at lower integrity level.
///
public int Flags;
///
- /// The time stamp for this message, equivalent to what GetMessageTime would return for this message.
+ /// The time stamp for this message, equivalent to what GetMessageTime would return for this message.
///
public int TimeStamp;
///
- /// Additional information associated with the message.
+ /// Additional information associated with the message.
///
public IntPtr AdditionalInformation;
}
diff --git a/src/ScreenGrab/ScreenGrab.csproj b/src/ScreenGrab/ScreenGrab.csproj
index 96df6cc..bb4e439 100644
--- a/src/ScreenGrab/ScreenGrab.csproj
+++ b/src/ScreenGrab/ScreenGrab.csproj
@@ -7,7 +7,7 @@
-
+
diff --git a/src/ScreenGrab/ScreenGrabView.xaml b/src/ScreenGrab/ScreenGrabView.xaml
new file mode 100644
index 0000000..141a740
--- /dev/null
+++ b/src/ScreenGrab/ScreenGrabView.xaml
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/ScreenGrab/ScreenGrabView.xaml.cs b/src/ScreenGrab/ScreenGrabView.xaml.cs
new file mode 100644
index 0000000..2b3dd6a
--- /dev/null
+++ b/src/ScreenGrab/ScreenGrabView.xaml.cs
@@ -0,0 +1,314 @@
+using System.Drawing;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Input;
+using System.Windows.Media;
+using Dapplo.Windows.User32;
+using ScreenGrab.Extensions;
+using ScreenGrab.Utilities;
+using Color = System.Windows.Media.Color;
+using Point = System.Windows.Point;
+using Size = System.Windows.Size;
+
+namespace ScreenGrab;
+
+public partial class ScreenGrabView
+{
+ #region Constructors
+
+ public ScreenGrabView(Action? action)
+ {
+ InitializeComponent();
+ _onImageCaptured = action;
+ }
+
+ #endregion Constructors
+
+ #region Properties
+
+ private DisplayInfo? CurrentScreen { get; set; }
+
+ #endregion Properties
+
+ #region Fields
+
+ private Point _clickedPoint;
+ private DpiScale? _dpiScale;
+ private bool _isSelecting;
+ private bool _isShiftDown;
+ private readonly Border _selectBorder = new();
+ private double _selectLeft;
+ private double _selectTop;
+ private Point _shiftPoint;
+ private double _xShiftDelta;
+ private double _yShiftDelta;
+
+ private readonly Action? _onImageCaptured;
+
+ #endregion Fields
+
+ #region Window Events
+
+ private void SetImageToBackground()
+ {
+ BackgroundImage.Source = null;
+ BackgroundImage.Source = ImageMethods.GetWindowBoundsImage(this);
+ BackgroundBrush.Opacity = 0.2;
+ }
+
+ private async void FreezeUnfreeze()
+ {
+ if (BackgroundImage.Source == null)
+ {
+ BackgroundBrush.Opacity = 0;
+ await Task.Delay(150);
+ SetImageToBackground();
+ }
+ else
+ {
+ BackgroundImage.Source = null;
+ }
+ }
+
+ private void CloseAllFullscreenGrabs()
+ {
+ foreach (var window in Application.Current.Windows)
+ if (window is ScreenGrabView sgv)
+ sgv.Close();
+ }
+
+ private void FreezeUnfreezeAllScreenGrabs()
+ {
+
+ foreach (var window in Application.Current.Windows)
+ if (window is ScreenGrabView sgv)
+ sgv.FreezeUnfreeze();
+ }
+
+ private void ScreenGrab_KeyDown(object sender, KeyEventArgs e)
+ {
+ switch (e.Key)
+ {
+ case Key.Escape:
+ CloseAllFullscreenGrabs();
+ break;
+ case Key.F:
+ FreezeUnfreezeAllScreenGrabs();
+ break;
+ }
+ }
+
+ private void ScreenGrab_KeyUp(object sender, KeyEventArgs e)
+ {
+ switch (e.Key)
+ {
+ case Key.LeftShift:
+ case Key.RightShift:
+ _isShiftDown = false;
+ _clickedPoint = new Point(_clickedPoint.X + _xShiftDelta, _clickedPoint.Y + _yShiftDelta);
+ break;
+ }
+ }
+
+ private void Window_Closed(object? sender, EventArgs e)
+ {
+ Close();
+
+ GC.Collect();
+ }
+
+ private void Window_Loaded(object sender, RoutedEventArgs e)
+ {
+ WindowState = WindowState.Maximized;
+ FullWindow.Rect = new Rect(0, 0, Width, Height);
+ KeyDown += ScreenGrab_KeyDown;
+ KeyUp += ScreenGrab_KeyUp;
+
+ SetImageToBackground();
+
+#if DEBUG
+ Topmost = false;
+#endif
+ }
+
+ private void Window_Unloaded(object sender, RoutedEventArgs e)
+ {
+ BackgroundImage.Source = null;
+ BackgroundImage.UpdateLayout();
+ CurrentScreen = null;
+ _dpiScale = null;
+
+ Loaded -= Window_Loaded;
+ Unloaded -= Window_Unloaded;
+
+ RegionClickCanvas.MouseDown -= RegionClickCanvas_MouseDown;
+ RegionClickCanvas.MouseMove -= RegionClickCanvas_MouseMove;
+ RegionClickCanvas.MouseUp -= RegionClickCanvas_MouseUp;
+
+ KeyDown -= ScreenGrab_KeyDown;
+ KeyUp -= ScreenGrab_KeyUp;
+ }
+
+ #endregion
+
+ #region Mouse Events
+
+ private void RegionClickCanvas_MouseDown(object sender, MouseButtonEventArgs e)
+ {
+ // Right click to close
+ if (e.RightButton == MouseButtonState.Pressed)
+ {
+ CloseAllFullscreenGrabs();
+ return;
+ }
+
+ _isSelecting = true;
+ RegionClickCanvas.CaptureMouse();
+ CursorClipper.ClipCursor(this);
+ _clickedPoint = e.GetPosition(this);
+ _selectBorder.Height = 1;
+ _selectBorder.Width = 1;
+
+ _dpiScale = VisualTreeHelper.GetDpi(this);
+
+ try
+ {
+ RegionClickCanvas.Children.Remove(_selectBorder);
+ }
+ catch (Exception)
+ {
+ // ignored
+ }
+
+ _selectBorder.BorderThickness = new Thickness(2);
+ var borderColor = Color.FromArgb(255, 175, 103, 193);
+ _selectBorder.BorderBrush = new SolidColorBrush(borderColor);
+ _ = RegionClickCanvas.Children.Add(_selectBorder);
+ Canvas.SetLeft(_selectBorder, _clickedPoint.X);
+ Canvas.SetTop(_selectBorder, _clickedPoint.Y);
+
+ DisplayInfo[] screens = DisplayInfo.AllDisplayInfos;
+ Point formsPoint = new((int)_clickedPoint.X, (int)_clickedPoint.Y);
+ foreach (var scr in screens)
+ {
+ var bound = scr.ScaledBounds();
+ if (bound.Contains(formsPoint))
+ CurrentScreen = scr;
+ }
+ }
+
+ private void RegionClickCanvas_MouseMove(object sender, MouseEventArgs e)
+ {
+ if (!_isSelecting)
+ return;
+
+ var movingPoint = e.GetPosition(this);
+
+ if (Keyboard.Modifiers == ModifierKeys.Shift)
+ {
+ PanSelection(movingPoint);
+ return;
+ }
+
+ _isShiftDown = false;
+
+ var left = Math.Min(_clickedPoint.X, movingPoint.X);
+ var top = Math.Min(_clickedPoint.Y, movingPoint.Y);
+
+ _selectBorder.Height = Math.Max(_clickedPoint.Y, movingPoint.Y) - top;
+ _selectBorder.Width = Math.Max(_clickedPoint.X, movingPoint.X) - left;
+ _selectBorder.Height += 2;
+ _selectBorder.Width += 2;
+
+ ClippingGeometry.Rect = new Rect(
+ new Point(left, top),
+ new Size(_selectBorder.Width - 2, _selectBorder.Height - 2));
+ Canvas.SetLeft(_selectBorder, left - 1);
+ Canvas.SetTop(_selectBorder, top - 1);
+ }
+
+ private void RegionClickCanvas_MouseUp(object sender, MouseButtonEventArgs e)
+ {
+ if (!_isSelecting)
+ return;
+
+ _isSelecting = false;
+ CurrentScreen = null;
+ CursorClipper.UnClipCursor();
+ RegionClickCanvas.ReleaseMouseCapture();
+ ClippingGeometry.Rect = new Rect(new Point(0, 0), new Size(0, 0));
+
+ var movingPoint = e.GetPosition(this);
+ var m = PresentationSource.FromVisual(this)!.CompositionTarget!.TransformToDevice;
+ movingPoint.X *= m.M11;
+ movingPoint.Y *= m.M22;
+
+ movingPoint.X = Math.Round(movingPoint.X);
+ movingPoint.Y = Math.Round(movingPoint.Y);
+
+ var xDimScaled = Canvas.GetLeft(_selectBorder) * m.M11;
+ var yDimScaled = Canvas.GetTop(_selectBorder) * m.M22;
+
+ Rectangle regionScaled = new(
+ (int)xDimScaled,
+ (int)yDimScaled,
+ (int)(_selectBorder.Width * m.M11),
+ (int)(_selectBorder.Height * m.M22));
+
+ try
+ {
+ RegionClickCanvas.Children.Remove(_selectBorder);
+ }
+ catch
+ {
+ // ignored
+ }
+
+ var absPosPoint = this.GetAbsolutePosition();
+
+ var thisCorrectedLeft = (int)absPosPoint.X + regionScaled.Left;
+ var thisCorrectedTop = (int)absPosPoint.Y + regionScaled.Top;
+
+ Rectangle correctedRegion = new(thisCorrectedLeft, thisCorrectedTop, regionScaled.Width, regionScaled.Height);
+ var bitmap = correctedRegion.GetRegionOfScreenAsBitmap();
+ _onImageCaptured?.Invoke(bitmap);
+
+ CloseAllFullscreenGrabs();
+ }
+
+ private void PanSelection(Point movingPoint)
+ {
+ if (!_isShiftDown)
+ {
+ _shiftPoint = movingPoint;
+ _selectLeft = Canvas.GetLeft(_selectBorder);
+ _selectTop = Canvas.GetTop(_selectBorder);
+ }
+
+ _isShiftDown = true;
+ _xShiftDelta = movingPoint.X - _shiftPoint.X;
+ _yShiftDelta = movingPoint.Y - _shiftPoint.Y;
+
+ var leftValue = _selectLeft + _xShiftDelta;
+ var topValue = _selectTop + _yShiftDelta;
+
+ if (CurrentScreen is not null && _dpiScale is not null)
+ {
+ double currentScreenLeft = CurrentScreen.Bounds.Left; // Should always be 0
+ var currentScreenRight = CurrentScreen.Bounds.Right / _dpiScale.Value.DpiScaleX;
+ double currentScreenTop = CurrentScreen.Bounds.Top; // Should always be 0
+ var currentScreenBottom = CurrentScreen.Bounds.Bottom / _dpiScale.Value.DpiScaleY;
+
+ leftValue = Math.Clamp(leftValue, currentScreenLeft, currentScreenRight - _selectBorder.Width);
+ topValue = Math.Clamp(topValue, currentScreenTop, currentScreenBottom - _selectBorder.Height);
+ }
+
+ ClippingGeometry.Rect = new Rect(
+ new Point(leftValue, topValue),
+ new Size(_selectBorder.Width - 2, _selectBorder.Height - 2));
+ Canvas.SetLeft(_selectBorder, leftValue - 1);
+ Canvas.SetTop(_selectBorder, topValue - 1);
+ }
+
+ #endregion
+}
\ No newline at end of file
diff --git a/src/ScreenGrab/Utilities/CursorClipper.cs b/src/ScreenGrab/Utilities/CursorClipper.cs
index 959e0b9..fb7357f 100644
--- a/src/ScreenGrab/Utilities/CursorClipper.cs
+++ b/src/ScreenGrab/Utilities/CursorClipper.cs
@@ -3,12 +3,12 @@
namespace ScreenGrab.Utilities;
///
-/// Functions to constrain the mouse cursor (typically used when dragging)
+/// Functions to constrain the mouse cursor (typically used when dragging)
///
public static class CursorClipper
{
///
- /// Constrain mouse cursor to the area of the specified UI element.
+ /// Constrain mouse cursor to the area of the specified UI element.
///
/// Target UI element.
/// True on success.
@@ -18,19 +18,16 @@ public static bool ClipCursor(FrameworkElement element)
var topLeft = element.PointToScreen(new Point(0, 0));
- PresentationSource source = PresentationSource.FromVisual(element);
- if (source?.CompositionTarget == null)
- {
- return false;
- }
+ var source = PresentationSource.FromVisual(element);
+ if (source?.CompositionTarget == null) return false;
- double dpiX = dpi96 * source.CompositionTarget.TransformToDevice.M11;
- double dpiY = dpi96 * source.CompositionTarget.TransformToDevice.M22;
+ var dpiX = dpi96 * source.CompositionTarget.TransformToDevice.M11;
+ var dpiY = dpi96 * source.CompositionTarget.TransformToDevice.M22;
var width = (int)((element.ActualWidth + 1) * dpiX / dpi96);
var height = (int)((element.ActualHeight + 1) * dpiY / dpi96);
- OSInterop.RECT rect = new OSInterop.RECT
+ var rect = new OSInterop.RECT
{
left = (int)topLeft.X,
top = (int)topLeft.Y,
@@ -42,7 +39,7 @@ public static bool ClipCursor(FrameworkElement element)
}
///
- /// Remove any mouse cursor constraint.
+ /// Remove any mouse cursor constraint.
///
/// True on success.
public static bool UnClipCursor()
diff --git a/src/ScreenGrab/Utilities/ImageMethods.cs b/src/ScreenGrab/Utilities/ImageMethods.cs
index 9423df6..ec69970 100644
--- a/src/ScreenGrab/Utilities/ImageMethods.cs
+++ b/src/ScreenGrab/Utilities/ImageMethods.cs
@@ -5,37 +5,39 @@
using System.Windows.Media;
using System.Windows.Media.Imaging;
using ScreenGrab.Extensions;
+using PixelFormat = System.Drawing.Imaging.PixelFormat;
namespace ScreenGrab.Utilities;
public static class ImageMethods
{
- public static ImageSource GetWindowBoundsImage(Window passedWindow)
+ public static ImageSource? GetWindowBoundsImage(Window passedWindow)
{
- Bitmap bmp = GetWindowsBoundsBitmap(passedWindow);
- return BitmapToImageSource(bmp);
+ var bmp = passedWindow.GetWindowsBoundsBitmap();
+ return bmp.ToImageSource();
}
- public static Bitmap GetWindowsBoundsBitmap(Window passedWindow)
+ public static Bitmap GetWindowsBoundsBitmap(this Window passedWindow)
{
- DpiScale dpi = VisualTreeHelper.GetDpi(passedWindow);
- int windowWidth = (int)(passedWindow.ActualWidth * dpi.DpiScaleX);
- int windowHeight = (int)(passedWindow.ActualHeight * dpi.DpiScaleY);
+ var dpi = VisualTreeHelper.GetDpi(passedWindow);
+ var windowWidth = (int)(passedWindow.ActualWidth * dpi.DpiScaleX);
+ var windowHeight = (int)(passedWindow.ActualHeight * dpi.DpiScaleY);
var absPosPoint = passedWindow.GetAbsolutePosition();
- int thisCorrectedLeft = (int)(absPosPoint.X);
- int thisCorrectedTop = (int)(absPosPoint.Y);
+ var thisCorrectedLeft = (int)absPosPoint.X;
+ var thisCorrectedTop = (int)absPosPoint.Y;
- Bitmap bmp = new(windowWidth, windowHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
- using Graphics g = Graphics.FromImage(bmp);
+ Bitmap bmp = new(windowWidth, windowHeight, PixelFormat.Format32bppArgb);
+ using var g = Graphics.FromImage(bmp);
g.CopyFromScreen(thisCorrectedLeft, thisCorrectedTop, 0, 0, bmp.Size, CopyPixelOperation.SourceCopy);
return bmp;
}
- public static BitmapImage BitmapToImageSource(Bitmap bitmap)
+ public static BitmapImage? ToImageSource(this Bitmap? bitmap)
{
+ if (bitmap == null) return default;
using MemoryStream memory = new();
using WrappingStream wrapper = new(memory);
@@ -54,20 +56,19 @@ public static BitmapImage BitmapToImageSource(Bitmap bitmap)
return bitmapImage;
}
-
- public static Bitmap GetRegionOfScreenAsBitmap(Rectangle region)
+
+ public static Bitmap GetRegionOfScreenAsBitmap(this Rectangle region)
{
- Bitmap bmp = new(region.Width, region.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
+ Bitmap bmp = new(region.Width, region.Height, PixelFormat.Format32bppArgb);
using var g = Graphics.FromImage(bmp);
g.CopyFromScreen(region.Left, region.Top, 0, 0, bmp.Size, CopyPixelOperation.SourceCopy);
- bmp = PadImage(bmp);
+ bmp = bmp.PadImage();
- // Singleton.Instance.CacheLastBitmap(bmp);
return bmp;
}
-
- public static Bitmap PadImage(Bitmap image, int minW = 64, int minH = 64)
+
+ public static Bitmap PadImage(this Bitmap image, int minW = 64, int minH = 64)
{
if (image.Height >= minH && image.Width >= minW)
return image;
diff --git a/src/ScreenGrab/Utilities/WrappingStream.cs b/src/ScreenGrab/Utilities/WrappingStream.cs
index c687d27..0b47528 100644
--- a/src/ScreenGrab/Utilities/WrappingStream.cs
+++ b/src/ScreenGrab/Utilities/WrappingStream.cs
@@ -4,14 +4,16 @@
namespace ScreenGrab.Utilities;
///
-/// A that wraps another stream. The major feature of is that it does not dispose the
-/// underlying stream when it is disposed; this is useful when using classes such as and
-/// that take ownership of the stream passed to their constructors.
+/// A that wraps another stream. The major feature of is that it
+/// does not dispose the
+/// underlying stream when it is disposed; this is useful when using classes such as and
+/// that take ownership of the stream passed to their
+/// constructors.
///
public class WrappingStream : Stream
{
///
- /// Initializes a new instance of the class.
+ /// Initializes a new instance of the class.
///
/// The wrapped stream.
public WrappingStream(Stream streamBase)
@@ -20,229 +22,223 @@ public WrappingStream(Stream streamBase)
if (streamBase == null)
throw new ArgumentNullException("streamBase");
- m_streamBase = streamBase;
+ WrappedStream = streamBase;
}
///
- /// Gets a value indicating whether the current stream supports reading.
+ /// Gets a value indicating whether the current stream supports reading.
///
/// true if the stream supports reading; otherwise, false.
- public override bool CanRead
- {
- get { return m_streamBase == null ? false : m_streamBase.CanRead; }
- }
+ public override bool CanRead => WrappedStream == null ? false : WrappedStream.CanRead;
///
- /// Gets a value indicating whether the current stream supports seeking.
+ /// Gets a value indicating whether the current stream supports seeking.
///
/// true if the stream supports seeking; otherwise, false.
- public override bool CanSeek
- {
- get { return m_streamBase == null ? false : m_streamBase.CanSeek; }
- }
+ public override bool CanSeek => WrappedStream == null ? false : WrappedStream.CanSeek;
///
- /// Gets a value indicating whether the current stream supports writing.
+ /// Gets a value indicating whether the current stream supports writing.
///
/// true if the stream supports writing; otherwise, false.
- public override bool CanWrite
- {
- get { return m_streamBase == null ? false : m_streamBase.CanWrite; }
- }
+ public override bool CanWrite => WrappedStream == null ? false : WrappedStream.CanWrite;
///
- /// Gets the length in bytes of the stream.
+ /// Gets the length in bytes of the stream.
///
public override long Length
{
get
{
ThrowIfDisposed();
- if (m_streamBase is not null)
- return m_streamBase.Length;
+ if (WrappedStream is not null)
+ return WrappedStream.Length;
return 0;
}
}
///
- /// Gets or sets the position within the current stream.
+ /// Gets or sets the position within the current stream.
///
public override long Position
{
get
{
ThrowIfDisposed();
- if (m_streamBase is not null)
- return m_streamBase.Position;
+ if (WrappedStream is not null)
+ return WrappedStream.Position;
return 0;
}
set
{
ThrowIfDisposed();
- if (m_streamBase is not null)
- m_streamBase.Position = value;
+ if (WrappedStream is not null)
+ WrappedStream.Position = value;
}
}
///
- /// Begins an asynchronous read operation.
+ /// Gets the wrapped stream.
+ ///
+ /// The wrapped stream.
+ protected Stream? WrappedStream { get; private set; }
+
+ ///
+ /// Begins an asynchronous read operation.
///
public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state)
{
ThrowIfDisposed();
- if (m_streamBase is not null && callback is not null && state is not null)
- return m_streamBase.BeginRead(buffer, offset, count, callback, state);
+ if (WrappedStream is not null && callback is not null && state is not null)
+ return WrappedStream.BeginRead(buffer, offset, count, callback, state);
return new NullAsyncResult();
}
///
- /// Begins an asynchronous write operation.
+ /// Begins an asynchronous write operation.
///
- public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state)
+ public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback? callback,
+ object? state)
{
ThrowIfDisposed();
- if (m_streamBase is not null && callback is not null && state is not null)
- return m_streamBase.BeginWrite(buffer, offset, count, callback, state);
+ if (WrappedStream is not null && callback is not null && state is not null)
+ return WrappedStream.BeginWrite(buffer, offset, count, callback, state);
return new NullAsyncResult();
}
///
- /// Waits for the pending asynchronous read to complete.
+ /// Waits for the pending asynchronous read to complete.
///
public override int EndRead(IAsyncResult asyncResult)
{
ThrowIfDisposed();
- if (m_streamBase is not null)
- return m_streamBase.EndRead(asyncResult);
+ if (WrappedStream is not null)
+ return WrappedStream.EndRead(asyncResult);
return 0;
}
///
- /// Ends an asynchronous write operation.
+ /// Ends an asynchronous write operation.
///
public override void EndWrite(IAsyncResult asyncResult)
{
ThrowIfDisposed();
- if (m_streamBase is not null)
- m_streamBase.EndWrite(asyncResult);
+ if (WrappedStream is not null)
+ WrappedStream.EndWrite(asyncResult);
}
///
- /// Clears all buffers for this stream and causes any buffered data to be written to the underlying device.
+ /// Clears all buffers for this stream and causes any buffered data to be written to the underlying device.
///
public override void Flush()
{
ThrowIfDisposed();
- if (m_streamBase is not null)
- m_streamBase.Flush();
+ if (WrappedStream is not null)
+ WrappedStream.Flush();
}
///
- /// Reads a sequence of bytes from the current stream and advances the position
- /// within the stream by the number of bytes read.
+ /// Reads a sequence of bytes from the current stream and advances the position
+ /// within the stream by the number of bytes read.
///
public override int Read(byte[] buffer, int offset, int count)
{
ThrowIfDisposed();
- if (m_streamBase is not null)
- return m_streamBase.Read(buffer, offset, count);
- else
- return 0;
+ if (WrappedStream is not null)
+ return WrappedStream.Read(buffer, offset, count);
+ return 0;
}
///
- /// Reads a byte from the stream and advances the position within the stream by one byte, or returns -1 if at the end of the stream.
+ /// Reads a byte from the stream and advances the position within the stream by one byte, or returns -1 if at the end
+ /// of the stream.
///
public override int ReadByte()
{
ThrowIfDisposed();
- if (m_streamBase is not null)
- return m_streamBase.ReadByte();
- else
- return 0;
+ if (WrappedStream is not null)
+ return WrappedStream.ReadByte();
+ return 0;
}
///
- /// Sets the position within the current stream.
+ /// Sets the position within the current stream.
///
- /// A byte offset relative to the parameter.
- /// A value of type indicating the reference point used to obtain the new position.
+ /// A byte offset relative to the parameter.
+ ///
+ /// A value of type indicating the reference point used to
+ /// obtain the new position.
+ ///
/// The new position within the current stream.
public override long Seek(long offset, SeekOrigin origin)
{
ThrowIfDisposed();
- if (m_streamBase is not null)
- return m_streamBase.Seek(offset, origin);
- else
- return 0;
+ if (WrappedStream is not null)
+ return WrappedStream.Seek(offset, origin);
+ return 0;
}
///
- /// Sets the length of the current stream.
+ /// Sets the length of the current stream.
///
/// The desired length of the current stream in bytes.
public override void SetLength(long value)
{
ThrowIfDisposed();
- if (m_streamBase is not null)
- m_streamBase.SetLength(value);
+ if (WrappedStream is not null)
+ WrappedStream.SetLength(value);
}
///
- /// Writes a sequence of bytes to the current stream and advances the current position
- /// within this stream by the number of bytes written.
+ /// Writes a sequence of bytes to the current stream and advances the current position
+ /// within this stream by the number of bytes written.
///
public override void Write(byte[] buffer, int offset, int count)
{
ThrowIfDisposed();
- if (m_streamBase is not null)
- m_streamBase.Write(buffer, offset, count);
+ if (WrappedStream is not null)
+ WrappedStream.Write(buffer, offset, count);
}
///
- /// Writes a byte to the current position in the stream and advances the position within the stream by one byte.
+ /// Writes a byte to the current position in the stream and advances the position within the stream by one byte.
///
public override void WriteByte(byte value)
{
ThrowIfDisposed();
- if (m_streamBase is not null)
- m_streamBase.WriteByte(value);
- }
-
- ///
- /// Gets the wrapped stream.
- ///
- /// The wrapped stream.
- protected Stream? WrappedStream
- {
- get { return m_streamBase; }
+ if (WrappedStream is not null)
+ WrappedStream.WriteByte(value);
}
///
- /// Releases the unmanaged resources used by the and optionally releases the managed resources.
+ /// Releases the unmanaged resources used by the and optionally releases the managed
+ /// resources.
///
- /// true to release both managed and unmanaged resources; false to release only unmanaged resources.
+ ///
+ /// true to release both managed and unmanaged resources; false to release only unmanaged
+ /// resources.
+ ///
protected override void Dispose(bool disposing)
{
// doesn't close the base stream, but just prevents access to it through this WrappingStream
if (disposing)
- m_streamBase = null;
+ WrappedStream = null;
base.Dispose(disposing);
}
@@ -250,8 +246,7 @@ private void ThrowIfDisposed()
{
// throws an ObjectDisposedException if this object has been disposed
- if (m_streamBase == null)
+ if (WrappedStream == null)
throw new ObjectDisposedException(GetType().Name);
}
- Stream? m_streamBase;
}
\ No newline at end of file
diff --git a/tests/ScreenGrab.Sample/MainWindow.xaml.cs b/tests/ScreenGrab.Sample/MainWindow.xaml.cs
index 2c9df59..ee917a9 100644
--- a/tests/ScreenGrab.Sample/MainWindow.xaml.cs
+++ b/tests/ScreenGrab.Sample/MainWindow.xaml.cs
@@ -1,6 +1,4 @@
using System.Windows;
-using Dapplo.Windows.User32;
-using ScreenGrab.Extensions;
using ScreenGrab.Utilities;
namespace ScreenGrab.Sample;
@@ -19,58 +17,11 @@ private void Capture_Click(object sender, RoutedEventArgs e)
{
Clean();
- NewScreenGrab();
-
- // var view = new Grab();
- // if (view.ShowDialog() == true)
- // {
- // var result = view.Image;
- // Img.Source = ImageMethods.BitmapToImageSource(result);
- // }
- }
-
- private void NewScreenGrab()
- {
- DisplayInfo[] allScreens = DisplayInfo.AllDisplayInfos;
- WindowCollection allWindows = Application.Current.Windows;
-
- List allFullscreenGrab = new();
-
- int numberOfScreens = allScreens.Count();
-
- foreach (Window window in allWindows)
- if (window is Grab grab)
- allFullscreenGrab.Add(grab);
-
- int numberOfFullscreenGrabWindowsToCreate = numberOfScreens - allFullscreenGrab.Count;
-
- for (int i = 0; i < numberOfFullscreenGrabWindowsToCreate; i++)
+ var grab = new Grab
{
- allFullscreenGrab.Add(new Grab());
- }
-
- int count = 0;
-
- double sideLength = 40;
-
- foreach (DisplayInfo screen in allScreens)
- {
- Grab fullScreenGrab = allFullscreenGrab[count];
- fullScreenGrab.WindowStartupLocation = WindowStartupLocation.Manual;
- fullScreenGrab.Width = sideLength;
- fullScreenGrab.Height = sideLength;
- fullScreenGrab.WindowState = WindowState.Normal;
-
- Point screenCenterPoint = screen.ScaledCenterPoint();
-
- fullScreenGrab.Left = screenCenterPoint.X - (sideLength / 2);
- fullScreenGrab.Top = screenCenterPoint.Y - (sideLength / 2);
-
- fullScreenGrab.Show();
- fullScreenGrab.Activate();
-
- count++;
- }
+ OnImageCaptured = bitmap => Img.Source = bitmap.ToImageSource()
+ };
+ grab.Capture();
}
private void Clean_Click(object sender, RoutedEventArgs e)