-
Notifications
You must be signed in to change notification settings - Fork 145
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
Add Force Feedback support to vjoy and joystick plugin #48
Comments
Is there any chance of this hitting mainline soon? I'd really love to be able to get FFB effects in games that need vjoy for input device merging. |
What a coincidence you just asked that @aubade :) I've been working on it in the past but there are some nasty problems. But finally I've gotten around to a seemingly working version.
I might need some help from Anders to get the code working with proper practices, and I should definitely get an FFB wheel to continue development. |
Fantastic! I just got the thing to compile (Though, just to warn, I had to delete some $ characters in the code; google indicated they were probably because of failed copy-pastes?), but I'm not sure how to set up a script to do this? If you can give me some example scriptcode I'd be happy to help you test this. (I've got a Logitech Wingman Strike Force 3D atm. Also a very old iForce joystick that won't work past WinXP, but I could still try playing around with that if it's of interest and freepie can still run on XP) |
The dollar signs are a new C# 6.0 String Interpolation feature. Basically string.Format("hello {0}", Name) is equivalent to $"hello {Name}". This will create a slowly ramping up force (only SlimDX test):
And this will forward FB data (for the moment being only constant force):
|
Nice work on getting something to work! We are still compatible with VS2010 (I think haven't tried in a while :D). Using String Interpolation from VS 2015 will break that, its only a compile time feature and not CLR so you can still run the program on CLR with .NET 4.0 but you will need VS2015 to compile it, haven't decided if we should require our devs to use VS2015 or not just yet. I looked at the code and its a huge mess right now :D Could you clean in up and I can assist you in getting it more FreePIE like? I do not have a force feedback device either |
Btw I also see there are alot of changes that are not really changes, do you use the correct tab setting (Ínsert spacec 4) |
I can change the string interpolations to string.Format for the time being (I'm too used to them, totally forgot about older version compatibility). Haven't looked at similar formatting either, so my code still has tab indents. I'll fix that. Yes it's huge mess, for two main reasons: 1. I haven't been able to test it so I'm not even sure if the current approach works (hence I first want to know that before progressing). However, what I think for now (very basic plan) is to have an easy oneline "automatically forward FFB commands from vJoy device to joystick", and a complete Python implementation so users can modify/forward FFB data however they wish. |
Okay, so the first snippet works fine! The automatic nonff-compatability-mode autocentering shuts down on script-run and I feel a stick-forward force slowly intensify. The centering spring returns as soon as I shut the script down. Unfortunately, the second snippet seems to not work at all; I've tried an external application ( http://www.fs-force.com/support.htm has a program called ForceTest that can send arbitrary effects to arbitrary sticks), as well as combining both scripts. When the scripts are combined; registering the real stick as vjoy's ffb target, then sending effects to the vjoy stick, the autocentering never disables and I never feel the force. (however, if set to send effects directly to the real stick, it does still work). I've copied the console output when running this combined script if it's of any help at all.
Log output: https://dl.dropboxusercontent.com/u/187059/vjoyffb.txt |
It's weird that it doesn't work since it receives all the correct data and sets the settings correctly. The only difference I know of is polar vs cartesian coordinates. I'll modify it and see if that makes a difference. Log doesn't really help since it's missing the beginning (I should've indented the if(force % 100 == 0): and SetConstantforce below so that it doesn't keep setting that value. However I can see the same log here as well (even tho I don't own an FFB device doesn't mean I can't log what the vJoy device receives, or even forward from vJoy device 0 to 1, however I'm not sure if that causes any problems since all the vJoy stuff is static - the callback triggers for each device rather than per device, have to split that up myself) Btw can you try one more thing? Move the OperateEffect line to directly below SetConstantForce, something like this:
Might be that the effect needs to be restarted every time it's changed (at least that's what I've seen when reading force data from another game... It kept sending start operations (even without modifying the magnitude each time)) |
Sadly, this doesn't seem to be working either; Same joystick-side behavior as above. This time I stopped the program much earlier so as to catch the beginning of the log: https://dl.dropboxusercontent.com/u/187059/vjoyffb2.txt Incidentally, I don't know if this is important but every even-numbered time (second, fourth, sixth, etc) I try to run this or my earlier attempted script, it errors out with the error "Unable to create effect: An item with the same key has already been added." on the CreateEffect line, however on odd-numbered run attempts it does run. |
Oh blight it all, i'm very sorry; the not-working thing was my fault. I'd ignored a vjoy "please reboot" prompt the other day; after rebooting, my snippet indeed works... but with a stick-back force instead of a stick-forward force. It, however, crashes FreePIE upon script stop. Your revised script makes the force cut in and out |
Wow, you just posted that when I wanted to respond :D So it works with a game or that ForceTest application now? I know of weird behaviour with effects, dispossing etc, I haven't yet been able to look at it... Multiple packets are sent to dispose every effect separately, and to dispose them altogether. FreePIE disposes the joystick/vJoy devices as well, probably ending up in some problems. |
Unfortunately, external applications don't seem to be working atm. The games I've tried (Freespace 2's SCP and IL-2 Sturmovik 1946) don't give any errors, but I don't feel any forces. ForceTest gives an error on device select/reinitialize, at least:
And gives an error when applying the grooves effect:
but apart from that, effects are silently discarded. |
The only effect that is currently completely forwarded is Constant(Force). |
Okay, then yeah. :( Unfortunately it looks ilke Constant Force from FreePIE is fine, but from ForceTest isn't going through. |
Okay, from FFB inspector it works, if inconsistently; the program seems a bit crashy. I have to unplug the real joystick, start FFB inspector, replug real joystick, start FreePIE, run script, otherwise FFBinspector crashes. Then, sometimes it doesn't actually generate the force when i tell it to start effect, but when it does work, I do feel the forces. |
Cool, finally it 'works' 👍 I guess that's a problem when scripts stop, things are not correctly disposed, event handler thingies (vJoy exports a method to register a callback method, but no way to get rid of it, so it seems it's held until FreePIE has been restarted). I'll have to look at that later, maybe after I explain to Anders how it works he has some ideas. But at least the basic part is working, which I'm pretty happy about. |
Fantastic! feel free to @ me anytime if you need my help. |
I will, though I don't expect to work much on this next week. That is, unless I make some big steps with Anders, as I'm not planning to work a lot only to find out there's a much smarter design/implementation possible. Besides, university (and The Division which is released tuesday) is taking up my time. |
I created a thread at MTBS that we can use to talk development and clean up of the code. |
I have added some more logging which have found more problems with the forwarding code. Please check the forum, you probably have more knowledge into the Ffb protocol |
I've read the forum, just didn't have any time to test anything last week. |
Any news about the force feedback support ? |
Hi, im not active on the FreePIE project right now, are working on a VR game full time. But it seems there has been some progress, my suggestion is contacting MarijnS95 in this thread http://www.mtbs3d.com/phpBB/viewtopic.php?f=139&t=21859&start=40 |
@jbinard I'm not that active on it anymore. I was about a month ago (did some huge refactors/cleanups as well as some major breakthoughs packet-wise), but the fact I still don't have an FFB device means it's almost impossible for me to complete it; I have to rely on other people to do the testing/debugging, without proper tools or knowledge about the inner workings. Quick iteration is impossible as I have to send a compiled build out every time I make a tiny change; then request others to test exactly what I want and pray I logged the correct information, which takes days instead of minutes when done locally. That said though, the forum is the best way to discuss. The version on github/the forum is a bit dated already, mostly missing some minor fixes and debugging stuff everywhere. |
I've been toying with this for a bit. Here's some notes for any others trying this. What I've mostly ran into is this line returning an E_INVALIDARG: https://github.com/MarijnS95/FreePIE/blob/Ffb/FreePIE.Core.Plugins/Dx/Device.cs#L194 I've noticed this only happens when using Polar coords. If I change the -1 in 'createEffect' to '0'.
Also, sometimes |
Which is as expected; I 'recently' changed the function signature. In the past the -1 represented the duration (-1 meaning 'infinite'), but now it's a boolean for switching between polar and Cartesian coordinates (-1 evaluates to
Anyway, when using Cartesian coordinates,
Yes, if you've followed my ramblings on the Spintires forum, it turns out the wheel and/or driver keeps track of these effects even when being disposed. I sent out some fixes for that on the Spintires forum, but never actually committed it until now; see here for the code that tries to avoid creating an effect when it exists. According to Lombra on the ST forum, it doesn't seem to work.
Not sure why this was removed by an edit. False positive? |
Correct. |
Is it supposed to work/do something? For my purpose, trying to simulate a stickshift with the sequential shifter of my Logitech DF GT for Spintires, the passthrough of registerFfbDevice would be enough. |
Now this looks cool: https://www.mtbs3d.com/phpBB/viewtopic.php?f=139&t=18724 |
I don't think you want todo sensitive timing things on the script thread. Its defaulted to 64hz (16ms). You could have a thread going on in the background in the plugin for example, the Serial com plugin does that for example. Though if you don't have any I/O there will be no interupts and the thread will use all resources on that CPU core. |
For now increasing the timing to 500hz did help and even vjoy latency without force feedback is much better. Thank you very much for this valuable information, I will look at it in the future! |
That ComDevicePlugin did not help. I am facing another situation. Both VJoy and SlimDX only register their global handlers and there is a lot of static methods as well. The current latency with System Timer is between 3ms and 9ms, which is great. There is occasional spike to 20ms or even 300ms. But in SlimDX docs there is mentioned that FFB processing must be fast because it is blocking operation. There will be some basic logic mistake somewhere in current usage of VJoy and SlimDX libraries. Even 9ms of FFB packet processing will cause stuttering to the game (even with keyboard control). When game stops sending FFB packets, there is no stuttering. This is the last thing to solve (plus Ramp effect params tweak). |
I need to refresh my C# skills as I work in Java for the last 5 years. But something like this helps to unblock the processing, but now the DirectX device will not receive FFB information. The packets are parsed and processed and written out to console though. It will probably need some kind of synchronized block when working with Device class. This code processes the FFB packet and response in-game is smooth. It will just not get delivered to SlimDX Device registered in Global handlers, probably due to some threading issues. No exception though.
|
With Task.Run, some packets that come at the same time will get lost. Tried to add lock(Device) {} block, but that does not help. But If I keep adjusting parameters, it gets received by some time and force feedback will work. Just need to somehow manage to not keep overwriting packets. Perhaps the data pointer IntPtr gets changed in the middle of creating the FfbPacket object. |
I have new commit here: cyberluke@65775eb So the issue above with C++ pointers has been confirmed. Analysis:
Partially Failed Solution:
But it looks like this and InternalFfbPacket itself is IntPtr. So you have to deal with pointer and its nested pointer in order to do it properly!
At this time I thought I'm lucky to know so many programming languages... So in callback you want to do only this:
Of course you need to have Destructor as well:
Because this sequential solution of packets processing in C# is not fast and is blocking and cannot be paralelized easily. If you would go with ARM or ATMEL microcontroller and do the processing there, it would be much faster than in C#. This is so painful branch to work with :-D one bottleneck next to each other. One syntax error next to each other. I take it back. The generics and async processing is useless and not working. It's 3AM again and I need to work more... |
So I fixed this branch in C#, but now I need to rewrite everything in C++ because callback and rerouting of packets will be always bottleneck here :-/ |
Meanwhile there is pull request to fix two VJoy bugs. First is Gain Packet is always zero due to wrong type cast. Second is a mistake in helper class, which returns always 2 bytes only (but it is not used in this branch, so only Gain packet is issue). That's why in this branch I always set min. gain to 5000: njz3/vJoy#3 |
Updated FFB fork: https://github.com/cyberluke/FreePIE/tree/Ffb So Erik removed Marjin's AsyncActionRunner because of some memory exceptions. These memory exceptions were happening because FFB callback provides Int Pointer to FFB packet, but this gets rewritten by the next packet. Marjin had some unsafe FFB branch in his fork, but the marshalling is not correct. He forgot to work with the nested Int Pointer IntPtrData inside FFB packet. Also it was slow. So now FFBPacket constructor has been fixed and split to two parts. First starts in sync callback. Second is for async lazy load to improve latency.
In FFB callback we call FFBPacket constructor to only quickly clone data bytes into our own property without creating any C++ pointer. Plus we read Packet Type to optimize further processing decision logic. In Init() method is the code to lazily initialize C++ pointer to our managed C# data, so underlying VJoy C++ library (C# wrapper) can be used. This happens in async method and it does not block FFB callback anymore. This results in smooth gameplay, game UI thread does not stutter anymore. Latency delay of FFB packets is between 9-30ms with spikes of 300ms. This results in bad experience as force feedback is delayed and does not correspond to the game. This is without AsyncActionRunner. Further addition of AsyncActionRunner only slows it down. Which is strange. The performance is worse than single thread. With incoming packets, the delay keeps increasing up to 20 seconds. It queues all packets quickly, nothing is lost. But then the actual processing of individual packets sequentially bottlenecks each other packet increasing delay. I tried to optimize it by allowing some packets to be processed in parallel and trying to discard possible duplicate packets, but that does not solve the issue. Currently I need to implement the same solution only in C++ in order to compare the speed. This is the big issue now. It is working, but due to creating new SlimDX Effect object each packet (like 50 packets in 5ms), it kills the gaming experince. |
Some further hints: This would help only with blocking GC call, but there are more performance issues on the road. |
4:30 AM time for status. First lets have a look at this picture --> Process delay: 0ms Looks like it is not working? But it is working! How? Cyberluke smashed keyboard randomly providing a series of illegal operations as well as random code blocks in memory deletion. Also had to write a little bit different VJoy C++ API. Next time...try harder |
Probably solved Ramp Effect. There is a bug in SlimDX as several people on the internet thought. But nobody try to open DirectX SDK help or look at the SlimDX class. So here is nice DirectX 9 page explaining even parameter range: http://doc.51windows.net/Directx9_SDK/input/ref/structs/dirampforce.htm SlimDX and VJoy use int instead of long, but that should be ok as the range is from 0 to 10000. EDIT: the above link have incorrect character. Correct range is -10 000 to 10 000. You need to really download that Direct9 SDK and open *.chm help file included.
This is SlimDX implementation:
If you compare RampForce.cpp with ConstantForce.cpp, you see that RampForce should return:
This is probably some copy&paste error. Now I need to download three versions of DirectX SDKs, but my hybrid multiboot WinXp / Win10 machine is out of space, so I have to probably boot to Hirens Boot CD and change partition order then change partition size. Which means: backup data now :-) |
Few notes for @AndersMalmgren why not to move to latest .NET. In Czech, we call it "salamova metoda" or ham method. Each year they will push you a little with passive agressivity and you loose something. This year it is .NET 4.7. Next year, there will be only .NET 5.0, then 6.0. And voila! From superb project that can be used for many years, you will get Windows 11 or Windows 12 only app. Users need to buy new Windows to get legacy app running. It is a proven Apple and Microsoft business model. Back to SlimDX: Because Windows 10 removed DirectX SDK - we know that. And yes, it looks quite easy to just pull DX9 and XAudio headers via Nuget package. Plus installing XAudio2 runtime. Ok. But it still won't compile. And guess what? It won't compile even as C++ package without .NET! The reason is that Microsoft constantly keeps changing even old deprecated interfaces on a purpose. They just want to break compatibility on purpose to tell you: "You need to buy new computer!" Here is specific SlimDX issue: They completely changed several XAudio classes for Windows 10 SDK, even it is stable/deprecated. They backported breaking changes. Same as VCREDIST_X86 (Visual Studio 2015 C++ Runtime) - it should run on Windows XP and always did. But THIS YEAR Microsoft removed a lot of DLLs on purpose even from 2010, 2015 C++ runtimes to remove WXP. So it means, you install it from official MS website on WXP, but it still won't work! And you don't know why. Then you download VCREDIST_X86 from 2021, available only on Archive.org, and it start to work on Windows XP!!! It work always till few months recently they start removing DLLs even from outdated installers hosted on their website. They claim that SHA-1 signature is not supported anymore. But that does not mean they cannot host old files. They just remove legacy download completely. So you will not find Windows 7.1 DDK (driver development kit) for VJoy, for example. So on Windows XP, SlimDX compiles out of the box. On Windows 10, you would need to read ten pages on fan blog and REWRITE XAudio calls and parameters. This would on purpose only break Win XP, Win Vista, Win7 compatibility. While, if you not lazy developer, and you do your job properly, you will compile it on Windows XP (or Windows 7) and it will run on all OSes, including Win 10. SlimDX: FIXED, they have pull request here: SlimDX/slimdx#515 Compiled Release DLL x86 is already in FreePIE. Same as new VJoy. |
Ramp Effect working. Including parameters. Tweaked also a few other parameters. It runs much faster if you disable Console.WriteLine() calls.
|
The Spring Effect force is not perfect yet. Sometimes it is delayed and jumps in force.
|
@cyberluke I dont have time to maintain FreePIE, I put all my free time into a VR game project. https://www.youtube.com/c/MDADigital Moving the GUI to .NET 6 shouldnt be a problem. The problem is that there is alot of Windows specific code pinvoke etc. I guess its possible with additional packages to get Windows speciifc features from full framework in .NET 6, I havent investigated what it takes.
That disables output to the console. Which you dont want. Only write importanta stuff to the console. I think its mosly used to write warnings to the Error panel like if (!match)
Console.Error.WriteLine("vJoy version of Driver ({0:X}) does NOT match DLL Version ({1:X})", driverVersion, apiVersion); Only use Console.WriteLine during development. When going live throw errors for the script to stop or Console.Error.WriteLine for warning |
Nice, I was making VR controllers and was on CES 2016 in LV. Here: https://www.facebook.com/realmagicvr/ and here: https://futurezone.at/digital-life/real-magic-haende-sollen-als-vr-controller-dienen/264.283.726 and smart VR shoe: https://www.youtube.com/watch?v=1fNNxPqh-S8&list=UUT7Ad5kcEYETdI914zGOKuQ ...the VR shoe would be able to compute rotation and relative position as well as precise pressure. Then there could be a kind of pressure based floor in VR arena for absolute position without camera. But it did not make any money and now I work as enterprise Java integration tech lead. If you don't want to be a mantainer, I can help, at least for some time. It would be my pleasure! But I would preserve, not introduce any breaking changes because I think that is silly and not necessary. You know, you don't understand: Nobody want .NET 6. Why to kill compatibility. After COVID retrogaming movement is raising. Win 11 will always run older .NET software, so it will stay compatible. Now it can still run on Windows XP. I buy a lot of Steam games, remakes, and GoG games. And they do not work on Windows 10. Like Mig-29 Fulcrum I am testing now. It does not work in fullscreen properly. Aquanox have issues with EAX sound, even I have three different Sound Blaster soundcards. So I have dual boot to WinXp and Win 10. On top of that I have 10 computers here including Voodoo 2 SLI and Pentium MMX. |
|
I'm not sure I like that, We shouldnt have any Console.WriteLines in the plugins once they are developed. Only one that should be writing to the console is the scripts using diagnostics.debug |
I agree, but it was like that when I came here. On the other hand there will be always need to retest a code, so there needs to be something. I can get it outside of PR and use it only in my fork and focus on my fork only to get the job done. |
I'm of the school that you add such logging when you need it and remove it when you are done. Plus break points are better 9 times out of 10. But yeah like you said. I think it should be in another PR. |
If you get 5000 packets in 2 minutes, you really really do not want to set a breakpoint :-) sometimes you need to:
Debugger with breakpoint is if you looking for a specific exception or value of single element. Realtime communication is not that case. I will not be adding and removing such logging every month. Today, I look at several projects that use tracing and debug. They use pragma directive for compiler, so I've chosen that approach. I respect your opinion, but I think it is not practical. It depends what kind of functionality are you developing. In VR you also cannot set breakpoint and wear helmet. No, VJoy prints a lot of stuff to console. You can see it here in this PR, in the screenshots. It is not only warning and errors. So I might remove diagnostics.enable() and diagnostics.disable() and continue working on my fork. You said you don't have time to mantain it here anyway. But I am keeping Console.WriteLine() and compiler directives in my code, namely #if DEBUG and #endif. The only thing I might change is the name 'DEBUG' to something else. I can change it to 'TRACE_ENABLE' for example because these are tracing outputs. That is commonly used in software development. |
Vjoy plugin does not print to console in master. Must be debug code in that branch. Spraying with if debug statement will make code less readable. It's fine doing under development and even ok to check in under dev branch. Put i wouldn't accept a pull to master without debug code removed |
Even VJoy kernel driver have this in source. It is not if debug statement. It is compiler directive. That is something else. I try to be helpful here and provide maximum verbosity, but I think our professional opinions will differ even more soon. Thank you, I will not be doing any pull request then. Have a nice day and good luck with your VR project. |
If you generate empty project in Visual Studio (C++), it will do it for you in the same manner. So my proposal is industry practice.
|
|
New Device.cs (SlimDX integration) implemented: https://github.com/cyberluke/FreePIE/tree/Ffb Now it does not ignore the first CreateEffect message that does not contain parameters. Because don't forget that FFB device is slow. This message allows to allocate memory and create new object inside FFB device. So the flow is:
Every other time, we get only: This is how Microsoft designed this FFB protocol to be efficient for the target device. The target device updates only changed parameters thanks to this. TODO:
|
Video of current progress, working in Windows 10: https://www.youtube.com/watch?v=pIR5bgpmE7E |
I have not checked if the C# SDK has the support yet, but here is a demo written in C
http://sourceforge.net/p/vjoystick/code/HEAD/tree/branches/Incompatible/ForceFB/apps/FfbMon/FfbMon.cpp
http://vjoystick.sourceforge.net/site/index.php/forum/5-Discussion/393-force-feedback-support?start=20
The text was updated successfully, but these errors were encountered: