Joystick Plugin

This is probably because as the plugin is right now it only supports one joystick at a time and my guess is that HOTAS are detected as two separate joysticks. I believe The Britain was working on extending support to multiple joysticks, but we haven’t had an update from him in a while. It wouldn’t be difficult to support multiple joysticks, but it is a fair bit of code re-factoring. If you have some C++ skills take a look!

Thanks for the quick response, getnamo. So the current plug-in would have the same issue even with the different Saitek stick/throttle combos mentioned previously in this thread?

Unfortunately, I’ve only just started diving into C++ and do most of my Unreal work with Blueprints. I’d like to figure this out but I’m not sure it’s something I’d be capable of in a timely manner.

Thanks again for the help.

I got around the issue by using Thrustmaster’s TARGET software, which lets you combine the two controllers via a “virtual controller”. Guide here: https://.frontier.co.uk/showthread.php?t=33932

Hopefully this is the right thread for this question: How would I add a Joystick interface in C++ rather than in Blueprint? I have the Blueprint example working great, but now I’m working on something else.

Thanks!
-John

I gave implementing support for multiple joysticks a try: https://github.com//UEJoystickPlugin

It’s quite a large refactoring. But I simplified the structure somewhat in the process, and ended up with fewer lines than before :slight_smile:

The blueprint interface is similar, but not backwards compatible. The JoystickComponent now has a Get Joystick method that can get a specific joystick. In addition to the state from the last frame you can now query which type of joystick it is using Product Id or Product Name. So it should be possible (but not that simple) to support a two-device-HOTAS using blueprints. I want to use my X55 so I might try to make something better for that.

The regular input events are sent to a different player per joystick. I haven’t tried it out much, but by for example using Create Player with Controler Id set to 1 I get a split screen where I can control one player with each joystick! (using the Flying template)

Please try it out!

I had a look through this code, the changes are definitely welcome as they clean up a lot of things in addition to multiple joysticks; though I haven’t had a chance to try out the functionality. Only personal preference is that I prefer having a controller reference emitted with each event instead of player id (you can have that as a property on the emitted single controller), but with the additional get controller function its a matter of preference.

You should make a pull request on the main branch, great work!

I agree with your preference, so I tried to make it more like that again (I only made the change because I ran into a memory bug). Now the button/axis events get a JoystickState USTRUCT and the Plugged in/unplugged events get a JoystickInfo USTRUCT containing info about the device. I quite like the result! Except maybe player index should still be sent directly with the event instead of inside the JoystickState, but this works. This should make it easier to adapt blueprints from the previous versions of the plugin too.

To for example see the name of the joystick that had a button pressed you still have to use the GetJoystick method though. Like this:

getnamo and , thank you for your work, you saved me today. This is really something that should really be in the engine from start.
Do you have any plans on enhancing this plugin? Thanks!

You’re welcome and I agree that this should be in the engine, though probably in a much cleaner form.

tsky has forked the plugin to try to bind it to SDL instead of directinput, which should allow the plugin to work across more platforms. Apart from that 's addition of multiple inputs leaves only force feedback and code cleanup todo. What features do you feel are missing?

Actually, no functionality is missing. It’s just not very comfortable to use the first time :slight_smile:

I’m having some issues using the throttle… it seems that if I print the output from EventOutputJoystickAxisChanged I get the followng:

LogBlueprintUserMessages: JoystickX=-0.006 Y=0.007 Z=-1.000
LogBlueprintUserMessages: JoystickX=-0.008 Y=0.028 Z=-1.000
LogBlueprintUserMessages: JoystickX=-0.012 Y=0.061 Z=-1.000
LogBlueprintUserMessages: JoystickX=-0.015 Y=0.088 Z=-1.000
LogBlueprintUserMessages: JoystickX=-0.022 Y=0.135 Z=-1.000
LogBlueprintUserMessages: JoystickX=-0.023 Y=0.183 Z=-1.000
LogBlueprintUserMessages: JoystickX=-0.024 Y=0.232 Z=-1.000
LogBlueprintUserMessages: JoystickX=-0.029 Y=0.299 Z=-1.000
LogBlueprintUserMessages: JoystickX=-0.035 Y=0.343 Z=-1.000
LogBlueprintUserMessages: JoystickX=-0.043 Y=0.392 Z=-1.000
LogBlueprintUserMessages: JoystickX=-0.047 Y=0.425 Z=-1.000
LogBlueprintUserMessages: JoystickX=-0.051 Y=0.471 Z=-1.000
LogBlueprintUserMessages: JoystickX=-0.054 Y=0.501 Z=-1.000
LogBlueprintUserMessages: JoystickX=-0.058 Y=0.545 Z=-1.000
LogBlueprintUserMessages: JoystickX=-0.061 Y=0.593 Z=-1.000
LogBlueprintUserMessages: JoystickX=-0.064 Y=0.619 Z=-1.000
LogBlueprintUserMessages: JoystickX=-0.066 Y=0.628 Z=-1.000
LogBlueprintUserMessages: JoystickX=-0.067 Y=0.631 Z=-1.000
LogBlueprintUserMessages: JoystickX=-0.067 Y=0.630 Z=-1.000
LogBlueprintUserMessages: JoystickX=-0.067 Y=0.623 Z=-1.000
LogBlueprintUserMessages: JoystickX=-0.065 Y=0.614 Z=-1.000
LogBlueprintUserMessages: JoystickX=-0.063 Y=0.604 Z=-1.000
LogBlueprintUserMessages: JoystickX=-0.060 Y=0.582 Z=-1.000
LogBlueprintUserMessages: JoystickX=-0.055 Y=0.549 Z=-1.000
LogBlueprintUserMessages: JoystickX=-0.051 Y=0.515 Z=-1.000
LogBlueprintUserMessages: JoystickX=-0.048 Y=0.485 Z=-1.000
LogBlueprintUserMessages: JoystickX=-0.046 Y=0.464 Z=-1.000
LogBlueprintUserMessages: JoystickX=-0.046 Y=0.452 Z=-1.000
LogBlueprintUserMessages: JoystickX=-0.046 Y=0.451 Z=-1.000
LogBlueprintUserMessages: JoystickX=-0.046 Y=0.451 Z=-1.000
LogBlueprintUserMessages: JoystickX=-0.046 Y=0.451 Z=-1.000
LogBlueprintUserMessages: JoystickX=-0.045 Y=0.445 Z=-1.000
LogBlueprintUserMessages: JoystickX=-0.042 Y=0.434 Z=-1.000
LogBlueprintUserMessages: JoystickX=-0.036 Y=0.396 Z=-1.000
LogBlueprintUserMessages: JoystickX=-0.028 Y=0.337 Z=-1.000
LogBlueprintUserMessages: JoystickX=-0.019 Y=0.263 Z=-1.000
LogBlueprintUserMessages: JoystickX=-0.010 Y=0.181 Z=-1.000
LogBlueprintUserMessages: JoystickX=-0.003 Y=0.091 Z=-1.000
LogBlueprintUserMessages: JoystickX=-0.000 Y=0.000 Z=-1.000
LogBlueprintUserMessages: JoystickX=-0.009 Y=-0.000 Z=-1.000
LogBlueprintUserMessages: JoystickX=-0.011 Y=-0.000 Z=-1.000
LogBlueprintUserMessages: JoystickX=-0.006 Y=0.009 Z=-1.000
LogBlueprintUserMessages: JoystickX=-0.005 Y=0.005 Z=-1.000
LogBlueprintUserMessages: JoystickX=-0.000 Y=-0.000 Z=0.598
LogBlueprintUserMessages: JoystickX=-0.000 Y=-0.000 Z=0.591
LogBlueprintUserMessages: JoystickX=-0.000 Y=-0.000 Z=0.581
LogBlueprintUserMessages: JoystickX=-0.000 Y=-0.000 Z=0.564
LogBlueprintUserMessages: JoystickX=-0.000 Y=-0.000 Z=0.532
LogBlueprintUserMessages: JoystickX=-0.000 Y=-0.000 Z=0.497
LogBlueprintUserMessages: JoystickX=-0.000 Y=-0.000 Z=0.434
LogBlueprintUserMessages: JoystickX=-0.000 Y=-0.000 Z=0.398
LogBlueprintUserMessages: JoystickX=-0.000 Y=-0.000 Z=0.342
LogBlueprintUserMessages: JoystickX=-0.000 Y=-0.000 Z=0.299
LogBlueprintUserMessages: JoystickX=-0.000 Y=-0.000 Z=0.256
LogBlueprintUserMessages: JoystickX=-0.000 Y=-0.000 Z=0.187
LogBlueprintUserMessages: JoystickX=-0.000 Y=-0.000 Z=0.146
LogBlueprintUserMessages: JoystickX=-0.000 Y=-0.000 Z=0.088
LogBlueprintUserMessages: JoystickX=-0.000 Y=-0.000 Z=0.051
LogBlueprintUserMessages: JoystickX=-0.000 Y=-0.000 Z=0.005
LogBlueprintUserMessages: JoystickX=-0.000 Y=-0.000 Z=-0.038
LogBlueprintUserMessages: JoystickX=-0.000 Y=-0.000 Z=-0.076
LogBlueprintUserMessages: JoystickX=-0.000 Y=-0.000 Z=-0.098
LogBlueprintUserMessages: JoystickX=-0.000 Y=-0.000 Z=-0.117
LogBlueprintUserMessages: JoystickX=-0.000 Y=-0.000 Z=-0.135
LogBlueprintUserMessages: JoystickX=-0.000 Y=-0.000 Z=-0.149
LogBlueprintUserMessages: JoystickX=-0.000 Y=-0.000 Z=-0.158
LogBlueprintUserMessages: JoystickX=-0.000 Y=-0.000 Z=-0.163
OCULUS: [From Service] {ERR-009w} [HIDDevice] SetFeatureReport 17 failed
LogBlueprintUserMessages: JoystickX=-0.000 Y=-0.000 Z=-0.154
LogBlueprintUserMessages: JoystickX=-0.000 Y=-0.000 Z=-0.141
LogBlueprintUserMessages: JoystickX=-0.000 Y=-0.000 Z=-0.127
LogBlueprintUserMessages: JoystickX=-0.000 Y=-0.000 Z=-0.111
LogBlueprintUserMessages: JoystickX=-0.000 Y=-0.000 Z=-0.087
LogBlueprintUserMessages: JoystickX=-0.000 Y=-0.000 Z=-0.041
LogBlueprintUserMessages: JoystickX=-0.000 Y=-0.000 Z=0.018
LogBlueprintUserMessages: JoystickX=-0.000 Y=-0.000 Z=0.088
LogBlueprintUserMessages: JoystickX=-0.000 Y=-0.000 Z=0.148
LogBlueprintUserMessages: JoystickX=-0.000 Y=-0.000 Z=0.212
LogBlueprintUserMessages: JoystickX=-0.000 Y=-0.000 Z=0.307
LogBlueprintUserMessages: JoystickX=-0.000 Y=-0.000 Z=0.429
LogBlueprintUserMessages: JoystickX=-0.000 Y=-0.000 Z=0.526
LogBlueprintUserMessages: JoystickX=-0.000 Y=-0.000 Z=0.595
LogBlueprintUserMessages: JoystickX=-0.000 Y=-0.000 Z=0.671
LogBlueprintUserMessages: JoystickX=-0.000 Y=-0.000 Z=0.693
LogBlueprintUserMessages: JoystickX=-0.000 Y=-0.000 Z=0.776
LogBlueprintUserMessages: JoystickX=-0.000 Y=-0.000 Z=0.837
LogBlueprintUserMessages: JoystickX=-0.000 Y=-0.000 Z=0.911
LogBlueprintUserMessages: JoystickX=-0.000 Y=-0.000 Z=0.962
LogBlueprintUserMessages: JoystickX=-0.000 Y=-0.000 Z=1.000

Without manipulating the throttle I get values of maximum deflection.

For reference: the range of the Joystick from off to full throttle is 1 to -1.

The Joystick was on full off at the beginning of the log, so [1], when I then manipulated the throttle, it returned the correct value, and then wen I stropped and just manipulated the stick, I get -1 for Z all the time. Is there a way to cache the last value that wasn’t -1 and return that for each time I touch the stick ?
And now looking over the log critically I’m getting 0’s for X and Y, am I somehow getting input from two joysticks, on one vector ?

Looking through this more carefully I can’t seem to distinguish the different joysticks. I supposedly have 5 active sticks, but can’t seem to chose from that array which one I want to read values from.

Try the (in development) SDL-based fork, it’s the first version to handle input events for multiple-joystick-HOTAS in a usable manner :slight_smile:

You need to compile the plugin, the precomiled dll is not the latest version.
(The readme mentions compiling SDL2 from source too but you don’t need to if you’re using Windows)

Do I need to setup the linker manually ? I though the generate project files did that automatically, based on dependencies / includes.\

I get the following error:

Error 1 error C1083: Cannot open include file: ‘SDL2/SDL.h’: No such file or directory e:\perforce\dc_mb_01\mcvr\plugins\joystickplugin\source\joystickplugin\private\DeviceSDL.h 20 1 McVR

Error 2 error : Failed to produce item: E:\Perforce\dc_MB_01\McVR\Intermediate\Build\Win64\McVREditor\Development\Plugins\Dynamic\UE4Editor-JoystickPlugin.exp E:\DD_Perforce\dc_MB_01\McVR\Intermediate\ProjectFiles\ERROR McVR

