Kodi Community Forum

Full Version: USB SNES controller axis problems on Linux
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
In the emulators themselves and the GUI controller configurator the "right" and "up" value of the axis does not work.

I've checked it out using jstest-gtk, and the controllers are working fine.

Eventually I tried setting the values in the buttonmap.xml file manually, like so:

<controller id="game.controller.snes">
                <feature name="a" button="1" />
                <feature name="b" button="2" />
                <feature name="up" axis="-1" />
                <feature name="down" axis="+1" />
                <feature name="left" axis="-0" />
                <feature name="right" axis="+0" />
                <feature name="leftbumper" button="4" />
                <feature name="rightbumper" button="5" />
                <feature name="select" button="8" />
                <feature name="start" button="9" />
                <feature name="x" button="0" />
                <feature name="y" button="3" />

But this didn't seem to fix anything inside the emulator.

The device in question is known under these product & vendor ids: 081f:e401
Here's the amazon page: http://www.amazon.com/gp/product/B00FFL7...8&ps%20c=1

Is there anything else I can do to get this to work?[/php]
Maybe the same workaround like this one is needed:

I hadn't time over the last weeks to provide a FR on Lakka, butso far the Controller is working, but mine is a different one.
Hmm, interesting... But I'm not sure if it's a kernel issue.

I can configure the buttons in plain zsnes just fine, it's seems like it just breaks in Kodi (and so libretro)
I don't really want to recompile my kernel just for this.
I think I know what the problem is. Can you post a debug log?
Sure, is this enough?
Here's the problem. your dpad is being detected as an anomalous trigger:
16:52:07 T:139888866895808   DEBUG: AddOnLog: Joystick Support: Anomalous trigger detected on axis 1 (initial value = -1.000000)
16:52:11 T:139888866895808   DEBUG: AddOnLog: Joystick Support: Anomalous trigger detected on axis 0 (initial value = 1.000000)

A normal trigger has a value of 0.0 on startup, and travels to 1.0 or -1.0 when fully pressed. An anomalous trigger doesn't start at 0. At rest, it has a value of -1.0 or 1.0. Also, it can travel to either 0 (half-axis) or the opposite of the rest value (full-axis).

I've observed anomalous triggers on Xbox-like controllers on OSX. I'm not sure where else they show up, but the code needs to be robust enough to handle this.

Detecting anomalous triggers is difficult, because some joystick APIs (e.g. cocoa on OSX) only report changes in state. triggers have no value until the first motion, so we can't sniff for anomalous triggers at startup. Also, drivers don't differentiate between triggers and analog sticks, both are float values in the range [-1.0, 1.0].

To solve this problem, I make the assumption that initial perturbations are minimal. As a result, the rest value of the trigger is the closest of {-1.0, 0.0, 1.0} to the first value reported. A rest value of 0.0 indicates a normal trigger, and a rest value of 1.0 or -1.0 indicates an anomalous one.

However, this assumption breaks down in several cases:
  • When the controller is plugged in with a trigger or analog stick that is already fully pressed
  • When the samplerate is too low (initial perturbation is a significant distance)
  • When drivers are lame and instead of digital buttons, they report dpads as analog sticks with the discrete values -1.0, 0.0, 1.0.

So in your case, the driver is reporting the Dpad as an analog stick, but the axes can only take on the discrete values -1.0, 0.0 and 1.0. When right or up is pushed, the value for that axis jumps from 0.0 to 1.0 instantaneously.

Welcome to joystick driver fuckery.

To fix this, we need a better algorithm for detecting and anomalous triggers. I tried a few different approaches, but each attempt was buggy and overly-complex. I finally went with KISS and implemented a mini FSM with two states: anomalous/not anomalous and half-range/full-range.

Some ideas I had:
  • consider trigger velocity as well as position
  • add another state: discrete dpad/not a discrete dpad
  • use a low-pass filter to smooth out the position/velocity

Do you think any of these ideas could help? Can you think of a good way to detect anomalous triggers?

For reference, here's the current anomalous trigger filter: AnomalousTriggerFilter.cpp
Do we need a calibration functionality for that? On Windows when I plugged in by 8bitdo NES30 controller I couldn't press left (or right I don't remember) on the D-Pad and I had to go through the joystick calibration wizard where I specifically had to press and release every button/axis and it used that to determine the "centre" position of the D-Pad etc. Obviously this would only be needed for these special cases. On Windows this functionality is provided by the OS. Not sure about other OSes.

But since ZSNES can handle this by itself there's probably also room for improvement in our implementation.
What do you mean? without adjusting anomalous triggers, kodi thinks the axis is always fully activated. It's almost impossible to map the axis to a joystick feature, and when it is mapped, kodi glitches out because it always sees the trigger as being pressed.

We could detect this when button mapping, but that adds complexity to the configuration gui and hampers ux. Also, up until now the joystick APIs have been independent from button mapping. It'd be nice to keep these separate.
So right now Kodi detects it is an "anomolous trigger", but just ignores it?
almost, it detects an anomalous trigger and applies a filter depending on the state:

* Not anomalous (centered at 0): x := x
* Centered at -1, half axis:     x := x + 1
* Centered at -1, full axis:     x := (x + 1) / 2
* Centered at 1, half axis:      x := x - 1
* Centered at 1, full axis:      x := (x - 1) / 2

The first value determines the center. The first opposite value determines that the trigger uses the full range [-1.0, 1.0]. Obviously, the trigger only uses a half-axis if the center is 1.0 and the value is never negative (or the center is -1.0 and the value is never positive)

So for your controller and driver, when right (1.0) is first pressed, this is closest to 1.0, so a filter of x := x - 1 is applied and Kodi sees a 0.0 (centered, per the assumption that initial perturbations are closest to the center)

When left (-1.0) is pressed, this has an opposite sign, so now the filter is x := (x - 1) / 2. So for left, Kodi sees a -1.0.

So the filter x := (x - 1) / 2 is applied to all values. As right is pressed, then unpressed, then left is pressed (value goes from 1.0 to 0.0 to -1.0); Kodi thinks the supposed trigger goes from unpressed, to half-pressed, to fully pressed (0.0 to -0.5 to -1.0). Note that when right and left are unpressed, Kodi sees a constant stream of -0.5 values. This screws up the configuration GUI and button actions.

The root of the problem is joystick driver fuckery. Joystick drivers all presest the dpad differently. Some drivers present 4 buttons, some drivers present a bitwise-ored flag of cardinal and intercardinal directions, some drivers present a POV angle from 0 to 360 with discrete values.

Your driver presents two axes (left/right and up/down) that can only take on the discrete values {-1.0, 0.0, 1.0}. Why use floats to represent integers that should be bools? Because joystick driver fuckery.
Fixed in 04d3044. I'll include the fix in the next round of builds