[X3R Linux] Joystick Hat Switch doesn't work

Ask here if you experience technical problems with X³: Reunion, X²: The Threat, X-Tension or X-Beyond The Frontier

Moderators: timon37, Moderators for English X Forum

Brainsample
Posts: 6
Joined: Sat, 2. Feb 13, 05:58

[X3R Linux] Joystick Hat Switch doesn't work

Post by Brainsample »

First of all, THANK YOU so very much for porting X3 to Linux!

Second: With the latest update on Steam, most of the joystick functionality is working, but the hat switch still doesn't seem to do anything.

I assume it's just not implemented yet, but I'll be glad to provide any additional information to get it working.
Chromatix
Posts: 3
Joined: Wed, 23. Apr 08, 04:05
x3tc

Post by Chromatix »

The joystick I'm using doesn't have a hat, but I have noticed bizarrely high sensitivity in the XY axes. The throttle seems to work okay, although it had a weird dead spot in the middle.

I tried writing an sdlBasic program just now to look at what SDL is returning, but although it sees the right numbers of axes and buttons, it returns only zeroes when I read any of them, even if I move the stick to the limits or hold buttons down. But that's obviously not what I get in-game, so that's probably an sdlBasic fault. (No great loss, it just reminds me why BASIC dialects are not used by serious programmers.)

However, after a little more testing I think I've diagnosed the real problem: the very high manoeuvrability of an upgraded M4 fighter combined with a linear stick response results in lack of fine control near the centre position. This is confirmed by going to a system with a very large landmark in the background, observing how frequently it appears at full stick deflection, and then observing that it appears roughly half as often at roughly half deflection.

A potential fix would be to implement a quadratic or cubic response curve, so that low stick deflections result in fine control, while maximum deflection still makes rapid, coarse movements to the limit of the ship's ability.

As a workaround, I'll try adjusting the scale factor in the input configuration. I notice there's also a toggle for the hat there, so the OP could check that is turned on for him.
Brainsample
Posts: 6
Joined: Sat, 2. Feb 13, 05:58

Post by Brainsample »

A really useful program to show how SDL is seeing your controllers can be found HERE.

My throttle also has a dead zone in the center. I think this may be done in the Linux kernel. All analog axes get a small dead zone, and it's apparent in both SDL and non-SDL joystick acceess.

I have tried checking and unchecking the "Use POV to look around" setting in the setup, and it doesn't work either way.
Brainsample
Posts: 6
Joined: Sat, 2. Feb 13, 05:58

Post by Brainsample »

Well, I'm not that observant, because I missed the stickied thread for reporting Linux X3 issues.

But since we're already talking about joystick stuff, I'm going to point out some things that might help others playing X3 on Linux. What follows is probably way more information about this subject than anybody but myself cares to know.

I was right when I said that the dead zone for axes is being set in the kernel.

There are two ways to access a joystick/gamepad in Linux. There is the joydev interface, and the evdev interface. They both have pros and cons.

The joydev interface is read through a device file that will be named /dev/input/js0 for the first controller you plug in, /dev/input/js1 for the second, etc.

You can calibrate the joystick using utilites such as jscal, which is part of the confusingly named Linux Console Project. It's a command line program with somewhat obtuse options, but it allows you to calibrate, set dead zones, and remap axes and buttons. I believe it's actually part of the package called "joystick" for Ubuntu and Debian.

A nicer, graphical tool for calibrating is jstest-gtk. I don't know how many distros have this in their repos, so you might need to compile it yourself.

Using the tools jscal-store and jscal-restore, and a udev rule, you can save your calibration and have it automatically loaded when the joystick is plugged in. There's a bit to setting that up that I'm not going to go into, although I understand that Debian and Ubuntu will do it automatically when you have the "joystick" package installed..

The down side of the joydev interface is that it doesn't have any identification for axes or buttons. The application just sees a number of axes and a number of buttons, without being able to identify if it's supposed to be an X, Y, Rudder, or Throttle. Also, it has no facility for hat switches/D-pads. It just reports eachas two additional axes, which can make it difficult to assign them to functions in a game.

The evdev interface, on the other hand, identifies all the axes and buttons and hat switches to the application. Evdev devices are created as /dev/input/event*, like js devices, but the numbers of your js and event devices are highly unlikely to match up, because evdev devices also can be keyboards, mice, and just about any other kind of input device.

Here's the rub: The calibration you do on the joydev interface, using jscal does *not* affect the evdev interface. So, if you re-order some buttons and axes, and remove the dead zone from your throttle axis, and the game is using the evdev interface, none of you calibration will show up in the game.

The evdev interface doesn't have the same capabilities for calibration that the joydev interface has. You can't re-order axes or buttons, but you *can* set the deadzones per axis. The problem is, there's almost no software out there that will do this.

I found a tool that's part of the game VDrift, called G25manage. It's for calibrating a Logitech steering controller, but it has the ability to set dead zones for any absolute axis evdev devices (i.e. joysticks).

But what does all this have to do with X3?

X3 for Linux uses SDL for handling hardware. SDL is a cross platform library that makes it much easier to port games to other platforms, because it abstracts things like keyboard and controller input in to a common, easy to use interface.

Now, when running on Linux, SDL can use both the evdev *or* the joydev interface. By default, it tries to use evdev, then falls back to joydev.

If the calibration you're doing with jscal isn't showing up in game, you can force X3 to use the joydev interface instead by setting an environment variable at the command line, like so:

Code: Select all

export SDL_JOYSTICK_DEVICE=/dev/input/js0
Then you can launch X3R_Config from the same command line (so it inherits the variable):

