microsoft-ui-xaml icon indicating copy to clipboard operation
microsoft-ui-xaml copied to clipboard

Problems with Input Injection

Open kitswas opened this issue 2 years ago • 4 comments

Describe the bug

  1. Multiple calls to InputInjector.TryCreate() cause the app to crash.
  2. InitializeGamepadInjection() always causes an app to crash if called after a call to UninitializeGamepadInjection() on the same InputInjector instance.

Similar problems have been reported for mouse injection.

if an InputInjector is created and used a second time no mouse input is simulated (without failure).

Steps to reproduce the bug

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Windows.Gaming.Input;
using Windows.UI.Input.Preview.Injection;

namespace PC_Win
{
    internal class GamepadInjector
    {
        private InjectedInputGamepadInfo gamepadState;
        private readonly InputInjector injector;
        private bool isConnected;

        public GamepadInjector()
        {
            injector = InputInjector.TryCreate();
            gamepadState = new InjectedInputGamepadInfo();
            isConnected = false;
        }

        public void ConnectGamepad()
        {
            if (!isConnected)
            {
                try
                {
                    injector.InitializeGamepadInjection();
                    isConnected = true;
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                }
            }
        }

        public void DisconnectGamepad()
        {
            if (isConnected)
            {
                try
                {
                    injector.UninitializeGamepadInjection();
                    isConnected = false;
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                }
            }
        }

        public void Update(InjectedInputGamepadInfo state)
        {
            gamepadState = state;
        }

        public void PressButton(GamepadButtons button)
        {
            gamepadState.Buttons |= button;
        }

        public void ReleaseButton(GamepadButtons button)
        {
            gamepadState.Buttons &= ~button;
        }

        public void Inject()
        {
            if (isConnected)
            {
                injector.InjectGamepadInput(gamepadState);
            }
        }

        ~GamepadInjector()
        {
            DisconnectGamepad();
        }
    }
}

Make an object of this class and call the functions as described. The above is part of a WinUI3 app.

The same app rewritten in C++ using Cpp/WinRT (with Qt6 for GUI) has the same problems.
And the same happened in Rust with the windows-rs crate. See comment.

This clearly points towards a problem in the library.

Expected behavior

The InputInjector.InitializeGamepadInjection() docs say:

Calling this method is analogous to connecting a physical gamepad, which also triggers a GamepadAdded event.

A physical gamepad is assigned a persistent unique ID (see NonRoamableId) that does not change when the device is connected and disconnected. Similarly, a virtual gamepad created with InitializeGamepadInjection is also assigned a unique ID that persists across calls to UninitializeGamepadInjection and InitializeGamepadInjection for the same InputInjector instance.

A virtual reconnect should behave adequately then.

Creating and initializing multiple InputInjector instances should work without crashing. It is equivalent to connecting multiple devices in reality.

Screenshots

No response

NuGet package version

None

Windows version

Windows 11 (22H2): Build 22621

Additional context

No response

kitswas avatar Jul 13 '23 12:07 kitswas

You may use this website (not mine) to test the Gamepad Input.
It works. (At least till the apps crash)

kitswas avatar Jul 13 '23 12:07 kitswas

The debugger (gdb) tells me the problem lies in

SyntheticController_UnregisterReportCallback of XboxgipSynthetic in xboxgipsynthetic.dll

VS Code screenshot

Full stack trace:

xboxgipsynthetic.dll!XboxgipSynthetic!SyntheticController_UnregisterReportCallback (Unknown Source:0)
xboxgipsynthetic.dll!XboxgipSynthetic!SyntheticController_UnregisterReportCallback (Unknown Source:0)
xboxgipsynthetic.dll!XboxgipSynthetic!SyntheticController_UnregisterReportCallback (Unknown Source:0)
xboxgipsynthetic.dll!XboxgipSynthetic!SyntheticController_UnregisterReportCallback (Unknown Source:0)
kernel32.dll!KERNEL32!BaseThreadInitThunk (Unknown Source:0)
ntdll.dll!ntdll!RtlUserThreadStart (Unknown Source:0)
[Unknown/Just-In-Time compiled code] (Unknown Source:0)

The program segfaults soon after.

Do let me know if this helps or if this is a false positive.

Note: This is C++, not C#. The code is almost a direct translation of the reproducible example above.

kitswas avatar Jun 28 '25 17:06 kitswas

XboxgipSynthetic.dll - Is the source-code for this library available anywhere?
I would like to fix it if possible.

@michael-hawker @bpulliam

kitswas avatar Oct 10 '25 13:10 kitswas

Help this guy out please :) Would love to have his app working! It's a great open source alternative for some pretty shitty commercial software.