XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFESystem

【Rust】XFE系统,基于Rust和汇编

公开
关注 0 Fork 0 Star 0
UTF-8
using System.Text.Json;

namespace XFESystem.Desktop;

public enum DesktopDisplayMode { Duplicate, Extend, SelectedOnly }
public sealed record DesktopDisplay(string Id, string Name, int NativeWidth, int NativeHeight);
public sealed record DesktopDisplayPosition(string Id, int X, int Y);

/// <summary>A bounded, immutable preference; coordinates are desktop layout units.</summary>
public sealed class DesktopDisplayConfiguration
{
    public DesktopDisplayMode Mode { get; }
    public string PrimaryId { get; }
    public IReadOnlyList<DesktopDisplayPosition> Positions { get; }
    public DesktopDisplayConfiguration(DesktopDisplayMode mode, string primaryId, IEnumerable<DesktopDisplayPosition> positions)
    { Mode = mode; PrimaryId = primaryId; Positions = Array.AsReadOnly(positions.Take(9).ToArray()); }
    public DesktopDisplayConfiguration WithMode(DesktopDisplayMode mode) => new(mode, PrimaryId, Positions);
    public DesktopDisplayConfiguration WithPrimary(string id) => new(Mode, id, Positions);
    public DesktopDisplayConfiguration Move(string id, int x, int y) => new(Mode, PrimaryId, Positions.Select(p => p.Id == id ? new(id, x, y) : p));

    private static string Quote(string value) => "\"" + JsonEncodedText.Encode(value).ToString() + "\"";
    public string ToJson() => "{\"Version\":1,\"Mode\":" + Quote(Mode.ToString()) +
        ",\"Primary\":" + Quote(PrimaryId) + ",\"Positions\":[" +
        string.Join(',', Positions.Select(p => "{\"Id\":" + Quote(p.Id) + ",\"X\":" + p.X.ToString(System.Globalization.CultureInfo.InvariantCulture) + ",\"Y\":" + p.Y.ToString(System.Globalization.CultureInfo.InvariantCulture) + "}")) + "]}";

    public static DesktopDisplayConfiguration Parse(string text)
    {
        if (text.Length > 8192) throw new FormatException("Display settings exceed the supported size.");
        using var document = JsonDocument.Parse(text, new JsonDocumentOptions { MaxDepth = 5 });
        var root = document.RootElement;
        RequireFields(root, "Version", "Mode", "Primary", "Positions");
        if (root.GetProperty("Version").GetInt32() != 1 ||
            !Enum.TryParse<DesktopDisplayMode>(root.GetProperty("Mode").GetString(), out var mode) || !Enum.IsDefined(mode))
            throw new FormatException("Unsupported display settings version or mode.");
        string primary = root.GetProperty("Primary").GetString() ?? "";
        var positions = new List<DesktopDisplayPosition>();
        var list = root.GetProperty("Positions");
        if (list.ValueKind != JsonValueKind.Array || list.GetArrayLength() is < 1 or > 8) throw new FormatException("Invalid display count.");
        foreach (var item in list.EnumerateArray())
        {
            RequireFields(item, "Id", "X", "Y");
            string id = item.GetProperty("Id").GetString() ?? "";
            if (id.Length is < 1 or > 128 || positions.Any(p => p.Id == id)) throw new FormatException("Invalid or duplicate display identity.");
            positions.Add(new(id, item.GetProperty("X").GetInt32(), item.GetProperty("Y").GetInt32()));
        }
        return new(mode, primary, positions);
    }
    private static void RequireFields(JsonElement element, params string[] names)
    {
        if (element.ValueKind != JsonValueKind.Object) throw new FormatException("Display settings must be objects.");
        var seen = new HashSet<string>(StringComparer.Ordinal);
        foreach (var property in element.EnumerateObject())
            if (!names.Contains(property.Name, StringComparer.Ordinal) || !seen.Add(property.Name)) throw new FormatException("Unknown or duplicate display setting.");
        if (seen.Count != names.Length) throw new FormatException("Incomplete display settings.");
    }
}

public sealed record DesktopDisplayScreen(DesktopDisplay Display, DesktopBounds Bounds, bool IsPrimary);

/// <summary>Validates hardware identities, memory budget, overlap and reachable monitor edges.</summary>
public sealed class DesktopDisplayLayout
{
    public IReadOnlyList<DesktopDisplayScreen> Screens { get; }
    public DesktopDisplayScreen Primary { get; }
    public int Width { get; }
    public int Height { get; }
    private DesktopDisplayLayout(DesktopDisplayScreen[] screens, int width, int height)
    { Screens = Array.AsReadOnly(screens); Primary = screens.Single(s => s.IsPrimary); Width = width; Height = height; }

    public static DesktopDisplayConfiguration Default(IReadOnlyList<DesktopDisplay> displays, int scalePercent)
    {
        int x = 0, y = 0, rowHeight = 0;
        var positions = displays.Select(d =>
        {
            int w = d.NativeWidth * 100 / scalePercent, h = d.NativeHeight * 100 / scalePercent;
            if (x > 32768) { x = 0; y += rowHeight; rowHeight = 0; }
            var position = new DesktopDisplayPosition(d.Id, x, y); x += w; rowHeight = Math.Max(rowHeight, h); return position;
        }).ToArray();
        return new(DesktopDisplayMode.Duplicate, displays[0].Id, positions);
    }

    public static DesktopDisplayLayout Create(IReadOnlyList<DesktopDisplay> displays, DesktopDisplayConfiguration configuration, int scalePercent)
    {
        if (displays.Count is < 1 or > 8 || scalePercent is < 100 or > 400 || !Enum.IsDefined(configuration.Mode) ||
            displays.Any(d => string.IsNullOrEmpty(d.Id) || d.Id.Length > 128 || d.NativeWidth is < 320 or > 16384 ||
                d.NativeHeight is < 200 or > 16384 || (long)d.NativeWidth * d.NativeHeight > 33_554_432) ||
            displays.Select(d => d.Id).Distinct(StringComparer.Ordinal).Count() != displays.Count ||
            !displays.Any(d => d.Id == configuration.PrimaryId) || configuration.Positions.Count != displays.Count)
            throw new ArgumentException("The display configuration does not match the connected outputs.");
        foreach (var display in displays)
            if (configuration.Positions.Count(p => p.Id == display.Id) != 1) throw new ArgumentException("A display position is missing or duplicated.");
        if (configuration.Positions.Any(p => p.X is < -32768 or > 32768 || p.Y is < -32768 or > 32768))
            throw new ArgumentException("The display arrangement is outside the supported desktop.");
        DesktopBounds Bounds(DesktopDisplay d)
        {
            var p = configuration.Positions.Single(p => p.Id == d.Id);
            return new(p.X, p.Y, Math.Max(1, d.NativeWidth * 100 / scalePercent), Math.Max(1, d.NativeHeight * 100 / scalePercent));
        }
        var primary = displays.Single(d => d.Id == configuration.PrimaryId);
        if (configuration.Mode != DesktopDisplayMode.Extend)
        {
            var b = Bounds(primary) with { X = 0, Y = 0 };
            var active = configuration.Mode == DesktopDisplayMode.Duplicate ? displays : [primary];
            return new(active.Select(d => new DesktopDisplayScreen(d, b, d.Id == primary.Id)).ToArray(), b.Width, b.Height);
        }
        var rectangles = displays.Select(Bounds).ToArray();
        for (int i = 0; i < rectangles.Length; i++)
            for (int j = 0; j < i; j++)
                if (Overlap(rectangles[i], rectangles[j])) throw new ArgumentException("Displays cannot overlap in Extend mode.");
        var reachable = new HashSet<int> { 0 };
        for (int pass = 0; pass < displays.Count; pass++)
            for (int i = 0; i < displays.Count; i++)
                if (!reachable.Contains(i) && reachable.Any(j => Touches(rectangles[i], rectangles[j]))) reachable.Add(i);
        if (reachable.Count != displays.Count) throw new ArgumentException("Arrange the displays so their edges touch.");
        int left = rectangles.Min(b => b.X), top = rectangles.Min(b => b.Y);
        int width = rectangles.Max(b => b.X + b.Width) - left, height = rectangles.Max(b => b.Y + b.Height) - top;
        if ((long)width * scalePercent / 100 * (height * (long)scalePercent / 100) > 33_554_432)
            throw new ArgumentException("This arrangement exceeds the desktop pixel budget.");
        return new(displays.Select((d, i) => new DesktopDisplayScreen(d, rectangles[i] with { X = rectangles[i].X - left, Y = rectangles[i].Y - top }, d.Id == primary.Id)).ToArray(), width, height);
    }

    public (int X, int Y) ConstrainPointer(int x, int y)
    {
        (int X, int Y) closest = default;
        long nearest = long.MaxValue;
        for (int index = 0; index < Screens.Count; index++)
        {
            var b = Screens[index].Bounds;
            if (b.Contains(x, y)) return (x, y);
            var position = (X: Math.Clamp(x, b.X, b.X + b.Width - 1), Y: Math.Clamp(y, b.Y, b.Y + b.Height - 1));
            long dx = (long)x - position.X, dy = (long)y - position.Y;
            // Coordinates come from the bounded native desktop viewport.
            long distance = dx * dx + dy * dy;
            if (distance < nearest) { nearest = distance; closest = position; }
        }
        return closest;
    }

    public static bool Overlap(DesktopBounds a, DesktopBounds b) => a.X < b.X + b.Width && b.X < a.X + a.Width && a.Y < b.Y + b.Height && b.Y < a.Y + a.Height;
    private static bool Touches(DesktopBounds a, DesktopBounds b) =>
        (a.X + a.Width == b.X || b.X + b.Width == a.X) && Math.Max(a.Y, b.Y) < Math.Min(a.Y + a.Height, b.Y + b.Height) ||
        (a.Y + a.Height == b.Y || b.Y + b.Height == a.Y) && Math.Max(a.X, b.X) < Math.Min(a.X + a.Width, b.X + b.Width);
}

public interface IDesktopDisplayManager
{
    IReadOnlyList<DesktopDisplay> Displays { get; }
    DesktopDisplayConfiguration Current { get; }
    DesktopDisplayLayout Layout { get; }
    int ScalePercent { get; }
    string DetectionMessage { get; }
    bool TryApply(DesktopDisplayConfiguration configuration, out string? error);
    void Identify(bool visible);
    void Detect();
    event Action? Changed;
}