X-55 Twist Rudder Axis Doesn't Work
#11
Can you list off a few so I can  try? I've tried games such as Descent FreeSpace, Freespace 2, X-Wing Alliance, Mechwarrior 3, Wing Commander 3 and 4, even Jedi Knight and Quake 1 and 2, and they all detect input from the rudder axis properly. I don't know which DI they use, but I suspect Quake and Jedi Knight are old enough to have used DI3.

Just for kicks, I tried it in Descent 2 Win95, and even that detects the axis

It's not like your problem where an axis goes unmapped. It IS mapped to Rz, which is the correct axis for rudder. It does NOT map Axis Z, since there is no throttle slider/dial on the joystick. DirectInput allows the Z axis specifically to be unmapped/skipped, but SDL does not. That's the root of the problem here.

EDIT: Oh yeah, I finally got around to trying it on Linux, and it works fine there. So it seems that it's a Windows specific problem. Yet every single non-SDL Windows game I've tried detects it properly. Hmm...
Reply
#12
Here are 2 games you can use to see how your controller maps to the various structures.

Try out Talon demo to find out how your controller maps to the DIJOYSTATE structure.
http://www.indiedb.com/games/talon/downloads/talon-demo
It uses Direct Input v5+ like Forsaken, hence using the DIJOYSTATE structure.

in Talon Demo\talon\client
look for a file that starts with config and ends with .cs
place this within (I is optional, means invert)

Code:
moveMap.bind(joystick0, "rzaxis", yaw);
moveMap.bind(joystick0, "rxaxis", I, pitch);
moveMap.bind(joystick0, "ryaxis", I, roll);
moveMap.bind(joystick0, "xaxis", moveAxisLR);
moveMap.bind(joystick0, "yaxis", I, moveAxisFB);
moveMap.bind(joystick0, "zaxis", I, moveAxisUD);

Change it around to work with your contoller. The 2nd parameter corresponds to properties of DIJOYSTATE

The original Windows Quake uses DX3. I know FitzQuake sourceport still uses DX3
http://www.celephais.net/fitzquake/
Probably most do, but I've looked over the source for this one to make sure.

create a file id1/autoexec.cfg
place this within

Code:
joyname "my joystick"
joystick 1
joyadvanced 1

joyadvaxisx 3    //x    3=game_lateral
joyadvaxisy 1    //y    1=game_longitudonal
joyadvaxisz 5    //z
joyadvaxisr 4    //r    4=game_yaw
joyadvaxisu 6    //u
joyadvaxisv 2    //v    2=game_pitch

alter the joyadvaxis* values to figure out how your joystick maps to the JOYINFOEX structure (xyzruv)

Just out of curiosity if you type joy.cpl in the start box does your controller show up? Are you using a driver for the controller? What OS version you using, I'm suprised you can run Win95 games still.

"DirectInput allows the Z axis specifically to be unmapped/skipped, but SDL does not"
Well SDL 1.2 is using DirectInput (well the older version mixed up with multi-media stuff) but maybe SDL still mis-handles it somehow, maybe I could find it in SDL's code.
Reply
#13
WinQuake recognizes it as axis R, as expected. Axis Z does nothing, also as expected, as it is unmapped.

Talon demo is still downloading, so I'll let you know. I expect rudder to be rzaxis, though. EDIT: Yup, rudder is detected as rzaxis.

In SDL, this is code I would look for: My theory is that it only checks the first n axes for input, n being the number of axes as reported by the device. Not taking into account that one axis may not be in one of the first n axis slots, for example.

I mainly run Windows 8.1 x64, but I have a 32-bit XP partition handy for running older stuff. However, you'd be surprised to learn how many W95 games run on Windows 8. (D2 W95 runs, albeit too fast)

Yes, the X-55 stick shows up in joy.cpl, and the axis works properly in its preview window. I do have Saitek X-55 drivers, but the stick is an HID-compliant device so they are not strictly needed. The same issue happens if I uninstall the drivers, so I do not think drivers are a factor.
Reply
#14
I think I discovered the problem, it does appear to be as you've expected.

file: \SDL-1.2.15\src\joystick\win32\SDL_mmjoystick.c
function: void SDL_SYS_JoystickUpdate(SDL_Joystick *joystick)