Code: Select all

cd ~/.steam/root/SteamApps/common/X3\ -\ Reunion/
./X3R_config
...and X3 should see your joystick calibration. It won't, however, recognize your hat switch (X3 doesn't yet, anyway, hence the origin of this thread), but it will show two more axes, so if you want to use your hat switch for anything that a joystick axis can do.

Sheesh, I think that's enough for now.
timon37
EGOSOFT
EGOSOFT
Posts: 508
Joined: Fri, 14. Dec 12, 11:02
x4

Post by timon37 »

Hi, a lot happened here;)

As far as I'm aware evdev shouldn't have any kind of configurable deadzones, unless some filtering module attaches to it (maybe kde/gnome configures something?). It's likely that the device itself has something builtin, then again that probably wouldn't be configured to add a deadzone on a throttle.

Either way I am using the SDL hat interface so it should theoretically work.
But I don't have any device to test it:(

Does sdl actually report hat changes as hat changes for you?
Or does it report them only as axes?
If necessary I can add JoyPovX/Y axes that should make the hat work like a hat even though it's reported as two axes.
Brainsample
Posts: 6
Joined: Sat, 2. Feb 13, 05:58

Post by Brainsample »

Regarding evdev devices and calibration:

I was surprised to find this functionality, but it's definitely there.

In the kernel API headers, in linux/input.h, there are ioctls defined for absolute value axes:

Code: Select all

#define EVIOCGABS(abs)		_IOR('E', 0x40 + (abs), struct input_absinfo)	/* get abs value/limits */
#define EVIOCSABS(abs)		_IOW('E', 0xc0 + (abs), struct input_absinfo)	/* set abs value/limits */
And looking in the same file for the input_absinfo struct shows:

Code: Select all

/**
 * struct input_absinfo - used by EVIOCGABS/EVIOCSABS ioctls
 * @value: latest reported value for the axis.
 * @minimum: specifies minimum value for the axis.
 * @maximum: specifies maximum value for the axis.
 * @fuzz: specifies fuzz value that is used to filter noise from
 *	the event stream.
 * @flat: values that are within this value will be discarded by
 *	joydev interface and reported as 0 instead.
 * @resolution: specifies resolution for the values reported for
 *	the axis.
 *
 * Note that input core does not clamp reported values to the
 * [minimum, maximum] limits, such task is left to userspace.
 *
 * Resolution for main axes (ABS_X, ABS_Y, ABS_Z) is reported in
 * units per millimeter (units/mm), resolution for rotational axes
 * (ABS_RX, ABS_RY, ABS_RZ) is reported in units per radian.
 */
struct input_absinfo {
	__s32 value;
	__s32 minimum;
	__s32 maximum;
	__s32 fuzz;
	__s32 flat;
	__s32 resolution;
};
The "flat" value is the dead zone. Note the minimum and maximum values, which I think could be used to calibrate a joystick that doesn't return the full range of values.

Googling for examples of EVIOCSABS led me to the G25manage utility, which can list and set the values of that ioctl. For example:

Code: Select all

./G25manage --showcalibration=/dev/input/event4
Supported Absolute axes:
  Absolute axis 0x00 (0) (X Axis) (min: 0, max: 255, flatness: 15 (=5.88%), fuzz: 0)
  Absolute axis 0x01 (1) (Y Axis) (min: 0, max: 255, flatness: 15 (=5.88%), fuzz: 0)
  Absolute axis 0x02 (2) (Z Axis) (min: 0, max: 255, flatness: 15 (=5.88%), fuzz: 0)
  Absolute axis 0x05 (5) (Z Rate Axis) (min: 0, max: 255, flatness: 15 (=5.88%), fuzz: 0)
  Absolute axis 0x10 (16) (Hat zero, x axis) (min: -1, max: 1, flatness: 0 (=0.00%), fuzz: 0)
  Absolute axis 0x11 (17) (Hat zero, y axis) (min: -1, max: 1, flatness: 0 (=0.00%), fuzz: 0)

./G25manage --evdev=/dev/input/event4 --deadzone=0 --axis=2
Event device file: /dev/input/event4
New dead zone value: 0
Axis index to deal with: 2
Trying to set axis 2 deadzone to: 0
  Absolute axis 0x02 (2) (Z Axis) Setting deadzone value to : 0
(min: 0, max: 255, flatness: 0 (=0.00%), fuzz: 0)
That gets rid of the dead zone for the throttle on my controller.

If I get the time and inclination, I'll try to hack together something like jscal/jscal-store/jscal-restore to make it easier to save and restore settings.

This is more important now, because last night after my megapost, I found that since X3 updated to SDL2, half of what I wrote in my previous post is now invalid.

It appears that the SDL_JOYSTICK_DEVICE env no longer has any effect. SDL2 seems to always use evdev. I confirmed this by modifying sdl-jstest and compiling it against SDL2. I got the same results.

So, back to hat switches, SDL is definitely identifying it correctly, and showing SDL_JOYHATMOTION events.

If you have a USB gamepad with dual analog sticks and a D-pad, or an Xbox controller, you can try testing with those. SDL (when using evdev) picks up the D-pad as a hat switch, at least on all the ones I've tried.

If you've made it this far, thanks for reading!
timon37
EGOSOFT
EGOSOFT
Posts: 508
Joined: Fri, 14. Dec 12, 11:02
x4

Post by timon37 »

Hah true it's there, missed that, linux is evolving;)

Mine reports the d-pad as 4 buttons. I'll just make another build with some printfs for this.

Return to “X³: Reunion, X²: The Threat, X-T and X-BTF - Technical Support”