package org.pollux3d.tuio;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.java.games.input.Mouse;
import org.pollux3d.gesture.GestureSystem;
import org.tuio.TuioCursor;
import com.jme3.input.InputManager;
import com.jme3.input.KeyInput;
import com.jme3.input.MouseInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.input.controls.MouseButtonTrigger;
import com.jme3.math.Vector2f;
/**
* TuioInput is an wrapper class for TUIO Clients.
*
* @author Martin Wind
*
*/
public class TuioInput implements ActionListener {
private static final Logger logger = Logger.getLogger(TuioInput.class.getName());
/**
* Singleton instance
*/
private static TuioInput instance = new TuioInput();
/**
* TuioDevice implementation
*/
private TuioDevice device = null;
/**
* List of available cursors
*/
private static Set<Integer> availableCursors = new HashSet<Integer>();
/**
* List of cursors to delete from the available cursors list
*/
private static Set<Integer> availableCursorsToDelete = new HashSet<Integer>();
/**
* List of active cursors
*/
private static Set<Integer> activeCursors = new HashSet<Integer>();
/**
* List of active cursors
*/
private static Map<Integer, TuioCursorStore> store = new HashMap<Integer, TuioCursorStore>();
/**
* mouse button trigger pressed
*/
private boolean mouseActive = false;
/**
* mouse button
*/
private int mouseButton = MouseInput.BUTTON_LEFT;
/**
* mouse release event fired?
*/
private boolean mouseReleased = true;
/**
* Screen width
*/
private int screenWidth;
/**
* Screen height
*/
private int screenHeight;
/**
* Window name
*/
private String windowName = null;
/**
* List of active listeners
*/
protected ArrayList<TuioInputListener> listeners;
/**
* InputManger used for Mouse to TUIO
*/
private InputManager inputManager = null;
/**
* use Mouse to TUIO
*/
private boolean useMouse = false;
/**
* last mouse position for delta
*/
private Vector2f lastMousePos = new Vector2f(0,0);
/**
* last mouse position for delta
*/
private Vector2f lastRightMousePos = new Vector2f(0,0);
private float zoomMouseToTuio = 0;
/**
* Singleton
*/
private TuioInput() {}
public void setInputManager(InputManager inputManager) {
this.inputManager = inputManager;
inputManager.addMapping("MouseToTuio_Active", new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
inputManager.addListener(this, "MouseToTuio_Active");
inputManager.addMapping("MouseToTuio_Right_Active", new MouseButtonTrigger(MouseInput.BUTTON_RIGHT));
inputManager.addListener(this, "MouseToTuio_Right_Active");
inputManager.addMapping("SIMPLEAPP_Zoom", new KeyTrigger(KeyInput.KEY_UP));
inputManager.addListener(this, "SIMPLEAPP_Zoom");
inputManager.addMapping("SIMPLEAPP_ZoomMin", new KeyTrigger(KeyInput.KEY_DOWN));
inputManager.addListener(this, "SIMPLEAPP_ZoomMin");
}
/**
* use mouse to TUIO bridge
* @param useMouse
*/
public void setUseMouse(boolean useMouse) {
if (this.inputManager == null && useMouse) throw new NullPointerException("Cant use mouse without inputManager");
this.useMouse = useMouse;
}
/**
* set an TuioDevice implementation
*
* @param device the TuioDevice to use
*/
public void setTuioDevice(TuioDevice device) {
// runtime checks
if (device == null) throw new NullPointerException("Error tuio device is null");
if (this.device != null) throw new NullPointerException("Error tuio device is already set");
if (screenWidth == 0 || screenHeight == 0) throw new NullPointerException("Error tuio screen is not set");
if (windowName == null) throw new NullPointerException("Error tuio window name ist not set");
// initialize device
device.initialize(windowName);
logger.log(Level.INFO, "TuioDevice "+device.getClass().getName()+" initialized");
this.device = device;
}
/**
* Has to be set before setTuioDevice.
* The windows 7 tuio bridge needs it to install an hook.
*
* @param windowName the window name of the application
*/
public void setWindowName(String windowName) {
this.windowName = windowName;
}
/**
* Has to be set before setTuioDevice.
*
* @param width the screen width
* @param height the screen height
*/
public void setScreen(int width, int height) {
screenWidth = width;
screenHeight = height;
}
/**
* destroys the TuioInput implementation
*/
public void destroy() {
if (this.device != null) {
this.device.destroy();
logger.log(Level.INFO, "TuioDevice "+device.getClass().getName()+" destroy");
this.device = null;
}
removeListeners();
}
/**
* triggers the TuioEvents in the TuioInputListeners
*/
public void update() {
// use real TUIO
if (!this.useMouse) {
// if we have listeners
if (listeners != null) {
// get the cursors
Map<Long,TuioCursor> cursors = device.getCursors();
Set<Long> sessionIds = cursors.keySet();
// delete the active cursors
activeCursors.clear();
// if there are cursors in the map
if (!sessionIds.isEmpty()) {
// for all cursors
for(long sessionId : sessionIds) {
TuioCursor cursor = cursors.get(sessionId);
if (cursor == null) continue;
// get the cursor id (0,1..)
int CursorID = cursor.getCursorID();
// add it to the active cursors
activeCursors.add(CursorID);
// if the cursor id is not in the availableCursors set then add it and...
if (availableCursors.add(CursorID)) {
// for all listeners call onNew
for (int i = 0; i < listeners.size(); i++) {
TuioInputListener listener = listeners.get(i);
listener.onNew(CursorID, cursor.getScreenX(screenWidth), screenHeight-cursor.getScreenY(screenHeight));
}
} else {
// the cursor id is in the availableCursors set
// get or create the cursor store
TuioCursorStore cstore = null;
if (store.containsKey(CursorID)) {
cstore = store.get(CursorID);
} else {
cstore = new TuioCursorStore();
}
// if the cursor has moved (note hasMoved had to be called to recalculate the position)
if (cstore.hasMoved(cursor.getScreenX(screenWidth), cursor.getScreenY(screenHeight))) {
for (int i = 0; i < listeners.size(); i++) {
// for all listeners call onMove
TuioInputListener listener = listeners.get(i);
listener.onMove(CursorID, cstore.getDeltaX(), cstore.getDeltaY(), cstore.getX(), screenHeight-cstore.getY());
}
store.put(CursorID, cstore);
}
}
}
}
availableCursorsToDelete.clear();
// for all availableCursors
for (int cursorId : availableCursors) {
// check if its active
if (!activeCursors.contains(cursorId)) {
// if not active put it on availableCursorsToDelete
availableCursorsToDelete.add(cursorId);
// remove id from the cursor store
store.remove(cursorId);
// for all listeners call onRelease
for (int i = 0; i < listeners.size(); i++) {
TuioInputListener listener = listeners.get(i);
listener.onRelease(cursorId);
}
}
}
// delte the availableCursorsToDelete from availableCursors
availableCursors.removeAll(availableCursorsToDelete);
}
// mouse to TUIO bridge
} else {
Vector2f mousePos = inputManager.getCursorPosition();
if (mouseButton == MouseInput.BUTTON_LEFT) {
if (mouseActive && mouseReleased) {
for (int i = 0; i < listeners.size(); i++) {
mouseReleased = false;
lastMousePos = mousePos;
TuioInputListener listener = listeners.get(i);
listener.onNew(0, (int) mousePos.x, (int) mousePos.y);
}
} else if (mouseActive && !mouseReleased) {
for (int i = 0; i < listeners.size(); i++) {
TuioInputListener listener = listeners.get(i);
listener.onMove(0, (int) (mousePos.x - lastMousePos.x), (int) (mousePos.y - lastMousePos.y), (int) mousePos.x, (int) mousePos.y);
}
} else if (!mouseActive && !mouseReleased) {
for (int i = 0; i < listeners.size(); i++) {
mouseReleased = true;
lastMousePos = new Vector2f(0,0);
TuioInputListener listener = listeners.get(i);
listener.onRelease(0);
}
}
}
if (mouseButton == MouseInput.BUTTON_RIGHT) {
mouseReleased = false;
if(mouseActive && !mouseReleased){
Vector2f delta = mousePos.subtract(lastRightMousePos);
if (delta.length() > 0) {
GestureSystem.get().move(delta);
}
}
}
if (zoomMouseToTuio != 0) {
GestureSystem.get().zoom(zoomMouseToTuio);
zoomMouseToTuio = 0;
}
lastRightMousePos = mousePos.clone();
}
}
/**
* @return the TuioInput instance
*/
public static TuioInput get() {
return instance;
}
/**
* Subscribe a listener to receive tuio events. Enable event generation.
*
* @param listener
* to be subscribed
*/
public void addListener( TuioInputListener listener ) {
if (device == null && !this.useMouse) throw new NullPointerException("Error tuio device is null");
if ( listeners == null ) {
listeners = new ArrayList<TuioInputListener>();
}
listeners.add( listener );
}
/**
* Unsubscribe a listener. Disable event generation if no more listeners.
*
* @param listener to be unsubscribed
*/
public void removeListener( TuioInputListener listener ) {
if ( listeners != null ) {
listeners.remove( listener );
if (listeners.size() == 0) listeners = null;
}
}
/**
* Remove all listeners and disable event generation.
*/
public void removeListeners() {
if ( listeners != null ) {
listeners.clear();
listeners = null;
}
}
/**
* Check if a listener is already added to this TuioInput
*
* @param listener listener to check for
* @return true if listener is contained in the listenerlist
*/
public boolean containsListener( TuioInputListener listener ) {
return listeners != null && listeners.contains( listener );
}
/**
* Get all added mouse listeners
*
* @return ArrayList of listeners added to this MouseInput
*/
public ArrayList<TuioInputListener> getListeners() {
return listeners;
}
public void onAction(String name, boolean isPressed, float tpf) {
if (name.equals("MouseToTuio_Active")){
mouseActive = isPressed;
mouseButton = MouseInput.BUTTON_LEFT;
} else if (name.equals("MouseToTuio_Right_Active")){
mouseActive = isPressed;
mouseButton = MouseInput.BUTTON_RIGHT;
} else if (name.equals("SIMPLEAPP_Zoom")){
zoomMouseToTuio -= 50;
} else if (name.equals("SIMPLEAPP_ZoomMin")){
zoomMouseToTuio += 50;
}
}
}