[Alpha]JoystickWrapper: Read Joysticks via DirectInput / XInput without loops (C# DLL) 0.0.5 - 18th Mar 2017

Post gaming related scripts
doubledave22
Posts: 343
Joined: 08 Jun 2019, 17:36

Re: [Alpha]JoystickWrapper: Read Joysticks via DirectInput / XInput without loops (C# DLL) 0.0.5 - 18th Mar 2017

14 May 2021, 13:55

Wow thanks, the powershell command did fix it. I have a lot of users on my software though and I'm not sure I feel comfortable giving them instructions to do this if their controller isnt detected. Are there any workarounds or is this it? Thanks again!
doubledave22
Posts: 343
Joined: 08 Jun 2019, 17:36

Re: [Alpha]JoystickWrapper: Read Joysticks via DirectInput / XInput without loops (C# DLL) 0.0.5 - 18th Mar 2017

01 Jul 2021, 17:56

@evilC I have gotten around to using this library and have a couple questions if you have a chance!

1) In the instructions it mentions to save all the dll's and Joystickwrapper.ahk to get started. Do I need to keep JoystickWrapper.cs/csproj, packages.config, StaticData.cs, Properties folder with Assemblyinfo.cs? I plan on only using xinput and want to keep the least amount of overhead.

2) How can I prevent the script from crashing if game controller is removed? Here is the error I am getting when unplugging the device.
Unhandled Exception: SharpDX.SharpDXException: HRESULT: [0x8007048F], Module: [Unknown], ApiCode: [Unknown/Unknown], Message: The device is not connected.

at SharpDX.Result.CheckError()
at SharpDX.XInput.Controller.GetState()
at JWNameSpace.JoystickWrapper.SubscribedXIStick.Poll()
at JWNameSpace.JoystickWrapper.SubscribedSticks.<MonitorSticks>b__19_0()
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
I have tried monitoring WM_DEVICECHANGE and quickly unsubscribing from all events but it doesnt seem reliable. Perhaps because it's racing whatever is happening inside the dlls.

If i unsubscribe from all events then remove controller it's fine but I don't want the script crashing if the controller is unplugged preemptively .

Thanks for you contributions and help thus far!
User avatar
evilC
Posts: 4822
Joined: 27 Feb 2014, 12:30

Re: [Alpha]JoystickWrapper: Read Joysticks via DirectInput / XInput without loops (C# DLL) 0.0.5 - 18th Mar 2017

06 Jul 2021, 14:56

doubledave22 wrote:
01 Jul 2021, 17:56
Do I need to keep
All you need is the JoystickWrapper.ahk file and the DLLs
doubledave22 wrote:
01 Jul 2021, 17:56
I plan on only using xinput and want to keep the least amount of overhead.
XInput ?! I would recommend against using this library to read XInput devices. Both triggers will report as one merged axis, and it will be impossible to tell the difference between no triggers pressed and both pressed. For XInput, use Lexikos' XInput library
doubledave22 wrote:
01 Jul 2021, 17:56
2) How can I prevent the script from crashing if game controller is removed? Here is the error I am getting when unplugging the device.
Unhandled Exception: SharpDX.SharpDXException: HRESULT: [0x8007048F], Module: [Unknown], ApiCode: [Unknown/Unknown], Message: The device is not connected.

at SharpDX.Result.CheckError()
at SharpDX.XInput.Controller.GetState()
at JWNameSpace.JoystickWrapper.SubscribedXIStick.Poll()
at JWNameSpace.JoystickWrapper.SubscribedSticks.<MonitorSticks>b__19_0()
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
Maybe possible by editing the C# code, but not something I implemented
doubledave22
Posts: 343
Joined: 08 Jun 2019, 17:36

Re: [Alpha]JoystickWrapper: Read Joysticks via DirectInput / XInput without loops (C# DLL) 0.0.5 - 18th Mar 2017

06 Jul 2021, 15:39

evilC wrote:
06 Jul 2021, 14:56
All you need is the JoystickWrapper.ahk file and the DLLs
perfect thanks.
evilC wrote: XInput ?! I would recommend against using this library to read XInput devices. Both triggers will report as one merged axis, and it will be impossible to tell the difference between no triggers pressed and both pressed. For XInput, use Lexikos' XInput library
Oh. I must have done something wrong during SimpleExample because I couldn't get the directinput to register properly (worked in monitordemo though so I am sure I could figure it out) so I ended up going with xinput.

This thread right? https://www.autohotkey.com/boards/viewtopic.php?f=6&t=29659 I think I struggled to find the right dll when I first looked at it. I will have to take another look.
Maybe possible by editing the C# code, but not something I implemented
Is there a way to view the C# code? I have only ever worked with AHK so forgive me but I am starting to poke into C# and I like having actual projects to do to learn.

Lastly, I did send you a direct email which you may have seen, but I had one more question in there I didn't include here.

I am struggling with critical threads and the script crashing. Here is a very simple modification that can illustrate the issue:

I changed simpleexample.ahk slightly to use xInput instead of directinput (i know the GetAnyDeviceGuid method is direct but its fine).
(given your recommendation above I will try directinput next) but I just wanted to illustrate the issue.

This subscribes to the 10 buttons on my xbox controller. When hitting any basic button you should see a tooltip "Button2: 1" or "Button3: 0". I have added a critical thread when Button1 is pressed and if you run this script you will notice the script then becomes unresponsive.

Code: Select all

#persistent
#SingleInstance Force
#Include JoystickWrapper.ahk
jw := new JoystickWrapper("JoystickWrapper.dll")

if (guid := jw.GetAnyDeviceGuid()){
	
	loop, 10
		jw.SubscribeXboxButton(1, A_Index, Func("TestFunc").Bind("Button" a_index))
	
} else {
	MsgBox "No sticks found"
	ExitApp
}

TestFunc(type, value){
	Tooltip % type ": " value
	
	if (type = "Button1")
		Critical_Thread()
}

^Esc::
	ExitApp
	
	
Critical_Thread()
{
	Critical
	
	sleep, 500
}

Any idea what's going on here? I had a similar issue when using an OCR script and ran a critical thread and got a crash. I may make a separate post about this but figured I'd ask here.

Thanks for getting back to me, apologies if this is a massive annoyance
User avatar
evilC
Posts: 4822
Joined: 27 Feb 2014, 12:30

Re: [Alpha]JoystickWrapper: Read Joysticks via DirectInput / XInput without loops (C# DLL) 0.0.5 - 18th Mar 2017

06 Jul 2021, 17:36

Oh crap, I completely forgot (I wrote this so long ago...), this library does support XInput...

To view the C# source, simply open the JoystickWrapper.sln file using Visual Studio. There's a TestApp project in there as well as the JoystickWrapper which allows you to test the library entirely within Visual Studio

The crash you mentioned is possibly because when you press a button, you set the thread critical, and then go into a sleep, you are locking up the thread and it maybe does not like that. For example, new input comes in, and the C# code tries to execute some AHK code, but because you have a critical thread running, it's uninterruptable, so goes boom
I mean, think about it, when you move an axis, you are NEVER going to be able to move it by just one unit and hold it precisely there for 500ms, so you will always get multiple updates every time you move the stick.

You should bear in mind that AHK is NOT a multi-threaded language, it fakes it. You should not even have long running loops in your AHK in response to input - you should use SetTimer instead.
doubledave22
Posts: 343
Joined: 08 Jun 2019, 17:36

Re: [Alpha]JoystickWrapper: Read Joysticks via DirectInput / XInput without loops (C# DLL) 0.0.5 - 18th Mar 2017

09 Jul 2021, 08:47

evilC wrote:
06 Jul 2021, 17:36
Oh crap, I completely forgot (I wrote this so long ago...), this library does support XInput...

To view the C# source, simply open the JoystickWrapper.sln file using Visual Studio. There's a TestApp project in there as well as the JoystickWrapper which allows you to test the library entirely within Visual Studio

The crash you mentioned is possibly because when you press a button, you set the thread critical, and then go into a sleep, you are locking up the thread and it maybe does not like that. For example, new input comes in, and the C# code tries to execute some AHK code, but because you have a critical thread running, it's uninterruptable, so goes boom
I mean, think about it, when you move an axis, you are NEVER going to be able to move it by just one unit and hold it precisely there for 500ms, so you will always get multiple updates every time you move the stick.

You should bear in mind that AHK is NOT a multi-threaded language, it fakes it. You should not even have long running loops in your AHK in response to input - you should use SetTimer instead.
Thanks for the clarification, the critical stuff makes a lot of sense. I set the callback thread to be non-critical and called the critical threads with a boundfunc and settimer which seemed to temporarily solve the crashes I was having. I imagine much of this would be solved with multiple actual threads but it is what it is.

I wanted to use your library because I thought it was possible to implement controller support and button detection without some sort of polling loop. I think (correct me if I'm wrong) yours still needs to run a loop to check button states. If this is the case I think I will just go with the Lexikos xinput stuff and build out my own loops with settimer like you mentioned. It should give me more control, plus didnt notice the crash when the controller was unplugged so monitoring WM_DEVICECHANGE should work in that case to kill any timers. Thanks again for your help!
User avatar
evilC
Posts: 4822
Joined: 27 Feb 2014, 12:30

Re: [Alpha]JoystickWrapper: Read Joysticks via DirectInput / XInput without loops (C# DLL) 0.0.5 - 18th Mar 2017

09 Jul 2021, 10:33

Both are poll-based. I think APIs generally work like this because of the way games work. The game does not want to be interrupted while it is rendering, it will want to poll the input, then render, then poll the input again, render again etc.
Handling disconnect (certainly for XInput) would be simple, I think all you would have to do is put a new line before this one:
https://github.com/evilC/JoystickWrapper/blob/88b16df8a569a6ad9717282905925180a875eb35/JoystickWrapper/JoystickWrapper.cs#L891

Code: Select all

if (!controller.IsConnected)
   return
That's all I basically do in another project of mine and it handles disconnects fine
doubledave22
Posts: 343
Joined: 08 Jun 2019, 17:36

Re: [Alpha]JoystickWrapper: Read Joysticks via DirectInput / XInput without loops (C# DLL) 0.0.5 - 18th Mar 2017

09 Jul 2021, 13:16

Yep, that would solve it. Unless there's some obvious benefit to using the sharp dlls vs the lexikos xinput one I am just going to go with the latter. I will be checking out your code some more as I explore C# though. :salute:
User avatar
evilC
Posts: 4822
Joined: 27 Feb 2014, 12:30

Re: [Alpha]JoystickWrapper: Read Joysticks via DirectInput / XInput without loops (C# DLL) 0.0.5 - 18th Mar 2017

09 Jul 2021, 13:47

It's also worth adding that there's more of a benefit to doing DirectInput reading via SharpDX - trying to poll directinput using native AHK calls would probably be hella tricky, and whilst you can already read DI devices using GetKeyState, that's limited to 6 axes, 32 buttons whereas SharpDX gives access to 8 axes and 128 buttons. Also GetKeyState mangles the mid position (reporting ~49.97 for middle) whereas you get native 0...32768 reporting via SharpDX
User avatar
evilC
Posts: 4822
Joined: 27 Feb 2014, 12:30

Re: [Alpha]JoystickWrapper: Read Joysticks via DirectInput / XInput without loops (C# DLL) 0.0.5 - 18th Mar 2017

09 Jul 2021, 13:50

Oh, and one final pro/con... Lexikos' XInput library lets you read the Guide button, whereas SharpDX does not (It's an undocumented feature not officially part of the XInput spec). However you can't block the native functionality of the Guide button with either, so it's pretty useless anyway in my experience
doubledave22
Posts: 343
Joined: 08 Jun 2019, 17:36

Re: [Alpha]JoystickWrapper: Read Joysticks via DirectInput / XInput without loops (C# DLL) 0.0.5 - 18th Mar 2017

10 Jul 2021, 10:42

evilC wrote:
09 Jul 2021, 13:47
It's also worth adding that there's more of a benefit to doing DirectInput reading via SharpDX - trying to poll directinput using native AHK calls would probably be hella tricky, and whilst you can already read DI devices using GetKeyState, that's limited to 6 axes, 32 buttons whereas SharpDX gives access to 8 axes and 128 buttons. Also GetKeyState mangles the mid position (reporting ~49.97 for middle) whereas you get native 0...32768 reporting via SharpDX
Hmm... not sure exactly what you mean. Here's my general strategy for grabbing the button/axes that are pressed:

Lexikos library outputs an object like this:
[bLeftTrigger] -> 0
[bRightTrigger] -> 0
[dwPacketNumber] -> 9396
[sThumbLX] -> 0
[sThumbLY] -> 0
[sThumbRX] -> 0
[sThumbRY] -> 0
[wButtons] -> 0
and I am able to compare states from the previous by comparing against the last poll
[bLeftTrigger] -> 0
[bRightTrigger] -> 0
[dwPacketNumber] -> 9409
[sThumbLX] -> 0
[sThumbLY] -> 0
[sThumbRX] -> 0
[sThumbRY] -> 0
[wButtons] -> 32768
Result here would be +32768 for wButtons so I know Y has been pressed. If the result was -32768 then I'd know Y was released.

For the axes:
[bLeftTrigger] -> 0
[bRightTrigger] -> 0
[dwPacketNumber] -> 9471
[sThumbLX] -> 32767
[sThumbLY] -> -6172
[sThumbRX] -> 0
[sThumbRY] -> 0
[wButtons] -> 0
looks like its ranging from -32767 to 32767. I don't think theres any getkeystates going on here as far as I can tell. I am only offering game controller support so I think the buttons will be limited to what you see on an x-box controller so I don't know if that matters much to me.
User avatar
evilC
Posts: 4822
Joined: 27 Feb 2014, 12:30

Re: [Alpha]JoystickWrapper: Read Joysticks via DirectInput / XInput without loops (C# DLL) 0.0.5 - 18th Mar 2017

10 Jul 2021, 10:54

Yes, that's XInput (Xbox controller specific API), I was talking about DirectInput (Generic joystick / HOTAS controllers etc). In AHK normally these are read via GetKeyState("1JoyX"), which yields a value from 0 to 100, with middle being 49.97. This is implemented in the AHK source code using the legacy WinMM API, which only supports 6 axes and 32 buttons - whereas "full" DirectInput spec is 8 axes, 128 buttons.
AHK's lacklustre support for DirectInput devices was the primary driver for me writing my library - I just added XInput support to the library because it wasn't much extra effort
doubledave22
Posts: 343
Joined: 08 Jun 2019, 17:36

Re: [Alpha]JoystickWrapper: Read Joysticks via DirectInput / XInput without loops (C# DLL) 0.0.5 - 18th Mar 2017

10 Jul 2021, 11:18

Ok I think I fully get it now. You added better directinput support but the xinput stuff isn't wildly different than what lexikos posted. I think I more or less wanted to know the difference between your xinput implementation vs lexikos' implementation. I think you covered this in the compiled vs interpreted aspect as well as the guide button though.
User avatar
evilC
Posts: 4822
Joined: 27 Feb 2014, 12:30

Re: [Alpha]JoystickWrapper: Read Joysticks via DirectInput / XInput without loops (C# DLL) 0.0.5 - 18th Mar 2017

10 Jul 2021, 11:29

Right - also in addition to the polling loop, the code deciding if anything has changed is all handled for you in my library (And again, is done in compiled code) - but TBH the amount of CPU time involved is probably pretty meaningless.
This is of course assuming that you are using SetTimer to poll lexikos' library, and not a loop/sleep - I would recommend against that!
doubledave22
Posts: 343
Joined: 08 Jun 2019, 17:36

Re: [Alpha]JoystickWrapper: Read Joysticks via DirectInput / XInput without loops (C# DLL) 0.0.5 - 18th Mar 2017

10 Jul 2021, 12:11

Yeah, I have a timer set. I am using a pretty aggressive interval (10ms) because I am handling mouse movement with the same timer. Maybe I should run multiple timers since buttons don't need that level of accuracy.

That said, cpu usage seems really low even with the 10ms. What is the polling interval on yours? I glanced through yours and I see a Thread.Sleep(1);
User avatar
evilC
Posts: 4822
Joined: 27 Feb 2014, 12:30

Re: [Alpha]JoystickWrapper: Read Joysticks via DirectInput / XInput without loops (C# DLL) 0.0.5 - 18th Mar 2017

10 Jul 2021, 13:08

It calls 1, but that's just to get the minimum granularity. Either C#'s Thread.Sleep(10) or AHK's Sleep 10 / SetTimer, Foo, 10 won't be at 10ms, it will typically be at like ~14ms (It depends on system configuration), which is the lowest granularity supported.
If you want to go lower, you need to use something like MultiMedia timers.
When you say "Handling mouse movement", what do you mean? Reading mouse movement, or sending fake mouse movement? (ie something like a mouse_event DllCall)
In general, 10ms is very slow in mouse terms - real mice tend to update more in the 1-2ms range. Doing stuff like that in pure AHK is likely to cause a real CPU overhead - you are likely to see significant benefits to offloading at least part of mouse movement handling code to C#
doubledave22
Posts: 343
Joined: 08 Jun 2019, 17:36

Re: [Alpha]JoystickWrapper: Read Joysticks via DirectInput / XInput without loops (C# DLL) 0.0.5 - 18th Mar 2017

21 Jul 2021, 12:34

evilC wrote:
10 Jul 2021, 13:08
When you say "Handling mouse movement", what do you mean? Reading mouse movement, or sending fake mouse movement? (ie something like a mouse_event DllCall)
I am actually simulating mouse movement with mousemove inside AHK based on how far the controller is moved etc. I modified the old joystick mouse movement scripts to work with your library. It doesn't have to be perfect it's mostly for emergency mouse movement use for my users.

Anyway... as it turns out handling the button pressed myself through an ahk timer is definitely not going to work out due to single threading issues as you mentioned. Sometimes the button presses/releases are missed (i.e. during a critical thread) especially when multiple controller buttons are pressed and it seems impossible to buffer them. After some more testing with yours it definitely works better which means I am going to have to modify your dll (which is something I've never done).

I am very new to C# and I am having loads of issues getting Test.cs to even run. I understand the basics of namespaces/classes/using etc but I don't really understand Visual Studio yet and I have hit a wall.

I have cloned your github repo and opened it in Visual Studio. The folder structure seems correct in the Solutions Explorer. I am getting loads of build errors when I try to click "Start" on Test.cs.

There's loads of these... clearly I am pointing the debugger in the wrong location but I haven't changed anything from the cloned repo.
The type or namespace name 'SharpDX' could not be found (are you missing a using directive or an assembly reference?)
Any ideas on how to get started running your repo on C# in Visual Studio? Thanks again man
doubledave22
Posts: 343
Joined: 08 Jun 2019, 17:36

Re: [Alpha]JoystickWrapper: Read Joysticks via DirectInput / XInput without loops (C# DLL) 0.0.5 - 18th Mar 2017

21 Jul 2021, 13:26

Ok I am not really sure what I did but I managed to build and run the Test.cs. I put in your fix:

if (!controller.IsConnected)
return


and this works for xinput however for directinput I am still getting an unhandled exception:

SharpDX.SharpDXException: 'HRESULT: [0x8007001E], Module: [SharpDX.DirectInput], ApiCode: [DIERR_INPUTLOST/InputLost], Message: The system cannot read from the specified device.
'

Code: Select all

            public void Poll()
            {
                joystick.Poll();
                var data = joystick.GetBufferedData();           <-------- Error here
                // Iterate each report
                foreach (var state in data)
                {
                    if (Inputs.ContainsKey(state.Offset))
                    {
                        Inputs[state.Offset].ProcessPollRecord(state.Value);
                    }
                }
            }
SharpDX.SharpDXException: 'HRESULT: [0x8007001E], Module: [SharpDX.DirectInput], ApiCode: [DIERR_INPUTLOST/InputLost], Message: The system cannot read from the specified device.
In Test.cs (like in Simpleexample.ahk) I am also unable to view any of the directinput controller presses (but xinput works).

If I just use the xinput I suppose this isn't a huge deal.

Edit: Also I was able to update the .dll which I am very proud of myself for doing and it works inside my ahk script for unplugging the controller.

One other thing... I was able to get the vibration to work using lex's library but I dont see any setstate methods anywhere in the joystickwrapper. I believe its in the sharp dlls somewhere. How would I go about implementing this?

Return to “Gaming Scripts (v1)”

Who is online

Users browsing this forum: No registered users and 33 guests