Axis.Identifier

Right, I know this has come up before, lots, and never been resolved, but this time I intend to do something about it :slight_smile:

as it stands, Axis.Identifier is abused left right and centre. The API docs are fairly clear that it should be used as a type identifier, but that doesn’t say what the types are. e.g. there are types for different axis, like a rudder or a throttle, but there are not types for different buttons, ‘A’, ‘Z’, ‘ctrl’ etc. I have a couple of suggestions.

  1. Restrict that Axis.Identifier statics to genuine type, so Button, or Axis. I hate this one, but it’s an option.

  2. Use the current standard defined types, and just fix the usage of them in the plugins.

  3. Update the types and add ButtonX and ButtonY type identifiers.

  4. make Axis.Identifier.Button.X type structures where Axis.Identifier.Button extends Axis.Identifier and Axis.Identifier.Button.X extends Axis.Identifier.Button, this way you can have as narrow or wide a type search as you like. This would mean moving the existing types around so that there is an Axis.Identifier.Axis.X etc.

  5. Just have one huge long list of them, extending the current list to include all the button names etc.

  6. Modify Axis.Identifier, so that it includes a Type field, the type is one of Axis, Button or a few others we think of, and the Axis.Identifier is one of a huge list containing all the new types for buttons etc.

I just want to see what the consensus is amongs both jinput devs and API users.

Cheers

Endolf

I don’t like #1 or #6. The subclassing scheme seems to make more sense from an OO programming perspective.

[quote]I don’t like #1 or #6. The subclassing scheme seems to make more sense from an OO programming perspective.
[/quote]
I agree.

  1. sounds good. the only thing that annoys me is the Axis is used way to often. Isn’t there a better word for it? the whole thing would look ridiculous in code:

package foo;

public class Axis{

 public class Identifier{
  
  public class Axis {

   public static final Axis X = new foo.Axis.Identifier.Axis("X");

  }
 }
}

that looks error prone. yeah right, compiler will catch it easily but it makes programming the stuff not very friendly.
please find a new name for (net.java…)Axis which does not interfere with the name of a device feature. it is awful to distinguish between axis and Axis in documentation all the time :frowning:

btw:

err … um thats a mistake, isn’t it? X is an instance of Axis.Identifier.Button not a subclass? the example above think its an instance.

another question: can plugin developers create their own Axis.Identifier and Axis.Identifier.SOME_CLASS instances or is everything given as constants?

[quote] the whole thing would look ridiculous in code:


package foo;

public class Axis{

 public class Identifier{
  
  public class Axis {

   public static final Axis X = new foo.Axis.Identifier.Axis("X");

  }
 }
}

that looks error prone. yeah right, compiler will catch it easily but it makes programming the stuff not very friendly.
[/quote]
Remember that code would only look like that in a few places WITHIN JInput. Where the plugin programmers need to deal with defining the Axis Identifiers. For USERS of JInput and most places within the plugins it will just look like a fully qualified class name.

When using it you’ll also have Axis.Identifier.Axis.X, which isn’t nice, and yes, it was a mistake, X is an instance of Axis.Identifier.Axis in this case. Would also need to remember that anyone not using AbstractController would need to make sure they update the way Controller.getAxis(Axis.Identifier) works, and we would need a new method Controller.getAxis(Class identifierType)

unless anyone can think of a new name for Axis.Identifier.Axis etc, then I’ll go ahead and start implementing it. I also want to get the ControllerEnvironment.isSupported() method in that was discussed some time ago, that just returns true or false based on wether the plugin is supported in this environment or not, for example, the linux plugin won’t work unless the OS property is linux, and the AWT plugin (that doesn’t exist yet) will only work if an awt class can be loaded.

Endolf

my suggestions for replacement of net.java.games.input.Axis:
Feature
Control - taken from HID naming: http://www.osr.com/ddk/intinput/hidclass_4omf.htm

looks strange to me. maybe using inheritance for that isnt the best idea…

what about:


public class Axis {

 // not an interface to force single-inheritance model
 public static class Identifier {
   public abstract Type getType();
 }

 // non-overrideable/non-user instanceable (type-safe enum)
 public final static class Type{
   public static final BUTTON = new ...
   public static final ABSOLUTE_AXIS = new ...
   public static final RELATIVE_AXIS = new ...   
 }

}

// non-user or plugin-designer overrideable class
public final class ButtonIdentifier extends Axis.Identifier {
  // non-user instanceable
  private ButtonIdentifier() { }

  // hardcoded Axis.Type for all instances of this class
  public Axis.Type getType() { return Axis.Type.BUTTON; }

  // hardcoded constants for use by plugin developers/users
  public static final ButtonIdentifier START = new ButtonIdentifier("Start");

  // more constants ...

}

// more direct Axis.Identifier subclasses defining public final fields for
// (rel/abs) axes, keys

(that would be a compromise to my former intention to separate Axis.Type and Axis.Identifier - here they play an intermixed role because of Axis.Identifier subclass instances referencing Axis.Type objects)

Controller now needs getAxis(Axis.Identifier ai) and getAxis(Axis.Type). This is more expressive than getAxis(Class clazz) where clazz could be anything from Hashtable.class, over Boolean.class to StrictMath.class. For the way I suggest a documentation only needs to say that all public fields of Axis.Type are valid arguments.

btw: replace all ‘Axis’ with ‘Control’ or ‘Feature’. Control fits better to the standard (HID) but may cause confusion because of the already chosen Controller-class. What about:
Controller => InputDevice
Axis => Control
I know it may cause discomfort because of all that renaming but I think we agree on the fact that jinput’s classnames were not chosen very advisedly.

[quote]I also want to get the ControllerEnvironment.isSupported()
[/quote]
let us discuss this here (where it was first mentioned):
http://www.java-gaming.org/cgi-bin/JGNetForums/YaBB.cgi?board=jinput;action=display;num=1077169583

Thats number 6 (or what I was thinking of anyway) on the list, so is that a vote for 4 and a vote for 6? :slight_smile:

Endolf

its kind of a combination of both. but unlike 6 there is not one huge list of constants: they are separated into several Axis.Identifier subclasses (ButtonIdentifier, …).
the reason for the subclass solution is that it allows some kind of grouping which would not be possible when putting all constants into Axis.Identifier.

my main complaint with 4 is Controller.getAxis(Class clazz) …
I am not sure whether it was a good idea to introduce Axis.Identifier.getType() … hmmm.

what about the renaming thing?

Well, I’m still against the Axis.Type thing. The language does that for you… use the class heirarchy… it’s more flexible that way.

So controllers and Axis have types based on the class heirarchy. if (controller instanceof Mouse) is simple and easy to read. It tells you that you can use Mouse methods on that controller etc. Maybe just interfaces are enough.

I’m thinking that I would be coding something like this:


if( controller instanceof Mouse )
{
   Axis horizontal = ((Mouse)controller).getXAxis();
}

which works fine because we know that a Mouse has an X Axis and a Y Axis, even if the controller is actually an instance of TrackBall, so long as Mouse is a super class it all works out…

Of course I should probably shut up until I actually use the API seriously :slight_smile:


if( horizontal instanceof AnalogAxis )
{
  // analog stick?
}
if( horizontal instance of DigitalAxis )
{
  // direction pad?
}
if( horizontal instanceof RelativeAxis )
{
  // trackball/ mouse ball
}

[quote]my main complaint with 4 is Controller.getAxis(Class clazz) …
[/quote]
With JDK 1.5, you can specify a bounds on the Class type, so you can write this as,

<T extends Axis.Identifier> Axis Controller.getAxis( Class<T> identifierClass )

or whatever makes sense.

God bless,
-Toby Reyelts

Another suggetion on this. Hows about the Axis.Identifier.Button and Axis.Identifier.Button.X style id’s as before, with a method called something like ‘ofType’ that takes an ID, and Axis.Identifier.Button is an implementation of Axis.Identifier too, when ofType is called on a specific button it checks if the passed Axis.Identifier is itself or if it’s Axis.Identifier.Button. this solves the nasty method that takes a class

Comments?

Endolf

(I plan on looking at this soon, as I’ve fixed the linux plugin without re-writting chunks of it :))

This took some time until I understood what you are telling … especially because of the term:

[quote]or if it’s Axis.Identifier.Button
[/quote]
You probably meant “or if its an instance of Axis.Identifier.Button”. This would give us to the following implementation of “ofType”:


public boolean ofType(Axis.Identifier id){
return id == this || id instanceof Axis.Identifier.Button;
}

The problem I see here is that the user has to provide an instance of Axis.Identifier which as you said can be Axis.Identifier.Button.X or such. IMHO when the method is called it would look like this:

someAxisId.ofType(Axis.Identifier.Button.X)
which would be equivalent to:
someAxisId.ofType(Axis.Identifier.Button.ANY_OTHER).

the ‘ofType’ approach seems a little bit odd but the “Axis.Identifier.Button extends Axis.Identifier thing” looks good: It is similar to what swpalmer brought up already and would allow things like:

someAxisId instanceof Axis.Identifier.Button.

This would not be that ambigous although I am not a big fan of the idea that the nested-nested class inherits from its surrounding class …
I know its possible but it reminds me of a C function returning an array of function pointers on functions returning arrays of integers and taking some amazing arguments … :slight_smile:

maybe we could have a separate ButtonIdentifier class which inherits Axis.Identifier but is not nested inside it.

Nope, no idea what I was talking about there :), but hows about a Axis.Identifier.Button.ANY and Axis.Identifier.Axis.ANY etc, that can be passed in and checked for in the ofType method (of which the naming sux, but I couldn’t think of anything else)

Endolf

I’m completely lost now… I’m going to wait for someone to document how JInput plugins are supposed to work and how the API is supposed to be used and then come back and RTFM.
As it is I don’t see how JInput works in a reasonable cross-platform way.

As I see it, the Axis.Identifier is mainly going to be used to pass into Axis[] Controller.getAxis(Axis.Identifier) method, so the axis id’s need to be consistent across all plugins. The end user will say, hey, I want an X button from this controller that I know is a gamepad, or hey, I want the A key from this keyboard. And they will use those to check for changes to control the game play. Thats why we need to standardise it as I see it. The second part of the problem, is that a user might want to so ‘I don’t care which button I get, I need them all, so give me all the buttons on this controller’, which is where Axis.Identifier.Button.Any comes in, as a special axis id that can be passed in to the getAxis method on a controller, to aid plugin development the new method on axis ‘ofType’ would be introduced so that the plugin developer can just loop through all the controller axis going if axis.ofType(id), add it to the list to return.

Hope that makes some sence

Cheers

Endolf

maybe I can add my 2¤ cents experience of what the user might want because our game (freefodder.dev.java.net) can run with JInput as its input API (in CVS only atm :’( ):

It would be nice if I were able to access certain things directly: Like endolf said one might want a specific key on the keyboard. This is a good thing whenever fixed control bindings are needed. Eg. our ingame menu should always be controllable with cursor keys and the ESC key is important too because it acts as the key which aborts the auto-detection when auto-detecting controls.

As endolf said cross-plattform constants like Axis.Identifier would help here.

IMHO for user-defined control bindings one needs something which can be saved to disk (or java.util.prefs) and restored at a later time. In FFMKI our ‘solution’ is to store a path of objects. Such a path describes where to find a certain Axis instance when beginning to search in the initial Controller array.

eg. I have an Axis instance and know it is accessible when calling


controllers[4].getControllers()[1].getAxis(16)

(where controllers is the array of Controller instances returned from DefaultEnvironmentPlugin)

the path which is saved to disk is:
new ControllerNode(4, new ControllerNode(1, new AxisLeaf(16)));

(Now you know why I beg for ‘flat’ Controller instances which do not have subcontrollers itself.)

With unique identifiers one could store something that describes the input device (index?) and something that corresponds to the identifier (?).

endolf proposed:

I wonder why this method should return an array of Axis objects. I thought there would be only one instance per identifier or is this just a hack for the ANY identifier to return more than one?

Well, I give up insisting on Axis.Type (or something like that) in favor of getting the Axis.Identifier thing as easy as possible (and implemented ASAP). :slight_smile:

Starting from endolf’s initial choices I think option 2) is the way to go. (but adding different classes for each group of identifiers and not a long list like in 5).

[quote]As I see it, the Axis.Identifier is mainly going to be used to pass into Axis[] Controller.getAxis(Axis.Identifier) method…
[/quote]
Ok. sounds good. But I would return a single Axis not an array.

[quote]…which is where Axis.Identifier.Button.Any comes in, as a special axis id that can be passed in to the getAxis method on a controller, to aid plugin development the new method on axis ‘ofType’ would be introduced so that the plugin developer can just loop through all the controller axis going if axis.ofType(id), add it to the list to return.
[/quote]
I don’t like the idea of Axis.Identifier.Button.Any the way it is described here. Why not just enumerate the existing axis with an iterator or just have a getAllAxis() method that doesn’t take an Identifier.

Hi
Ok, if people don’t want the Axis.Identifier.Button.Any style id’s then it’s simple, and in this case the getAxis(Axis.Identifier) will just return a single Axis.

So, the only thing then is do we do

Axis.Identifier.Button.X,
Axis.Identifier.Key.A and
Axis.Identifier.Axis.X

or

Axis.Identifier.Button_X,
Axis.Identifier.Key_A and
Axis.Identifier.Axis_X

I much prefer the first, even with the Axis.Identifier.Axis nasty name.

If we can sort this asap I’ll start reworking the coreAPI and plugins.

Cheers

Endolf

IMHO the first suggestion is the way to go but please rename net.java.games.input.Axis to something making more sense.