AndersMalmgren / FreePIE

Programmable Input Emulator
641 stars 145 forks source link

Add Force Feedback support to vjoy and joystick plugin #48

Open AndersMalmgren opened 9 years ago

AndersMalmgren commented 9 years ago

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

cyberluke commented 2 years ago

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.

// ConsoleApplication1.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "ConsoleApplication1.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// The one and only application object

CWinApp theApp;

using namespace std;

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
cyberluke commented 2 years ago
  1. fixed polar coords

  2. discovered that flight stick might have Y axis on position 0 and X axis on position 1 after investigating VJoy kernel driver, virtual device and several real devices

  3. Logitech G940 does not have any performance issues, but original Microsoft Sidewinder Force Feedback 2 joystick shows increasing packet delay bug again. Probably less powerful MCU. But it works directly ingame. This leads me to idea that current Device.cs class in FreePIE responsible for integration with SlimDX needs a complete overhaul. The communication must be completely different. We are not using Effect.setParameters() now at all. I believe that instead of doing 'new Effect' and 'new EffectParameters' in SlimDX on every packet, there should be only one instance of Effect and on next EffectReportPacket we just call SetParameters on existing instance. Now because there is 'new EffectParameters' call on each new packet, SlimDX will scream that you cannot call setParameters on it, because it is different instance than being uploaded on device. Therefore all methods needs refactoring into one generic method that will be smart enough to only create new instances when truly needed.

  4. there needs to be some smart auto detection of axis at the beginning (you can print it out and you see axis [0] have different integer number (that's axis id) than vjoy axis [0]. Therefore they are reverted. Now you cannot rewrite VJoy kernel driver because that information is encoded in USB HID profile in vjoy.inx driver manifest. And that information is taken from Microsoft Sidewinder Force Feedback 2. You would need USB Hid analyzer, take it from the real device, and replicate that in VJoy driver. Current approach is keeping VJoy its specific axis features and properties and implementing a bridge between VJoy and real device. Apart from smart axis detection, you need to recalculate ConditionSet and put packet0 into condition[1] and packet1 into condition[0]. There is no other workaround, you cannot change the hardware definition (HID). Good is that most apps send polar coords. For other coords, you will need to change incoming and outgoing axis direction properties (X,Y) or X,Y,Z for spherical coords. Then there is like 10 other properties that can differ. Including range. So each device tells you its range in USB HID descriptor (or Windows registry) and you should recalculate VJoy range to your actual real device range. Good thing is that is some feature such as TriggerRepeatInterval is not present on target device and you send it, it gets simply ignored as defined in DirectX documentation (and it is true from the tests)

cyberluke commented 2 years ago

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: 1) CreateEffect ===> this gets sent to device 2) SetEnvelope 3) SetConstantForce or SetPeriodicForce (TypeSpecificParameters) 4) Effect Report (contains direction, gain) ===> at this point we conctruct effect parameters from message 2, 3, 4, but we do not create effect anymore, we use SetParameters only. Now there is caveat. You need to set Flags there. If this effect is created for the first time, you set EffectParametersFlags.All.

Every other time, we get only: 3) SetConstantForce or SetPeriodicForce (TypeSpecificParameters) 4) Effect Report (contains direction, gain) ===> at this point we construct effect parameters from message 3 and 4 and we compare all individual values with previous values we have stored in memory in C#. For each changed parameter we add it to Flags. So it will look for example like this: Direction | Gain | TypeSpecificParameters or just Direction or just TypeSpecificParameters

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:

cyberluke commented 1 year ago

Video of current progress, working in Windows 10: https://www.youtube.com/watch?v=pIR5bgpmE7E