chore: import upstream snapshot with attribution
Spell checking / Check Spelling (push) Has been cancelled
Spell checking / Update PR (push) Has been cancelled
Publish Dev Docs Website / build (push) Failing after 1s
Publish Dev Docs Website / deploy (push) Has been skipped
Spell checking / Report (Push) (push) Has been cancelled
Spell checking / Report (PR) (push) Has been cancelled
Spell checking / Check Spelling (push) Has been cancelled
Spell checking / Update PR (push) Has been cancelled
Publish Dev Docs Website / build (push) Failing after 1s
Publish Dev Docs Website / deploy (push) Has been skipped
Spell checking / Report (Push) (push) Has been cancelled
Spell checking / Report (PR) (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Globalization;
|
||||
|
||||
namespace MouseJump.Common.Helpers;
|
||||
|
||||
public static class ConfigHelper
|
||||
{
|
||||
public static Color? ToUnnamedColor(Color? value)
|
||||
{
|
||||
if (!value.HasValue)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var color = value.Value;
|
||||
return Color.FromArgb(color.A, color.R, color.G, color.B);
|
||||
}
|
||||
|
||||
public static string? SerializeToConfigColorString(Color? value)
|
||||
{
|
||||
if (!value.HasValue)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var color = value.Value;
|
||||
return color switch
|
||||
{
|
||||
Color { IsNamedColor: true } =>
|
||||
$"{nameof(Color)}.{color.Name}",
|
||||
Color { IsSystemColor: true } =>
|
||||
$"{nameof(SystemColors)}.{color.Name}",
|
||||
_ =>
|
||||
$"#{color.R:X2}{color.G:X2}{color.B:X2}",
|
||||
};
|
||||
}
|
||||
|
||||
public static Color? DeserializeFromConfigColorString(string? value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// e.g. "#AABBCC"
|
||||
if (value.StartsWith('#'))
|
||||
{
|
||||
var culture = CultureInfo.InvariantCulture;
|
||||
if ((value.Length == 7)
|
||||
&& int.TryParse(value[1..3], NumberStyles.HexNumber, culture, out var r)
|
||||
&& int.TryParse(value[3..5], NumberStyles.HexNumber, culture, out var g)
|
||||
&& int.TryParse(value[5..7], NumberStyles.HexNumber, culture, out var b))
|
||||
{
|
||||
return Color.FromArgb(0xFF, r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
const StringComparison comparison = StringComparison.InvariantCulture;
|
||||
|
||||
// e.g. "Color.Red"
|
||||
const string colorPrefix = $"{nameof(Color)}.";
|
||||
if (value.StartsWith(colorPrefix, comparison))
|
||||
{
|
||||
var colorName = value[colorPrefix.Length..];
|
||||
var property = typeof(Color).GetProperties()
|
||||
.SingleOrDefault(property => property.Name == colorName);
|
||||
if (property is not null)
|
||||
{
|
||||
return (Color?)property.GetValue(null, null);
|
||||
}
|
||||
}
|
||||
|
||||
// e.g. "SystemColors.Highlight"
|
||||
const string systemColorPrefix = $"{nameof(SystemColors)}.";
|
||||
if (value.StartsWith(systemColorPrefix, comparison))
|
||||
{
|
||||
var colorName = value[systemColorPrefix.Length..];
|
||||
var property = typeof(SystemColors).GetProperties()
|
||||
.SingleOrDefault(property => property.Name == colorName);
|
||||
if (property is not null)
|
||||
{
|
||||
return (Color?)property.GetValue(null, null);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,250 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Diagnostics;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Drawing.Imaging;
|
||||
|
||||
using MouseJump.Common.Imaging;
|
||||
using MouseJump.Common.Models.Drawing;
|
||||
using MouseJump.Common.Models.Layout;
|
||||
using MouseJump.Common.Models.Styles;
|
||||
|
||||
namespace MouseJump.Common.Helpers;
|
||||
|
||||
public static class DrawingHelper
|
||||
{
|
||||
public static Bitmap RenderPreview(
|
||||
PreviewLayout previewLayout,
|
||||
IImageRegionCopyService imageCopyService,
|
||||
Action<Bitmap>? previewImageCreatedCallback = null,
|
||||
Action? previewImageUpdatedCallback = null)
|
||||
{
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
|
||||
// initialize the preview image
|
||||
var previewBounds = previewLayout.PreviewBounds.OuterBounds.ToRectangle();
|
||||
var previewImage = new Bitmap(previewBounds.Width, previewBounds.Height, PixelFormat.Format32bppPArgb);
|
||||
var previewGraphics = Graphics.FromImage(previewImage);
|
||||
previewImageCreatedCallback?.Invoke(previewImage);
|
||||
|
||||
DrawingHelper.DrawRaisedBorder(previewGraphics, previewLayout.PreviewStyle.CanvasStyle, previewLayout.PreviewBounds);
|
||||
DrawingHelper.DrawBackgroundFill(
|
||||
previewGraphics,
|
||||
previewLayout.PreviewStyle.CanvasStyle,
|
||||
previewLayout.PreviewBounds,
|
||||
[]);
|
||||
|
||||
// sort the source and target screen areas into the order we want to
|
||||
// draw them, putting the activated screen first (we need to capture
|
||||
// and draw the activated screen before we show the form because
|
||||
// otherwise we'll capture the form as part of the screenshot!)
|
||||
var sourceScreens = new List<RectangleInfo> { previewLayout.Screens[previewLayout.ActivatedScreenIndex] }
|
||||
.Concat(previewLayout.Screens.Where((_, idx) => idx != previewLayout.ActivatedScreenIndex))
|
||||
.ToList();
|
||||
var targetScreens = new List<BoxBounds> { previewLayout.ScreenshotBounds[previewLayout.ActivatedScreenIndex] }
|
||||
.Concat(previewLayout.ScreenshotBounds.Where((_, idx) => idx != previewLayout.ActivatedScreenIndex))
|
||||
.ToList();
|
||||
|
||||
// draw all the screenshot bezels
|
||||
foreach (var screenshotBounds in previewLayout.ScreenshotBounds)
|
||||
{
|
||||
DrawingHelper.DrawRaisedBorder(
|
||||
previewGraphics, previewLayout.PreviewStyle.ScreenStyle, screenshotBounds);
|
||||
}
|
||||
|
||||
var refreshRequired = false;
|
||||
var placeholdersDrawn = false;
|
||||
for (var i = 0; i < sourceScreens.Count; i++)
|
||||
{
|
||||
imageCopyService.CopyImageRegion(previewGraphics, sourceScreens[i], targetScreens[i].ContentBounds);
|
||||
refreshRequired = true;
|
||||
|
||||
// show the placeholder images and show the form if it looks like it might take
|
||||
// a while to capture the remaining screenshot images (but only if there are any)
|
||||
if (stopwatch.ElapsedMilliseconds > 250)
|
||||
{
|
||||
// draw placeholder backgrounds for any undrawn screens
|
||||
if (!placeholdersDrawn)
|
||||
{
|
||||
DrawingHelper.DrawScreenPlaceholders(
|
||||
previewGraphics,
|
||||
previewLayout.PreviewStyle.ScreenStyle,
|
||||
targetScreens.GetRange(i + 1, targetScreens.Count - i - 1));
|
||||
placeholdersDrawn = true;
|
||||
}
|
||||
|
||||
previewImageUpdatedCallback?.Invoke();
|
||||
refreshRequired = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (refreshRequired)
|
||||
{
|
||||
previewImageUpdatedCallback?.Invoke();
|
||||
}
|
||||
|
||||
stopwatch.Stop();
|
||||
|
||||
return previewImage;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws a border shape with an optional raised 3d highlight and shadow effect.
|
||||
/// </summary>
|
||||
private static void DrawRaisedBorder(
|
||||
Graphics graphics, BoxStyle boxStyle, BoxBounds boxBounds)
|
||||
{
|
||||
var borderStyle = boxStyle.BorderStyle;
|
||||
if ((borderStyle.Horizontal == 0) || (borderStyle.Vertical == 0))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (borderStyle.Color is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// draw the main box border
|
||||
using var borderBrush = new SolidBrush(borderStyle.Color.Value);
|
||||
var borderRegion = new Region(boxBounds.BorderBounds.ToRectangle());
|
||||
borderRegion.Exclude(boxBounds.PaddingBounds.ToRectangle());
|
||||
graphics.FillRegion(borderBrush, borderRegion);
|
||||
|
||||
// draw the highlight and shadow
|
||||
var bounds = boxBounds.BorderBounds.ToRectangle();
|
||||
using var highlight = new Pen(Color.FromArgb(0x44, 0xFF, 0xFF, 0xFF));
|
||||
using var shadow = new Pen(Color.FromArgb(0x44, 0x00, 0x00, 0x00));
|
||||
|
||||
var outer = (
|
||||
Left: bounds.Left,
|
||||
Top: bounds.Top,
|
||||
Right: bounds.Right - 1,
|
||||
Bottom: bounds.Bottom - 1
|
||||
);
|
||||
var inner = (
|
||||
Left: bounds.Left + (int)borderStyle.Left - 1,
|
||||
Top: bounds.Top + (int)borderStyle.Top - 1,
|
||||
Right: bounds.Right - (int)borderStyle.Right,
|
||||
Bottom: bounds.Bottom - (int)borderStyle.Bottom
|
||||
);
|
||||
|
||||
for (var i = 0; i < borderStyle.Depth; i++)
|
||||
{
|
||||
// left edge
|
||||
if (borderStyle.Left >= i * 2)
|
||||
{
|
||||
graphics.DrawLine(highlight, outer.Left, outer.Top, outer.Left, outer.Bottom);
|
||||
graphics.DrawLine(shadow, inner.Left, inner.Top, inner.Left, inner.Bottom);
|
||||
}
|
||||
|
||||
// top edge
|
||||
if (borderStyle.Top >= i * 2)
|
||||
{
|
||||
graphics.DrawLine(highlight, outer.Left, outer.Top, outer.Right, outer.Top);
|
||||
graphics.DrawLine(shadow, inner.Left, inner.Top, inner.Right, inner.Top);
|
||||
}
|
||||
|
||||
// right edge
|
||||
if (borderStyle.Right >= i * 2)
|
||||
{
|
||||
graphics.DrawLine(highlight, inner.Right, inner.Top, inner.Right, inner.Bottom);
|
||||
graphics.DrawLine(shadow, outer.Right, outer.Top, outer.Right, outer.Bottom);
|
||||
}
|
||||
|
||||
// bottom edge
|
||||
if (borderStyle.Bottom >= i * 2)
|
||||
{
|
||||
graphics.DrawLine(highlight, inner.Left, inner.Bottom, inner.Right, inner.Bottom);
|
||||
graphics.DrawLine(shadow, outer.Left, outer.Bottom, outer.Right, outer.Bottom);
|
||||
}
|
||||
|
||||
// shrink the outer border for the next iteration
|
||||
outer = (
|
||||
outer.Left + 1,
|
||||
outer.Top + 1,
|
||||
outer.Right - 1,
|
||||
outer.Bottom - 1
|
||||
);
|
||||
|
||||
// enlarge the inner border for the next iteration
|
||||
inner = (
|
||||
inner.Left - 1,
|
||||
inner.Top - 1,
|
||||
inner.Right + 1,
|
||||
inner.Bottom + 1
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws a gradient-filled background shape.
|
||||
/// </summary>
|
||||
private static void DrawBackgroundFill(
|
||||
Graphics graphics, BoxStyle boxStyle, BoxBounds boxBounds, IEnumerable<RectangleInfo> excludeBounds)
|
||||
{
|
||||
var backgroundBounds = boxBounds.PaddingBounds;
|
||||
|
||||
using var backgroundBrush = DrawingHelper.GetBackgroundStyleBrush(boxStyle.BackgroundStyle, backgroundBounds);
|
||||
if (backgroundBrush == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// it's faster to build a region with the screen areas excluded
|
||||
// and fill that than it is to fill the entire bounding rectangle
|
||||
var backgroundRegion = new Region(backgroundBounds.ToRectangle());
|
||||
foreach (var exclude in excludeBounds)
|
||||
{
|
||||
backgroundRegion.Exclude(exclude.ToRectangle());
|
||||
}
|
||||
|
||||
graphics.FillRegion(backgroundBrush, backgroundRegion);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws placeholder background images for the specified screens on the preview.
|
||||
/// </summary>
|
||||
private static void DrawScreenPlaceholders(
|
||||
Graphics graphics, BoxStyle screenStyle, IList<BoxBounds> screenBounds)
|
||||
{
|
||||
if (screenBounds.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (screenStyle?.BackgroundStyle?.Color1 == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using var brush = new SolidBrush(screenStyle.BackgroundStyle.Color1.Value);
|
||||
graphics.FillRectangles(brush, screenBounds.Select(bounds => bounds.PaddingBounds.ToRectangle()).ToArray());
|
||||
}
|
||||
|
||||
private static Brush? GetBackgroundStyleBrush(BackgroundStyle backgroundStyle, RectangleInfo backgroundBounds)
|
||||
{
|
||||
var backgroundBrush = backgroundStyle switch
|
||||
{
|
||||
{ Color1: not null, Color2: not null } =>
|
||||
/* draw a gradient fill if both colors are specified */
|
||||
new LinearGradientBrush(
|
||||
backgroundBounds.ToRectangle(),
|
||||
backgroundStyle.Color1.Value,
|
||||
backgroundStyle.Color2.Value,
|
||||
LinearGradientMode.ForwardDiagonal),
|
||||
{ Color1: not null } =>
|
||||
/* draw a solid fill if only one color is specified */
|
||||
new SolidBrush(
|
||||
backgroundStyle.Color1.Value),
|
||||
{ Color2: not null } =>
|
||||
/* draw a solid fill if only one color is specified */
|
||||
new SolidBrush(
|
||||
backgroundStyle.Color2.Value),
|
||||
_ => (Brush?)null,
|
||||
};
|
||||
return backgroundBrush;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using MouseJump.Common.Models.Drawing;
|
||||
using MouseJump.Common.Models.Layout;
|
||||
using MouseJump.Common.Models.Styles;
|
||||
|
||||
namespace MouseJump.Common.Helpers;
|
||||
|
||||
public static class LayoutHelper
|
||||
{
|
||||
public static PreviewLayout GetPreviewLayout(
|
||||
PreviewStyle previewStyle, List<RectangleInfo> screens, PointInfo activatedLocation)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(previewStyle);
|
||||
ArgumentNullException.ThrowIfNull(screens);
|
||||
|
||||
if (screens.Count == 0)
|
||||
{
|
||||
throw new ArgumentException("Value must contain at least one item.", nameof(screens));
|
||||
}
|
||||
|
||||
var builder = new PreviewLayout.Builder();
|
||||
builder.Screens = screens.ToList();
|
||||
|
||||
// calculate the bounding rectangle for the virtual screen
|
||||
builder.VirtualScreen = LayoutHelper.GetCombinedScreenBounds(builder.Screens);
|
||||
|
||||
// find the screen that contains the activated location - this is the
|
||||
// one we'll show the preview form on
|
||||
var activatedScreen = builder.Screens.Single(
|
||||
screen => screen.Contains(activatedLocation));
|
||||
builder.ActivatedScreenIndex = builder.Screens.IndexOf(activatedScreen);
|
||||
|
||||
// work out the maximum allowed size of the preview form:
|
||||
// * can't be bigger than the activated screen
|
||||
// * can't be bigger than the configured canvas size
|
||||
var maxPreviewSize = activatedScreen.Size
|
||||
.Intersect(previewStyle.CanvasSize);
|
||||
|
||||
// the "content area" (i.e. drawing area) for screenshots is inside the
|
||||
// preview border and inside the preview padding (if any)
|
||||
var maxContentSize = maxPreviewSize
|
||||
.Shrink(previewStyle.CanvasStyle.MarginStyle)
|
||||
.Shrink(previewStyle.CanvasStyle.BorderStyle)
|
||||
.Shrink(previewStyle.CanvasStyle.PaddingStyle);
|
||||
|
||||
// work out the actual size of the "content area" by scaling the virtual screen
|
||||
// to fit inside the maximum content area while maintaining its aspect ration.
|
||||
// we'll also offset it to allow for any margins, borders and padding
|
||||
var contentBounds = builder.VirtualScreen.Size
|
||||
.ScaleToFit(maxContentSize, out var scalingRatio)
|
||||
.Round()
|
||||
.Clamp(maxContentSize)
|
||||
.PlaceAt(0, 0)
|
||||
.Offset(previewStyle.CanvasStyle.MarginStyle.Left, previewStyle.CanvasStyle.MarginStyle.Top)
|
||||
.Offset(previewStyle.CanvasStyle.BorderStyle.Left, previewStyle.CanvasStyle.BorderStyle.Top)
|
||||
.Offset(previewStyle.CanvasStyle.PaddingStyle.Left, previewStyle.CanvasStyle.PaddingStyle.Top);
|
||||
|
||||
// now we know the actual size of the content area we can work outwards to
|
||||
// get the size of the background bounds including margins, borders and padding
|
||||
builder.PreviewStyle = previewStyle;
|
||||
builder.PreviewBounds = LayoutHelper.GetBoxBoundsFromContentBounds(
|
||||
contentBounds,
|
||||
previewStyle.CanvasStyle);
|
||||
|
||||
// ... and then the size and position of the preview form on the activated screen
|
||||
// * center the form to the activated position, but nudge it back
|
||||
// inside the visible area of the activated screen if it falls outside
|
||||
var formBounds = builder.PreviewBounds.OuterBounds
|
||||
.Center(activatedLocation)
|
||||
.Clamp(activatedScreen);
|
||||
builder.FormBounds = formBounds;
|
||||
|
||||
// now calculate the positions of each of the screenshot images on the preview
|
||||
builder.ScreenshotBounds = builder.Screens
|
||||
.Select(
|
||||
screen => LayoutHelper.GetBoxBoundsFromOuterBounds(
|
||||
screen
|
||||
.Offset(builder.VirtualScreen.Location.ToSize().Invert())
|
||||
.Scale(scalingRatio)
|
||||
.Offset(builder.PreviewBounds.ContentBounds.Location.ToSize())
|
||||
.Round(),
|
||||
previewStyle.ScreenStyle))
|
||||
.ToList();
|
||||
|
||||
return builder.Build();
|
||||
}
|
||||
|
||||
public static RectangleInfo GetCombinedScreenBounds(List<RectangleInfo> screens)
|
||||
{
|
||||
return screens.Skip(1).Aggregate(
|
||||
seed: screens.First(),
|
||||
(bounds, screen) => bounds.Union(screen));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the bounds of the various areas of a box, given the content bounds and the box style.
|
||||
/// Starts with the content bounds and works outward, enlarging the content bounds by the padding, border, and margin sizes to calculate the outer bounds of the box.
|
||||
/// </summary>
|
||||
/// <param name="contentBounds">The content bounds of the box.</param>
|
||||
/// <param name="boxStyle">The style of the box, which includes the sizes of the margin, border, and padding areas.</param>
|
||||
/// <returns>A <see cref="BoxBounds"/> object that represents the bounds of the different areas of the box.</returns>
|
||||
/// <exception cref="ArgumentNullException">Thrown when <paramref name="contentBounds"/> or <paramref name="boxStyle"/> is null.</exception>
|
||||
/// <exception cref="ArgumentException">Thrown when any of the styles in <paramref name="boxStyle"/> is null.</exception>
|
||||
public static BoxBounds GetBoxBoundsFromContentBounds(
|
||||
RectangleInfo contentBounds,
|
||||
BoxStyle boxStyle)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(contentBounds);
|
||||
ArgumentNullException.ThrowIfNull(boxStyle);
|
||||
if (boxStyle.PaddingStyle == null || boxStyle.BorderStyle == null || boxStyle.MarginStyle == null)
|
||||
{
|
||||
throw new ArgumentException(null, nameof(boxStyle));
|
||||
}
|
||||
|
||||
var paddingBounds = contentBounds.Enlarge(boxStyle.PaddingStyle);
|
||||
var borderBounds = paddingBounds.Enlarge(boxStyle.BorderStyle);
|
||||
var marginBounds = borderBounds.Enlarge(boxStyle.MarginStyle);
|
||||
var outerBounds = marginBounds;
|
||||
return new(
|
||||
outerBounds, marginBounds, borderBounds, paddingBounds, contentBounds);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the bounds of the various areas of a box, given the outer bounds and the box style.
|
||||
/// This method starts with the outer bounds and works inward, shrinking the outer bounds by the margin, border, and padding sizes to calculate the content bounds of the box.
|
||||
/// </summary>
|
||||
/// <param name="outerBounds">The outer bounds of the box.</param>
|
||||
/// <param name="boxStyle">The style of the box, which includes the sizes of the margin, border, and padding areas.</param>
|
||||
/// <returns>A <see cref="BoxBounds"/> object that represents the bounds of the different areas of the box.</returns>
|
||||
/// <exception cref="ArgumentNullException">Thrown when <paramref name="outerBounds"/> or <paramref name="boxStyle"/> is null.</exception>
|
||||
/// <exception cref="ArgumentException">Thrown when any of the styles in <paramref name="boxStyle"/> is null.</exception>
|
||||
public static BoxBounds GetBoxBoundsFromOuterBounds(
|
||||
RectangleInfo outerBounds,
|
||||
BoxStyle boxStyle)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(outerBounds);
|
||||
ArgumentNullException.ThrowIfNull(boxStyle);
|
||||
if (outerBounds == null || boxStyle.MarginStyle == null || boxStyle.BorderStyle == null || boxStyle.PaddingStyle == null)
|
||||
{
|
||||
throw new ArgumentException(null, nameof(boxStyle));
|
||||
}
|
||||
|
||||
var marginBounds = outerBounds;
|
||||
var borderBounds = marginBounds.Shrink(boxStyle.MarginStyle);
|
||||
var paddingBounds = borderBounds.Shrink(boxStyle.BorderStyle);
|
||||
var contentBounds = paddingBounds.Shrink(boxStyle.PaddingStyle);
|
||||
return new(
|
||||
outerBounds, marginBounds, borderBounds, paddingBounds, contentBounds);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using MouseJump.Common.Models.Drawing;
|
||||
using MouseJump.Common.NativeMethods;
|
||||
using static MouseJump.Common.NativeMethods.Core;
|
||||
using static MouseJump.Common.NativeMethods.User32;
|
||||
|
||||
namespace MouseJump.Common.Helpers;
|
||||
|
||||
public static class MouseHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Calculates where to move the cursor to by projecting a point from
|
||||
/// the preview image onto the desktop and using that as the target location.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The preview image origin is (0, 0) but the desktop origin may be non-zero,
|
||||
/// or even negative if the primary monitor is not the at the top-left of the
|
||||
/// entire desktop rectangle, so results may contain negative coordinates.
|
||||
/// </remarks>
|
||||
public static PointInfo GetJumpLocation(PointInfo previewLocation, SizeInfo previewSize, RectangleInfo desktopBounds)
|
||||
{
|
||||
return previewLocation
|
||||
.Scale(previewSize.ScaleToFitRatio(desktopBounds.Size))
|
||||
.Offset(desktopBounds.Location);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the current position of the cursor.
|
||||
/// </summary>
|
||||
public static PointInfo GetCursorPosition()
|
||||
{
|
||||
var lpPoint = new LPPOINT(new POINT(0, 0));
|
||||
var result = User32.GetCursorPos(lpPoint);
|
||||
if (!result)
|
||||
{
|
||||
throw new Win32Exception(
|
||||
Marshal.GetLastWin32Error());
|
||||
}
|
||||
|
||||
var point = lpPoint.ToStructure();
|
||||
lpPoint.Free();
|
||||
|
||||
return new PointInfo(
|
||||
point.x, point.y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves the cursor to the specified location.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// See https://github.com/mikeclayton/FancyMouse/pull/3
|
||||
/// </remarks>
|
||||
public static void SetCursorPosition(PointInfo location)
|
||||
{
|
||||
// set the new cursor position *twice* - the cursor sometimes end up in
|
||||
// the wrong place if we try to cross the dead space between non-aligned
|
||||
// monitors - e.g. when trying to move the cursor from (a) to (b) we can
|
||||
// *sometimes* - for no clear reason - end up at (c) instead.
|
||||
//
|
||||
// +----------------+
|
||||
// |(c) (b) |
|
||||
// | |
|
||||
// | |
|
||||
// | |
|
||||
// +---------+ |
|
||||
// | (a) | |
|
||||
// +---------+----------------+
|
||||
//
|
||||
// setting the position again seems to fix this and moves the
|
||||
// cursor to the expected location (b)
|
||||
var target = location.ToPoint();
|
||||
for (var i = 0; i < 2; i++)
|
||||
{
|
||||
var result = User32.SetCursorPos(target.X, target.Y);
|
||||
if (!result)
|
||||
{
|
||||
throw new Win32Exception(
|
||||
Marshal.GetLastWin32Error());
|
||||
}
|
||||
|
||||
var current = MouseHelper.GetCursorPosition();
|
||||
if ((current.X == target.X) || (current.Y == target.Y))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// temporary workaround for issue #1273
|
||||
MouseHelper.SimulateMouseMovementEvent(location);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends an input simulating an absolute mouse move to the new location.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// See https://github.com/microsoft/PowerToys/issues/24523
|
||||
/// https://github.com/microsoft/PowerToys/pull/24527
|
||||
/// </remarks>
|
||||
private static void SimulateMouseMovementEvent(PointInfo location)
|
||||
{
|
||||
var inputs = new User32.INPUT[]
|
||||
{
|
||||
new(
|
||||
type: INPUT_TYPE.INPUT_MOUSE,
|
||||
data: new INPUT.DUMMYUNIONNAME(
|
||||
mi: new MOUSEINPUT(
|
||||
dx: (int)MouseHelper.CalculateAbsoluteCoordinateX(location.X),
|
||||
dy: (int)MouseHelper.CalculateAbsoluteCoordinateY(location.Y),
|
||||
mouseData: 0,
|
||||
dwFlags: MOUSE_EVENT_FLAGS.MOUSEEVENTF_MOVE | MOUSE_EVENT_FLAGS.MOUSEEVENTF_ABSOLUTE,
|
||||
time: 0,
|
||||
dwExtraInfo: ULONG_PTR.Null))),
|
||||
};
|
||||
var result = User32.SendInput(
|
||||
(UINT)inputs.Length,
|
||||
new LPINPUT(inputs),
|
||||
INPUT.Size * inputs.Length);
|
||||
if (result != inputs.Length)
|
||||
{
|
||||
throw new Win32Exception(
|
||||
Marshal.GetLastWin32Error());
|
||||
}
|
||||
}
|
||||
|
||||
private static decimal CalculateAbsoluteCoordinateX(decimal x)
|
||||
{
|
||||
// If MOUSEEVENTF_ABSOLUTE value is specified, dx and dy contain normalized absolute coordinates between 0 and 65,535.
|
||||
// see https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-mouseinput
|
||||
return (x * 65535) / User32.GetSystemMetrics(SYSTEM_METRICS_INDEX.SM_CXSCREEN);
|
||||
}
|
||||
|
||||
private static decimal CalculateAbsoluteCoordinateY(decimal y)
|
||||
{
|
||||
// If MOUSEEVENTF_ABSOLUTE value is specified, dx and dy contain normalized absolute coordinates between 0 and 65,535.
|
||||
// see https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-mouseinput
|
||||
return (y * 65535) / User32.GetSystemMetrics(SYSTEM_METRICS_INDEX.SM_CYSCREEN);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.ComponentModel;
|
||||
|
||||
using MouseJump.Common.Models.Drawing;
|
||||
using MouseJump.Common.NativeMethods;
|
||||
using static MouseJump.Common.NativeMethods.Core;
|
||||
using static MouseJump.Common.NativeMethods.User32;
|
||||
|
||||
namespace MouseJump.Common.Helpers;
|
||||
|
||||
public static class ScreenHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Duplicates functionality available in System.Windows.Forms.SystemInformation
|
||||
/// to reduce the dependency on WinForms
|
||||
/// </summary>
|
||||
private static RectangleInfo GetVirtualScreen()
|
||||
{
|
||||
return new(
|
||||
User32.GetSystemMetrics(SYSTEM_METRICS_INDEX.SM_XVIRTUALSCREEN),
|
||||
User32.GetSystemMetrics(SYSTEM_METRICS_INDEX.SM_YVIRTUALSCREEN),
|
||||
User32.GetSystemMetrics(SYSTEM_METRICS_INDEX.SM_CXVIRTUALSCREEN),
|
||||
User32.GetSystemMetrics(SYSTEM_METRICS_INDEX.SM_CYVIRTUALSCREEN));
|
||||
}
|
||||
|
||||
public static IEnumerable<ScreenInfo> GetAllScreens()
|
||||
{
|
||||
// enumerate the monitors attached to the system
|
||||
var hMonitors = new List<HMONITOR>();
|
||||
var callback = new User32.MONITORENUMPROC(
|
||||
(hMonitor, hdcMonitor, lprcMonitor, dwData) =>
|
||||
{
|
||||
hMonitors.Add(hMonitor);
|
||||
return true;
|
||||
});
|
||||
var result = User32.EnumDisplayMonitors(HDC.Null, LPCRECT.Null, callback, LPARAM.Null);
|
||||
if (!result)
|
||||
{
|
||||
throw new Win32Exception(
|
||||
result.Value,
|
||||
$"{nameof(User32.EnumDisplayMonitors)} failed with return code {result.Value}");
|
||||
}
|
||||
|
||||
// get detailed info about each monitor
|
||||
foreach (var hMonitor in hMonitors)
|
||||
{
|
||||
var monitorInfoPtr = new LPMONITORINFO(
|
||||
new MONITORINFO((DWORD)MONITORINFO.Size, RECT.Empty, RECT.Empty, 0));
|
||||
result = User32.GetMonitorInfoW(hMonitor, monitorInfoPtr);
|
||||
if (!result)
|
||||
{
|
||||
throw new Win32Exception(
|
||||
result.Value,
|
||||
$"{nameof(User32.GetMonitorInfoW)} failed with return code {result.Value}");
|
||||
}
|
||||
|
||||
var monitorInfo = monitorInfoPtr.ToStructure();
|
||||
monitorInfoPtr.Free();
|
||||
|
||||
yield return new ScreenInfo(
|
||||
handle: hMonitor,
|
||||
primary: monitorInfo.dwFlags.HasFlag(User32.MONITOR_INFO_FLAGS.MONITORINFOF_PRIMARY),
|
||||
displayArea: new RectangleInfo(
|
||||
monitorInfo.rcMonitor.left,
|
||||
monitorInfo.rcMonitor.top,
|
||||
monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left,
|
||||
monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top),
|
||||
workingArea: new RectangleInfo(
|
||||
monitorInfo.rcWork.left,
|
||||
monitorInfo.rcWork.top,
|
||||
monitorInfo.rcWork.right - monitorInfo.rcWork.left,
|
||||
monitorInfo.rcWork.bottom - monitorInfo.rcWork.top));
|
||||
}
|
||||
}
|
||||
|
||||
public static ScreenInfo GetScreenFromPoint(
|
||||
List<ScreenInfo> screens,
|
||||
PointInfo pt)
|
||||
{
|
||||
// get the monitor handle from the point
|
||||
var hMonitor = User32.MonitorFromPoint(
|
||||
new((int)pt.X, (int)pt.Y),
|
||||
User32.MONITOR_FROM_FLAGS.MONITOR_DEFAULTTONEAREST);
|
||||
if (hMonitor.IsNull)
|
||||
{
|
||||
throw new InvalidOperationException($"no monitor found for point {pt}");
|
||||
}
|
||||
|
||||
// find the screen with the given monitor handle
|
||||
var screen = screens
|
||||
.Single(item => item.Handle == hMonitor);
|
||||
return screen;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using MouseJump.Common.Models.Drawing;
|
||||
using MouseJump.Common.Models.Styles;
|
||||
|
||||
namespace MouseJump.Common.Helpers;
|
||||
|
||||
public static class StyleHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Compact (legacy) preview style
|
||||
/// </summary>
|
||||
public static readonly PreviewStyle CompactPreviewStyle = new(
|
||||
canvasSize: new(
|
||||
width: 1600,
|
||||
height: 1200
|
||||
),
|
||||
canvasStyle: new(
|
||||
marginStyle: MarginStyle.Empty,
|
||||
borderStyle: new(
|
||||
color: SystemColors.Highlight,
|
||||
all: 6,
|
||||
depth: 0
|
||||
),
|
||||
paddingStyle: new(
|
||||
all: 0
|
||||
),
|
||||
backgroundStyle: new(
|
||||
color1: Color.FromArgb(0xFF, 0x0D, 0x57, 0xD2),
|
||||
color2: Color.FromArgb(0xFF, 0x03, 0x44, 0xC0)
|
||||
)
|
||||
),
|
||||
screenStyle: new(
|
||||
marginStyle: new(
|
||||
all: 0
|
||||
),
|
||||
borderStyle: new(
|
||||
color: Color.FromArgb(0xFF, 0x22, 0x22, 0x22),
|
||||
all: 0,
|
||||
depth: 0
|
||||
),
|
||||
paddingStyle: PaddingStyle.Empty,
|
||||
backgroundStyle: new(
|
||||
color1: Color.MidnightBlue,
|
||||
color2: Color.MidnightBlue
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Bezelled preview style
|
||||
/// </summary>
|
||||
public static readonly PreviewStyle BezelledPreviewStyle = new(
|
||||
canvasSize: new(
|
||||
width: 1600,
|
||||
height: 1200
|
||||
),
|
||||
canvasStyle: new(
|
||||
marginStyle: MarginStyle.Empty,
|
||||
borderStyle: new(
|
||||
color: SystemColors.Highlight,
|
||||
all: 6,
|
||||
depth: 0
|
||||
),
|
||||
paddingStyle: new(
|
||||
all: 4
|
||||
),
|
||||
backgroundStyle: new(
|
||||
color1: Color.FromArgb(0xFF, 0x0D, 0x57, 0xD2),
|
||||
color2: Color.FromArgb(0xFF, 0x03, 0x44, 0xC0)
|
||||
)
|
||||
),
|
||||
screenStyle: new(
|
||||
marginStyle: new(
|
||||
all: 4
|
||||
),
|
||||
borderStyle: new(
|
||||
color: Color.FromArgb(0xFF, 0x22, 0x22, 0x22),
|
||||
all: 12,
|
||||
depth: 4
|
||||
),
|
||||
paddingStyle: PaddingStyle.Empty,
|
||||
backgroundStyle: new(
|
||||
color1: Color.MidnightBlue,
|
||||
color2: Color.MidnightBlue
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
public static PreviewStyle WithCanvasSize(this PreviewStyle previewStyle, SizeInfo canvasSize)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(previewStyle);
|
||||
ArgumentNullException.ThrowIfNull(canvasSize);
|
||||
return new PreviewStyle(
|
||||
canvasSize: canvasSize,
|
||||
canvasStyle: previewStyle.CanvasStyle,
|
||||
screenStyle: previewStyle.ScreenStyle);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Diagnostics;
|
||||
|
||||
using MouseJump.Common.Models.Drawing;
|
||||
using MouseJump.Common.NativeMethods;
|
||||
using static MouseJump.Common.NativeMethods.Core;
|
||||
|
||||
namespace MouseJump.Common.Imaging;
|
||||
|
||||
/// <summary>
|
||||
/// Implements an IImageRegionCopyService that uses the current desktop window as the copy source.
|
||||
/// This is used during the main application runtime to generate preview images of the desktop.
|
||||
/// </summary>
|
||||
public sealed class DesktopImageRegionCopyService : IImageRegionCopyService
|
||||
{
|
||||
/// <summary>
|
||||
/// Copies the source region from the current desktop window
|
||||
/// to the target region on the specified Graphics object.
|
||||
/// </summary>
|
||||
public void CopyImageRegion(
|
||||
Graphics targetGraphics,
|
||||
RectangleInfo sourceBounds,
|
||||
RectangleInfo targetBounds)
|
||||
{
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
var (desktopHwnd, desktopHdc) = DesktopImageRegionCopyService.GetDesktopDeviceContext();
|
||||
var previewHdc = DesktopImageRegionCopyService.GetGraphicsDeviceContext(
|
||||
targetGraphics, Gdi32.STRETCH_BLT_MODE.STRETCH_HALFTONE);
|
||||
stopwatch.Stop();
|
||||
|
||||
var source = sourceBounds.ToRectangle();
|
||||
var target = targetBounds.ToRectangle();
|
||||
var result = Gdi32.StretchBlt(
|
||||
previewHdc,
|
||||
target.X,
|
||||
target.Y,
|
||||
target.Width,
|
||||
target.Height,
|
||||
desktopHdc,
|
||||
source.X,
|
||||
source.Y,
|
||||
source.Width,
|
||||
source.Height,
|
||||
Gdi32.ROP_CODE.SRCCOPY);
|
||||
if (!result)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"{nameof(Gdi32.StretchBlt)} returned {result.Value}");
|
||||
}
|
||||
|
||||
// we need to release the graphics device context handle before anything
|
||||
// else tries to use the Graphics object otherwise it'll give an error
|
||||
// from GDI saying "Object is currently in use elsewhere"
|
||||
DesktopImageRegionCopyService.FreeGraphicsDeviceContext(targetGraphics, ref previewHdc);
|
||||
|
||||
DesktopImageRegionCopyService.FreeDesktopDeviceContext(ref desktopHwnd, ref desktopHdc);
|
||||
}
|
||||
|
||||
private static (HWND DesktopHwnd, HDC DesktopHdc) GetDesktopDeviceContext()
|
||||
{
|
||||
var desktopHwnd = User32.GetDesktopWindow();
|
||||
var desktopHdc = User32.GetWindowDC(desktopHwnd);
|
||||
if (desktopHdc.IsNull)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"{nameof(User32.GetWindowDC)} returned null");
|
||||
}
|
||||
|
||||
return (desktopHwnd, desktopHdc);
|
||||
}
|
||||
|
||||
private static void FreeDesktopDeviceContext(ref HWND desktopHwnd, ref HDC desktopHdc)
|
||||
{
|
||||
if (!desktopHwnd.IsNull && !desktopHdc.IsNull)
|
||||
{
|
||||
var result = User32.ReleaseDC(desktopHwnd, desktopHdc);
|
||||
if (result == 0)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"{nameof(User32.ReleaseDC)} returned {result}");
|
||||
}
|
||||
}
|
||||
|
||||
desktopHwnd = HWND.Null;
|
||||
desktopHdc = HDC.Null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the target device context handle exists, and creates a new one from the
|
||||
/// specified Graphics object if not.
|
||||
/// </summary>
|
||||
private static HDC GetGraphicsDeviceContext(Graphics graphics, Gdi32.STRETCH_BLT_MODE mode)
|
||||
{
|
||||
var graphicsHdc = (HDC)graphics.GetHdc();
|
||||
|
||||
var result = Gdi32.SetStretchBltMode(graphicsHdc, mode);
|
||||
if (result == 0)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"{nameof(Gdi32.SetStretchBltMode)} returned {result}");
|
||||
}
|
||||
|
||||
return graphicsHdc;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Free the specified device context handle if it exists.
|
||||
/// </summary>
|
||||
private static void FreeGraphicsDeviceContext(Graphics graphics, ref HDC graphicsHdc)
|
||||
{
|
||||
if (graphicsHdc.IsNull)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
graphics.ReleaseHdc(graphicsHdc.Value);
|
||||
graphicsHdc = HDC.Null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using MouseJump.Common.Models.Drawing;
|
||||
|
||||
namespace MouseJump.Common.Imaging;
|
||||
|
||||
public interface IImageRegionCopyService
|
||||
{
|
||||
/// <summary>
|
||||
/// Copies the source region from the provider's source image (e.g. the interactive desktop,
|
||||
/// a static image, etc.) to the target region on the specified Graphics object.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Implementations of this interface are used to capture regions of the interactive desktop
|
||||
/// during runtime, or to capture regions of a static reference image during unit tests.
|
||||
/// </remarks>
|
||||
void CopyImageRegion(
|
||||
Graphics targetGraphics,
|
||||
RectangleInfo sourceBounds,
|
||||
RectangleInfo targetBounds);
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Drawing.Drawing2D;
|
||||
|
||||
using MouseJump.Common.Models.Drawing;
|
||||
|
||||
namespace MouseJump.Common.Imaging;
|
||||
|
||||
/// <summary>
|
||||
/// Implements an IImageRegionCopyService that uses the specified image as the copy source.
|
||||
/// This is used for testing the DrawingHelper rather than as part of the main application.
|
||||
/// </summary>
|
||||
public sealed class StaticImageRegionCopyService : IImageRegionCopyService
|
||||
{
|
||||
public StaticImageRegionCopyService(Image sourceImage)
|
||||
{
|
||||
this.SourceImage = sourceImage ?? throw new ArgumentNullException(nameof(sourceImage));
|
||||
}
|
||||
|
||||
private Image SourceImage
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies the source region from the static source image
|
||||
/// to the target region on the specified Graphics object.
|
||||
/// </summary>
|
||||
public void CopyImageRegion(
|
||||
Graphics targetGraphics,
|
||||
RectangleInfo sourceBounds,
|
||||
RectangleInfo targetBounds)
|
||||
{
|
||||
// prevent the background bleeding through into screen images
|
||||
// (see https://github.com/mikeclayton/FancyMouse/issues/44)
|
||||
targetGraphics.PixelOffsetMode = PixelOffsetMode.Half;
|
||||
targetGraphics.InterpolationMode = InterpolationMode.NearestNeighbor;
|
||||
|
||||
targetGraphics.DrawImage(
|
||||
image: this.SourceImage,
|
||||
destRect: targetBounds.ToRectangle(),
|
||||
srcRect: sourceBounds.ToRectangle(),
|
||||
srcUnit: GraphicsUnit.Pixel);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace MouseJump.Common.Models.Drawing;
|
||||
|
||||
public sealed class BoxBounds
|
||||
{
|
||||
/*
|
||||
|
||||
see https://www.w3schools.com/css/css_boxmodel.asp
|
||||
|
||||
+--------------[bounds]---------------+
|
||||
|▒▒▒▒▒▒▒▒▒▒▒▒▒▒[margin]▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒|
|
||||
|▒▒▓▓▓▓▓▓▓▓▓▓▓▓[border]▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒|
|
||||
|▒▒▓▓░░░░░░░░░░[padding]░░░░░░░░░░▓▓▒▒|
|
||||
|▒▒▓▓░░ ░░▓▓▒▒|
|
||||
|▒▒▓▓░░ ░░▓▓▒▒|
|
||||
|▒▒▓▓░░ [content] ░░▓▓▒▒|
|
||||
|▒▒▓▓░░ ░░▓▓▒▒|
|
||||
|▒▒▓▓░░ ░░▓▓▒▒|
|
||||
|▒▒▓▓░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▒▒|
|
||||
|▒▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒|
|
||||
|▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒|
|
||||
+-------------------------------------+
|
||||
|
||||
*/
|
||||
|
||||
public BoxBounds(
|
||||
RectangleInfo outerBounds,
|
||||
RectangleInfo marginBounds,
|
||||
RectangleInfo borderBounds,
|
||||
RectangleInfo paddingBounds,
|
||||
RectangleInfo contentBounds)
|
||||
{
|
||||
this.OuterBounds = outerBounds ?? throw new ArgumentNullException(nameof(outerBounds));
|
||||
this.MarginBounds = marginBounds ?? throw new ArgumentNullException(nameof(marginBounds));
|
||||
this.BorderBounds = borderBounds ?? throw new ArgumentNullException(nameof(borderBounds));
|
||||
this.PaddingBounds = paddingBounds ?? throw new ArgumentNullException(nameof(paddingBounds));
|
||||
this.ContentBounds = contentBounds ?? throw new ArgumentNullException(nameof(contentBounds));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the outer bounds of this layout box.
|
||||
/// </summary>
|
||||
public RectangleInfo OuterBounds
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public RectangleInfo MarginBounds
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public RectangleInfo BorderBounds
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public RectangleInfo PaddingBounds
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the bounds of the content area for this layout box.
|
||||
/// </summary>
|
||||
public RectangleInfo ContentBounds
|
||||
{
|
||||
get;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace MouseJump.Common.Models.Drawing;
|
||||
|
||||
/// <summary>
|
||||
/// Immutable version of a System.Drawing.Point object with some extra utility methods.
|
||||
/// </summary>
|
||||
public sealed class PointInfo
|
||||
{
|
||||
public PointInfo(decimal x, decimal y)
|
||||
{
|
||||
this.X = x;
|
||||
this.Y = y;
|
||||
}
|
||||
|
||||
public PointInfo(Point point)
|
||||
: this(point.X, point.Y)
|
||||
{
|
||||
}
|
||||
|
||||
public decimal X
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public decimal Y
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves this PointInfo inside the specified RectangleInfo.
|
||||
/// </summary>
|
||||
public PointInfo Clamp(RectangleInfo outer)
|
||||
{
|
||||
return new(
|
||||
x: Math.Clamp(this.X, outer.X, outer.Right),
|
||||
y: Math.Clamp(this.Y, outer.Y, outer.Bottom));
|
||||
}
|
||||
|
||||
public PointInfo Scale(decimal scalingFactor) => new(this.X * scalingFactor, this.Y * scalingFactor);
|
||||
|
||||
public PointInfo Offset(PointInfo amount) => new(this.X + amount.X, this.Y + amount.Y);
|
||||
|
||||
public Point ToPoint() => new((int)this.X, (int)this.Y);
|
||||
|
||||
public SizeInfo ToSize()
|
||||
{
|
||||
return new((int)this.X, (int)this.Y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stretches the point to the same proportional position in targetBounds as
|
||||
/// it currently is in sourceBounds
|
||||
/// </summary>
|
||||
public PointInfo Stretch(RectangleInfo source, RectangleInfo target)
|
||||
{
|
||||
return new PointInfo(
|
||||
x: ((this.X - source.X) / source.Width * target.Width) + target.X,
|
||||
y: ((this.Y - source.Y) / source.Height * target.Height) + target.Y);
|
||||
}
|
||||
|
||||
public PointInfo Truncate() =>
|
||||
new(
|
||||
(int)this.X,
|
||||
(int)this.Y);
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "{" +
|
||||
$"{nameof(this.X)}={this.X}," +
|
||||
$"{nameof(this.Y)}={this.Y}" +
|
||||
"}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,308 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
using MouseJump.Common.Models.Styles;
|
||||
using BorderStyle = MouseJump.Common.Models.Styles.BorderStyle;
|
||||
|
||||
namespace MouseJump.Common.Models.Drawing;
|
||||
|
||||
/// <summary>
|
||||
/// Immutable version of a System.Drawing.Rectangle object with some extra utility methods.
|
||||
/// </summary>
|
||||
public sealed class RectangleInfo
|
||||
{
|
||||
public static readonly RectangleInfo Empty = new(0, 0, 0, 0);
|
||||
|
||||
public RectangleInfo(decimal x, decimal y, decimal width, decimal height)
|
||||
{
|
||||
this.X = x;
|
||||
this.Y = y;
|
||||
this.Width = width;
|
||||
this.Height = height;
|
||||
}
|
||||
|
||||
public RectangleInfo(Rectangle rectangle)
|
||||
: this(rectangle.X, rectangle.Y, rectangle.Width, rectangle.Height)
|
||||
{
|
||||
}
|
||||
|
||||
public RectangleInfo(Point location, SizeInfo size)
|
||||
: this(location.X, location.Y, size.Width, size.Height)
|
||||
{
|
||||
}
|
||||
|
||||
public RectangleInfo(SizeInfo size)
|
||||
: this(0, 0, size.Width, size.Height)
|
||||
{
|
||||
}
|
||||
|
||||
public decimal X
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public decimal Y
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public decimal Width
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public decimal Height
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
public decimal Left =>
|
||||
this.X;
|
||||
|
||||
[JsonIgnore]
|
||||
public decimal Top =>
|
||||
this.Y;
|
||||
|
||||
[JsonIgnore]
|
||||
public decimal Right =>
|
||||
this.X + this.Width;
|
||||
|
||||
[JsonIgnore]
|
||||
public decimal Bottom =>
|
||||
this.Y + this.Height;
|
||||
|
||||
[JsonIgnore]
|
||||
public decimal Area =>
|
||||
this.Width * this.Height;
|
||||
|
||||
[JsonIgnore]
|
||||
public PointInfo Location =>
|
||||
new(this.X, this.Y);
|
||||
|
||||
[JsonIgnore]
|
||||
public PointInfo Midpoint =>
|
||||
new(
|
||||
x: this.X + (this.Width / 2),
|
||||
y: this.Y + (this.Height / 2));
|
||||
|
||||
[JsonIgnore]
|
||||
public SizeInfo Size => new(this.Width, this.Height);
|
||||
|
||||
/// <summary>
|
||||
/// Centers the rectangle around a specified point.
|
||||
/// </summary>
|
||||
/// <param name="point">The <see cref="PointInfo"/> around which the rectangle will be centered.</param>
|
||||
/// <returns>A new <see cref="RectangleInfo"/> that is centered around the specified point.</returns>
|
||||
public RectangleInfo Center(PointInfo point) =>
|
||||
new(
|
||||
x: point.X - (this.Width / 2),
|
||||
y: point.Y - (this.Height / 2),
|
||||
width: this.Width,
|
||||
height: this.Height);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new <see cref="RectangleInfo"/> that is moved within the bounds of the specified outer rectangle.
|
||||
/// If the current rectangle is larger than the outer rectangle, an exception is thrown.
|
||||
/// </summary>
|
||||
/// <param name="outer">The outer <see cref="RectangleInfo"/> within which to confine this rectangle.</param>
|
||||
/// <returns>A new <see cref="RectangleInfo"/> that is the result of moving this rectangle within the bounds of the outer rectangle.</returns>
|
||||
/// <exception cref="ArgumentException">Thrown when the current rectangle is larger than the outer rectangle.</exception>
|
||||
public RectangleInfo Clamp(RectangleInfo outer)
|
||||
{
|
||||
if ((this.Width > outer.Width) || (this.Height > outer.Height))
|
||||
{
|
||||
throw new ArgumentException($"Value cannot be larger than {nameof(outer)}.");
|
||||
}
|
||||
|
||||
return new(
|
||||
x: Math.Clamp(this.X, outer.X, outer.Right - this.Width),
|
||||
y: Math.Clamp(this.Y, outer.Y, outer.Bottom - this.Height),
|
||||
width: this.Width,
|
||||
height: this.Height);
|
||||
}
|
||||
|
||||
/// <remarks>
|
||||
/// Adapted from https://github.com/dotnet/runtime
|
||||
/// See https://github.com/dotnet/runtime/blob/dfd618dc648ba9b11dd0f8034f78113d69f223cd/src/libraries/System.Drawing.Primitives/src/System/Drawing/Rectangle.cs
|
||||
/// </remarks>
|
||||
public bool Contains(decimal x, decimal y) =>
|
||||
this.X <= x && x < this.X + this.Width && this.Y <= y && y < this.Y + this.Height;
|
||||
|
||||
/// <remarks>
|
||||
/// Adapted from https://github.com/dotnet/runtime
|
||||
/// See https://github.com/dotnet/runtime/blob/dfd618dc648ba9b11dd0f8034f78113d69f223cd/src/libraries/System.Drawing.Primitives/src/System/Drawing/Rectangle.cs
|
||||
/// </remarks>
|
||||
public bool Contains(PointInfo pt) =>
|
||||
this.Contains(pt.X, pt.Y);
|
||||
|
||||
/// <remarks>
|
||||
/// Adapted from https://github.com/dotnet/runtime
|
||||
/// See https://github.com/dotnet/runtime/blob/dfd618dc648ba9b11dd0f8034f78113d69f223cd/src/libraries/System.Drawing.Primitives/src/System/Drawing/Rectangle.cs
|
||||
/// </remarks>
|
||||
public bool Contains(RectangleInfo rect) =>
|
||||
(this.X <= rect.X) && (rect.X + rect.Width <= this.X + this.Width) &&
|
||||
(this.Y <= rect.Y) && (rect.Y + rect.Height <= this.Y + this.Height);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new <see cref="RectangleInfo"/> that is larger than the current rectangle.
|
||||
/// The dimensions of the new rectangle are calculated by enlarging the current rectangle's dimensions by the size of the border.
|
||||
/// </summary>
|
||||
/// <param name="border">The <see cref="BorderStyle"/> that specifies the amount to enlarge the rectangle on each side.</param>
|
||||
/// <returns>A new <see cref="RectangleInfo"/> that is larger than the current rectangle by the specified border amounts.</returns>
|
||||
public RectangleInfo Enlarge(BorderStyle border) =>
|
||||
new(
|
||||
this.X - border.Left,
|
||||
this.Y - border.Top,
|
||||
this.Width + border.Horizontal,
|
||||
this.Height + border.Vertical);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new <see cref="RectangleInfo"/> that is larger than the current rectangle.
|
||||
/// The dimensions of the new rectangle are calculated by enlarging the current rectangle's dimensions by the size of the margin.
|
||||
/// </summary>
|
||||
/// <param name="margin">The <see cref="MarginStyle"/> that specifies the amount to enlarge the rectangle on each side.</param>
|
||||
/// <returns>A new <see cref="RectangleInfo"/> that is larger than the current rectangle by the specified margin amounts.</returns>
|
||||
public RectangleInfo Enlarge(MarginStyle margin) =>
|
||||
new(
|
||||
this.X - margin.Left,
|
||||
this.Y - margin.Top,
|
||||
this.Width + margin.Horizontal,
|
||||
this.Height + margin.Vertical);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new <see cref="RectangleInfo"/> that is larger than the current rectangle.
|
||||
/// The dimensions of the new rectangle are calculated by enlarging the current rectangle's dimensions by the size of the padding.
|
||||
/// </summary>
|
||||
/// <param name="padding">The <see cref="PaddingStyle"/> that specifies the amount to enlarge the rectangle on each side.</param>
|
||||
/// <returns>A new <see cref="RectangleInfo"/> that is larger than the current rectangle by the specified padding amounts.</returns>
|
||||
public RectangleInfo Enlarge(PaddingStyle padding) =>
|
||||
new(
|
||||
this.X - padding.Left,
|
||||
this.Y - padding.Top,
|
||||
this.Width + padding.Horizontal,
|
||||
this.Height + padding.Vertical);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new <see cref="RectangleInfo"/> that is offset by the specified amount.
|
||||
/// </summary>
|
||||
/// <param name="amount">The <see cref="SizeInfo"/> representing the amount to offset in both the X and Y directions.</param>
|
||||
/// <returns>A new <see cref="RectangleInfo"/> that is offset by the specified amount.</returns>
|
||||
public RectangleInfo Offset(SizeInfo amount) =>
|
||||
this.Offset(amount.Width, amount.Height);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new <see cref="RectangleInfo"/> that is offset by the specified X and Y distances.
|
||||
/// </summary>
|
||||
/// <param name="dx">The distance to offset the rectangle along the X-axis.</param>
|
||||
/// <param name="dy">The distance to offset the rectangle along the Y-axis.</param>
|
||||
/// <returns>A new <see cref="RectangleInfo"/> that is offset by the specified X and Y distances.</returns>
|
||||
public RectangleInfo Offset(decimal dx, decimal dy) =>
|
||||
new(this.X + dx, this.Y + dy, this.Width, this.Height);
|
||||
|
||||
public RectangleInfo Round() =>
|
||||
this.Round(0);
|
||||
|
||||
public RectangleInfo Round(int decimals) => new(
|
||||
Math.Round(this.X, decimals),
|
||||
Math.Round(this.Y, decimals),
|
||||
Math.Round(this.Width, decimals),
|
||||
Math.Round(this.Height, decimals));
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new <see cref="RectangleInfo"/> that is a scaled version of the current rectangle.
|
||||
/// The dimensions of the new rectangle are calculated by multiplying the current rectangle's dimensions by the scaling factor.
|
||||
/// </summary>
|
||||
/// <param name="scalingFactor">The factor by which to scale the rectangle's dimensions.</param>
|
||||
/// <returns>A new <see cref="RectangleInfo"/> that is a scaled version of the current rectangle.</returns>
|
||||
public RectangleInfo Scale(decimal scalingFactor) =>
|
||||
new(
|
||||
this.X * scalingFactor,
|
||||
this.Y * scalingFactor,
|
||||
this.Width * scalingFactor,
|
||||
this.Height * scalingFactor);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new <see cref="RectangleInfo"/> that is smaller than the current rectangle.
|
||||
/// The dimensions of the new rectangle are calculated by shrinking the current rectangle's dimensions by the size of the border.
|
||||
/// </summary>
|
||||
/// <param name="border">The <see cref="BorderStyle"/> that specifies the amount to shrink the rectangle on each side.</param>
|
||||
/// <returns>A new <see cref="RectangleInfo"/> that is smaller than the current rectangle by the specified border amounts.</returns>
|
||||
public RectangleInfo Shrink(BorderStyle border) =>
|
||||
new(
|
||||
this.X + border.Left,
|
||||
this.Y + border.Top,
|
||||
this.Width - border.Horizontal,
|
||||
this.Height - border.Vertical);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new <see cref="RectangleInfo"/> that is smaller than the current rectangle.
|
||||
/// The dimensions of the new rectangle are calculated by shrinking the current rectangle's dimensions by the size of the margin.
|
||||
/// </summary>
|
||||
/// <param name="margin">The <see cref="MarginStyle"/> that specifies the amount to shrink the rectangle on each side.</param>
|
||||
/// <returns>A new <see cref="RectangleInfo"/> that is smaller than the current rectangle by the specified margin amounts.</returns>
|
||||
public RectangleInfo Shrink(MarginStyle margin) =>
|
||||
new(
|
||||
this.X + margin.Left,
|
||||
this.Y + margin.Top,
|
||||
this.Width - margin.Horizontal,
|
||||
this.Height - margin.Vertical);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new <see cref="RectangleInfo"/> that is smaller than the current rectangle.
|
||||
/// The dimensions of the new rectangle are calculated by shrinking the current rectangle's dimensions by the size of the padding.
|
||||
/// </summary>
|
||||
/// <param name="padding">The <see cref="PaddingStyle"/> that specifies the amount to shrink the rectangle on each side.</param>
|
||||
/// <returns>A new <see cref="RectangleInfo"/> that is smaller than the current rectangle by the specified padding amounts.</returns>
|
||||
public RectangleInfo Shrink(PaddingStyle padding) =>
|
||||
new(
|
||||
this.X + padding.Left,
|
||||
this.Y + padding.Top,
|
||||
this.Width - padding.Horizontal,
|
||||
this.Height - padding.Vertical);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new <see cref="RectangleInfo"/> where the X, Y, Width, and Height properties of the current rectangle are truncated to integers.
|
||||
/// </summary>
|
||||
/// <returns>A new <see cref="RectangleInfo"/> with the X, Y, Width, and Height properties of the current rectangle truncated to integers.</returns>
|
||||
public RectangleInfo Truncate() =>
|
||||
new(
|
||||
(int)this.X,
|
||||
(int)this.Y,
|
||||
(int)this.Width,
|
||||
(int)this.Height);
|
||||
|
||||
/// <remarks>
|
||||
/// Adapted from https://github.com/dotnet/runtime
|
||||
/// See https://github.com/dotnet/runtime/blob/dfd618dc648ba9b11dd0f8034f78113d69f223cd/src/libraries/System.Drawing.Primitives/src/System/Drawing/Rectangle.cs
|
||||
/// </remarks>
|
||||
public RectangleInfo Union(RectangleInfo rect)
|
||||
{
|
||||
var x1 = Math.Min(this.X, rect.X);
|
||||
var x2 = Math.Max(this.X + this.Width, rect.X + rect.Width);
|
||||
var y1 = Math.Min(this.Y, rect.Y);
|
||||
var y2 = Math.Max(this.Y + this.Height, rect.Y + rect.Height);
|
||||
|
||||
return new RectangleInfo(x1, y1, x2 - x1, y2 - y1);
|
||||
}
|
||||
|
||||
public Rectangle ToRectangle() =>
|
||||
new(
|
||||
(int)this.X,
|
||||
(int)this.Y,
|
||||
(int)this.Width,
|
||||
(int)this.Height);
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "{" +
|
||||
$"{nameof(this.Left)}={this.Left}," +
|
||||
$"{nameof(this.Top)}={this.Top}," +
|
||||
$"{nameof(this.Width)}={this.Width}," +
|
||||
$"{nameof(this.Height)}={this.Height}" +
|
||||
"}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace MouseJump.Common.Models.Drawing;
|
||||
|
||||
/// <summary>
|
||||
/// Immutable version of a System.Windows.Forms.Screen object so we don't need to
|
||||
/// take a dependency on WinForms just for screen info.
|
||||
/// </summary>
|
||||
public sealed class ScreenInfo
|
||||
{
|
||||
public ScreenInfo(int handle, bool primary, RectangleInfo displayArea, RectangleInfo workingArea)
|
||||
{
|
||||
// this.Handle is a HMONITOR that has been cast to an int because we don't want
|
||||
// to expose the HMONITOR type outside the current assembly.
|
||||
this.Handle = handle;
|
||||
this.Primary = primary;
|
||||
this.DisplayArea = displayArea ?? throw new ArgumentNullException(nameof(displayArea));
|
||||
this.WorkingArea = workingArea ?? throw new ArgumentNullException(nameof(workingArea));
|
||||
}
|
||||
|
||||
public int Handle
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public bool Primary
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public RectangleInfo DisplayArea
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public RectangleInfo WorkingArea
|
||||
{
|
||||
get;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using MouseJump.Common.Models.Styles;
|
||||
using BorderStyle = MouseJump.Common.Models.Styles.BorderStyle;
|
||||
|
||||
namespace MouseJump.Common.Models.Drawing;
|
||||
|
||||
/// <summary>
|
||||
/// Immutable version of a System.Drawing.Size object with some extra utility methods.
|
||||
/// </summary>
|
||||
public sealed class SizeInfo
|
||||
{
|
||||
public SizeInfo(decimal width, decimal height)
|
||||
{
|
||||
this.Width = width;
|
||||
this.Height = height;
|
||||
}
|
||||
|
||||
public SizeInfo(Size size)
|
||||
: this(size.Width, size.Height)
|
||||
{
|
||||
}
|
||||
|
||||
public decimal Width
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public decimal Height
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public SizeInfo Clamp(SizeInfo max)
|
||||
{
|
||||
return new(
|
||||
width: Math.Clamp(this.Width, 0, max.Width),
|
||||
height: Math.Clamp(this.Height, 0, max.Height));
|
||||
}
|
||||
|
||||
public SizeInfo Clamp(decimal maxWidth, decimal maxHeight)
|
||||
{
|
||||
return new(
|
||||
width: Math.Clamp(this.Width, 0, maxWidth),
|
||||
height: Math.Clamp(this.Height, 0, maxHeight));
|
||||
}
|
||||
|
||||
public SizeInfo Enlarge(BorderStyle border) =>
|
||||
new(
|
||||
this.Width + border.Horizontal,
|
||||
this.Height + border.Vertical);
|
||||
|
||||
public SizeInfo Enlarge(PaddingStyle padding) =>
|
||||
new(
|
||||
this.Width + padding.Horizontal,
|
||||
this.Height + padding.Vertical);
|
||||
|
||||
/// <summary>
|
||||
/// Rounds down the width and height of this size to the nearest whole number.
|
||||
/// </summary>
|
||||
/// <returns>A new <see cref="SizeInfo"/> instance with floored dimensions.</returns>
|
||||
public SizeInfo Floor()
|
||||
{
|
||||
return new SizeInfo(
|
||||
Math.Floor(this.Width),
|
||||
Math.Floor(this.Height));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the intersection of this size with another size, resulting in a size that represents
|
||||
/// the overlapping dimensions. Both sizes must be non-negative.
|
||||
/// </summary>
|
||||
/// <param name="size">The size to intersect with this instance.</param>
|
||||
/// <returns>A new <see cref="SizeInfo"/> instance representing the intersection of the two sizes.</returns>
|
||||
/// <exception cref="ArgumentException">Thrown when either this size or the specified size has negative dimensions.</exception>
|
||||
public SizeInfo Intersect(SizeInfo size)
|
||||
{
|
||||
if ((this.Width < 0) || (this.Height < 0) || (size.Width < 0) || (size.Height < 0))
|
||||
{
|
||||
throw new ArgumentException("Sizes must be non-negative");
|
||||
}
|
||||
|
||||
return new(
|
||||
Math.Min(this.Width, size.Width),
|
||||
Math.Min(this.Height, size.Height));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="SizeInfo"/> instance with the width and height negated, effectively inverting its dimensions.
|
||||
/// </summary>
|
||||
/// <returns>A new <see cref="SizeInfo"/> instance with inverted dimensions.</returns>
|
||||
public SizeInfo Invert() =>
|
||||
new(-this.Width, -this.Height);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new <see cref="RectangleInfo"/> instance representing a rectangle with this size,
|
||||
/// positioned at the specified coordinates.
|
||||
/// </summary>
|
||||
/// <param name="x">The x-coordinate of the upper-left corner of the rectangle.</param>
|
||||
/// <param name="y">The y-coordinate of the upper-left corner of the rectangle.</param>
|
||||
/// <returns>A new <see cref="RectangleInfo"/> instance representing the positioned rectangle.</returns>
|
||||
public RectangleInfo PlaceAt(decimal x, decimal y) =>
|
||||
new(x, y, this.Width, this.Height);
|
||||
|
||||
public SizeInfo Round() =>
|
||||
this.Round(0);
|
||||
|
||||
public SizeInfo Round(int decimals) => new(
|
||||
Math.Round(this.Width, decimals),
|
||||
Math.Round(this.Height, decimals));
|
||||
|
||||
public SizeInfo Scale(decimal scalingFactor) => new(
|
||||
this.Width * scalingFactor,
|
||||
this.Height * scalingFactor);
|
||||
|
||||
/// <summary>
|
||||
/// Scales this size to fit within the bounds of another size, while maintaining the aspect ratio.
|
||||
/// </summary>
|
||||
/// <param name="bounds">The size to fit this size into.</param>
|
||||
/// <returns>A new <see cref="SizeInfo"/> instance representing the scaled size.</returns>
|
||||
public SizeInfo ScaleToFit(SizeInfo bounds, out decimal scalingRatio)
|
||||
{
|
||||
var widthRatio = bounds.Width / this.Width;
|
||||
var heightRatio = bounds.Height / this.Height;
|
||||
switch (widthRatio.CompareTo(heightRatio))
|
||||
{
|
||||
case < 0:
|
||||
scalingRatio = widthRatio;
|
||||
return new(bounds.Width, this.Height * widthRatio);
|
||||
case 0:
|
||||
// widthRatio and heightRatio are the same, so just pick one
|
||||
scalingRatio = widthRatio;
|
||||
return bounds;
|
||||
case > 0:
|
||||
scalingRatio = heightRatio;
|
||||
return new(this.Width * heightRatio, bounds.Height);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the scaling ratio needed to fit this size within the bounds of another size without distorting the aspect ratio.
|
||||
/// </summary>
|
||||
/// <param name="bounds">The size to fit this size into.</param>
|
||||
/// <returns>The scaling ratio as a decimal.</returns>
|
||||
/// <exception cref="ArgumentException">Thrown if the width or height of the bounds is zero.</exception>
|
||||
public decimal ScaleToFitRatio(SizeInfo bounds)
|
||||
{
|
||||
if (bounds.Width == 0 || bounds.Height == 0)
|
||||
{
|
||||
throw new ArgumentException($"{nameof(bounds.Width)} or {nameof(bounds.Height)} cannot be zero", nameof(bounds));
|
||||
}
|
||||
|
||||
var widthRatio = bounds.Width / this.Width;
|
||||
var heightRatio = bounds.Height / this.Height;
|
||||
var scalingRatio = Math.Min(widthRatio, heightRatio);
|
||||
|
||||
return scalingRatio;
|
||||
}
|
||||
|
||||
public SizeInfo Shrink(BorderStyle border) =>
|
||||
new(this.Width - border.Horizontal, this.Height - border.Vertical);
|
||||
|
||||
public SizeInfo Shrink(MarginStyle margin) =>
|
||||
new(this.Width - margin.Horizontal, this.Height - margin.Vertical);
|
||||
|
||||
public SizeInfo Shrink(PaddingStyle padding) =>
|
||||
new(this.Width - padding.Horizontal, this.Height - padding.Vertical);
|
||||
|
||||
public Size ToSize() => new((int)this.Width, (int)this.Height);
|
||||
|
||||
public Point ToPoint() => new((int)this.Width, (int)this.Height);
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "{" +
|
||||
$"{nameof(this.Width)}={this.Width}," +
|
||||
$"{nameof(this.Height)}={this.Height}" +
|
||||
"}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
using MouseJump.Common.Models.Drawing;
|
||||
using MouseJump.Common.Models.Styles;
|
||||
|
||||
namespace MouseJump.Common.Models.Layout;
|
||||
|
||||
public sealed class PreviewLayout
|
||||
{
|
||||
public sealed class Builder
|
||||
{
|
||||
public Builder()
|
||||
{
|
||||
this.Screens = new();
|
||||
this.ScreenshotBounds = new();
|
||||
}
|
||||
|
||||
public PreviewStyle? PreviewStyle
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public RectangleInfo? VirtualScreen
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public List<RectangleInfo> Screens
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public int ActivatedScreenIndex
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public RectangleInfo? FormBounds
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public BoxBounds? PreviewBounds
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public List<BoxBounds> ScreenshotBounds
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
public PreviewLayout Build()
|
||||
{
|
||||
return new PreviewLayout(
|
||||
previewStyle: this.PreviewStyle ?? throw new InvalidOperationException($"{nameof(this.PreviewStyle)} must be initialized before calling {nameof(this.Build)}."),
|
||||
virtualScreen: this.VirtualScreen ?? throw new InvalidOperationException($"{nameof(this.VirtualScreen)} must be initialized before calling {nameof(this.Build)}."),
|
||||
screens: this.Screens ?? throw new InvalidOperationException($"{nameof(this.Screens)} must be initialized before calling {nameof(this.Build)}."),
|
||||
activatedScreenIndex: this.ActivatedScreenIndex,
|
||||
formBounds: this.FormBounds ?? throw new InvalidOperationException($"{nameof(this.FormBounds)} must be initialized before calling {nameof(this.Build)}."),
|
||||
previewBounds: this.PreviewBounds ?? throw new InvalidOperationException($"{nameof(this.PreviewBounds)} must be initialized before calling {nameof(this.Build)}."),
|
||||
screenshotBounds: this.ScreenshotBounds ?? throw new InvalidOperationException($"{nameof(this.ScreenshotBounds)} must be initialized before calling {nameof(this.Build)}."));
|
||||
}
|
||||
}
|
||||
|
||||
public PreviewLayout(
|
||||
PreviewStyle previewStyle,
|
||||
RectangleInfo virtualScreen,
|
||||
List<RectangleInfo> screens,
|
||||
int activatedScreenIndex,
|
||||
RectangleInfo formBounds,
|
||||
BoxBounds previewBounds,
|
||||
List<BoxBounds> screenshotBounds)
|
||||
{
|
||||
this.PreviewStyle = previewStyle ?? throw new ArgumentNullException(nameof(previewStyle));
|
||||
this.VirtualScreen = virtualScreen ?? throw new ArgumentNullException(nameof(virtualScreen));
|
||||
this.Screens = (screens ?? throw new ArgumentNullException(nameof(screens)))
|
||||
.ToList().AsReadOnly();
|
||||
this.ActivatedScreenIndex = activatedScreenIndex;
|
||||
this.FormBounds = formBounds ?? throw new ArgumentNullException(nameof(formBounds));
|
||||
this.PreviewBounds = previewBounds ?? throw new ArgumentNullException(nameof(previewBounds));
|
||||
this.ScreenshotBounds = (screenshotBounds ?? throw new ArgumentNullException(nameof(screenshotBounds)))
|
||||
.ToList().AsReadOnly();
|
||||
}
|
||||
|
||||
public PreviewStyle PreviewStyle
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public RectangleInfo VirtualScreen
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public ReadOnlyCollection<RectangleInfo> Screens
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public int ActivatedScreenIndex
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public RectangleInfo FormBounds
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public BoxBounds PreviewBounds
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public ReadOnlyCollection<BoxBounds> ScreenshotBounds
|
||||
{
|
||||
get;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace MouseJump.Common.Models.Settings;
|
||||
|
||||
public enum PreviewType
|
||||
{
|
||||
Custom = 0,
|
||||
Compact = 1,
|
||||
Bezelled = 2,
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace MouseJump.Common.Models.Styles;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the background fill style for a drawing object.
|
||||
/// </summary>
|
||||
public sealed class BackgroundStyle
|
||||
{
|
||||
public static readonly BackgroundStyle Empty = new(
|
||||
Color.Transparent,
|
||||
Color.Transparent
|
||||
);
|
||||
|
||||
public BackgroundStyle(
|
||||
Color? color1,
|
||||
Color? color2)
|
||||
{
|
||||
this.Color1 = color1;
|
||||
this.Color2 = color2;
|
||||
}
|
||||
|
||||
public Color? Color1
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public Color? Color2
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "{" +
|
||||
$"{nameof(this.Color1)}={this.Color1}," +
|
||||
$"{nameof(this.Color2)}={this.Color2}" +
|
||||
"}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace MouseJump.Common.Models.Styles;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the border style for a drawing object.
|
||||
/// </summary>
|
||||
public sealed class BorderStyle
|
||||
{
|
||||
public static readonly BorderStyle Empty = new(null, 0, 0);
|
||||
|
||||
public BorderStyle(Color? color, decimal all, decimal depth)
|
||||
: this(color, all, all, all, all, depth)
|
||||
{
|
||||
}
|
||||
|
||||
public BorderStyle(Color? color, decimal left, decimal top, decimal right, decimal bottom, decimal depth)
|
||||
{
|
||||
this.Color = color;
|
||||
this.Left = left;
|
||||
this.Top = top;
|
||||
this.Right = right;
|
||||
this.Bottom = bottom;
|
||||
this.Depth = depth;
|
||||
}
|
||||
|
||||
public Color? Color
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public decimal Left
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public decimal Top
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public decimal Right
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public decimal Bottom
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the "depth" of the 3d highlight and shadow effect on the border.
|
||||
/// </summary>
|
||||
public decimal Depth
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public decimal Horizontal => this.Left + this.Right;
|
||||
|
||||
public decimal Vertical => this.Top + this.Bottom;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "{" +
|
||||
$"{nameof(this.Color)}={this.Color}," +
|
||||
$"{nameof(this.Left)}={this.Left}," +
|
||||
$"{nameof(this.Top)}={this.Top}," +
|
||||
$"{nameof(this.Right)}={this.Right}," +
|
||||
$"{nameof(this.Bottom)}={this.Bottom}," +
|
||||
$"{nameof(this.Depth)}={this.Depth}" +
|
||||
"}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace MouseJump.Common.Models.Styles;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the styles to apply to a simple box-layout based drawing object.
|
||||
/// </summary>
|
||||
public sealed class BoxStyle
|
||||
{
|
||||
/*
|
||||
|
||||
see https://www.w3schools.com/css/css_boxmodel.asp
|
||||
|
||||
+--------------[bounds]---------------+
|
||||
|▒▒▒▒▒▒▒▒▒▒▒▒▒▒[margin]▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒|
|
||||
|▒▒▓▓▓▓▓▓▓▓▓▓▓▓[border]▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒|
|
||||
|▒▒▓▓░░░░░░░░░░[padding]░░░░░░░░░░▓▓▒▒|
|
||||
|▒▒▓▓░░ ░░▓▓▒▒|
|
||||
|▒▒▓▓░░ ░░▓▓▒▒|
|
||||
|▒▒▓▓░░ [content] ░░▓▓▒▒|
|
||||
|▒▒▓▓░░ ░░▓▓▒▒|
|
||||
|▒▒▓▓░░ ░░▓▓▒▒|
|
||||
|▒▒▓▓░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▓▓▒▒|
|
||||
|▒▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▒▒|
|
||||
|▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒|
|
||||
+-------------------------------------+
|
||||
|
||||
*/
|
||||
|
||||
public static readonly BoxStyle Empty = new(MarginStyle.Empty, BorderStyle.Empty, PaddingStyle.Empty, BackgroundStyle.Empty);
|
||||
|
||||
public BoxStyle(
|
||||
MarginStyle marginStyle,
|
||||
BorderStyle borderStyle,
|
||||
PaddingStyle paddingStyle,
|
||||
BackgroundStyle backgroundStyle)
|
||||
{
|
||||
this.MarginStyle = marginStyle ?? throw new ArgumentNullException(nameof(marginStyle));
|
||||
this.BorderStyle = borderStyle ?? throw new ArgumentNullException(nameof(borderStyle));
|
||||
this.PaddingStyle = paddingStyle ?? throw new ArgumentNullException(nameof(paddingStyle));
|
||||
this.BackgroundStyle = backgroundStyle ?? throw new ArgumentNullException(nameof(backgroundStyle));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the margin style for this layout box.
|
||||
/// </summary>
|
||||
public MarginStyle MarginStyle
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the border style for this layout box.
|
||||
/// </summary>
|
||||
public BorderStyle BorderStyle
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the padding style for this layout box.
|
||||
/// </summary>
|
||||
public PaddingStyle PaddingStyle
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the background fill style for the content area of this layout box.
|
||||
/// </summary>
|
||||
public BackgroundStyle BackgroundStyle
|
||||
{
|
||||
get;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace MouseJump.Common.Models.Styles;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the margin style for a drawing object.
|
||||
/// </summary>
|
||||
public sealed class MarginStyle
|
||||
{
|
||||
public static readonly MarginStyle Empty = new(0);
|
||||
|
||||
public MarginStyle(decimal all)
|
||||
: this(all, all, all, all)
|
||||
{
|
||||
}
|
||||
|
||||
public MarginStyle(decimal left, decimal top, decimal right, decimal bottom)
|
||||
{
|
||||
this.Left = left;
|
||||
this.Top = top;
|
||||
this.Right = right;
|
||||
this.Bottom = bottom;
|
||||
}
|
||||
|
||||
public decimal Left
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public decimal Top
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public decimal Right
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public decimal Bottom
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public decimal Horizontal => this.Left + this.Right;
|
||||
|
||||
public decimal Vertical => this.Top + this.Bottom;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "{" +
|
||||
$"{nameof(this.Left)}={this.Left}," +
|
||||
$"{nameof(this.Top)}={this.Top}," +
|
||||
$"{nameof(this.Right)}={this.Right}," +
|
||||
$"{nameof(this.Bottom)}={this.Bottom}" +
|
||||
"}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace MouseJump.Common.Models.Styles;
|
||||
|
||||
/// <summary>
|
||||
/// Represents the margin style for a drawing object.
|
||||
/// </summary>
|
||||
public sealed class PaddingStyle
|
||||
{
|
||||
public static readonly PaddingStyle Empty = new(0);
|
||||
|
||||
public PaddingStyle(decimal all)
|
||||
: this(all, all, all, all)
|
||||
{
|
||||
}
|
||||
|
||||
public PaddingStyle(decimal left, decimal top, decimal right, decimal bottom)
|
||||
{
|
||||
this.Left = left;
|
||||
this.Top = top;
|
||||
this.Right = right;
|
||||
this.Bottom = bottom;
|
||||
}
|
||||
|
||||
public decimal Left
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public decimal Top
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public decimal Right
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public decimal Bottom
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public decimal Horizontal => this.Left + this.Right;
|
||||
|
||||
public decimal Vertical => this.Top + this.Bottom;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "{" +
|
||||
$"{nameof(this.Left)}={this.Left}," +
|
||||
$"{nameof(this.Top)}={this.Top}," +
|
||||
$"{nameof(this.Right)}={this.Right}," +
|
||||
$"{nameof(this.Bottom)}={this.Bottom}" +
|
||||
"}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using MouseJump.Common.Models.Drawing;
|
||||
|
||||
namespace MouseJump.Common.Models.Styles;
|
||||
|
||||
public sealed class PreviewStyle
|
||||
{
|
||||
public PreviewStyle(
|
||||
SizeInfo canvasSize,
|
||||
BoxStyle canvasStyle,
|
||||
BoxStyle screenStyle)
|
||||
{
|
||||
this.CanvasSize = canvasSize ?? throw new ArgumentNullException(nameof(canvasSize));
|
||||
this.CanvasStyle = canvasStyle ?? throw new ArgumentNullException(nameof(canvasStyle));
|
||||
this.ScreenStyle = screenStyle ?? throw new ArgumentNullException(nameof(screenStyle));
|
||||
}
|
||||
|
||||
public SizeInfo CanvasSize
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public BoxStyle CanvasStyle
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
public BoxStyle ScreenStyle
|
||||
{
|
||||
get;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<!-- Look at Directory.Build.props in root for common stuff as well -->
|
||||
<Import Project="$(RepoRoot)src\Common.Dotnet.CsWinRT.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
|
||||
<ProjectGuid>{923DF87C-CA99-4D1C-B1D2-959174E95BFA}</ProjectGuid>
|
||||
<AssemblyName>PowerToys.MouseJump.Common</AssemblyName>
|
||||
<AssemblyTitle>PowerToys.MouseJump.Common</AssemblyTitle>
|
||||
<AssemblyDescription>PowerToys MouseJump.Common</AssemblyDescription>
|
||||
<OutputType>Library</OutputType>
|
||||
<OutputPath>$(RepoRoot)$(Platform)\$(Configuration)</OutputPath>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
|
||||
<ApplicationHighDpiMode>PerMonitorV2</ApplicationHighDpiMode>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Nullable>enable</Nullable>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,44 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace MouseJump.Common.NativeMethods;
|
||||
|
||||
internal static partial class Core
|
||||
{
|
||||
/// <summary>
|
||||
/// A Boolean variable (should be TRUE or FALSE).
|
||||
/// This type is declared in WinDef.h as follows:
|
||||
/// typedef int BOOL;
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// See https://learn.microsoft.com/en-us/windows/win32/winprog/windows-data-types
|
||||
/// </remarks>
|
||||
internal readonly struct BOOL
|
||||
{
|
||||
public readonly int Value;
|
||||
|
||||
public BOOL(int value)
|
||||
{
|
||||
this.Value = value;
|
||||
}
|
||||
|
||||
public BOOL(bool value)
|
||||
{
|
||||
this.Value = value ? 1 : 0;
|
||||
}
|
||||
|
||||
public static implicit operator bool(BOOL value) => value.Value != 0;
|
||||
|
||||
public static implicit operator BOOL(bool value) => new(value);
|
||||
|
||||
public static implicit operator int(BOOL value) => value.Value;
|
||||
|
||||
public static implicit operator BOOL(int value) => new(value);
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{this.GetType().Name}({this.Value})";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace MouseJump.Common.NativeMethods;
|
||||
|
||||
internal static partial class Core
|
||||
{
|
||||
/// <summary>
|
||||
/// The CRECT structure defines a rectangle by the coordinates of its upper-left and lower-right corners.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// See https://learn.microsoft.com/en-us/windows/win32/api/windef/ns-windef-rect
|
||||
/// </remarks>
|
||||
[SuppressMessage("Naming Rules", "SA1307:AccessibleFieldsMustBeginWithUpperCaseLetter", Justification = "Name and value taken from Win32Api")]
|
||||
internal readonly struct CRECT
|
||||
{
|
||||
public static readonly CRECT Empty = new(0, 0, 0, 0);
|
||||
|
||||
public readonly LONG left;
|
||||
public readonly LONG top;
|
||||
public readonly LONG right;
|
||||
public readonly LONG bottom;
|
||||
|
||||
public CRECT(
|
||||
int left, int top, int right, int bottom)
|
||||
{
|
||||
this.left = left;
|
||||
this.top = top;
|
||||
this.right = right;
|
||||
this.bottom = bottom;
|
||||
}
|
||||
|
||||
public CRECT(
|
||||
LONG left, LONG top, LONG right, LONG bottom)
|
||||
{
|
||||
this.left = left;
|
||||
this.top = top;
|
||||
this.right = right;
|
||||
this.bottom = bottom;
|
||||
}
|
||||
|
||||
public static int Size =>
|
||||
Marshal.SizeOf(typeof(CRECT));
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"left={this.left},top={this.top},right={this.right},bottom={this.bottom}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace MouseJump.Common.NativeMethods;
|
||||
|
||||
internal static partial class Core
|
||||
{
|
||||
/// <summary>
|
||||
/// A 32-bit unsigned integer. The range is 0 through 4294967295 decimal.
|
||||
/// This type is declared in IntSafe.h as follows:
|
||||
/// typedef unsigned long DWORD;
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// See https://learn.microsoft.com/en-us/windows/win32/winprog/windows-data-types
|
||||
/// </remarks>
|
||||
internal readonly struct DWORD
|
||||
{
|
||||
public readonly uint Value;
|
||||
|
||||
public DWORD(uint value)
|
||||
{
|
||||
this.Value = value;
|
||||
}
|
||||
|
||||
public static int Size =>
|
||||
Marshal.SizeOf(typeof(DWORD));
|
||||
|
||||
public static implicit operator uint(DWORD value) => value.Value;
|
||||
|
||||
public static implicit operator DWORD(uint value) => new(value);
|
||||
|
||||
public static explicit operator int(DWORD value) => (int)value.Value;
|
||||
|
||||
public static explicit operator DWORD(int value) => new((uint)value);
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{this.GetType().Name}({this.Value})";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace MouseJump.Common.NativeMethods;
|
||||
|
||||
internal static partial class Core
|
||||
{
|
||||
/// <summary>
|
||||
/// A handle to an object.
|
||||
/// This type is declared in WinNT.h as follows:
|
||||
/// typedef PVOID HANDLE;
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// See https://learn.microsoft.com/en-us/windows/win32/winprog/windows-data-types
|
||||
/// </remarks>
|
||||
internal readonly struct HANDLE
|
||||
{
|
||||
public static readonly HANDLE Null = new(IntPtr.Zero);
|
||||
|
||||
public readonly IntPtr Value;
|
||||
|
||||
public HANDLE(IntPtr value)
|
||||
{
|
||||
this.Value = value;
|
||||
}
|
||||
|
||||
public bool IsNull => this.Value == HANDLE.Null.Value;
|
||||
|
||||
public static implicit operator IntPtr(HANDLE value) => value.Value;
|
||||
|
||||
public static explicit operator HANDLE(IntPtr value) => new(value);
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{this.GetType().Name}({this.Value})";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace MouseJump.Common.NativeMethods;
|
||||
|
||||
internal static partial class Core
|
||||
{
|
||||
/// <summary>
|
||||
/// A handle to a device context (DC).
|
||||
/// This type is declared in WinDef.h as follows:
|
||||
/// typedef HANDLE HDC;
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// See https://learn.microsoft.com/en-us/windows/win32/winprog/windows-data-types
|
||||
/// </remarks>
|
||||
internal readonly struct HDC
|
||||
{
|
||||
public static readonly HDC Null = new(IntPtr.Zero);
|
||||
|
||||
public readonly IntPtr Value;
|
||||
|
||||
public HDC(IntPtr value)
|
||||
{
|
||||
this.Value = value;
|
||||
}
|
||||
|
||||
public bool IsNull => this.Value == HDC.Null.Value;
|
||||
|
||||
public static implicit operator IntPtr(HDC value) => value.Value;
|
||||
|
||||
public static explicit operator HDC(IntPtr value) => new(value);
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{this.GetType().Name}({this.Value})";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace MouseJump.Common.NativeMethods;
|
||||
|
||||
internal static partial class Core
|
||||
{
|
||||
/// <summary>
|
||||
/// A handle to a display monitor.
|
||||
/// This type is declared in WinDef.h as follows:
|
||||
/// if(WINVER >= 0x0500) typedef HANDLE HMONITOR;
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// See https://learn.microsoft.com/en-us/windows/win32/winprog/windows-data-types
|
||||
/// </remarks>
|
||||
internal readonly struct HMONITOR
|
||||
{
|
||||
public static readonly HMONITOR Null = new(IntPtr.Zero);
|
||||
|
||||
public readonly IntPtr Value;
|
||||
|
||||
public HMONITOR(IntPtr value)
|
||||
{
|
||||
this.Value = value;
|
||||
}
|
||||
|
||||
public bool IsNull => this.Value == HMONITOR.Null.Value;
|
||||
|
||||
public static implicit operator int(HMONITOR value) => value.Value.ToInt32();
|
||||
|
||||
public static explicit operator HMONITOR(int value) => new(value);
|
||||
|
||||
public static implicit operator IntPtr(HMONITOR value) => value.Value;
|
||||
|
||||
public static explicit operator HMONITOR(IntPtr value) => new(value);
|
||||
|
||||
public static implicit operator HANDLE(HMONITOR value) => new(value.Value);
|
||||
|
||||
public static explicit operator HMONITOR(HANDLE value) => new(value.Value);
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{this.GetType().Name}({this.Value})";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace MouseJump.Common.NativeMethods;
|
||||
|
||||
internal static partial class Core
|
||||
{
|
||||
/// <summary>
|
||||
/// A handle to a window.
|
||||
/// This type is declared in WinDef.h as follows:
|
||||
/// typedef HANDLE HWND;
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// See https://learn.microsoft.com/en-us/windows/win32/winprog/windows-data-types
|
||||
/// </remarks>
|
||||
internal readonly struct HWND
|
||||
{
|
||||
public static readonly HWND Null = new(IntPtr.Zero);
|
||||
|
||||
[SuppressMessage("StyleCop.CSharp.NamingRules", "SA1310:Field names should not contain underscore", Justification = "Name and value taken from Win32Api")]
|
||||
public static readonly HWND HWND_MESSAGE = new(-3);
|
||||
|
||||
public readonly IntPtr Value;
|
||||
|
||||
public HWND(IntPtr value)
|
||||
{
|
||||
this.Value = value;
|
||||
}
|
||||
|
||||
public bool IsNull => this.Value == HWND.Null.Value;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{this.GetType().Name}({this.Value})";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace MouseJump.Common.NativeMethods;
|
||||
|
||||
internal static partial class Core
|
||||
{
|
||||
/// <summary>
|
||||
/// A 32-bit signed integer.The range is -2147483648 through 2147483647 decimal.
|
||||
/// This type is declared in WinNT.h as follows:
|
||||
/// typedef long LONG;
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// See https://learn.microsoft.com/en-us/windows/win32/winprog/windows-data-types
|
||||
/// </remarks>
|
||||
internal readonly struct LONG
|
||||
{
|
||||
public readonly int Value;
|
||||
|
||||
public LONG(int value)
|
||||
{
|
||||
this.Value = value;
|
||||
}
|
||||
|
||||
public static implicit operator int(LONG value) => value.Value;
|
||||
|
||||
public static implicit operator LONG(int value) => new(value);
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{this.GetType().Name}({this.Value})";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace MouseJump.Common.NativeMethods;
|
||||
|
||||
internal static partial class Core
|
||||
{
|
||||
/// <summary>
|
||||
/// A message parameter.
|
||||
/// This type is declared in WinDef.h as follows:
|
||||
/// typedef LONG_PTR LPARAM;
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// See https://learn.microsoft.com/en-us/windows/win32/winprog/windows-data-types
|
||||
/// </remarks>
|
||||
internal readonly struct LPARAM
|
||||
{
|
||||
public static readonly LPARAM Null = new(IntPtr.Zero);
|
||||
|
||||
public readonly IntPtr Value;
|
||||
|
||||
public LPARAM(IntPtr value)
|
||||
{
|
||||
this.Value = value;
|
||||
}
|
||||
|
||||
public bool IsNull => this.Value == LPARAM.Null.Value;
|
||||
|
||||
public static implicit operator IntPtr(LPARAM value) => value.Value;
|
||||
|
||||
public static explicit operator LPARAM(IntPtr value) => new(value);
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{this.GetType().Name}({this.Value})";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace MouseJump.Common.NativeMethods;
|
||||
|
||||
internal static partial class Core
|
||||
{
|
||||
internal readonly struct LPCRECT
|
||||
{
|
||||
public static readonly LPCRECT Null = new(IntPtr.Zero);
|
||||
|
||||
public readonly IntPtr Value;
|
||||
|
||||
public LPCRECT(IntPtr value)
|
||||
{
|
||||
this.Value = value;
|
||||
}
|
||||
|
||||
public LPCRECT(CRECT value)
|
||||
{
|
||||
this.Value = LPCRECT.ToPtr(value);
|
||||
}
|
||||
|
||||
public bool IsNull => this.Value == LPCRECT.Null.Value;
|
||||
|
||||
private static IntPtr ToPtr(CRECT value)
|
||||
{
|
||||
var ptr = Marshal.AllocHGlobal(CRECT.Size);
|
||||
Marshal.StructureToPtr(value, ptr, false);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
public void Free()
|
||||
{
|
||||
Marshal.FreeHGlobal(this.Value);
|
||||
}
|
||||
|
||||
public static implicit operator IntPtr(LPCRECT value) => value.Value;
|
||||
|
||||
public static explicit operator LPCRECT(IntPtr value) => new(value);
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{this.GetType().Name}({this.Value})";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace MouseJump.Common.NativeMethods;
|
||||
|
||||
internal static partial class Core
|
||||
{
|
||||
internal readonly struct LPPOINT
|
||||
{
|
||||
public static readonly LPPOINT Null = new(IntPtr.Zero);
|
||||
|
||||
public readonly IntPtr Value;
|
||||
|
||||
public LPPOINT(IntPtr value)
|
||||
{
|
||||
this.Value = value;
|
||||
}
|
||||
|
||||
public LPPOINT(POINT value)
|
||||
{
|
||||
this.Value = LPPOINT.ToPtr(value);
|
||||
}
|
||||
|
||||
public bool IsNull => this.Value == LPPOINT.Null.Value;
|
||||
|
||||
private static IntPtr ToPtr(POINT value)
|
||||
{
|
||||
var ptr = Marshal.AllocHGlobal(POINT.Size);
|
||||
Marshal.StructureToPtr(value, ptr, false);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
public POINT ToStructure()
|
||||
{
|
||||
return Marshal.PtrToStructure<POINT>(this.Value);
|
||||
}
|
||||
|
||||
public void Free()
|
||||
{
|
||||
Marshal.FreeHGlobal(this.Value);
|
||||
}
|
||||
|
||||
public static implicit operator IntPtr(LPPOINT value) => value.Value;
|
||||
|
||||
public static explicit operator LPPOINT(IntPtr value) => new(value);
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{this.GetType().Name}({this.Value})";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace MouseJump.Common.NativeMethods;
|
||||
|
||||
internal static partial class Core
|
||||
{
|
||||
internal readonly struct LPRECT
|
||||
{
|
||||
public static readonly LPRECT Null = new(IntPtr.Zero);
|
||||
|
||||
public readonly IntPtr Value;
|
||||
|
||||
public LPRECT(IntPtr value)
|
||||
{
|
||||
this.Value = value;
|
||||
}
|
||||
|
||||
public LPRECT(RECT value)
|
||||
{
|
||||
this.Value = LPRECT.ToPtr(value);
|
||||
}
|
||||
|
||||
public bool IsNull => this.Value == LPRECT.Null.Value;
|
||||
|
||||
private static IntPtr ToPtr(RECT value)
|
||||
{
|
||||
var ptr = Marshal.AllocHGlobal(RECT.Size);
|
||||
Marshal.StructureToPtr(value, ptr, false);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
public void Free()
|
||||
{
|
||||
Marshal.FreeHGlobal(this.Value);
|
||||
}
|
||||
|
||||
public static implicit operator IntPtr(LPRECT value) => value.Value;
|
||||
|
||||
public static explicit operator LPRECT(IntPtr value) => new(value);
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{this.GetType().Name}({this.Value})";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace MouseJump.Common.NativeMethods;
|
||||
|
||||
internal static partial class Core
|
||||
{
|
||||
/// <summary>
|
||||
/// The POINT structure defines the x- and y-coordinates of a point.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// See https://learn.microsoft.com/en-us/windows/win32/api/windef/ns-windef-point
|
||||
/// </remarks>
|
||||
[SuppressMessage("SA1307", "SA1307:AccessibleFieldsMustBeginWithUpperCaseLetter", Justification = "Names match Win32 api")]
|
||||
internal readonly struct POINT
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies the x-coordinate of the point.
|
||||
/// </summary>
|
||||
public readonly LONG x;
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the y-coordinate of the point.
|
||||
/// </summary>
|
||||
public readonly LONG y;
|
||||
|
||||
public POINT(
|
||||
int x,
|
||||
int y)
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public POINT(
|
||||
LONG x,
|
||||
LONG y)
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public static int Size =>
|
||||
Marshal.SizeOf(typeof(POINT));
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"x={this.x},y={this.y}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace MouseJump.Common.NativeMethods;
|
||||
|
||||
internal static partial class Core
|
||||
{
|
||||
/// <summary>
|
||||
/// The RECT structure defines a rectangle by the coordinates of its upper-left and lower-right corners.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// See https://learn.microsoft.com/en-us/windows/win32/api/windef/ns-windef-rect
|
||||
/// </remarks>
|
||||
[SuppressMessage("Naming Rules", "SA1307:AccessibleFieldsMustBeginWithUpperCaseLetter", Justification = "Name and value taken from Win32Api")]
|
||||
internal readonly struct RECT
|
||||
{
|
||||
public static readonly RECT Empty = new(0, 0, 0, 0);
|
||||
|
||||
public readonly LONG left;
|
||||
public readonly LONG top;
|
||||
public readonly LONG right;
|
||||
public readonly LONG bottom;
|
||||
|
||||
public RECT(
|
||||
int left, int top, int right, int bottom)
|
||||
{
|
||||
this.left = left;
|
||||
this.top = top;
|
||||
this.right = right;
|
||||
this.bottom = bottom;
|
||||
}
|
||||
|
||||
public RECT(
|
||||
LONG left, LONG top, LONG right, LONG bottom)
|
||||
{
|
||||
this.left = left;
|
||||
this.top = top;
|
||||
this.right = right;
|
||||
this.bottom = bottom;
|
||||
}
|
||||
|
||||
public static int Size =>
|
||||
Marshal.SizeOf(typeof(RECT));
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"left={this.left},top={this.top},right={this.right},bottom={this.bottom}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace MouseJump.Common.NativeMethods;
|
||||
|
||||
internal static partial class Core
|
||||
{
|
||||
/// <summary>
|
||||
/// An unsigned INT. The range is 0 through 4294967295 decimal.
|
||||
/// This type is declared in WinDef.h as follows:
|
||||
/// typedef unsigned int UINT;
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// See https://learn.microsoft.com/en-us/windows/win32/winprog/windows-data-types
|
||||
/// </remarks>
|
||||
internal readonly struct UINT
|
||||
{
|
||||
public readonly uint Value;
|
||||
|
||||
public UINT(uint value)
|
||||
{
|
||||
this.Value = value;
|
||||
}
|
||||
|
||||
public static implicit operator uint(UINT value) => value.Value;
|
||||
|
||||
public static implicit operator UINT(uint value) => new(value);
|
||||
|
||||
public static explicit operator int(UINT value) => (int)value.Value;
|
||||
|
||||
public static explicit operator UINT(int value) => new((uint)value);
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{this.GetType().Name}({this.Value})";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace MouseJump.Common.NativeMethods;
|
||||
|
||||
internal static partial class Core
|
||||
{
|
||||
/// <summary>
|
||||
/// An unsigned LONG_PTR.
|
||||
/// This type is declared in BaseTsd.h as follows:
|
||||
/// C++
|
||||
/// #if defined(_WIN64)
|
||||
/// typedef unsigned __int64 ULONG_PTR;
|
||||
/// #else
|
||||
/// typedef unsigned long ULONG_PTR;
|
||||
/// #endif
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// See https://learn.microsoft.com/en-us/windows/win32/winprog/windows-data-types
|
||||
/// </remarks>
|
||||
internal readonly struct ULONG_PTR
|
||||
{
|
||||
public static readonly ULONG_PTR Null = new(UIntPtr.Zero);
|
||||
|
||||
public readonly UIntPtr Value;
|
||||
|
||||
public ULONG_PTR(UIntPtr value)
|
||||
{
|
||||
this.Value = value;
|
||||
}
|
||||
|
||||
public static implicit operator UIntPtr(ULONG_PTR value) => value.Value;
|
||||
|
||||
public static explicit operator ULONG_PTR(UIntPtr value) => new(value);
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{this.GetType().Name}({this.Value})";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace MouseJump.Common.NativeMethods;
|
||||
|
||||
internal static partial class Core
|
||||
{
|
||||
/// <summary>
|
||||
/// A 16-bit unsigned integer.The range is 0 through 65535 decimal.
|
||||
/// This type is declared in WinDef.h as follows:
|
||||
/// typedef unsigned short WORD;
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// See https://learn.microsoft.com/en-us/windows/win32/winprog/windows-data-types
|
||||
/// </remarks>
|
||||
internal readonly struct WORD
|
||||
{
|
||||
public readonly ushort Value;
|
||||
|
||||
public WORD(ushort value)
|
||||
{
|
||||
this.Value = value;
|
||||
}
|
||||
|
||||
public static implicit operator ulong(WORD value) => value.Value;
|
||||
|
||||
public static implicit operator WORD(ushort value) => new(value);
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{this.GetType().Name}({this.Value})";
|
||||
}
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace MouseJump.Common.NativeMethods;
|
||||
|
||||
internal static partial class Gdi32
|
||||
{
|
||||
/// <summary>
|
||||
/// A raster-operation code. These codes define how the color data for the source
|
||||
/// rectangle is to be combined with the color data for the destination rectangle
|
||||
/// to achieve the final color.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// See https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-bitblt
|
||||
/// </remarks>
|
||||
internal enum ROP_CODE : uint
|
||||
{
|
||||
BLACKNESS = 0x00000042,
|
||||
CAPTUREBLT = 0x40000000,
|
||||
DSTINVERT = 0x00550009,
|
||||
MERGECOPY = 0x00C000CA,
|
||||
MERGEPAINT = 0x00BB0226,
|
||||
NOMIRRORBITMAP = 0x80000000,
|
||||
NOTSRCCOPY = 0x00330008,
|
||||
NOTSRCERASE = 0x001100A6,
|
||||
PATCOPY = 0x00F00021,
|
||||
PATINVERT = 0x005A0049,
|
||||
PATPAINT = 0x00FB0A09,
|
||||
SRCAND = 0x008800C6,
|
||||
SRCCOPY = 0x00CC0020,
|
||||
SRCERASE = 0x00440328,
|
||||
SRCINVERT = 0x00660046,
|
||||
SRCPAINT = 0x00EE0086,
|
||||
WHITENESS = 0x00FF0062,
|
||||
}
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace MouseJump.Common.NativeMethods;
|
||||
|
||||
internal static partial class Gdi32
|
||||
{
|
||||
/// <summary>
|
||||
/// The stretching mode.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// See https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-setstretchbltmode
|
||||
/// </remarks>
|
||||
internal enum STRETCH_BLT_MODE : int
|
||||
{
|
||||
BLACKONWHITE = 1,
|
||||
COLORONCOLOR = 3,
|
||||
HALFTONE = 4,
|
||||
WHITEONBLACK = 2,
|
||||
STRETCH_ANDSCANS = STRETCH_BLT_MODE.BLACKONWHITE,
|
||||
STRETCH_DELETESCANS = STRETCH_BLT_MODE.COLORONCOLOR,
|
||||
STRETCH_HALFTONE = STRETCH_BLT_MODE.HALFTONE,
|
||||
STRETCH_ORSCANS = STRETCH_BLT_MODE.WHITEONBLACK,
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using static MouseJump.Common.NativeMethods.Core;
|
||||
|
||||
namespace MouseJump.Common.NativeMethods;
|
||||
|
||||
internal static partial class Gdi32
|
||||
{
|
||||
/// <summary>
|
||||
/// The SetStretchBltMode function sets the bitmap stretching mode in the specified device context.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// If the function succeeds, the return value is the previous stretching mode.
|
||||
/// If the function fails, the return value is zero.
|
||||
/// This function can return the following value.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// See https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-setstretchbltmode
|
||||
/// </remarks>
|
||||
[LibraryImport(Libraries.Gdi32)]
|
||||
internal static partial int SetStretchBltMode(
|
||||
HDC hdc,
|
||||
STRETCH_BLT_MODE mode);
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using static MouseJump.Common.NativeMethods.Core;
|
||||
|
||||
namespace MouseJump.Common.NativeMethods;
|
||||
|
||||
internal static partial class Gdi32
|
||||
{
|
||||
/// <summary>
|
||||
/// The StretchBlt function copies a bitmap from a source rectangle into a destination
|
||||
/// rectangle, stretching or compressing the bitmap to fit the dimensions of the
|
||||
/// destination rectangle, if necessary. The system stretches or compresses the bitmap
|
||||
/// according to the stretching mode currently set in the destination device context.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// If the function succeeds, the return value is nonzero.
|
||||
/// If the function fails, the return value is zero.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// See https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-stretchblt
|
||||
/// </remarks>
|
||||
[LibraryImport(Libraries.Gdi32)]
|
||||
internal static partial BOOL StretchBlt(
|
||||
HDC hdcDest,
|
||||
int xDest,
|
||||
int yDest,
|
||||
int wDest,
|
||||
int hDest,
|
||||
HDC hdcSrc,
|
||||
int xSrc,
|
||||
int ySrc,
|
||||
int wSrc,
|
||||
int hSrc,
|
||||
ROP_CODE rop);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace MouseJump.Common.NativeMethods;
|
||||
|
||||
internal static class Libraries
|
||||
{
|
||||
public const string Gdi32 = "gdi32";
|
||||
public const string User32 = "user32";
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using static MouseJump.Common.NativeMethods.Core;
|
||||
|
||||
namespace MouseJump.Common.NativeMethods;
|
||||
|
||||
internal static partial class User32
|
||||
{
|
||||
/// <summary>
|
||||
/// The EnumDisplayMonitors function enumerates display monitors (including invisible
|
||||
/// pseudo-monitors associated with the mirroring drivers) that intersect a region formed
|
||||
/// by the intersection of a specified clipping rectangle and the visible region of a
|
||||
/// device context. EnumDisplayMonitors calls an application-defined MonitorEnumProc
|
||||
/// callback function once for each monitor that is enumerated. Note that
|
||||
/// GetSystemMetrics (SM_CMONITORS) counts only the display monitors.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// If the function succeeds, the return value is nonzero.
|
||||
/// If the function fails, the return value is zero.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// See https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-enumdisplaymonitors
|
||||
/// </remarks>
|
||||
[LibraryImport(Libraries.User32)]
|
||||
internal static partial BOOL EnumDisplayMonitors(
|
||||
HDC hdc,
|
||||
LPCRECT lprcClip,
|
||||
MONITORENUMPROC lpfnEnum,
|
||||
LPARAM dwData);
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using static MouseJump.Common.NativeMethods.Core;
|
||||
|
||||
namespace MouseJump.Common.NativeMethods;
|
||||
|
||||
internal static partial class User32
|
||||
{
|
||||
/// <summary>
|
||||
/// The GetMonitorInfo function retrieves information about a display monitor.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// If the function succeeds, the return value is nonzero.
|
||||
/// If the function fails, the return value is zero.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// See https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-enumdisplaymonitors
|
||||
/// </remarks>
|
||||
[LibraryImport(Libraries.User32)]
|
||||
internal static partial BOOL GetMonitorInfoW(
|
||||
HMONITOR hMonitor,
|
||||
LPMONITORINFO lpmi);
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using static MouseJump.Common.NativeMethods.Core;
|
||||
|
||||
namespace MouseJump.Common.NativeMethods;
|
||||
|
||||
internal static partial class User32
|
||||
{
|
||||
/// <summary>
|
||||
/// The GetWindowDC function retrieves the device context (DC) for the entire window,
|
||||
/// including title bar, menus, and scroll bars. A window device context permits painting
|
||||
/// anywhere in a window, because the origin of the device context is the upper-left
|
||||
/// corner of the window instead of the client area.
|
||||
///
|
||||
/// GetWindowDC assigns default attributes to the window device context each time it
|
||||
/// retrieves the device context. Previous attributes are lost.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// If the function succeeds, the return value is a handle to a device context for the specified window.
|
||||
/// If the function fails, the return value is NULL, indicating an error or an invalid hWnd parameter.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// See https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getwindowdc
|
||||
/// </remarks>
|
||||
[LibraryImport(Libraries.User32)]
|
||||
internal static partial HDC GetWindowDC(
|
||||
HWND hWnd);
|
||||
}
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace MouseJump.Common.NativeMethods;
|
||||
|
||||
internal static partial class User32
|
||||
{
|
||||
/// <remarks>
|
||||
/// See https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-sendinput
|
||||
/// </remarks>
|
||||
internal readonly struct LPMONITORINFO
|
||||
{
|
||||
public static readonly LPMONITORINFO Null = new(IntPtr.Zero);
|
||||
|
||||
public readonly IntPtr Value;
|
||||
|
||||
public LPMONITORINFO(IntPtr value)
|
||||
{
|
||||
this.Value = value;
|
||||
}
|
||||
|
||||
public LPMONITORINFO(MONITORINFO value)
|
||||
{
|
||||
this.Value = LPMONITORINFO.ToPtr(value);
|
||||
}
|
||||
|
||||
public MONITORINFO ToStructure()
|
||||
{
|
||||
return Marshal.PtrToStructure<MONITORINFO>(this.Value);
|
||||
}
|
||||
|
||||
private static IntPtr ToPtr(MONITORINFO value)
|
||||
{
|
||||
var ptr = Marshal.AllocHGlobal(MONITORINFO.Size);
|
||||
Marshal.StructureToPtr(value, ptr, false);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
public void Free()
|
||||
{
|
||||
Marshal.FreeHGlobal(this.Value);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{this.GetType().Name}({this.Value})";
|
||||
}
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using static MouseJump.Common.NativeMethods.Core;
|
||||
|
||||
namespace MouseJump.Common.NativeMethods;
|
||||
|
||||
internal static partial class User32
|
||||
{
|
||||
/// <summary>
|
||||
/// A MonitorEnumProc function is an application-defined callback function that is called by the EnumDisplayMonitors function.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// See https://learn.microsoft.com/en-us/windows/win32/api/winuser/nc-winuser-monitorenumproc
|
||||
/// </remarks>
|
||||
internal delegate BOOL MONITORENUMPROC(
|
||||
HMONITOR unnamedParam1,
|
||||
HDC unnamedParam2,
|
||||
LPRECT unnamedParam3,
|
||||
LPARAM unnamedParam4);
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using static MouseJump.Common.NativeMethods.Core;
|
||||
|
||||
namespace MouseJump.Common.NativeMethods;
|
||||
|
||||
internal static partial class User32
|
||||
{
|
||||
/// <summary>
|
||||
/// Used by SendInput to store information for synthesizing input events such as keystrokes, mouse movement, and mouse clicks.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// See https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-monitorinfo
|
||||
/// </remarks>
|
||||
[SuppressMessage("SA1307", "SA1307:AccessibleFieldsMustBeginWithUpperCaseLetter", Justification = "Parameter name matches Win32 api")]
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal readonly struct MONITORINFO
|
||||
{
|
||||
public readonly DWORD cbSize;
|
||||
public readonly RECT rcMonitor;
|
||||
public readonly RECT rcWork;
|
||||
public readonly MONITOR_INFO_FLAGS dwFlags;
|
||||
|
||||
public MONITORINFO(DWORD cbSize, RECT rcMonitor, RECT rcWork, MONITOR_INFO_FLAGS dwFlags)
|
||||
{
|
||||
this.cbSize = cbSize;
|
||||
this.rcMonitor = rcMonitor;
|
||||
this.rcWork = rcWork;
|
||||
this.dwFlags = dwFlags;
|
||||
}
|
||||
|
||||
public static int Size =>
|
||||
Marshal.SizeOf(typeof(MONITORINFO));
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace MouseJump.Common.NativeMethods;
|
||||
|
||||
[SuppressMessage("SA1310", "SA1310:FieldNamesMustNotContainUnderscore", Justification = "Names match Win32 api")]
|
||||
internal static partial class User32
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines the function's return value if the point is not contained within any display monitor.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// See https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-monitorfrompoint
|
||||
/// </remarks>
|
||||
internal enum MONITOR_FROM_FLAGS : uint
|
||||
{
|
||||
MONITOR_DEFAULTTONULL = 0x00000000,
|
||||
MONITOR_DEFAULTTOPRIMARY = 0x00000001,
|
||||
MONITOR_DEFAULTTONEAREST = 0x00000002,
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace MouseJump.Common.NativeMethods;
|
||||
|
||||
[SuppressMessage("SA1310", "SA1310:FieldNamesMustNotContainUnderscore", Justification = "Names match Win32 api")]
|
||||
internal static partial class User32
|
||||
{
|
||||
/// <summary>
|
||||
/// A set of flags that represent attributes of the display monitor.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// See https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-monitorinfo
|
||||
/// </remarks>
|
||||
internal enum MONITOR_INFO_FLAGS : uint
|
||||
{
|
||||
MONITORINFOF_PRIMARY = 1,
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using static MouseJump.Common.NativeMethods.Core;
|
||||
|
||||
namespace MouseJump.Common.NativeMethods;
|
||||
|
||||
internal static partial class User32
|
||||
{
|
||||
/// <summary>
|
||||
/// The MonitorFromPoint function retrieves a handle to the display monitor that contains a specified point.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// If the point is contained by a display monitor, the return value is an HMONITOR handle to that display monitor.
|
||||
/// If the point is not contained by a display monitor, the return value depends on the value of dwFlags.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// See https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-monitorfrompoint
|
||||
/// </remarks>
|
||||
[LibraryImport(Libraries.User32)]
|
||||
internal static partial HMONITOR MonitorFromPoint(
|
||||
POINT pt,
|
||||
MONITOR_FROM_FLAGS dwFlags);
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using static MouseJump.Common.NativeMethods.Core;
|
||||
|
||||
namespace MouseJump.Common.NativeMethods;
|
||||
|
||||
internal static partial class User32
|
||||
{
|
||||
/// <summary>
|
||||
/// The ReleaseDC function releases a device context (DC), freeing it for use by other
|
||||
/// applications. The effect of the ReleaseDC function depends on the type of DC. It
|
||||
/// frees only common and window DCs. It has no effect on class or private DCs.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The return value indicates whether the DC was released. If the DC was released, the return value is 1.
|
||||
/// If the DC was not released, the return value is zero.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// See https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-releasedc
|
||||
/// </remarks>
|
||||
[LibraryImport(Libraries.User32)]
|
||||
internal static partial int ReleaseDC(
|
||||
HWND hWnd,
|
||||
HDC hDC);
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using static MouseJump.Common.NativeMethods.Core;
|
||||
|
||||
namespace MouseJump.Common.NativeMethods;
|
||||
|
||||
internal static partial class User32
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains information about a simulated message generated by an input device
|
||||
/// other than a keyboard or mouse.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// See https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-hardwareinput
|
||||
/// </remarks>
|
||||
[SuppressMessage("SA1307", "SA1307:AccessibleFieldsMustBeginWithUpperCaseLetter", Justification = "Parameter name matches Win32 api")]
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal readonly struct HARDWAREINPUT
|
||||
{
|
||||
public readonly DWORD uMsg;
|
||||
public readonly WORD wParamL;
|
||||
public readonly WORD wParamH;
|
||||
|
||||
public HARDWAREINPUT(
|
||||
DWORD uMsg,
|
||||
WORD wParamL,
|
||||
WORD wParamH)
|
||||
{
|
||||
this.uMsg = uMsg;
|
||||
this.wParamL = wParamL;
|
||||
this.wParamH = wParamH;
|
||||
}
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace MouseJump.Common.NativeMethods;
|
||||
|
||||
internal static partial class User32
|
||||
{
|
||||
/// <summary>
|
||||
/// Used by SendInput to store information for synthesizing input events such as keystrokes, mouse movement, and mouse clicks.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// See https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-input
|
||||
/// </remarks>
|
||||
[SuppressMessage("SA1307", "SA1307:AccessibleFieldsMustBeginWithUpperCaseLetter", Justification = "Parameter name matches Win32 api")]
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal readonly struct INPUT
|
||||
{
|
||||
public readonly INPUT_TYPE type;
|
||||
public readonly DUMMYUNIONNAME data;
|
||||
|
||||
public INPUT(INPUT_TYPE type, DUMMYUNIONNAME data)
|
||||
{
|
||||
this.type = type;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public static int Size =>
|
||||
Marshal.SizeOf(typeof(INPUT));
|
||||
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public readonly struct DUMMYUNIONNAME
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public readonly MOUSEINPUT mi;
|
||||
[FieldOffset(0)]
|
||||
public readonly KEYBDINPUT ki;
|
||||
[FieldOffset(0)]
|
||||
public readonly HARDWAREINPUT hi;
|
||||
|
||||
public DUMMYUNIONNAME(MOUSEINPUT mi)
|
||||
{
|
||||
this.mi = mi;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace MouseJump.Common.NativeMethods;
|
||||
|
||||
[SuppressMessage("SA1310", "SA1310:FieldNamesMustNotContainUnderscore", Justification = "Names match Win32 api")]
|
||||
internal static partial class User32
|
||||
{
|
||||
/// <summary>
|
||||
/// The type of the input event.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// See https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-input
|
||||
/// </remarks>
|
||||
internal enum INPUT_TYPE : uint
|
||||
{
|
||||
INPUT_MOUSE = 0,
|
||||
INPUT_KEYBOARD = 1,
|
||||
INPUT_HARDWARE = 2,
|
||||
}
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using static MouseJump.Common.NativeMethods.Core;
|
||||
|
||||
namespace MouseJump.Common.NativeMethods;
|
||||
|
||||
internal static partial class User32
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains information about a simulated keyboard event.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// See https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-keybdinput
|
||||
/// </remarks>
|
||||
[SuppressMessage("SA1307", "SA1307:AccessibleFieldsMustBeginWithUpperCaseLetter", Justification = "Parameter name matches Win32 api")]
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal readonly struct KEYBDINPUT
|
||||
{
|
||||
public readonly WORD wVk;
|
||||
public readonly WORD wScan;
|
||||
public readonly DWORD dwFlags;
|
||||
public readonly DWORD time;
|
||||
public readonly ULONG_PTR dwExtraInfo;
|
||||
|
||||
public KEYBDINPUT(
|
||||
WORD wVk,
|
||||
WORD wScan,
|
||||
DWORD dwFlags,
|
||||
DWORD time,
|
||||
ULONG_PTR dwExtraInfo)
|
||||
{
|
||||
this.wVk = wVk;
|
||||
this.wScan = wScan;
|
||||
this.dwFlags = dwFlags;
|
||||
this.time = time;
|
||||
this.dwExtraInfo = dwExtraInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace MouseJump.Common.NativeMethods;
|
||||
|
||||
internal static partial class User32
|
||||
{
|
||||
/// <remarks>
|
||||
/// See https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-sendinput
|
||||
/// </remarks>
|
||||
internal readonly struct LPINPUT
|
||||
{
|
||||
public static readonly LPINPUT Null = new(IntPtr.Zero);
|
||||
|
||||
public readonly IntPtr Value;
|
||||
|
||||
public LPINPUT(IntPtr value)
|
||||
{
|
||||
this.Value = value;
|
||||
}
|
||||
|
||||
public LPINPUT(INPUT[] values)
|
||||
{
|
||||
this.Value = LPINPUT.ToPtr(values);
|
||||
}
|
||||
|
||||
public INPUT ToStructure()
|
||||
{
|
||||
return Marshal.PtrToStructure<INPUT>(this.Value);
|
||||
}
|
||||
|
||||
public IEnumerable<INPUT> ToStructure(int count)
|
||||
{
|
||||
var ptr = this.Value;
|
||||
var size = INPUT.Size;
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
yield return Marshal.PtrToStructure<INPUT>(this.Value);
|
||||
ptr += size;
|
||||
}
|
||||
}
|
||||
|
||||
private static IntPtr ToPtr(INPUT[] values)
|
||||
{
|
||||
var mem = Marshal.AllocHGlobal(INPUT.Size * values.Length);
|
||||
var ptr = mem;
|
||||
var size = INPUT.Size;
|
||||
foreach (var value in values)
|
||||
{
|
||||
Marshal.StructureToPtr(value, ptr, false);
|
||||
ptr += size;
|
||||
}
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
public void Free()
|
||||
{
|
||||
Marshal.FreeHGlobal(this.Value);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{this.GetType().Name}({this.Value})";
|
||||
}
|
||||
}
|
||||
}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using static MouseJump.Common.NativeMethods.Core;
|
||||
|
||||
namespace MouseJump.Common.NativeMethods;
|
||||
|
||||
internal static partial class User32
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains information about a simulated mouse event.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// See https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-mouseinput
|
||||
/// </remarks>
|
||||
[SuppressMessage("SA1307", "SA1307:AccessibleFieldsMustBeginWithUpperCaseLetter", Justification = "Parameter name matches Win32 api")]
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal readonly struct MOUSEINPUT
|
||||
{
|
||||
public readonly int dx;
|
||||
public readonly int dy;
|
||||
public readonly DWORD mouseData;
|
||||
public readonly MOUSE_EVENT_FLAGS dwFlags;
|
||||
public readonly DWORD time;
|
||||
public readonly ULONG_PTR dwExtraInfo;
|
||||
|
||||
public MOUSEINPUT(
|
||||
int dx,
|
||||
int dy,
|
||||
DWORD mouseData,
|
||||
MOUSE_EVENT_FLAGS dwFlags,
|
||||
DWORD time,
|
||||
ULONG_PTR dwExtraInfo)
|
||||
{
|
||||
this.dx = dx;
|
||||
this.dy = dy;
|
||||
this.mouseData = mouseData;
|
||||
this.dwFlags = dwFlags;
|
||||
this.time = time;
|
||||
this.dwExtraInfo = dwExtraInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace MouseJump.Common.NativeMethods;
|
||||
|
||||
[SuppressMessage("SA1310", "SA1310:FieldNamesMustNotContainUnderscore", Justification = "Names match Win32 api")]
|
||||
internal static partial class User32
|
||||
{
|
||||
/// <remarks>
|
||||
/// See https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-mouseinput
|
||||
/// </remarks>
|
||||
[Flags]
|
||||
internal enum MOUSE_EVENT_FLAGS : uint
|
||||
{
|
||||
MOUSEEVENTF_MOVE = 0x0001,
|
||||
MOUSEEVENTF_LEFTDOWN = 0x0002,
|
||||
MOUSEEVENTF_LEFTUP = 0x0004,
|
||||
MOUSEEVENTF_RIGHTDOWN = 0x0008,
|
||||
MOUSEEVENTF_RIGHTUP = 0x0010,
|
||||
MOUSEEVENTF_MIDDLEDOWN = 0x0020,
|
||||
MOUSEEVENTF_MIDDLEUP = 0x0040,
|
||||
MOUSEEVENTF_XDOWN = 0x0080,
|
||||
MOUSEEVENTF_XUP = 0x0100,
|
||||
MOUSEEVENTF_WHEEL = 0x0800,
|
||||
MOUSEEVENTF_HWHEEL = 0x1000,
|
||||
MOUSEEVENTF_MOVE_NOCOALESCE = 0x2000,
|
||||
MOUSEEVENTF_VIRTUALDESK = 0x4000,
|
||||
MOUSEEVENTF_ABSOLUTE = 0x8000,
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using static MouseJump.Common.NativeMethods.Core;
|
||||
|
||||
namespace MouseJump.Common.NativeMethods;
|
||||
|
||||
internal static partial class User32
|
||||
{
|
||||
/// <summary>
|
||||
/// Synthesizes keystrokes, mouse motions, and button clicks.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The function returns the number of events that it successfully inserted into the keyboard or mouse input stream.
|
||||
/// If the function returns zero, the input was already blocked by another thread.
|
||||
/// To get extended error information, call GetLastError.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// See https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-sendinput
|
||||
/// </remarks>
|
||||
[LibraryImport(Libraries.User32, SetLastError = true)]
|
||||
internal static partial UINT SendInput(
|
||||
UINT cInputs,
|
||||
LPINPUT pInputs,
|
||||
int cbSize);
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using static MouseJump.Common.NativeMethods.Core;
|
||||
|
||||
namespace MouseJump.Common.NativeMethods;
|
||||
|
||||
internal static partial class User32
|
||||
{
|
||||
/// <summary>
|
||||
/// Retrieves the position of the mouse cursor, in screen coordinates.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// Returns nonzero if successful or zero otherwise.
|
||||
/// To get extended error information, call GetLastError.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// See https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getcursorpos
|
||||
/// </remarks>
|
||||
[LibraryImport(Libraries.User32, SetLastError = true)]
|
||||
internal static partial BOOL GetCursorPos(
|
||||
LPPOINT lpPoint);
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using static MouseJump.Common.NativeMethods.Core;
|
||||
|
||||
namespace MouseJump.Common.NativeMethods;
|
||||
|
||||
internal static partial class User32
|
||||
{
|
||||
/// <summary>
|
||||
/// Retrieves a handle to the desktop window. The desktop window covers the entire
|
||||
/// screen. The desktop window is the area on top of which other windows are painted.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The return value is a handle to the desktop window.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// See https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getdesktopwindow
|
||||
/// </remarks>
|
||||
[LibraryImport(Libraries.User32)]
|
||||
internal static partial HWND GetDesktopWindow();
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace MouseJump.Common.NativeMethods;
|
||||
|
||||
internal static partial class User32
|
||||
{
|
||||
/// <summary>
|
||||
/// Retrieves the specified system metric or system configuration setting.
|
||||
///
|
||||
/// Note that all dimensions retrieved by GetSystemMetrics are in pixels.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// If the function succeeds, the return value is the requested system metric or configuration setting.
|
||||
/// If the function fails, the return value is 0. GetLastError does not provide extended error information.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// See https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getsystemmetrics
|
||||
/// </remarks>
|
||||
[LibraryImport(Libraries.User32)]
|
||||
internal static partial int GetSystemMetrics(
|
||||
SYSTEM_METRICS_INDEX smIndex);
|
||||
}
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace MouseJump.Common.NativeMethods;
|
||||
|
||||
[SuppressMessage("SA1310", "SA1310:FieldNamesMustNotContainUnderscore", Justification = "Names match Win32 api")]
|
||||
internal static partial class User32
|
||||
{
|
||||
internal enum SYSTEM_METRICS_INDEX : uint
|
||||
{
|
||||
SM_ARRANGE = 56,
|
||||
SM_CLEANBOOT = 67,
|
||||
SM_CMONITORS = 80,
|
||||
SM_CMOUSEBUTTONS = 43,
|
||||
SM_CONVERTIBLESLATEMODE = 0x2003,
|
||||
SM_CXBORDER = 5,
|
||||
SM_CXCURSOR = 13,
|
||||
SM_CXDLGFRAME = 7,
|
||||
SM_CXDOUBLECLK = 36,
|
||||
SM_CXDRAG = 68,
|
||||
SM_CXEDGE = 45,
|
||||
SM_CXFIXEDFRAME = SM_CXDLGFRAME,
|
||||
SM_CXFOCUSBORDER = 83,
|
||||
SM_CXFRAME = 32,
|
||||
SM_CXFULLSCREEN = 16,
|
||||
SM_CXHSCROLL = 21,
|
||||
SM_CXHTHUMB = 10,
|
||||
SM_CXICON = 11,
|
||||
SM_CXICONSPACING = 38,
|
||||
SM_CXMAXIMIZED = 61,
|
||||
SM_CXMAXTRACK = 59,
|
||||
SM_CXMENUCHECK = 71,
|
||||
SM_CXMENUSIZE = 54,
|
||||
SM_CXMIN = 28,
|
||||
SM_CXMINIMIZED = 57,
|
||||
SM_CXMINSPACING = 47,
|
||||
SM_CXMINTRACK = 34,
|
||||
SM_CXPADDEDBORDER = 92,
|
||||
SM_CXSCREEN = 0,
|
||||
SM_CXSIZE = 30,
|
||||
SM_CXSIZEFRAME = SM_CXFRAME,
|
||||
SM_CXSMICON = 49,
|
||||
SM_CXSMSIZE = 52,
|
||||
SM_CXVIRTUALSCREEN = 78,
|
||||
SM_CXVSCROLL = 2,
|
||||
SM_CYBORDER = 6,
|
||||
SM_CYCAPTION = 4,
|
||||
SM_CYCURSOR = 14,
|
||||
SM_CYDLGFRAME = 8,
|
||||
SM_CYDOUBLECLK = 37,
|
||||
SM_CYDRAG = 69,
|
||||
SM_CYEDGE = 46,
|
||||
SM_CYFIXEDFRAME = SM_CYDLGFRAME,
|
||||
SM_CYFOCUSBORDER = 84,
|
||||
SM_CYFRAME = 33,
|
||||
SM_CYFULLSCREEN = 17,
|
||||
SM_CYHSCROLL = 3,
|
||||
SM_CYICON = 12,
|
||||
SM_CYICONSPACING = 39,
|
||||
SM_CYKANJIWINDOW = 18,
|
||||
SM_CYMAXIMIZED = 62,
|
||||
SM_CYMAXTRACK = 60,
|
||||
SM_CYMENU = 15,
|
||||
SM_CYMENUCHECK = 72,
|
||||
SM_CYMENUSIZE = 55,
|
||||
SM_CYMIN = 29,
|
||||
SM_CYMINIMIZED = 58,
|
||||
SM_CYMINSPACING = 48,
|
||||
SM_CYMINTRACK = 35,
|
||||
SM_CYSCREEN = 1,
|
||||
SM_CYSIZE = 31,
|
||||
SM_CYSIZEFRAME = SM_CYFRAME,
|
||||
SM_CYSMCAPTION = 51,
|
||||
SM_CYSMICON = 50,
|
||||
SM_CYSMSIZE = 53,
|
||||
SM_CYVIRTUALSCREEN = 79,
|
||||
SM_CYVSCROLL = 20,
|
||||
SM_CYVTHUMB = 9,
|
||||
SM_DBCSENABLED = 42,
|
||||
SM_DEBUG = 22,
|
||||
SM_DIGITIZER = 94,
|
||||
SM_IMMENABLED = 82,
|
||||
SM_MAXIMUMTOUCHES = 95,
|
||||
SM_MEDIACENTER = 87,
|
||||
SM_MENUDROPALIGNMENT = 40,
|
||||
SM_MIDEASTENABLED = 74,
|
||||
SM_MOUSEPRESENT = 19,
|
||||
SM_MOUSEHORIZONTALWHEELPRESENT = 91,
|
||||
SM_MOUSEWHEELPRESENT = 75,
|
||||
SM_NETWORK = 63,
|
||||
SM_PENWINDOWS = 41,
|
||||
SM_REMOTECONTROL = 0x2001,
|
||||
SM_REMOTESESSION = 0x1000,
|
||||
SM_SAMEDISPLAYFORMA = 81,
|
||||
SM_SECURE = 44,
|
||||
SM_SERVERR2 = 89,
|
||||
SM_SHOWSOUNDS = 70,
|
||||
SM_SHUTTINGDOWN = 0x2000,
|
||||
SM_SLOWMACHINE = 73,
|
||||
SM_STARTER = 88,
|
||||
SM_SWAPBUTTON = 23,
|
||||
SM_SYSTEMDOCKED = 0x2004,
|
||||
SM_TABLETPC = 86,
|
||||
SM_XVIRTUALSCREEN = 76,
|
||||
SM_YVIRTUALSCREEN = 77,
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using static MouseJump.Common.NativeMethods.Core;
|
||||
|
||||
namespace MouseJump.Common.NativeMethods;
|
||||
|
||||
internal static partial class User32
|
||||
{
|
||||
/// <summary>
|
||||
/// Moves the cursor to the specified screen coordinates. If the new coordinates are not within
|
||||
/// the screen rectangle set by the most recent ClipCursor function call, the system automatically
|
||||
/// adjusts the coordinates so that the cursor stays within the rectangle.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// Returns nonzero if successful or zero otherwise.
|
||||
/// To get extended error information, call GetLastError.
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// See https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getcursorpos
|
||||
/// </remarks>
|
||||
[LibraryImport(Libraries.User32, SetLastError = true)]
|
||||
internal static partial BOOL SetCursorPos(
|
||||
int X,
|
||||
int Y);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("MouseJump.Common.UnitTests")]
|
||||
Reference in New Issue
Block a user