Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,48 @@ public static partial class MaaController
[LibraryImport("MaaFramework", StringMarshalling = StringMarshalling.Utf8)]
public static partial MaaControllerHandle MaaCustomControllerCreate([MarshalUsing(typeof(MaaMarshaller))] Custom.IMaaCustomController controller, nint controllerArg);

/// <summary>
/// Create a debug controller that serves images from a directory.
/// </summary>
/// <param name="readPath">Path to a directory of images (or a single image file).</param>
/// <returns>The controller handle, or nint.Zero on failure.</returns>
[LibraryImport("MaaFramework", StringMarshalling = StringMarshalling.Utf8)]
public static partial MaaControllerHandle MaaDbgControllerCreate(string readPath);

/// <summary>
/// Create a macOS controller for native macOS applications.
/// </summary>
/// <param name="windowId">The CGWindowID of the target window (0 for desktop).</param>
/// <param name="screencapMethod">macOS screencap method to use.</param>
/// <param name="inputMethod">macOS input method to use.</param>
/// <returns>The controller handle, or nint.Zero on failure.</returns>
[LibraryImport("MaaFramework", StringMarshalling = StringMarshalling.Utf8)]
public static partial MaaControllerHandle MaaMacOSControllerCreate(uint windowId, MaaMacOSScreencapMethod screencapMethod, MaaMacOSInputMethod inputMethod);

/// <summary>
/// Create an Android native controller.
/// </summary>
/// <param name="configJson">JSON config for the control unit.</param>
/// <returns>The controller handle, or nint.Zero on failure.</returns>
[LibraryImport("MaaFramework", StringMarshalling = StringMarshalling.Utf8)]
public static partial MaaControllerHandle MaaAndroidNativeControllerCreate(string configJson);

/// <summary>
/// Create a replay controller that replays recorded operations.
/// </summary>
/// <param name="recordingPath">Path to the recording JSONL file.</param>
/// <returns>The controller handle, or nint.Zero on failure.</returns>
[LibraryImport("MaaFramework", StringMarshalling = StringMarshalling.Utf8)]
public static partial MaaControllerHandle MaaDbgControllerCreate(string readPath, string writePath, MaaDbgControllerType type, string config);
public static partial MaaControllerHandle MaaReplayControllerCreate(string recordingPath);

/// <summary>
/// Create a record controller that wraps an existing controller and records all operations.
/// </summary>
/// <param name="inner">The inner controller to forward all operations to.</param>
/// <param name="recordingPath">Path to the recording JSONL file to write.</param>
/// <returns>The record controller handle, or nint.Zero on failure.</returns>
[LibraryImport("MaaFramework", StringMarshalling = StringMarshalling.Utf8)]
public static partial MaaControllerHandle MaaRecordControllerCreate(MaaControllerHandle inner, string recordingPath);

[LibraryImport("MaaFramework", StringMarshalling = StringMarshalling.Utf8)]
public static partial void MaaControllerDestroy(MaaControllerHandle ctrl);
Expand Down Expand Up @@ -87,6 +127,9 @@ public static partial class MaaController
[LibraryImport("MaaFramework", StringMarshalling = StringMarshalling.Utf8)]
public static partial MaaCtrlId MaaControllerPostTouchUp(MaaControllerHandle ctrl, int contact);

[LibraryImport("MaaFramework", StringMarshalling = StringMarshalling.Utf8)]
public static partial MaaCtrlId MaaControllerPostRelativeMove(MaaControllerHandle ctrl, int dx, int dy);

[LibraryImport("MaaFramework", StringMarshalling = StringMarshalling.Utf8)]
public static partial MaaCtrlId MaaControllerPostKeyDown(MaaControllerHandle ctrl, int keycode);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@
[return: MarshalAs(UnmanagedType.U1)]
public static partial bool MaaTaskerGetNodeDetail(MaaTaskerHandle tasker, MaaNodeId nodeId, MaaStringBufferHandle nodeName, out MaaRecoId recoId, out MaaActId actionId, [MarshalAs(UnmanagedType.U1)] out bool completed);

