WhiteMagic / JoystickGremlin

A tool for configuring and managing joystick devices.
http://whitemagic.github.io/JoystickGremlin/
GNU General Public License v3.0
313 stars 45 forks source link

Joystick Gremlin crashes if vjoy has OEMData flag for car controller #471

Open BuongiornoTexas opened 1 year ago

BuongiornoTexas commented 1 year ago

Bear with me - this is going to be a longish bug report, as I don't know enough about game controller drivers to know what is and isn't important.

Bug: Joystick Gremlin crashes if a vjoy device has JOY_HWS_ISCARCTRL (value 0x40) flag set in registry key OEMDData for the vjoy device. E.g. for vjoy device 1:

Computer\HKEY_CURRENT_USER\System\CurrentControlSet\Control\MediaProperties\PrivateProperties\Joystick\OEM\VID_1234&PID_BEAD\OEMData

Specifically, if the first byte of the value includes the 0x40 flag, the crash occurs. E.g.

No crash Crash
00 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00
03 00 00 00 00 00 00 00 43 00 00 00 00 00 00 00
03 00 88 01 fe 00 00 00 43 00 88 01 fe 00 00 00
03 00 08 10 19 00 00 00 43 00 08 10 19 00 00 00

Symptoms: Joystick gremlin crashes, pops up the following message, stays in memory (need to close with task manager), and unhelpfully, does not write to debug.txt.

image