Code:
    for (i = 0; i < joystick->naxes; i++) {

naxes is gotten back in function SDL_SYS_JoystickOpen from wNumAxes (report from Direct Input JoyCaps)
http://msdn.microsoft.com/en-us/library/...s.85).aspx
So if your joystick JoyCaps wNumAxes reports 3, then this messes up.

It only grabs these 3
pos[0] = joyinfo.dwXpos;
pos[1] = joyinfo.dwYpos;
pos[2] = joyinfo.dwZpos;

So you're correct, it is SDL messing up your controller, and not Direct Input! SDL assumes axes are contiguous and starts with dwXpos. What SDL should have done is utilize wCaps from Direct Input JoyCaps.

Code:
    for (i = 0; i < MAX_AXES; i++){

    if ((i>1) && ((wCaps & (1<<(i-2))) == 0)) {continue;}    //skip it, doesn't exist

This attempts to go through all 6, but skip ones that don't exist along the way.  I probably put excessive parenthesis, but I don't want to look up the order of operations. I'm going by these definitions I've read somewhere:

Code:
#define JOYCAPS_HASZ    1
#define JOYCAPS_HASR    2
#define JOYCAPS_HASU    4
#define JOYCAPS_HASV    8
Reply
#15
So, does this mean to fix this in DXX-Rebirth, a modified SDL will have to be built? Or is there a way to factor the change into Rebirth itself?

Also, it's going to take more than that change to fix it. Checks if axis >= naxes are in several places, such as SDL_PrivateJoystickAxis() in SDL_joystick.c. I think the most elegant solution would be to just increase joystick->naxes to accomodate the slots, by adding 1 if there is an axis that is unmapped (such as Z. SO, for the X-55, naxes would be 4 even though it really has 3 axes, since the axes are in slots 0, 1, and 3). But, it would throw off the axis count. Since this seems to be such an edge case to only pop up now I don't think it's a big deal if it does. It would be much simpler than remapping an axis down or adding checks to skip an axis in multiple places.

If this is the route, the DInput specs specify that there is to be no holes in axis mappings except for the Z Axis. So the check for this could be if the number of axes is greater than 2 yet JOYCAPS_HASZ is false, then increment naxes by 1. This could be done in SDL_SYS_JoystickOpen.

A better solution would be to make an array of size MAX_AXES that maps an index to the actual physical axis. I think the Linux implementation in SDL does this, which is why it works there (it also happens to have specific behaviors for certain joysticks). So for the X-55, the map would be { 0, 1, 3, 3, 4, 5 }. Then it would update axis 3 (the physical rudder axis) instead of trying to update axis 2 and getting nothing.
Reply
#16
Perhaps the easiest solution would be to change the compares with naxes with wCaps checks.
Such as
Code:
( axis < joystick->naxes )
changed to
Code:
((axis<2) || ((wCaps & (1<<(axis-2))) == 1))

Thing is naxes is correctly set to 3, but it's SDL's bad that they made the contiguous assumption. wCaps would have to be in the scope of these various functions however, either passed in or made as a global.

DXX wouldn't need to be modified, just re-compiled with a modified SDL. SDL would have to be modified, DXX wouldn't be able to code around the defect, the axis is never updated.

UPDATE:



Due to array accessing of the memory allocations such as
Code:
state = joystick->axes[axis];
instead of
Code:
joystick->axes = (Sint16 *)SDL_malloc (joystick->naxes*sizeof(Sint16));

joystick->naxes would need to change to the highest slot used, rather than the number of slots used. Set to 2 then If Z is used then 3, if r is used then 4, if u is used then 5, is v is used then 6.
Reply
#17
Quote:joystick->naxes would need to change to the highest slot used, rather than the number of slots used. Set to 2 then If Z is used then 3, if r is used then 4, if u is used then 5, is v is used then 6.

Yeah, that was my thought. It's the solution with the least amount of effort. Just one change in SDL_SYS_JoystickOpen. The side effect is that the X-55 would report as having 4 axes instead of 3 in Windows, but I can live with that. Functionality over form.

Like I mentioned earlier, it's probably the only joystick I know of that has this behavior (throttle axis unused but with rudder), so any other joysticks shouldn't be affected.
Reply
#18
Ya, just have naxes re-interpreted by all functions. Instead of it meaning number of axes, have it mean highest slot of axes used. It does seem that this way would be the most elegant solution. I believe you'd only have to change the Windows specific file, and leave the generic joystick files alone. Truth be told SDL already treats it that way for the most part anyhow. Just need to alter function: void SDL_SYS_JoystickUpdate(SDL_Joystick *joystick) similar to how I mentioned earlier, as well as the function before it that sets naxes. I haven't thoroughly examine the ramifications of this method, but it seems that it would work.
Reply
#19
The only ramification with increasing naxes is that there will be one extra axis that is never used and never receives input. Not elegant, but has a negligible memory and performance impact. And, of course, it reports that the joystick has more axes than it really does, which isn't very proper.

I think this should work as a proper solution, naxes is left alone. The axes update loop in UpdateJoystick is changed to:
Code:
int j;
for (i = 0, j = 0; i < joystick->naxes; i++, j++) { //axis i is the actual SDL axis to update, j is this function's internal axis
    if (i == 2 && !(SYS_Joystick[joystick->index].wCaps & JOYCAPS_HASZ)) //skip Z axis if undefined - DInput specifies this (fixes X-55 rudder axis)
        j++;
    if (joyinfo.dwFlags & flags[j]) {
        value = (int)(((float)pos[j] + transaxis[j].offset) * transaxis[j].scale);
        change = (value - joystick->axes[i]);
        if ( (change < -JOY_AXIS_THRESHOLD) || (change > JOY_AXIS_THRESHOLD) ) {
            SDL_PrivateJoystickAxis(joystick, (Uint8)i, (Sint16)value);
        }
    }
}
Essentially this maps the internal pos and transaxis array (j) to the proper SDL axis number (i). j matches i unless Z is not used, in which case j increments to skip it. So, for the X-55, the input data from axis 3 ® will be sent to SDL's axis 2, which is unused without this fix. The pos and transaxis arrays are internal to the SDL_mmjoystick.c file, and are defined for all 6 axes so no need to worry about memory mapping.
Reply
#20
(12-09-2014, 12:27 AM)Tarvis link Wrote:I think this should work as a proper solution, naxes is left alone. The axes update loop in UpdateJoystick is changed to:
Code:
for (i = 0, j = 0; i < joystick->naxes; i++, j++) { //axis i is the actual SDL axis to update, j is this function's internal axis
    if (i = 2 && !JOYCAPS_HASZ) //skip Z axis if undefined - DInput specifies this (fixes X-55 rudder axis)
        j++;
This does not do what you likely intended.  That conditional is parsed as:
- Set i to value 2
- Test if i is not zero (which, being 2, it will not be zero)
- If yes, test !JOYCAPS_HASZ
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)