/*********************************************************************** * mt4j Copyright (c) 2008 - 2009, C.Ruff, Fraunhofer-Gesellschaft All rights reserved. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * ***********************************************************************/ package org.mt4j.input.inputSources; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Deque; import java.util.List; import java.util.NoSuchElementException; import org.mt4j.MTApplication; import org.mt4j.input.inputData.MTInputEvent; /** * An abstract superclass for the abstraction of input sources. * Input source listener can listen to events from the inputsource. * * @author Christopher Ruff */ public abstract class AbstractInputSource { /** The input listeners. */ private List<IinputSourceListener> inputListeners; /** The event queue. */ private Deque<MTInputEvent> eventQueue; private MTApplication app; private List<IinputSourceListener> inputProcessorsToFireTo; /** * Instantiates a new abstract input source. * * @param mtApp the mt app */ public AbstractInputSource(MTApplication mtApp) { this.inputListeners = new ArrayList<IinputSourceListener>(); this.eventQueue = new ArrayDeque<MTInputEvent>(20); this.app = mtApp; inputProcessorsToFireTo = new ArrayList<IinputSourceListener>(10); } /** * Called by the inputmanager when this inputsource is registered with the application. * This method should not be invoked directly! */ public void onRegistered(){ app.registerPre(this); //Make processing call this class' pre() method at the beginning of each frame } /** * Called by the inputmanager when this inputsource is unregistered from the application * This method should not be invoked directly! */ public void onUnregistered(){ app.unregisterPre(this); } // /** // * Fires event type. // * Determines if this particular input source fires the specified input event type. // * // * @param evtClass the evt class // * // * @return true, if it does. // */ // abstract public boolean firesEventType(Class<? extends MTInputEvent> evtClass); /** * Queue input event for firing. * They will be fired automatically before the next frame in snychronization with * the render thread. Use this method instead of fireInputEvent()! * * @param inputEvt the input evt */ protected void enqueueInputEvent(MTInputEvent inputEvt){ // System.out.println("ENQUEUE EVENT: Cursor: " + ((MTFingerInputEvt)inputEvt).getCursor().getId() + " Evt-ID: " + ((MTFingerInputEvt)inputEvt).getId()); this.eventQueue.addLast(inputEvt); //TODO synchronize access? } /** * The input events have to be fired in processings (and openGL's) thread. * Called by processing. This method should not be invoked directly! */ public void pre(){ this.flushEvents(); } /** * Flushes the events. * <p>NOTE: not threadsafe! Has to be called in the opengl thread if in opengl mode! */ public void flushEvents(){ /* //FIXME DEBUG TEST REMOVE! int count = 0; for (Iterator<MTInputEvent> iterator = eventQueue.iterator(); iterator.hasNext();){ MTInputEvent e = (MTInputEvent) iterator.next(); if (e instanceof MTFingerInputEvt) { MTFingerInputEvt fe = (MTFingerInputEvt) e; if (fe.getId() == MTFingerInputEvt.INPUT_ENDED) { count++; } } } if (count >= 2){ System.out.println("--2 INPUT ENDED QUEUED!--"); } int iCount = 0; for (IinputSourceListener listener : inputListeners){ if (listener.isDisabled()){ iCount++; } } if (iCount >= inputListeners.size() && !eventQueue.isEmpty()){ System.out.println("--ALL INPUT PROCESSORS DISABLED!--"); } */ if (!eventQueue.isEmpty()){ // System.out.print("START FLUSH CURSOR: " + ((MTFingerInputEvt)eventQueue.peek()).getCursor().getId() + " Evt-ID: " + ((MTFingerInputEvt)eventQueue.peek()).getId()+ " "); //To ensure that all global input processors of the current scene //get the queued events even if through the result of one event processing the scene //gets changed and the currents scenes processors get disabled //Also ensure that all queued events get flushed to the scene although //as a result this scenes input processors get disabled //TODO do this only at real scene change? //-> else if we disable input processors it may get delayed.. //FIXME problem that this can get called twice - because called again in initiateScenechange inputProcessorsToFireTo.clear(); for (IinputSourceListener listener : inputListeners){ if (!listener.isDisabled()){ inputProcessorsToFireTo.add(listener); } } while (!eventQueue.isEmpty()){ try { MTInputEvent te = eventQueue.pollFirst(); this.fireInputEvent(te); } catch (NoSuchElementException e) { e.printStackTrace(); //System.err.println(e.getMessage()); } } // System.out.println("END FLUSH"); } } /** * Fire input event. * <br><b>Note:</b> This method should NOT be called directly. * Use the <code>queueInputEvent</code> and flushEvents() methods instead! * * @param inputEvt the input evt */ private void fireInputEvent(MTInputEvent inputEvt){ //Adds the events to the cursors one by one before firing inputEvt.preFire(); for (int i=0; i<inputProcessorsToFireTo.size(); i++) { inputProcessorsToFireTo.get(i).processInputEvent(inputEvt); } /* for (IinputSourceListener listener : inputListeners){ listener.processInputEvent(inputEvt); } */ } /** * Adds the input listener. * @param listener the listener */ public synchronized void addInputListener(IinputSourceListener listener){ if (!inputListeners.contains(listener)){ inputListeners.add(listener); } } /** * Removes the input listener. * @param listener the listener */ public synchronized void removeInputListener(IinputSourceListener listener){ if (inputListeners.contains(listener)){ inputListeners.remove(listener); } } /** * Gets the input listeners. * @return the input listeners */ public synchronized IinputSourceListener[] getInputListeners() { return (IinputSourceListener[])inputListeners.toArray(new IinputSourceListener[this.inputListeners.size()]); } }