Error 3 error MSB3073: The command ““E:\Program Files\Epic Games\4.7\Engine\Build\BatchFiles\Build.bat” McVREditor Win64 Development “E:\Perforce\dc_MB_01\McVR\McVR.uproject” -rocket” exited with code -1. C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V120\Microsoft.MakeFile.Targets 38 5 McVR

Yes, normally should this be done. BUT the .dll of SDL2 is not is the normal binary support of epic.
So as written by - read the hints in the git repository for compiling on your own. The plugins will work with all version >4.6.

I think the project is missing the thirdparty part compiled.

At least: You must have an project, which has C+±Files (even empties), to get compiling from editor to work. I this is not you can not recompile the plugins.

My actual directory structure:

Thirdparty SDL:

sdl_source.PNG

This is the directory where the plugin get the includes from. The sdl-build-directory, generated from cmake, i deleted…

If you compile the third-party (or use the SDL2.dll from repos) you must have this :

I hope this solves the trouble…

t.

I Do have my own empty class in the project, and it compiles fine without the Joystick plugin. And I’ve compiled source for the Mayo, and Leap devices, so I understand the logic behind it.

I installed CMAKE, configured it, created a Visual Studio 12 Project file, compiled and here’s the output:

Could NOT find PkgConfig (missing: PKG_CONFIG_EXECUTABLE)
0.2.1 :: 2 :: 1 :: 2 :: 2.0

SDL2 was configured with the following options:

Platform: Windows-6.1
64-bit: TRUE
Compiler: C:/Program Files (x86)/Microsoft Visual Studio 12.0/VC/bin/x86_amd64/cl.exe

Subsystems:
Atomic: ON
Audio: ON
Video: ON
Render: ON
Events: ON
Joystick: ON
Haptic: ON
Power: ON
Threads: ON
Timers: ON
File: ON
Loadso: ON
CPUinfo: ON
Filesystem: ON

Options:
3DNOW (Wanted: ON): OFF
ALSA (Wanted: OFF): OFF
ALSA_SHARED (Wanted: OFF): OFF
ALTIVEC (Wanted: ON): OFF
ARTS (Wanted: OFF): OFF
ARTS_SHARED (Wanted: OFF): OFF
ASSEMBLY (Wanted: ON): OFF
ASSERTIONS (Wanted: auto): auto
CLOCK_GETTIME (Wanted: OFF): OFF
DIRECTFB_SHARED (Wanted: OFF): OFF
DIRECTX (Wanted: ON): ON
DISKAUDIO (Wanted: ON): ON
DUMMYAUDIO (Wanted: ON): ON
ESD (Wanted: OFF): OFF
ESD_SHARED (Wanted: OFF): OFF
FUSIONSOUND (Wanted: OFF): OFF
FUSIONSOUND_SHARED (Wanted: OFF): OFF
GCC_ATOMICS (Wanted: OFF): OFF
INPUT_TSLIB (Wanted: OFF): OFF
LIBC (Wanted: OFF): OFF
MMX (Wanted: ON): OFF
NAS (Wanted: OFF): OFF
NAS_SHARED (Wanted: OFF): OFF
OSS (Wanted: OFF): OFF
PTHREADS (Wanted: OFF): OFF
PTHREADS_SEM (Wanted: OFF): OFF
PULSEAUDIO (Wanted: OFF): OFF
PULSEAUDIO_SHARED (Wanted: OFF): OFF
RENDER_D3D (Wanted: ON): ON
RPATH (Wanted: OFF): OFF
SDL_DLOPEN (Wanted: ON): OFF
SNDIO (Wanted: OFF): OFF
SSE (Wanted: ON): ON
SSE2 (Wanted: ON): ON
SSEMATH (Wanted: ON): OFF
VIDEO_COCOA (Wanted: OFF): OFF
VIDEO_DIRECTFB (Wanted: OFF): OFF
VIDEO_DUMMY (Wanted: ON): ON
VIDEO_MIR (Wanted: OFF): OFF
VIDEO_OPENGL (Wanted: ON): ON
VIDEO_OPENGLES (Wanted: ON): OFF
VIDEO_WAYLAND (Wanted: OFF): OFF
VIDEO_X11 (Wanted: OFF): OFF
VIDEO_X11_XCURSOR (Wanted: OFF): OFF
VIDEO_X11_XINERAMA (Wanted: OFF): OFF
VIDEO_X11_XINPUT (Wanted: OFF): OFF
VIDEO_X11_XRANDR (Wanted: OFF): OFF
VIDEO_X11_XSCRNSAVER (Wanted: OFF): OFF
VIDEO_X11_XSHAPE (Wanted: OFF): OFF
VIDEO_X11_XVM (Wanted: OFF): OFF
X11_SHARED (Wanted: OFF): OFF