I found this by accident when I was trying set up a Joystick Gremlin replacement for Forza emuwheel - The emuwheel device is not visible to the Steam version of Forza without an OEMData value (I also suspect the car controller flag is what Forza is checking for - I'm still digging into this).

BuongiornoTexas commented 1 year ago

From a bit more digging, the combination of vjoy, emuwheel and Forza Horizon 4 works for an OEMData value of: 40 00 00 00 00 00 00 00 and fails for 00 00 00 00 00 00 00 00 (emuwheel runs, but Forza doesn't see the devices).

I suspect the secret sauce lies between Forza and the registry (in which case, it should also work with Joystick Gremlin if we can address this crash). However, it's also possible that emuwheel is doing something to sort this issue - which I can't test, as it is closed source.

I'm happy to have a shot at a PR for this. But it may take a while, as I'll have to narrow down the problem and then fill a few a gaps in my knowledge before I've got any chance of resolving it.

BuongiornoTexas commented 1 year ago

After a bit more work, I was able to get system.log output with the 0x40 flag set and unset. It looks as though setting this flag does something causes a difference in the number of axes reported by dill and vjoy (GUIDs removed):

2022-12-29 09:56:37      DEBUG vJoy guid={XXXX}: (7, 64, 0)
2022-12-29 09:56:37      DEBUG vjoy id 1: (8, 64, 0) - ERROR - vJoy device exists but DILL does not see it
2022-12-29 09:56:37      ERROR Unable to match vJoy devices to windows devices.

...

2022-12-29 09:56:09      DEBUG vJoy guid={XXXX}: (8, 64, 0)
2022-12-29 09:56:09      DEBUG vjoy id 1: (8, 64, 0) - MATCH

If I'm reading the code correctly, the next step is digging into dill, which is outside my skillset, so this is probably as far as I can take this for now without some additional guidance.

WhiteMagic commented 1 year ago

If mangling the device information results in dill reporting fewer axes, then that is effectively saying that Windows itself believes that there are that many axes available. vJoy does not rely on the DirectInput system to know how many axes a device should have, thus causing this disagreement.

So the first thing is to check if Windows truly thinks there are only 7 axes present, easiest via joy.cpl. If that also only sees 7 axes then the changes made mess with how DirectInput processes the device and the mangling needs to be fixed. If joy.cpl reports 8 axes then that's a bug in dill, but I would be confused as to where that comes from as it directly reads DirectInput structs from Windows.

BuongiornoTexas commented 1 year ago

Thanks for that - I've gone and done some testing with vJoy in 8 axis mode and the 0x40 flag set in OEMData.

First up joy.cpl sees 8 axes present in vjoy:

image

I also hooked up UCR to feed my handbrake input to vJoy for each axis in turn. I then checked that each axis was registering with vJoy Monitor and joy.cpl. Things got a bit weirder here:

vJoy axis bound in UCR axis in vJoy Monitor axis in joy.cpl
X X X
Y sl0 Y
Z Y Z
RX RX RX
RY RY RY
RZ RZ RZ
Sl0 sl1 Slider
Sl1 NONE DETECTED^ Dial

^ Nothing moves on vJoy monitor.

So UCR and joy.cpl see the same thing (axes as expected), while vJoy monitor goes its own way with some sort of remapping of Y, sl0 and sl1? I ran the same test with no OEMData registry entry. This gave the results that I would expect to see for both vJoy monitor and joy.cpl:

vJoy axis bound in UCR axis in vJoy Monitor axis in joy.cpl
X X X
Y Y Y
Z Y Z
RX RX RX
RY RY RY
RZ RZ RZ
Sl0 sl0 Slider
Sl1 sl1 Dial

Given dill can only report what it gets from Windows, I assume the problem is further up the food chain. Maybe the OEMData flag is causing some weirdness between vJoy and windows? But even then joy.cpl doesn't see this, and shows the same axes regardless of the OEMData?

At this point, I'm willing to throw my hands in the air and shrug my shoulders on this one. Most driving setups need no more than 5 axes. And given vJoy is working with 7 axes in Joystick Gremlin, and can do multiple devices if really needed, I'm not sure how much more time it is worth spending on this issue. (Personally, I can definitely get by with 7 - I was mostly chasing detail as it looks a bug of some sort, and I got curious about the rabbit hole leading to it.)

WhiteMagic commented 1 year ago

Yeah it definitely seems like the flag does something funny somewhere but not clear where. Though it definitely looks like Windows and vJoy end up with different interpretations causing problems.

BuongiornoTexas commented 1 year ago

Do you want to leave it open for possible future work, or would you prefer to close it at this point? I've got no skin in the game, and I'm not going to dig any deeper at this point.

Cheers,

BG

Este44000 commented 1 year ago

Hello, I'm really annoying, I followed the conversation but I'm still stuck. The registry looks good, the .dll has been replaced..... I don't know where to go next? :: 2023-01-27 02:11:37 DEBUG -------------------------------------------------------------------------------- 2023-01-27 02:11:37 DEBUG 2023-01-27 02:11 2023-01-27 02:11:37 DEBUG Starting Joystick Gremlin R13.3 2023-01-27 02:11:37 DEBUG -------------------------------------------------------------------------------- 2023-01-27 02:11:38 INFO Initializing joystick devices 2023-01-27 02:11:38 DEBUG 3 joysticks detected 2023-01-27 02:11:38 DEBUG Added: name=vJoy Device guid={A33C5D30-9DBF-11ED-8002-444553540000} 2023-01-27 02:11:38 DEBUG Added: name=vJoy Device guid={A33C8440-9DBF-11ED-8004-444553540000} 2023-01-27 02:11:38 DEBUG Added: name=vJoy Device guid={A33CAB50-9DBF-11ED-8006-444553540000} 2023-01-27 02:11:38 DEBUG vJoy guid={A33C5D30-9DBF-11ED-8002-444553540000}: (2, 20, 4) 2023-01-27 02:11:38 DEBUG vJoy guid={A33C8440-9DBF-11ED-8004-444553540000}: (3, 32, 4) 2023-01-27 02:11:38 DEBUG vJoy guid={A33CAB50-9DBF-11ED-8006-444553540000}: (3, 0, 0) 2023-01-27 02:11:38 DEBUG vjoy id 1: (2, 20, 4) - MATCH 2023-01-27 02:11:38 DEBUG vjoy id 2: (3, 32, 4) - MATCH 2023-01-27 02:11:39 DEBUG vjoy id 3: (3, 0, 0) - MATCH 2023-01-27 02:11:39 INFO Checking vJoy installation 2023-01-27 02:11:39 INFO Initializing plugins 2023-01-27 02:11:39 DEBUG Loaded: cycle-modes 2023-01-27 02:11:39 DEBUG Loaded: description 2023-01-27 02:11:39 DEBUG Loaded: macro 2023-01-27 02:11:39 DEBUG Loaded: map-to-keyboard 2023-01-27 02:11:39 DEBUG Loaded: map-to-mouse 2023-01-27 02:11:39 DEBUG Loaded: noop 2023-01-27 02:11:39 DEBUG Loaded: pause 2023-01-27 02:11:39 DEBUG Loaded: play-sound 2023-01-27 02:11:39 DEBUG Loaded: previous-mode 2023-01-27 02:11:39 DEBUG Loaded: remap 2023-01-27 02:11:39 DEBUG Loaded: response-curve 2023-01-27 02:11:39 DEBUG Loaded: resume 2023-01-27 02:11:39 DEBUG Loaded: split-axis 2023-01-27 02:11:39 DEBUG Loaded: switch-mode 2023-01-27 02:11:39 DEBUG Loaded: temporary-mode-switch 2023-01-27 02:11:39 DEBUG Loaded: text-to-speech 2023-01-27 02:11:39 DEBUG Loaded: toggle-pause 2023-01-27 02:11:39 DEBUG Loaded: basic 2023-01-27 02:11:39 DEBUG Loaded: chain 2023-01-27 02:11:39 DEBUG Loaded: double_tap 2023-01-27 02:11:39 DEBUG Loaded: hat_buttons 2023-01-27 02:11:39 DEBUG Loaded: smart_toggle 2023-01-27 02:11:39 DEBUG Loaded: tempo 2023-01-27 02:11:39 INFO Gremlin UI created 2023-01-27 02:11:39 INFO Gremlin UI launching 2023-01-27 02:11:44 INFO Initializing joystick devices 2023-01-27 02:11:44 DEBUG 4 joysticks detected 2023-01-27 02:17:44 INFO Gremlin UI terminated 2023-01-27 02:17:44 INFO Terminating Gremlin 2023-01-27 02:42:48 DEBUG -------------------------------------------------------------------------------- 2023-01-27 02:42:48 DEBUG 2023-01-27 02:42 2023-01-27 02:42:48 DEBUG Starting Joystick Gremlin R13.3 2023-01-27 02:42:48 DEBUG -------------------------------------------------------------------------------- 2023-01-27 02:42:49 INFO Initializing joystick devices 2023-01-27 02:42:49 DEBUG 4 joysticks detected 2023-01-27 02:42:49 ERROR Uncaught exception: Traceback (most recent call last): File "joystick_gremlin.py", line 1269, in File "gremlin\joystick_handling.py", line 203, in joystick_devices_initialization File "dill__init.py", line 538, in get_device_information_by_index File "dill\init.py", line 357, in init__ UnicodeDecodeError: 'utf-8' codec can't decode byte 0xae in position 8: invalid start byte

2023-01-27 02:57:52 DEBUG -------------------------------------------------------------------------------- 2023-01-27 02:57:52 DEBUG 2023-01-27 02:57 2023-01-27 02:57:52 DEBUG Starting Joystick Gremlin R13.3 2023-01-27 02:57:52 DEBUG -------------------------------------------------------------------------------- 2023-01-27 02:57:54 INFO Initializing joystick devices 2023-01-27 02:57:54 DEBUG 4 joysticks detected 2023-01-27 02:57:54 ERROR Uncaught exception: Traceback (most recent call last): File "joystick_gremlin.py", line 1269, in File "gremlin\joystick_handling.py", line 203, in joystick_devices_initialization File "dill__init.py", line 538, in get_device_information_by_index File "dill\init.py", line 357, in init__ UnicodeDecodeError: 'utf-8' codec can't decode byte 0xae in position 8: invalid start byte

thx for your time

BuongiornoTexas commented 1 year ago

Hello, I'm really annoying, I followed the conversation but I'm still stuck. The registry looks good, the .dll has been replaced..

Are you trying to get a Forza game working, or is this a more general query?

Este44000 commented 1 year ago

Hello, it is not detected on forza and malfunctions on other games, but Win detects the pedals well. Could you tell me the path in regedit again so I can check if I haven't missed a possible error? image

BuongiornoTexas commented 1 year ago

Is it the steam or windows store version of FH? Steam version needs the registry fix, I don't think the Windows Store version does (and that is about all I know about the store version - I've only got the Steam one and can link to a guide for this if useful).

Este44000 commented 1 year ago

windows store in my case. But it's not so much for forza that I'm interested in. I would like to be able to use it as a lifter.

Este44000 commented 1 year ago

Definitly is that ...... Sry for time Ctrl+F is the best friend ! image

BuongiornoTexas commented 1 year ago

It's a long shot, but you could try changing the first byte in that OEMData to 40 and see if this sorts the detection in FH. (Not sure if this is needed for the G25, nor sure if it affects the store version).

Beyond that, I don't think I've got anything to add - sorry.

BuongiornoTexas commented 1 year ago

Hi @WhiteMagic - I think I may have found a possible explanation for the Joystick Gremlin missing the axis. My guess work (and thinking out loud) on the problem is:

If all of this reasoning is correct, could fixing this problem be as simple as adding 0x39 to the AxisCode list and making similar changes in the UI drop downs and other places this might show up? I'm planning to do a bit of trial and error on this, but it'd be good to get your thoughts as well.

If I have any success with this, would you like me to raise a PR, or would you just prefer a report of findings here?

BuongiornoTexas commented 1 year ago

Sorry - I also should have said - I got on track with this when I set up a multi-axis vjoy and couldn't access the z-axis from the Joystick gremlin UI. However, I also tried going into the xml configuration file and editing the code to use the z-axis (3), and I was able to get this output working correctly.

BuongiornoTexas commented 1 year ago

And ... After a more testing, I got that backwards. The issue is definitely coming from how DILL reports axes when OEMData is set. After a lot more digging, I think (not certain though) it because there was a change in axis naming conventions between DI 7.0 and DI 8.0. Unfortunately, the documentation is so fragmented that it is hard to pick out what exactly is happening. but there is definitely discussion on the Z axis being remapped to a slider - I also couldn't figure out any obvious way to pick this up!

At this stage, I think the best approach is to stop trying to get decade old code emulated, and instead write up a consistent set of guidelines for using Joystick Gremlin with the OEMData flag set - happy to have this incorporated as an appendix to the JG documentation when I'm done (which could be weeks to months - so it'll be radio silence for a while again).

