Skip to content

[Native] - Implement IsXInputDevice method in C# #1926

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Nov 17, 2023

Conversation

Jklawreszuk
Copy link
Collaborator

@Jklawreszuk Jklawreszuk commented Oct 11, 2023

PR Details

Description

My PR implements IsXInputDevice method in C#

Related Issue

#1394

Todo

  • - Need to check for regression

using SharpDX;
using SharpDX.DirectInput;
using Stride.Native.DirectInput;
using Microsoft.Win32;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would that make a problem with linux migration?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that this file compiles only when STRIDE_UI_WINFORMS or STRIDE_UI_WPF and are set only when StrideFramework is Windows

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so propably no

@manio143
Copy link
Member

manio143 commented Oct 11, 2023

While it's amazing to see so much C++ code replaced by so little C#, I'm worried we might not be able to accept code copied from a GPL licensed project into an MIT licensed project, unless with the explicit permission of the copyright holder to re-license the code.
This is because GPL is a viral license and GPL code can only be used in GPL projects.
The workaround is LGPL, where we would reference a compiled library that is an output of a GPL project.

@Jklawreszuk
Copy link
Collaborator Author

@manio143 Oh my. Good point, I forgot about the fact that GNU is not a completely "free" license. I'll try to investigate my own implementation then

@tebjan
Copy link
Member

tebjan commented Oct 11, 2023

You could also ask the author if he allows us to use that part of the code. The author always has full control over his work, no matter the license the code is published with.

@Eideren Eideren marked this pull request as draft October 11, 2023 19:27
@IXLLEGACYIXL
Copy link
Collaborator

IXLLEGACYIXL commented Oct 12, 2023

The problem is that the GPL code doesnt work with sharpdx

Sharpdx takes the HID path from a device and somehow builds an product ID ( GUID ) from it
what the GPL code does is just splitting the HID and takes the values and compares them which will never fit to the sharpdx guid

$devices = Get-WmiObject -Query 'SELECT * FROM Win32_PNPEntity WHERE DeviceID LIKE "%VID_%&PID_%&IG_%"'
this is how you can select the xinput devices
accordign to microsoft if it has IG_ in it then its an xinput device
https://learn.microsoft.com/en-us/windows/win32/xinput/xinput-and-directinput

to convert a sharpdx guid to a hid i only found that
https://stackoverflow.com/questions/67059441/how-to-map-directinput-sharpdx-device-to-its-corresponding-hid-c
but that mentioned class is internal

one option would be to accurately query with wql to get all xdevices and comparing the device path instead of the guid

the gpl code is just doing alot of fancy things but in the end it just converts this example hid path
HID\VID_045E&PID_028E&IG_00\3&8968588&0&0000
to that
045E028E
( not sure anymore aobut the leading zeros )
and this number is far away from a sharpdx guid

this shouldnt sound negative about the gpl code, i just couldnt find an alignment between sharpdx and the guid part of the code

if you need testing i can use my playstation controllers as xinput and help with testing

@archanox
Copy link

archanox commented Oct 31, 2023

I haven't checked if this code works or not, but chatgpt says you can do this,

using SharpDX.XInput;

// Create a controller object for the first player
var controller = new Controller(UserIndex.One);

// Check if the controller is connected
if (controller.IsConnected)
{
    // Get the controller capabilities
    var capabilities = controller.GetCapabilities(DeviceQueryType.Any);

    // Check if the controller is an XInput device
    if (capabilities.Type == DeviceType.Gamepad)
    {
        // Do something with the controller
        Console.WriteLine("XInput device detected");
    }
    else
    {
        // The controller is not an XInput device
        Console.WriteLine("Non-XInput device detected");
    }
}
else
{
    // No controller is connected
    Console.WriteLine("No controller detected");
}

And

using SharpDX.DirectInput;

// Create a DirectInput object
var directInput = new DirectInput();

// Create a device instance from the product GUID
var deviceInstance = directInput.GetDevice(productGuid);

// Check if the device is an XInput device
if (deviceInstance.Type == DeviceType.Gamepad)
{
    // The device is an XInput device
    Console.WriteLine("XInput device detected");
}
else
{
    // The device is not an XInput device
    Console.WriteLine("Non-XInput device detected");
}