CFLAGS: /DWIN32 /D_WINDOWS /W3
EXTRA_CFLAGS:
EXTRA_LDFLAGS:
EXTRA_LIBS: user32;gdi32;winmm;imm32;ole32;oleaut32;version;uuid;dinput8;dxguid;dxerr

Build Shared Library: ON
Build Static Library: ON

Configuring done
Generating done

Then Launched and compiled SDL2 with Visual Studio:

2> Generating Code…
3> SDL2-static.vcxproj -> E:\DD_Perforce\dc_MB_01\McVR\Plugins\JoystickPlugin\ThirdParty\SDL2\SDL2\Release\SDL2.lib
2> Creating library E:/DD_Perforce/dc_MB_01/McVR/Plugins/JoystickPlugin/ThirdParty/SDL2/SDL2/Release/SDL2.lib and object E:/DD_Perforce/dc_MB_01/McVR/Plugins/JoystickPlugin/ThirdParty/SDL2/SDL2/Release/SDL2.exp
2>MSVCRT.lib(cpu_disp.obj) : warning LNK4210: .CRT section exists; there may be unhandled static initializers or terminators
2> SDL2.vcxproj -> E:\DD_Perforce\dc_MB_01\McVR\Plugins\JoystickPlugin\ThirdParty\SDL2\SDL2\Release\SDL2.dll
5>------ Build started: Project: ALL_BUILD, Configuration: Release x64 ------
5> Building Custom Rule E:/DD_Perforce/dc_MB_01/McVR/Plugins/JoystickPlugin/ThirdParty/SDL2/SDL2-2.0.3/CMakeLists.txt
5> CMake does not need to re-run because E:\DD_Perforce\dc_MB_01\McVR\Plugins\JoystickPlugin\ThirdParty\SDL2\SDL2\CMakeFiles\generate.stamp is up-to-date.
6>------ Skipped Build: Project: INSTALL, Configuration: Release x64 ------
6>Project not selected to build for this solution configuration
========== Build: 5 succeeded, 0 failed, 0 up-to-date, 1 skipped ==========

I then copied the new SDL2.dll into E:\DD_Perforce\dc_MB_01\McVR\Plugins\JoystickPlugin\Binaries\Win64

and I still get the same error looking for the header file.

I also have the folder structure as shown: Although with no pdb’s because it can’t compile.

Do you have a file <ProjectDir>\Plugins\JoystickPlugin\Source\JoystickPlugin\JoystickPlugin.Build.cs that has a line


PublicIncludePaths.Add(IncludePathSDL2);

and



private string IncludePathSDL2
{
    get { return Path.GetFullPath(Path.Combine(ThirdPartyPath, "SDL2/SDL2", "include")); }
}

And no other *.Build.cs files under <ProjectDir>\Plugins\JoystickPlugin ?
Also, do you have a file <ProjectDir>\Plugins\JoystickPlugin\ThirdParty\SDL2\SDL2\include\SDL2\SDL.h ?

For anybody having similar issues:
I hacked my way though it, by including the Include path SDL2/SDL/include into the project’s include folders, and then I had to deal with the linker, which somehow always pointed to:
E:\DD_Perforce\dc_MB_01\McVR\Plugins\ThirdParty\SDL2\SDL2\Lib instead of
E:\DD_Perforce\dc_MB_01\McVR\Plugins\JoystickPlugin\ThirdParty\SDL2\SDL2\lib so I created that path and copied the files over, so it could find it, and it started compiling and linking, and succeeded. But I agree with everybody that this is something Epic should support (Joysticks / Wheels / GamePads).

Yes Line 86

Yes Lines 25,26,27,28

Yup

I can see in the picture that there is a missing subdirectory under “source”. When i do the first commit, i did the same “copy” error. Sam gaves me the hint.
So under the “Source” directory comes again an “JoystickPlugin”-Directory and under this you have to place the “Private” and “Public” and the build.cs. You can see the structure in my post (02-21-2015, 04:38 PM).
To be save you should do a clean check out of the last repo.

t.

I’m wondering if Tsky or anyone else has successfully compiled his fork for 4.7.4 and would be willing to make it available?