WhiteMagic commented 1 year ago

I had a quick look at things and I think it's a bit more complex than just accepting another axis id in Gremlin. The values used in Gremlin are what vJoy itself wants, and is unrelated to what a physical devices reports. The values 0x30 through 0x37 are simply the indices vJoy uses to refer to the eight possible axes available.

I'm unsure what the usage mode actually does on the DirectInput side. From memory, it should only affect how axes are named etc but not where their information is being written to. Dill simply reads the position information from this struct https://learn.microsoft.com/en-us/previous-versions/windows/desktop/ee416628%28v%3Dvs.85%29, which it obtains either through the DirectInput event system or by actively polling devices. But in either case that struct only has a fixed set of 8 axis values that. So theoretically, whatever the usage mode part does it should not affect where the information is written.

What might happen is that the way I configure devices to read data from does not work for t hat kind of device and that it needs special handling. If that's the case code in SDL2 or GLFW might have clues that point to that. The easiest way to try to figure these things out is to compile DILL and use the example programs it produces to explore what is actually seen.

As for PR etc., as the fix is going to be in DILL and not Gremlin a PR is the easiest way as that change will just result in a new DLL that then will work with Gremlin.

BuongiornoTexas commented 1 year ago

I had a quick look at things and I think it's a bit more complex than just accepting another axis id in Gremlin

Pretty well where I had got to when I realised I had things backwards!

From memory, it should only affect how axes are named

Should and microsoft. Brave words to use together :-) - I'm seeing some very weird behaviour when I use just the vjoy feeder and monitor. Still digging into this, and will report back when I've got a clearer idea (it's going to be a while before I figure out what is actually happening).

The easiest way to try to figure these things out is to compile DILL and use the example programs it produces to explore what is actually seen. As for PR etc., as the fix is going to be in DILL

I was hoping to avoid this, but I agree that this is where I need to go next. I guess I'm learning the basics of C++. Is there a specific version of MSVC++ I should be using for dill (hopefully one of the free ones)?

WhiteMagic commented 1 year ago

I can't recall which particular version I used but it might have been VC++17. Any decently recent one that supports C++11 and newer should be fine though. I used one that worked with the typically installed MSVC runtime environments to not have to mess with those for Gremlin as well.

BuongiornoTexas commented 1 year ago

Thanks - I'll dig into this when time allows. Could be a while though!