@IXLLEGACYIXL
Copy link
Collaborator

anything can be a xinput device, even a mouse, it depends how windows tries to use it

@Jklawreszuk Jklawreszuk marked this pull request as ready for review October 31, 2023 14:53
@Jklawreszuk Jklawreszuk changed the title [WIP] - [Native] - Implement IsXInputDevice method in C# [Native] - Implement IsXInputDevice method in C# Oct 31, 2023
@Jklawreszuk Jklawreszuk force-pushed the xinput branch 2 times, most recently from dcaa8a5 to 08269c3 Compare October 31, 2023 15:11

var mySession = CimSession.Create(null, DComOptions);

IEnumerable<CimInstance> allDevices = mySession.QueryInstances(@"root\cimv2", "WQL", "SELECT * FROM Win32_PNPEntity");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I imagine this query is not super cheap and results won't be different if called more than once a frame. Consider calling the query and transforming the IEnumerable with regex once, caching the result in the Scan() method, so that IsXInputDevice can be a simpler lookup.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Jklawreszuk - do you think your WQL optimization is enough here? The Scan() method goes in a loop over the devices and checks for each one if it's XInput - are we confident to say there usually wouldn't be many devices returned by DirectInput and thus this isn't a big perf issue? Otherwise we make a Windows call a few times in a tight loop and I imagine those are usually slower. However, at the same time Scan is called on initialization and then only upon manual request it seems.

Copy link
Collaborator Author

@Jklawreszuk Jklawreszuk Nov 3, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@manio143 Yea, Very good suggestion 👍. I guess, It is unlikely that something will change under the scan() method call. I updated changes, Is this what you had in mind?

@archanox
Copy link

archanox commented Nov 2, 2023

anything can be a xinput device, even a mouse, it depends how windows tries to use it

Sorry, I might have misunderstood the purpose of the function being replaced.

Btw, cheers for the thumbs down @Jklawreszuk...

@Jklawreszuk
Copy link
Collaborator Author

Jklawreszuk commented Nov 2, 2023

Sorry @archanox, I didn't have time to reply. I want to thank you for your help, however, both examples do not compile , because API doesn't even exist. So, that's why I gave you thumbs down, nothing personal.. 😅

@Jklawreszuk Jklawreszuk force-pushed the xinput branch 2 times, most recently from c774cb4 to 62abf51 Compare November 2, 2023 22:15
@@ -18,11 +20,15 @@ internal class InputSourceWindowsDirectInput : InputSourceBase
private readonly HashSet<Guid> devicesToRemove = new HashSet<Guid>();
private InputManager inputManager;
private DirectInput directInput;
private IEnumerable<CimInstance> allDevices;
private Regex regex;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider renaming it to xInputDeviceIdRegex

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

DComSessionOptions DComOptions = new DComSessionOptions();
DComOptions.Impersonation = ImpersonationType.Impersonate;

var mySession = CimSession.Create(null, DComOptions);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe all above and including this line has to be moved to GetAllXInputDevices()

@Jklawreszuk Jklawreszuk force-pushed the xinput branch 3 times, most recently from f071bb4 to 37f8135 Compare November 8, 2023 16:06
Copy link
Member

@manio143 manio143 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code wise it's good. If you can confirm it got tested I'll merge it.

@IXLLEGACYIXL
Copy link
Collaborator

IXLLEGACYIXL commented Nov 9, 2023

Code wise it's good. If you can confirm it got tested I'll merge it.

i can test it with a playstation controller and emulate that it should be treated as xinput, dunnno if thats sufficient

the query works so far

@manio143
Copy link
Member

manio143 commented Nov 9, 2023

There seems to be an issue with the build about no input files to clang - if there's no more cop files, we may need to turn off the property which triggers native lib compilation https://teamcity.stride3d.net/buildConfiguration/Engine_BuildWindowsOpenGL/23137?hideProblemsFromDependencies=false&hideTestsFromDependencies=false

