FreePIE icon indicating copy to clipboard operation
FreePIE copied to clipboard

Add Force Feedback support to vjoy and joystick plugin

Open AndersMalmgren opened this issue 10 years ago • 154 comments

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

AndersMalmgren avatar Jan 28 '15 09:01 AndersMalmgren

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.

aubade avatar Mar 03 '16 17:03 aubade

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. https://github.com/MarijnS95/FreePIE_FFB Be aware though, the code:

  • Does not follow correct coding practices. (see this as a testbench where I mess around)
  • Hasn't been tested (well you're gonna laugh: I don't have an FFB device, I'm just extremely interested in this stuff and building it for some other people)
  • Still has some problems with disposing devices and effects. Like I said the code is a bit messy ;)

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.

MarijnS95 avatar Mar 06 '16 01:03 MarijnS95

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)

aubade avatar Mar 06 '16 07:03 aubade

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):

if starting:
    jID = 1;#ID of your FFB device
    joystick[jID].CreateEffect(1, EffectType.ConstantForce, -1, [1, 0])
    joystick[jID].OperateEffect(1, EffectOperation.Start, 0)
    force = 0

diagnostics.watch(force)
if(force < 10000):
    force += 1
if(force % 100 == 0):
    joystick[jID].SetConstantForce(1, force)

And this will forward FB data (for the moment being only constant force):

if starting:
    vJoy[0].RegisterFFBDevice(joystick[2]) #vJoy[0] is the receiving vJoy device that is connected to the game, joystick[2] is the FFB device

MarijnS95 avatar Mar 06 '16 10:03 MarijnS95

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

AndersMalmgren avatar Mar 06 '16 10:03 AndersMalmgren

Btw I also see there are alot of changes that are not really changes, do you use the correct tab setting (Ínsert spacec 4)

AndersMalmgren avatar Mar 06 '16 10:03 AndersMalmgren

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). And 2: I first want to discuss with you how to proceed. There's multiple different approaches/implementations I can think of, but I've no idea which would suit FreePIE best. However I don't think this (issue tracker) is the best place to do that, I think moving to the forum or direct (voice) chat is the best option? Then I can explain how FFB works in both vJoy and SlimDX, and we can come up with a plan how to implement this in such a neat way as the rest of FreePIE.

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.

MarijnS95 avatar Mar 06 '16 17:03 MarijnS95

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.

#code snippet
if starting:
    vJoy[0].RegisterFFBDevice(joystick[1]) #vJoy[0] is the receiving vJoy device that is connected to the game, joystick[2] is the FFB device
    jID = 0;#ID of your FFB device
    joystick[jID].CreateEffect(1, EffectType.ConstantForce, -1, [1, 0])
    joystick[jID].OperateEffect(1, EffectOperation.Start, 0)
    force = 0

diagnostics.watch(force)
if(force < 10000):
    force += 1
if(force % 100 == 0):
    joystick[jID].SetConstantForce(1, force)

Log output: https://dl.dropboxusercontent.com/u/187059/vjoyffb.txt

aubade avatar Mar 06 '16 20:03 aubade

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:

if starting:
    vJoy[0].RegisterFFBDevice(joystick[1]) #vJoy[0] is the receiving vJoy device that is connected to the game, joystick[2] is the FFB device
    jID = 0;#ID of your FFB device
    joystick[jID].CreateEffect(1, EffectType.ConstantForce, -1, [1, 0])
    force = 0

diagnostics.watch(force)
if(force < 10000):
    force += 1
if(force % 100 == 0):
    joystick[jID].SetConstantForce(1, force)
    joystick[jID].OperateEffect(1, EffectOperation.Start, 0)

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))

MarijnS95 avatar Mar 06 '16 20:03 MarijnS95

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.

aubade avatar Mar 06 '16 20:03 aubade

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

aubade avatar Mar 06 '16 21:03 aubade

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.

MarijnS95 avatar Mar 06 '16 21:03 MarijnS95

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:

Enumerated Joystick : vJoy Device
Enumerated Joystick : Logitech WingMan Strike Force 3D USB
Supported Effects : 
   - Constant
   - Ramp Force
   - Square Wave
   - Sine Wave
   - Triangle Wave
   - Sawtooth Up Wave
   - Sawtooth Down Wave
   - Damper
   - Inertia
   - Friction
   - CustomForce

Creating effects for vJoy Device
Error creating Spring Effect. Your joystick may not support this effect.  : 
REGDB_E_CLASSNOTREG : 
Class not registered

And gives an error when applying the grooves effect:

Error starting Pavement Groove effect. : 
E_HANDLE : 
Invalid handle

but apart from that, effects are silently discarded.

aubade avatar Mar 06 '16 21:03 aubade

The only effect that is currently completely forwarded is Constant(Force).

MarijnS95 avatar Mar 06 '16 21:03 MarijnS95

Okay, then yeah. :( Unfortunately it looks ilke Constant Force from FreePIE is fine, but from ForceTest isn't going through.

aubade avatar Mar 06 '16 21:03 aubade

Try FFB inspector: https://www.lfs.net/forum/thread/76818-ForceFeedback-Inspector-(aka-shake-it-baby)

MarijnS95 avatar Mar 06 '16 21:03 MarijnS95

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.

aubade avatar Mar 06 '16 22:03 aubade

Cool, finally it 'works' :+1:

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.

MarijnS95 avatar Mar 06 '16 22:03 MarijnS95

Fantastic! feel free to @ me anytime if you need my help.

aubade avatar Mar 06 '16 22:03 aubade

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.

MarijnS95 avatar Mar 06 '16 22:03 MarijnS95

I created a thread at MTBS that we can use to talk development and clean up of the code.

http://www.mtbs3d.com/phpBB/viewtopic.php?f=139&t=21859

AndersMalmgren avatar Mar 07 '16 09:03 AndersMalmgren

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

AndersMalmgren avatar Mar 16 '16 08:03 AndersMalmgren

I've read the forum, just didn't have any time to test anything last week.

MarijnS95 avatar Mar 16 '16 08:03 MarijnS95

Any news about the force feedback support ?

jbinard avatar Nov 15 '16 17:11 jbinard

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

AndersMalmgren avatar Nov 18 '16 09:11 AndersMalmgren

@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.

MarijnS95 avatar Nov 18 '16 14:11 MarijnS95

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'. I get a wheel turning back and forth with the script below.

if starting:
    jID = 0;#ID of your FFB device
    joystick[jID].createEffect(0, EffectType.ConstantForce, -1, [0, 1])
    force = 0

diagnostics.watch(force)
if(force < 10000):
    force += 10
else:
    force = -10000

if(force % 100 == 0):
    joystick[jID].setConstantForce(0, force)
    joystick[jID].operateEffect(0, EffectOperation.Start, 0)

Also, sometimes Unable to create new effect: An item with the same key has already been added..

erik-smit avatar Feb 12 '17 10:02 erik-smit

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'. I get a wheel turning back and forth with the script below.

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 True, meaning "use polar coordinates"). In that case, the first argument of the array should represent the angle, and the second one must be 0 (which is not the case with the Cartesian parameters [0, 1]). See https://msdn.microsoft.com/en-us/library/windows/desktop/ee417536(v=vs.85).aspx:

Setting up the direction for a polar two-axis effect is only a little more complicated. Set the DIEFF_POLAR flag in dwFlags and set rglDirection to point to an array of two LONGs. The first element in this array is the direction from which you want the effect to come. The second element in the array must be 0.

Anyway, when using Cartesian coordinates, [0, 1] should give you an effect in the positive y-axis, which I do not expect to turn the wheel (as that is x-axis).

Also, sometimes Unable to create new effect: An item with the same key has already been added..

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.

However, when I put "vJoy[0].registerFfbDevice(joystick[dev])" in my script, I seem to be getting some forcefeedback from Spintires (game) passed to my wheel, so yay!

Not sure why this was removed by an edit. False positive?

MarijnS95 avatar Feb 12 '17 14:02 MarijnS95

Not sure why this was removed by an edit. False positive?

Correct.

erik-smit avatar Feb 12 '17 16:02 erik-smit

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.

erik-smit avatar Feb 12 '17 17:02 erik-smit