[LibraryImport("MaaFramework", StringMarshalling = StringMarshalling.Utf8)]
[return: MarshalAs(UnmanagedType.U1)]
public static partial bool MaaTaskerGetWaitFreezesDetail(MaaTaskerHandle tasker, MaaWfId wfId, MaaStringBufferHandle nodeName, MaaStringBufferHandle phase, [MarshalAs(UnmanagedType.U1)] out bool success, out MaaSize elapsedMs, MaaRecoId[]? recoIdList, ref MaaSize recoIdListSize, MaaRectHandle roi);

Check failure on line 114 in src/MaaFramework.Binding.Native/Interop/Framework/Instance/MaaTasker.cs

View workflow job for this annotation

GitHub Actions / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. Auto-generated code requires an explicit '#nullable' directive in source.

Check failure on line 114 in src/MaaFramework.Binding.Native/Interop/Framework/Instance/MaaTasker.cs

View workflow job for this annotation

GitHub Actions / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. Auto-generated code requires an explicit '#nullable' directive in source.

Check failure on line 114 in src/MaaFramework.Binding.Native/Interop/Framework/Instance/MaaTasker.cs

View workflow job for this annotation

GitHub Actions / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. Auto-generated code requires an explicit '#nullable' directive in source.

Check failure on line 114 in src/MaaFramework.Binding.Native/Interop/Framework/Instance/MaaTasker.cs

View workflow job for this annotation

GitHub Actions / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context. Auto-generated code requires an explicit '#nullable' directive in source.

[LibraryImport("MaaFramework", StringMarshalling = StringMarshalling.Utf8)]
[return: MarshalAs(UnmanagedType.U1)]
public static partial bool MaaTaskerGetTaskDetail(MaaTaskerHandle tasker, MaaTaskId taskId, MaaStringBufferHandle entry, MaaNodeId[] nodeIdList, ref MaaSize nodeIdListSize, out MaaStatus status);
Expand Down
5 changes: 5 additions & 0 deletions src/MaaFramework.Binding.Native/Interop/Framework/MaaDef.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,15 @@
// No bitwise OR, just set it
global using MaaDbgControllerType = System.UInt64;
global using MaaControllerFeature = System.UInt64;
// macOS controller types
global using MaaMacOSScreencapMethod = System.UInt64;
global using MaaMacOSInputMethod = System.UInt64;
// Gamepad types
global using MaaGamepadType = System.UInt64;
global using MaaGamepadButton = System.UInt64;
global using MaaGamepadTouch = System.UInt64;
// WaitFreezes id
global using MaaWfId = System.Int64;
global using MaaRectHandle = nint;

using System.Runtime.InteropServices;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
global using MaaToolkitAdbDeviceListHandle = nint;
global using MaaToolkitDesktopWindowHandle = nint;
global using MaaToolkitDesktopWindowListHandle = nint;
global using MaaMacOSPermission = System.Int32;

namespace MaaFramework.Binding.Interop.Native;

Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

#pragma warning disable CS1573 // 参数在 XML 注释中没有匹配的 param 标记
#pragma warning disable CS1591 // 缺少对公共可见类型或成员的 XML 注释

using System.Runtime.InteropServices;

namespace MaaFramework.Binding.Interop.Native;

public static partial class MaaToolkitMacOS
{
[LibraryImport("MaaToolkit")]
[return: MarshalAs(UnmanagedType.U1)]
public static partial bool MaaToolkitMacOSCheckPermission(MaaMacOSPermission perm);

[LibraryImport("MaaToolkit")]
[return: MarshalAs(UnmanagedType.U1)]
public static partial bool MaaToolkitMacOSRequestPermission(MaaMacOSPermission perm);

[LibraryImport("MaaToolkit")]
[return: MarshalAs(UnmanagedType.U1)]
public static partial bool MaaToolkitMacOSRevealPermissionSettings(MaaMacOSPermission perm);
}
7 changes: 7 additions & 0 deletions src/MaaFramework.Binding.Native/MaaController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@
/// <remarks>
/// Wrapper of <see cref="MaaControllerPostPressKey"/>.
/// </remarks>
[Obsolete($"Use {nameof(ClickKey)}() instead.")]

