[MWB] Use UWP API to inject mouse input (#27229)

* [MWB] Use UWP API to inject mouse input
This commit is contained in:
Andrey Nekrasov 2023-07-10 18:32:20 +02:00 committed by GitHub
parent e2d65dcb84
commit c3c15ffad1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 57 additions and 10 deletions

View File

@ -33,6 +33,7 @@
<PackageVersion Include="Microsoft.Windows.CsWin32" Version="0.2.46-beta" />
<PackageVersion Include="Microsoft.Windows.CsWinRT" Version="2.0.2" />
<PackageVersion Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.755" />
<PackageVersion Include="Microsoft.Windows.SDK.Contracts" Version="10.0.19041.1" />
<PackageVersion Include="Microsoft.WindowsAppSDK" Version="1.3.230502000" />
<PackageVersion Include="Microsoft.Xaml.Behaviors.WinUI.Managed" Version="2.0.9" />
<PackageVersion Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.39" />

View File

@ -308,6 +308,7 @@ SOFTWARE.
- Microsoft.Windows.CsWin32 0.2.46-beta
- Microsoft.Windows.CsWinRT 2.0.2
- Microsoft.Windows.SDK.BuildTools 10.0.22621.755
- Microsoft.Windows.SDK.Contracts 10.0.19041.1
- Microsoft.WindowsAppSDK 1.3.230502000
- Microsoft.Xaml.Behaviors.WinUI.Managed 2.0.9
- Microsoft.Xaml.Behaviors.Wpf 1.1.39

View File

@ -20,6 +20,7 @@ using System.Threading;
using Microsoft.Win32;
using MouseWithoutBorders.Class;
using MouseWithoutBorders.Form;
using Windows.UI.Input.Preview.Injection;
namespace MouseWithoutBorders
{
@ -110,6 +111,21 @@ namespace MouseWithoutBorders
Common.Log(e.Message);
}
try
{
InputSimulation.Injector = InputInjector.TryCreate();
if (InputSimulation.Injector != null)
{
InputSimulation.MoveMouseRelative(0, 0);
NativeMethods.InjectMouseInputAvailable = true;
}
}
catch (EntryPointNotFoundException)
{
NativeMethods.InjectMouseInputAvailable = false;
Common.Log($"{nameof(NativeMethods.InjectMouseInputAvailable)} = false");
}
bool dummy = Setting.Values.DrawMouseEx;
Is64bitOS = IntPtr.Size == 8;
tcpPort = Setting.Values.TcpPort;

View File

@ -15,6 +15,8 @@ using System.Globalization;
using System.Runtime.InteropServices;
using System.ServiceProcess;
using System.Threading.Tasks;
using Windows.UI.Input.Preview.Injection;
using static MouseWithoutBorders.Class.NativeMethods;
[module: SuppressMessage("Microsoft.Portability", "CA1901:PInvokeDeclarationsShouldBePortable", Scope = "member", Target = "MouseWithoutBorders.InputSimulation.#keybd_event(System.Byte,System.Byte,System.UInt32,System.Int32)", MessageId = "3", Justification = "Dotnet port with style preservation")]
[module: SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", Scope = "member", Target = "MouseWithoutBorders.InputSimulation.#InputProcessKeyEx(System.Int32,System.Int32,System.Boolean&)", MessageId = "MouseWithoutBorders.NativeMethods.LockWorkStation", Justification = "Dotnet port with style preservation")]
@ -23,15 +25,30 @@ namespace MouseWithoutBorders.Class
{
internal class InputSimulation
{
public static InputInjector Injector;
private InputSimulation()
{
}
internal static InjectedInputMouseInfo MouseInputToInjectedInputMouseInfo(MOUSEINPUT mouseInput)
{
var injectedInput = new InjectedInputMouseInfo();
injectedInput.DeltaX = mouseInput.dx;
injectedInput.DeltaY = mouseInput.dy;
injectedInput.MouseData = (uint)mouseInput.mouseData;
injectedInput.MouseOptions = (InjectedInputMouseOptions)mouseInput.dwFlags;
injectedInput.TimeOffsetInMilliseconds = (uint)mouseInput.time;
return injectedInput;
}
private static uint SendInputEx(NativeMethods.INPUT input)
{
Common.PaintCount = 0;
uint rv;
uint rv = 0;
if (Common.Is64bitOS)
{
NativeMethods.INPUT64 input64 = default;
@ -58,18 +75,27 @@ namespace MouseWithoutBorders.Class
input64.mi.dwExtraInfo = input.mi.dwExtraInfo;
}
NativeMethods.INPUT64[] inputs = { input64 };
// mouse click simulation
// TODO: Find alternative API that simulates mouse input more directly
rv = NativeMethods.SendInput64(1, inputs, Marshal.SizeOf(input64));
if (input.type == 0 && (input.mi.dwFlags & (int)NativeMethods.MOUSEEVENTF.MOVE) != 0 && NativeMethods.InjectMouseInputAvailable)
{
Injector.InjectMouseInput(new[] { MouseInputToInjectedInputMouseInfo(input64.mi) });
}
else
{
NativeMethods.INPUT64[] inputs = { input64 };
rv = NativeMethods.SendInput64(1, inputs, Marshal.SizeOf(input64));
}
}
else
{
NativeMethods.INPUT[] inputs = { input };
// TODO: Find alternative API that simulates mouse input more directly
rv = NativeMethods.SendInput(1, inputs, Marshal.SizeOf(input));
if (input.type == 0 && (input.mi.dwFlags & (int)NativeMethods.MOUSEEVENTF.MOVE) != 0 && NativeMethods.InjectMouseInputAvailable)
{
Injector.InjectMouseInput(new[] { MouseInputToInjectedInputMouseInfo(input.mi) });
}
else
{
NativeMethods.INPUT[] inputs = { input };
rv = NativeMethods.SendInput(1, inputs, Marshal.SizeOf(input));
}
}
return rv;

View File

@ -576,6 +576,8 @@ namespace MouseWithoutBorders.Class
[DllImport("user32.dll", EntryPoint = "SendInput", SetLastError = true)]
internal static extern uint SendInput64(uint nInputs, INPUT64[] pInputs, int cbSize);
internal static bool InjectMouseInputAvailable { get; set; }
[DllImport("user32.dll", EntryPoint = "GetMessageExtraInfo", SetLastError = true)]
internal static extern IntPtr GetMessageExtraInfo();

View File

@ -217,6 +217,7 @@
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.Windows.Compatibility" />
<PackageReference Include="Microsoft.Windows.SDK.Contracts" />
<PackageReference Include="StreamJsonRpc" />
</ItemGroup>
<ItemGroup>