@Jklawreszuk Jklawreszuk changed the title [Native] - Implement IsXInputDevice method in C# [WIP] - [Native] - Implement IsXInputDevice method in C# Nov 11, 2023
@Eideren Eideren marked this pull request as draft November 12, 2023 15:46
@Jklawreszuk Jklawreszuk changed the title [WIP] - [Native] - Implement IsXInputDevice method in C# [Native] - Implement IsXInputDevice method in C# Nov 15, 2023
@Jklawreszuk Jklawreszuk marked this pull request as ready for review November 15, 2023 23:49
@Jklawreszuk
Copy link
Collaborator Author

Jklawreszuk commented Nov 16, 2023

@manio143 I've managed to fix building my PR by simply checking if the input (c files collection) is empty.
I personally don't have a gamepad that supports xinput so it returned false oposed to @IXLLEGACYIXL when testing on XInput device, so it seems to work 👀

@IXLLEGACYIXL
Copy link
Collaborator

IXLLEGACYIXL commented Nov 16, 2023

@manio143 I've managed to fix building my PR by simply checking if the input (c files collection) is empty. I personally don't have a gamepad that supports xinput so it returned false oposed to @IXLLEGACYIXL when testing on XInput device, so it seems to work 👀

i tried your query and it works, but i cant tell if my xinput is even valid, as the playstation controller is emulated and my mouse too .. .i get with your query ( your test script ) these two devices... i think a real xinput device is needed which i dont have , only the emulated one so dont count on my test

the emulator converts falsely everything to xinput for reasons..so i cant test if a device is not an xinput

@manio143
Copy link
Member

Build looks good. I'll see if this works with my Xbox controller.

@manio143
Copy link
Member

Ok, so this doesn't fully work for me.
The device's productGuid is 02ff045e-0000-0000-0000-504944564944, but the deviceId received from the Cim query is "045e02ff" so it didn't recognize it correctly.
Seems the bug is in the string concatenation.
Instead of

match.Groups[1].ToString() + match.Groups[2].ToString()

should be

match.Groups[2].ToString() + match.Groups[1].ToString()

@IXLLEGACYIXL you mentioned this was working for you, can you provide what was the device Id in your case?

Also, there were duplicates in the deviceId list from Cim query - maybe we can run a .Distinct() before ToList()?

@Jklawreszuk
Copy link
Collaborator Author

Jklawreszuk commented Nov 16, 2023

Alright, good to hear 👍. Anyway, yes, let's filter duplicates. I hope that string concatenation is deterministic (i.e. PID + VID). Otherwise method needs to exctract PID and VID separately(??)

@IXLLEGACYIXL
Copy link
Collaborator

Ok, so this doesn't fully work for me.
The device's productGuid is 02ff045e-0000-0000-0000-504944564944, but the deviceId received from the Cim query is "045e02ff" so it didn't recognize it correctly.
Seems the bug is in the string concatenation.
Instead of

match.Groups[1].ToString() + match.Groups[2].ToString()

should be

match.Groups[2].ToString() + match.Groups[1].ToString()

@IXLLEGACYIXL you mentioned this was working for you, can you provide what was the device Id in your case?

Also, there were duplicates in the deviceId list from Cim query - maybe we can run a .Distinct() before ToList()?

ive only tested the query itself, not the entire thing

the guid is built but hidden and internal thats what ive written earlier

@manio143
Copy link
Member

 I hope that string concatenation is deterministic (i.e. PID + VID)

The way your regex is written guarantees determinism here.

@IXLLEGACYIXL
Copy link
Collaborator

Ok, so this doesn't fully work for me. The device's productGuid is 02ff045e-0000-0000-0000-504944564944, but the deviceId received from the Cim query is "045e02ff" so it didn't recognize it correctly. Seems the bug is in the string concatenation. Instead of

match.Groups[1].ToString() + match.Groups[2].ToString()

should be

match.Groups[2].ToString() + match.Groups[1].ToString()

@IXLLEGACYIXL you mentioned this was working for you, can you provide what was the device Id in your case?

Also, there were duplicates in the deviceId list from Cim query - maybe we can run a .Distinct() before ToList()?

so no for me its not working and i cant try as i lose my mouse with the emulator
ive only tried the wql

@manio143 manio143 merged commit bcd1a04 into stride3d:master Nov 17, 2023
@Jklawreszuk Jklawreszuk deleted the xinput branch November 17, 2023 19:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants