Example in JAVA

Post questions, comments and feedback to our 3Dconnexion Windows Development Team.

Moderator: Moderators

flodetours
Posts: 2
Joined: Thu Mar 22, 2007 6:54 am

Example in JAVA

Post by flodetours » Thu Mar 22, 2007 6:57 am

Hi !
I'm looking for an example using the JDK in JAVA (and not in JavaScript) to use the SpaceTraveler in a JAVA application. Could you help me plz.

Regards,

Florian

jwick
Moderator
Moderator
Posts: 2639
Joined: Wed Dec 20, 2006 2:25 pm
Location: USA
Contact:

Post by jwick » Thu Mar 22, 2007 7:22 am

Hi Florian,

The following post refers to what we have available currently for Java on Windows (a JNI interface). You may also want to try to use our new COM SDK.

viewtopic.php?p=383#383

Jim
3Dx Software Development

flodetours
Posts: 2
Joined: Thu Mar 22, 2007 6:54 am

Post by flodetours » Wed Mar 28, 2007 7:11 am

Thanks jim,

I downloaded the JNI example on the ftp, and it works fine if you leave the JNIsiapp.class in the default package. Unfortunatly, if you try to put it in another package (materiel.capteur3d in my case), it fails without any exception. I get a loop of the message "SpacemouseDevice: pollandprocessinput" (define on the method pollAndProcessInput of the SpacemouseDevice.java file), although I follow the steps define in the JNI book by sun, changing only the method name (for example JNICALL Java_materiel_capteur3d_JNIsiapp_SiInitialize replace JNICALL Java__JNIsiapp_SiInitialize ) in JNIsiapp.h and JNIsiapp.c.

I use to working with the JNI, but in this case, I don't know what to do !
Plz help !

Flo

jwick
Moderator
Moderator
Posts: 2639
Joined: Wed Dec 20, 2006 2:25 pm
Location: USA
Contact:

Post by jwick » Wed Mar 28, 2007 7:33 am

Hi Flo,

I wish I was of more help here. I wrote that code a long time ago. I do recall having some namespace problems though. Could it be a name scoping problem? Do you have to move it to a different package to make it work?

If you figure it out, please post the results here. We have several other people trying to use the 3Dx devices in Java/Java3D.

Jim

Brammel
Posts: 3
Joined: Wed May 09, 2007 1:41 am

Post by Brammel » Wed May 09, 2007 1:56 am

flodetours wrote:Thanks jim,

I downloaded the JNI example on the ftp, and it works fine if you leave the JNIsiapp.class in the default package. Unfortunatly, if you try to put it in another package (materiel.capteur3d in my case), it fails without any exception. I get a loop of the message "SpacemouseDevice: pollandprocessinput" (define on the method pollAndProcessInput of the SpacemouseDevice.java file), although I follow the steps define in the JNI book by sun, changing only the method name (for example JNICALL Java_materiel_capteur3d_JNIsiapp_SiInitialize replace JNICALL Java__JNIsiapp_SiInitialize ) in JNIsiapp.h and JNIsiapp.c.

I use to working with the JNI, but in this case, I don't know what to do !
Plz help !

Flo
Hi Flo,

I think you forgot to change this line in JNIsiappThread.java

Code: Select all

siapp.SiOpenWinInit("HelloUniverse","eventCallback");
Be sure you change "HelloUniverse" to the name of your applet class.

I also tried to recompile the jnisiapp.c and .h file to create a new dll file which I can use in a different package. The connection to the spacenavigator is ok, but when I touch it, the event generates this error (see the SiGetEvent method in the .c file):

Code: Select all

...SiGetEvent: Could not find field: event
Maybe it is because i changed line 109 of the .c file which generates a "too many initializers" (C2078) error:

Code: Select all

static jobject __gObj = {{0}};
to
static jobject __gObj = {0};
I have know idea if it's correct to change it.


Please help,

Thanks Bram

Brammel
Posts: 3
Joined: Wed May 09, 2007 1:41 am

Post by Brammel » Wed May 09, 2007 3:14 am

I found the solution!

My java classes are located in:

Code: Select all

package my.package;
If you compile the dll in Visual C++ 2006, change line 109 of JNIsiapp.c to

Code: Select all

static jobject __gObj={0};
And line 1988

Code: Select all

fid = (*env)->GetFieldID(env, cls, "event", "LJNIsiapp$SiSpwEvent;");
to

Code: Select all

fid = (*env)->GetFieldID(env, cls, "event", "Lmy/package/JNIsiapp$SiSpwEvent;");
and do the same for line 2056

Code: Select all

fid = (*env)->GetFieldID(env, cls, "bData", "LJNIsiapp$SiButtonData;");
to

Code: Select all

fid = (*env)->GetFieldID(env, cls, "bData", "Lmy/package/JNIsiapp$SiButtonData;");
Now everything works fine! Good luck!

brupbacher
Posts: 13
Joined: Tue Oct 02, 2007 1:35 pm

More Java Examples for USB version

Post by brupbacher » Tue Oct 02, 2007 1:49 pm

Hi,

I tried all the things you are describing, unfortunately I dont get any results...
I am using a USB version of the 3dconnexion device and the JAVA SDK described here...
I have the Java3D API in my CLASSPATH (every thing compiles well)
I have written some own Software and now I am trying to enhance it with some cool 3D input device...well...

So here are my questions...
- Can someone provide an example on how to use the API without Java3D
- How do I get Values/Events or any thing from the 3Dconnexion device?
- Does the API work with the USB version of the 3dConnexion Space mouse?

thanks and cheers
Oliver

brupbacher
Posts: 13
Joined: Tue Oct 02, 2007 1:35 pm

The Working Java Example

Post by brupbacher » Sat Oct 06, 2007 8:16 am

Hi all, after a little hacking and reading the news groupe, I finally got a valid result to use my USB 3Dconnexion space mouse :-).
The solution and code I offer here is based on readings in this forum and the follwoing two links which were also
mentionned in this forum. Some people allready had solutions for themselves but for legal reasons did not publish it.

http://fivedots.coe.psu.ac.th/~ad/jg2/ch11/index.html (Andrew Davison's Java Gaming and 3D Book)
https://jinput.dev.java.net/


So here it is:

Solution Overview:
1: Download, Install and understand the jinput api (read also stuff from Andrew Davison's Java 3D stuff it helps to understand)
2: implement a Class which defines your SpaceNavigator (3DConnexion in our case) see the implementaton bellow (see Code 2)
3: use the SpaceNavigator class in your code (see Code 1)

I think this is fairly simple thanks to the effort made by the jinput community (big thanks) and


Code 1: Use the SpaceNavigator

...

private static final int DELAY = 40;
private Timer pollTimer;
private SpaceNavigatorController spaceNavigatorController;


public static void main (String[] args) {

spaceNavigatorController = new SpaceNavigatorController();
addWindowListener(new WindowAdapter() {
public void windowClosing (WindowEvent e) {
pollTimer.stop(); // stop the timer
System.exit(0);
}
});
startPolling();
}

private void startPolling () {
ActionListener pollPerformer = new ActionListener() {
public void actionPerformed (ActionEvent e) {
spaceNavigatorController.poll();
}
};
pollTimer = new Timer(DELAY, pollPerformer);
pollTimer.start();
}

...


Code 2: SpaceNavigatorController Class

package nacked;

import net.java.games.input.Component;
import net.java.games.input.Controller;
import net.java.games.input.ControllerEnvironment;

/**
* Details for: SpaceNavigator, Stick, Unknown
* Components: (8)
* 0. Z Axis, z, relative, analog, 0.0
* 1. Y Axis, y, relative, analog, 0.0
* 2. X Axis, x, relative, analog, 0.0
* 3. Z Rotation, rz, relative, analog, 0.0
* 4. Y Rotation, ry, relative, analog, 0.0
* 5. X Rotation, rx, relative, analog, 0.0
* 6. Button 0, 0, absolute, digital, 0.0
* 7. Button 1, 1, absolute, digital, 0.0
* No Rumblers
* No subcontrollers
*/

public class SpaceNavigatorController {

public static final int NUM_BUTTONS = 2;

public static final int ZAXIS = 0;
public static final int YAXIS = 1;
public static final int XAXIS = 2;
public static final int ZROTATION = 3;
public static final int YROTATION = 4; // default value
public static final int XROTATION = 5;
public static final int BUTTON0 = 6;
public static final int BUTTON1 = 7;

// values returnd by the device during poll (may not be correct)
private static final float MAX_ROTATION = 1560.0f;
private static final float MAX_TRANSLATION = 1613.0f;

private int xAxisIdx, yAxisIdx, zAxisIdx, rxAxisIdx, ryAxisIdx, rzAxisIdx;
private int buttonsIdx[];

private Controller controller;
private Component[] comps;

public SpaceNavigatorController () {

ControllerEnvironment ce = ControllerEnvironment.getDefaultEnvironment();
Controller[] cs = ce.getControllers();
if (cs.length == 0) {
System.out.println("No controllers found");
System.exit(0);
} else System.out.println("Num. controllers: " + cs.length);

controller = findSpaceNavigator(cs);
System.out.println("Space Navigator controller: " + controller.getName() + ", " + controller.getType());

findCompIndices(controller);
}


private Controller findSpaceNavigator (Controller[] cs) {
Controller.Type type;
int i = 0;
while (i < cs.length) {
type = cs.getType();
if ((type == Controller.Type.STICK)) break;
i++;
}

if (i == cs.length) {
System.out.println("No Space Navigator found");
System.exit(0);
} else System.out.println("No Space Navigator index: " + i);

return cs;
}

private void findCompIndices (Controller controller)
/* Store the indices for the analog sticks axes
(x,y) and (z,rz), POV hat, and
button components of the controller.
*/ {
comps = controller.getComponents();
if (comps.length == 0) {
System.out.println("No Components found");
System.exit(0);
} else System.out.println("Num. Components: " + comps.length);

// get the indices for the axes of the analog sticks: (x,y) and (z,rz)
xAxisIdx = findCompIndex(comps, Component.Identifier.Axis.X, "x");
yAxisIdx = findCompIndex(comps, Component.Identifier.Axis.Y, "y");
zAxisIdx = findCompIndex(comps, Component.Identifier.Axis.Z, "y");

rxAxisIdx = findCompIndex(comps, Component.Identifier.Axis.RZ, "rx");
ryAxisIdx = findCompIndex(comps, Component.Identifier.Axis.RZ, "ry");
rzAxisIdx = findCompIndex(comps, Component.Identifier.Axis.RZ, "rz");

findButtons(comps);
}

private int findCompIndex (Component[] comps, Component.Identifier id, String nm) {
Component c;
for (int i = 0; i < comps.length; i++) {
c = comps;
if ((c.getIdentifier() == id)) {
System.out.println("Found " + c.getName() + "; index: " + i);
return i;
}
}

System.out.println("No " + nm + " component found");
return -1;
}

/**
* Search through comps[] for NUM_BUTTONS buttons, storing
* their indices in buttonsIdx[]. Ignore excessive buttons.
* If there aren't enough buttons, then fill the empty spots in
* buttonsIdx[] with -1's.
*/
private void findButtons (Component[] comps) {
buttonsIdx = new int[NUM_BUTTONS];
int numButtons = 0;
Component c;

for (int i = 0; i < comps.length; i++) {
c = comps;
if (isButton(c)) { // deal with a button
if (numButtons == NUM_BUTTONS) // already enough buttons
System.out.println("Found an extra button; index: " + i + ". Ignoring it");
else {
buttonsIdx[numButtons] = i; // store button index
System.out.println("Found " + c.getName() + "; index: " + i);
numButtons++;
}
}
}

// fill empty spots in buttonsIdx[] with -1's
if (numButtons < NUM_BUTTONS) {
System.out.println("Too few buttons (" + numButtons + "); expecting " + NUM_BUTTONS);
while (numButtons < NUM_BUTTONS) {
buttonsIdx[numButtons] = -1;
numButtons++;
}
}
} // end of findButtons()

/**
* Return true if the component is a digital/absolute button, and
* its identifier name ends with "Button" (i.e. the
* identifier class is Component.Identifier.Button).
*/
private boolean isButton (Component c) {
if (!c.isAnalog() && !c.isRelative()) { // digital and absolute
String className = c.getIdentifier().getClass().getName();
// System.out.println(c.getName() + " identifier: " + className);
if (className.endsWith("Button")) return true;
}
return false;
}

/**
* Return all the buttons in a single array. Each button value is
* a boolean.
*/
public boolean[] getButtons () {
boolean[] buttons = new boolean[NUM_BUTTONS];
float value;
for (int i = 0; i < NUM_BUTTONS; i++) {
value = comps[buttonsIdx].getPollData();
buttons = ((value == 0.0f) ? false : true);
}
return buttons;
} // end of getButtons()


public boolean isButtonPressed (int pos)
/* Return the button value (a boolean) for button number 'pos'.
pos is in the range 1-NUM_BUTTONS to match the game pad
button labels.
*/ {
if ((pos <1> NUM_BUTTONS)) {
System.out.println("Button position out of range (1-" + NUM_BUTTONS + "): " + pos);
return false;
}

if (buttonsIdx[pos - 1] == -1) // no button found at that pos
return false;

float value = comps[buttonsIdx[pos - 1]].getPollData();
// array range is 0-NUM_BUTTONS-1
return ((value == 0.0f) ? false : true);
} // end of isButtonPressed()

public void poll () {
controller.poll();
}


/**
* X Translation
*
* @return float value between 1613 and -1613
* <p>
* Note: the returned value my not be very logic and correct, I just measured them during pooling
*/
public float getTX () {
return comps[xAxisIdx].getPollData();
}

/**
* Y Translation
*
* @return float value between 1613 and -1613
* <p>
* Note: the returned value my not be very logic and correct, I just measured them during pooling
*/
public float getTY () {
return comps[yAxisIdx].getPollData();
}

/**
* Z Translation
*
* @return float value between 1613 and -1613
* <p>
* Note: the returned value my not be very logic and correct, I just measured them during pooling
*/
public float getTZ () {
return comps[zAxisIdx].getPollData();
}


/**
* X Rotation
*
* @return float value between 1560 and -1560
* <p>
* Note: the returned value my not be very logic and correct, I just measured them during pooling
*/
public float getRX () {
return comps[rxAxisIdx].getPollData();
}

/**
* Y Rotation
*
* @return float value between 1560 and -1560
* <p>
* Note: the returned value my not be very logic and correct, I just measured them during pooling
*/
public float getRY () {
return comps[ryAxisIdx].getPollData();
}

/**
* Z Rotation
*
* @return float value between 1560 and -1560
* <p>
* Note: the returned value my not be very logic and correct, I just measured them during pooling
*/
public float getRZ () {
return comps[rzAxisIdx].getPollData();
}
}

jwick
Moderator
Moderator
Posts: 2639
Joined: Wed Dec 20, 2006 2:25 pm
Location: USA
Contact:

Post by jwick » Mon Oct 08, 2007 8:39 am

Hi brupbacher,

Thanks Very Much for posting this. There has been a lot of interest in the SpaceNavigator from the Java community. Your posting should help them out quite a bit!

Jim
3Dx Software Development

brupbacher
Posts: 13
Joined: Tue Oct 02, 2007 1:35 pm

Hi Jim, and All (you are wellcome) I just found a BUG!!

Post by brupbacher » Mon Oct 08, 2007 8:46 am

Hi Jim and All other, you are wellcome.
I just found a BUG in my solution (not dramatic)

checkout the follwoing lines

xAxisIdx = findCompIndex(comps, Component.Identifier.Axis.X, "x");
yAxisIdx = findCompIndex(comps, Component.Identifier.Axis.Y, "y");
zAxisIdx = findCompIndex(comps, Component.Identifier.Axis.Z, "y");

rxAxisIdx = findCompIndex(comps, Component.Identifier.Axis.RZ, "rx");
ryAxisIdx = findCompIndex(comps, Component.Identifier.Axis.RZ, "ry");
rzAxisIdx = findCompIndex(comps, Component.Identifier.Axis.RZ, "rz");


must be replaced with the follwoing lines :-] sorry

xAxisIdx = findCompIndex(comps, Component.Identifier.Axis.X, "x");
yAxisIdx = findCompIndex(comps, Component.Identifier.Axis.Y, "y");
zAxisIdx = findCompIndex(comps, Component.Identifier.Axis.Z, "z");

rxAxisIdx = findCompIndex(comps, Component.Identifier.Axis.RX, "rx");
ryAxisIdx = findCompIndex(comps, Component.Identifier.Axis.RY, "ry");
rzAxisIdx = findCompIndex(comps, Component.Identifier.Axis.RZ, "rz");

enjoy :-) its really fun to have your own software running with a 3DSpace Navigator

cheers,

Oliver

ngomes
Moderator
Moderator
Posts: 1972
Joined: Mon Nov 27, 2006 7:22 am
Contact:

Post by ngomes » Tue Oct 09, 2007 3:54 am

Good stuff, brupbacher.

One question. In your method, you look for controllers of "STICK" type. Do you think that's enough to unequivocally determine that the controller is a 'SpaceNavigator? Won't it also enumerate simple joysticks?
Nuno Gomes

brupbacher
Posts: 13
Joined: Tue Oct 02, 2007 1:35 pm

Stick and Joysticks

Post by brupbacher » Tue Oct 09, 2007 4:29 am

Hi, yes you are right, I tried different things but
the 'Stick' type was the only one which showed the SpaceNaviagtor.
I do not use any standard joystick/pad in my environment (just the Stick and a Vacom Graphic Tablet) so I cannot answer this completely.

Probably you would have to add some more code for a better recognition of the device (e.g. the name of the expected device which can also be retrieved from the device, check the examples from the links i mentionned in my example (that stuff is well done), you should play around with them)

I tried to keep it as simple as possible :-)

if you have some enhancements to my example, please go ahead an post then, me and this community will be very thankfull,

cheers,

Oliver

ngomes
Moderator
Moderator
Posts: 1972
Joined: Mon Nov 27, 2006 7:22 am
Contact:

Post by ngomes » Tue Oct 09, 2007 5:45 am

I think I would only add code to check if all "component" identifiers (axes, buttons) can be found. 3Dconnexion 3D mice have 6DOF for motion and at least two buttons.

brupbacher
Posts: 13
Joined: Tue Oct 02, 2007 1:35 pm

6DOF and 2 Buttons

Post by brupbacher » Tue Oct 09, 2007 6:38 am

you mean just recognize the structure of the device...
yes that is a valid solution I guess...I would have gone the hard way by making a list of known devices (java propery.file) and searching the correct ones by vendor identifiers (this is good for very specialized devices), but your solution to detect gamepads it would be more general and is more apropriate to support gamepads in a general way...(since they all work the same way)

...go ahead, enhance the code ;-)

formatt
Posts: 6
Joined: Sat Oct 13, 2007 11:00 am

Post by formatt » Sat Jan 19, 2008 6:08 pm

Hi.

I've asked this question in the Mac forum, but I thought I'd try here to because it may not be Mac specific.

I've implemented the above code in my app and it exits with the message:

Code: Select all

Loading: net.java.games.input.OSXEnvironmentPlugin
Num. controllers: 5
No Space Navigator found
I'm running on Mac OS X 10.4 Intel. Running net.java.games.input.test.ControllerTextTest seems to pick up all my other peripherals but no Space Navigator.

Can anyone shed some light on this problem?

Thanks.

Matt.

Post Reply