Check warning on line 118 in src/MaaFramework.Binding.Native/MaaController.cs

View workflow job for this annotation

GitHub Actions / build

Do not forget to remove this deprecated code someday. (https://rules.sonarsource.com/csharp/RSPEC-1133)

Check warning on line 118 in src/MaaFramework.Binding.Native/MaaController.cs

View workflow job for this annotation

GitHub Actions / build

Do not forget to remove this deprecated code someday. (https://rules.sonarsource.com/csharp/RSPEC-1133)
public MaaJob PressKey(int keyCode)
=> CreateJob(MaaControllerPostPressKey(Handle, keyCode));

Expand Down Expand Up @@ -168,6 +168,13 @@
public MaaJob TouchUp(int contact)
=> CreateJob(MaaControllerPostTouchUp(Handle, contact));

/// <inheritdoc/>
/// <remarks>
/// Wrapper of <see cref="MaaControllerPostRelativeMove"/>.
/// </remarks>
public MaaJob RelativeMove(int dx, int dy)
=> CreateJob(MaaControllerPostRelativeMove(Handle, dx, dy));

/// <inheritdoc/>
/// <remarks>
/// Wrapper of <see cref="MaaControllerPostKeyDown"/>.
Expand Down Expand Up @@ -221,7 +228,7 @@
/// <remarks>
/// Wrapper of <see cref="MaaControllerStatus"/>.
/// </remarks>
[Obsolete("Deprecated from v4.5.0.")]

Check warning on line 231 in src/MaaFramework.Binding.Native/MaaController.cs

View workflow job for this annotation

GitHub Actions / build

Do not forget to remove this deprecated code someday. (https://rules.sonarsource.com/csharp/RSPEC-1133)

Check warning on line 231 in src/MaaFramework.Binding.Native/MaaController.cs

View workflow job for this annotation

GitHub Actions / build

Do not forget to remove this deprecated code someday. (https://rules.sonarsource.com/csharp/RSPEC-1133)
public MaaJobStatus GetStatus(MaaJob job)
{
ArgumentNullException.ThrowIfNull(job);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using static MaaFramework.Binding.Interop.Native.MaaController;

namespace MaaFramework.Binding;

/// <summary>
/// A wrapper class providing a reference implementation for <see cref="MaaAndroidNativeControllerCreate"/>.
/// </summary>
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public class MaaAndroidNativeController : MaaController
{
private readonly string _debugConfigJson;

[ExcludeFromCodeCoverage(Justification = "Debugger display.")]
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private string DebuggerDisplay => IsInvalid
? $"Invalid {GetType().Name}"
: $"{GetType().Name} {{ ConfigJson = {_debugConfigJson} }}";

/// <summary>
/// Creates a <see cref="MaaAndroidNativeController"/> instance.
/// </summary>
/// <param name="configJson">JSON config for the control unit.</param>
/// <param name="link">Executes <see cref="IMaaController.LinkStart"/> if <see cref="LinkOption.Start"/>; otherwise, not link.</param>
/// <param name="check">Checks LinkStart().Wait() status if <see cref="CheckStatusOption.ThrowIfNotSucceeded"/>; otherwise, not check.</param>
/// <remarks>
/// Wrapper of <see cref="MaaAndroidNativeControllerCreate"/>.
/// <para>This controller is only available on Android.</para>
/// </remarks>
/// <exception cref="ArgumentException"/>
/// <exception cref="MaaJobStatusException"/>
public MaaAndroidNativeController([StringSyntax("Json")] string configJson, LinkOption link = LinkOption.Start, CheckStatusOption check = CheckStatusOption.ThrowIfNotSucceeded)
{
ArgumentException.ThrowIfNullOrEmpty(configJson);

var handle = MaaAndroidNativeControllerCreate(configJson);
_ = MaaControllerAddSink(handle, MaaEventCallback, (nint)MaaHandleType.Controller);
SetHandle(handle, needReleased: true);

_debugConfigJson = configJson;

if (link == LinkOption.Start)
LinkStartOnConstructed(check, configJson);
}
}
24 changes: 7 additions & 17 deletions src/MaaFramework.Binding.Native/MaaController/MaaDbgController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,47 +11,37 @@ namespace MaaFramework.Binding;
public class MaaDbgController : MaaController
{
private readonly string _debugReadPath;
private readonly string _debugWritePath;
private readonly DbgControllerType _debugType;
private readonly string _debugConfig;

[ExcludeFromCodeCoverage(Justification = "Debugger display.")]
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private string DebuggerDisplay => IsInvalid
? $"Invalid {GetType().Name}"
: $"{GetType().Name} {{ ReadFrom = {_debugReadPath}, WriteTo = {_debugWritePath}, Type = {_debugType}, Config = {_debugConfig} }}";
: $"{GetType().Name} {{ ReadFrom = {_debugReadPath} }}";

/// <summary>
/// Creates a <see cref="MaaDbgController"/> instance.
/// </summary>
/// <param name="readPath">The read path.</param>
/// <param name="writePath">The write path.</param>
/// <param name="type">The DebugControllerType.</param>
/// <param name="config">The config.</param>
/// <param name="readPath">Path to a directory of images (or a single image file).</param>
/// <param name="link">Executes <see cref="IMaaController.LinkStart"/> if <see cref="LinkOption.Start"/>; otherwise, not link.</param>
/// <param name="check">Checks LinkStart().Wait() status if <see cref="CheckStatusOption.ThrowIfNotSucceeded"/>; otherwise, not check.</param>
/// <remarks>
/// Wrapper of <see cref="MaaDbgControllerCreate"/>.
/// <para>Images are loaded on connect and cycled through on each screencap request.</para>
/// <para>All input operations (click, swipe, etc.) are no-ops that return success.</para>
/// </remarks>
/// <exception cref="ArgumentException"/>
/// <exception cref="MaaJobStatusException"/>
public MaaDbgController(string readPath, string writePath, DbgControllerType type, [StringSyntax("Json")] string config = "{}", LinkOption link = LinkOption.Start, CheckStatusOption check = CheckStatusOption.ThrowIfNotSucceeded)
public MaaDbgController(string readPath, LinkOption link = LinkOption.Start, CheckStatusOption check = CheckStatusOption.ThrowIfNotSucceeded)
{
ArgumentException.ThrowIfNullOrEmpty(readPath);
ArgumentException.ThrowIfNullOrEmpty(writePath);
if (type == DbgControllerType.None) throw new ArgumentException($"Value cannot be {DbgControllerType.None}.", nameof(type));
ArgumentException.ThrowIfNullOrEmpty(config);

var handle = MaaDbgControllerCreate(readPath, writePath, (MaaDbgControllerType)type, config);
var handle = MaaDbgControllerCreate(readPath);
_ = MaaControllerAddSink(handle, MaaEventCallback, (nint)MaaHandleType.Controller);
SetHandle(handle, needReleased: true);

_debugReadPath = readPath;
_debugWritePath = writePath;
_debugType = type;
_debugConfig = config;

if (link == LinkOption.Start)
LinkStartOnConstructed(check, readPath, writePath, type, config);
LinkStartOnConstructed(check, readPath);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using static MaaFramework.Binding.Interop.Native.MaaController;

namespace MaaFramework.Binding;

/// <summary>
/// A wrapper class providing a reference implementation for <see cref="MaaMacOSControllerCreate"/>.
/// </summary>
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public class MaaMacOSController : MaaController
{
private readonly uint _debugWindowId;
private readonly MacOSScreencapMethod _debugScreencapMethod;
private readonly MacOSInputMethod _debugInputMethod;

[ExcludeFromCodeCoverage(Justification = "Debugger display.")]
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private string DebuggerDisplay => IsInvalid
? $"Invalid {GetType().Name}"
: $"{GetType().Name} {{ WindowId = {_debugWindowId}, ScreencapMethod = {_debugScreencapMethod}, InputMethod = {_debugInputMethod} }}";

/// <summary>
/// Creates a <see cref="MaaMacOSController"/> instance.
/// </summary>
/// <param name="windowId">The CGWindowID of the target window (0 for desktop).</param>
/// <param name="screencapMethod">macOS screencap method to use.</param>
/// <param name="inputMethod">macOS input method to use.</param>
/// <param name="link">Executes <see cref="IMaaController.LinkStart"/> if <see cref="LinkOption.Start"/>; otherwise, not link.</param>
/// <param name="check">Checks LinkStart().Wait() status if <see cref="CheckStatusOption.ThrowIfNotSucceeded"/>; otherwise, not check.</param>
/// <remarks>
/// Wrapper of <see cref="MaaMacOSControllerCreate"/>.
/// <para>This controller is designed for native macOS applications.</para>
/// <para>Requires Screen Recording permission for screencap.</para>
/// <para>Input simulation requires Accessibility permission.</para>
/// <para>Some features are not supported: start_app, stop_app, scroll.</para>
/// <para>Only single touch is supported (contact must be 0).</para>
/// </remarks>
/// <exception cref="MaaJobStatusException"/>
public MaaMacOSController(uint windowId, MacOSScreencapMethod screencapMethod, MacOSInputMethod inputMethod, LinkOption link = LinkOption.Start, CheckStatusOption check = CheckStatusOption.ThrowIfNotSucceeded)
{
var handle = MaaMacOSControllerCreate(windowId, (MaaMacOSScreencapMethod)screencapMethod, (MaaMacOSInputMethod)inputMethod);
_ = MaaControllerAddSink(handle, MaaEventCallback, (nint)MaaHandleType.Controller);
SetHandle(handle, needReleased: true);

_debugWindowId = windowId;
_debugScreencapMethod = screencapMethod;
_debugInputMethod = inputMethod;

if (link == LinkOption.Start)
LinkStartOnConstructed(check, windowId, screencapMethod, inputMethod);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using static MaaFramework.Binding.Interop.Native.MaaController;

namespace MaaFramework.Binding;

/// <summary>
/// A wrapper class providing a reference implementation for <see cref="MaaRecordControllerCreate"/>.
/// </summary>
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public class MaaRecordController : MaaController
{
private readonly string _debugRecordingPath;

[ExcludeFromCodeCoverage(Justification = "Debugger display.")]
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private string DebuggerDisplay => IsInvalid
? $"Invalid {GetType().Name}"
: $"{GetType().Name} {{ RecordingPath = {_debugRecordingPath} }}";

/// <summary>
/// Creates a <see cref="MaaRecordController"/> instance.
/// </summary>
/// <param name="inner">The inner controller to forward all operations to. Must not be null.</param>
/// <param name="recordingPath">Path to the recording JSONL file to write.</param>
/// <param name="link">Executes <see cref="IMaaController.LinkStart"/> if <see cref="LinkOption.Start"/>; otherwise, not link.</param>
/// <param name="check">Checks LinkStart().Wait() status if <see cref="CheckStatusOption.ThrowIfNotSucceeded"/>; otherwise, not check.</param>
/// <remarks>
/// Wrapper of <see cref="MaaRecordControllerCreate"/>.
/// <para>The record controller does NOT take ownership of the inner controller.</para>
/// <para>Screenshot images will be saved to a "{stem}-Screenshot" folder in the same directory as this file.</para>
/// <para>The recorded file can be replayed using <see cref="MaaReplayController"/>.</para>
/// </remarks>
/// <exception cref="ArgumentNullException"/>
/// <exception cref="ArgumentException"/>
/// <exception cref="MaaJobStatusException"/>
public MaaRecordController(MaaController inner, string recordingPath, LinkOption link = LinkOption.Start, CheckStatusOption check = CheckStatusOption.ThrowIfNotSucceeded)
{
ArgumentNullException.ThrowIfNull(inner);
ArgumentException.ThrowIfNullOrEmpty(recordingPath);

var handle = MaaRecordControllerCreate(inner.Handle, recordingPath);
_ = MaaControllerAddSink(handle, MaaEventCallback, (nint)MaaHandleType.Controller);
SetHandle(handle, needReleased: true);

_debugRecordingPath = recordingPath;

if (link == LinkOption.Start)
LinkStartOnConstructed(check, inner, recordingPath);
}
}
Loading
Loading