org.squidy.nodes.GestureRecognizerShake.java Source code

Java tutorial

Introduction

Here is the source code for org.squidy.nodes.GestureRecognizerShake.java

Source

/**
 * Squidy Interaction Library is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 of the License,
 * or (at your option) any later version.
 *
 * Squidy Interaction Library 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Squidy Interaction Library. If not, see
 * <http://www.gnu.org/licenses/>.
 *
 * 2009 Human-Computer Interaction Group, University of Konstanz.
 * <http://hci.uni-konstanz.de>
 *
 * Please contact info@squidy-lib.de or visit our website
 * <http://www.squidy-lib.de> for further information.
 */
package org.squidy.nodes;

import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;

import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlType;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.squidy.manager.controls.CheckBox;
import org.squidy.manager.controls.TextField;
import org.squidy.manager.data.DataConstant;
import org.squidy.manager.data.IData;
import org.squidy.manager.data.Processor;
import org.squidy.manager.data.Property;
import org.squidy.manager.data.impl.DataButton;
import org.squidy.manager.data.impl.DataDigital;
import org.squidy.manager.data.impl.DataInertial;
import org.squidy.manager.data.impl.DataKey;
import org.squidy.manager.data.impl.DataPosition2D;
import org.squidy.manager.data.impl.DataString;
import org.squidy.manager.model.AbstractNode;
import org.wiigee.device.Device;
import org.wiigee.event.AccelerationListener;
import org.wiigee.event.ButtonListener;
import org.wiigee.event.GestureEvent;
import org.wiigee.event.GestureListener;

/**
 * <code>GestureRecognizerShake</code>.
 *
 * <pre>
 * Date: Nov 21, 2008
 * Time: 5:13:03 PM
 * </pre>
 *
 * @author Nicolas Hirrle, nihirrle@htwg-konstanz.de, University of Konstanz
 * @version 1.0
 */
@XmlType(name = "GestureRecognizerShake")
@Processor(name = "GestureRecognizerShake", types = { Processor.Type.FILTER }, tags = { "gesture", "recognizer",
        "phidget" })
public class GestureRecognizerShake extends AbstractNode implements GestureListener {

    // Logger to log info, error, debug,... messages.
    private static final Log LOG = LogFactory.getLog(GestureRecognizerShake.class);

    // ################################################################################
    // BEGIN OF ADJUSTABLES
    // ################################################################################

    @XmlAttribute(name = "threshold")
    @Property(name = "Threshold", description = "Value threshold for adding to recognizer")
    @TextField
    private double threshold = 0.02;

    public double getThreshold() {
        return threshold;
    }

    public void setThreshold(double threshold) {
        this.threshold = threshold;
    }

    @XmlAttribute(name = "Loadgestures")
    @Property(name = "Loadgestures")
    @CheckBox
    private boolean loadGestures = true;

    public boolean isLoadGestures() {
        return loadGestures;
    }

    public void setLoadGestures(boolean loadGestures) {
        this.loadGestures = loadGestures;
    }

    @XmlAttribute(name = "InputIPhone")
    @Property(name = "InputIPhone")
    @CheckBox
    private boolean inputIPhone = true;

    public boolean isInputIPhone() {
        return inputIPhone;
    }

    public void setInputIPhone(boolean inputIPhone) {
        this.inputIPhone = inputIPhone;
    }

    // ################################################################################
    // END OF ADJUSTABLES
    // ################################################################################

    private String gestureFolder = "ext/shake/gestures";
    private HashMap<Integer, Gestures> gesturesLoaded;
    private Device wiigee;
    private DataInertial lastInertial;
    private long lastIPhoneTouch;
    private boolean isRecognizing = false;
    private Object synch = new Object();

    /*
     * (non-Javadoc)
     *
     * @see org.squidy.manager.model.AbstractNode#onStart()
     */
    @Override
    public void onStart() {
        if (inputIPhone)
            gestureFolder = "ext/iphone/gestures";
        else
            gestureFolder = "ext/shake/gestures";

        lastInertial = new DataInertial(GestureRecognizerShake.class, 0.5f, 0.5f, 0.5f);
        gesturesLoaded = new HashMap<Integer, Gestures>();

        wiigee = new Device(false);

        wiigee.setTrainButton(4);
        wiigee.setRecognitionButton(3);
        wiigee.setCloseGestureButton(8);
        wiigee.addGestureListener(this);
        if (loadGestures)
            loadGestures();
    }

    /*
     * (non-Javadoc)
     *
     * @see org.squidy.manager.model.AbstractNode#onStop()
     */
    @Override
    public void onStop() {
        gesturesLoaded.clear();
    }

    public DataPosition2D process(DataPosition2D dataPosition2D) {
        if (inputIPhone) {
            //         synchronized (synch) {
            //            lastIPhoneTouch = System.currentTimeMillis();
            //         }
            //         // check first if old Recognition is running
            //         if (!isRecognizing) {
            //            startSampleRecognition();
            //            isRecognizing = true;
            //            checkWhenToStop();
            //         }
            if (dataPosition2D.hasAttribute(iPhone.TOUCHES_BEGAN)) {
                if (dataPosition2D.getAttribute(iPhone.TOUCHES_BEGAN).equals("TOUCHES_BEGAN")) {
                    startSampleRecognition();
                }
            } else if (dataPosition2D.hasAttribute(iPhone.TOUCHES_ENDED)) {
                if (dataPosition2D.getAttribute(iPhone.TOUCHES_ENDED).equals("TOUCHES_ENDED")) {
                    stopSampleRecognition();
                }
            }
        }

        return null;
    }

    //   private void checkWhenToStop() {
    //      new Thread() {
    //         public void run() {
    //            synchronized (synch) {
    //               long timeNow = System.currentTimeMillis();
    //               while (timeNow - 50 > lastIPhoneTouch) {
    //                  try {
    //                     Thread.sleep(10);
    //                  } catch (InterruptedException e) {
    //                     e.printStackTrace();
    //                  }
    //                  timeNow = System.currentTimeMillis();
    //               }
    //               stopSampleRecognition();
    //               isRecognizing = false;
    //            }
    //         }
    //      }.start();
    //   }

    /**
     * @param dataInertial
     * @return
     */
    public IData process(DataInertial dataInertial) {

        if (dataInertial.getAbsoluteValue() > (1 + threshold)
                || dataInertial.getAbsoluteValue() < (1 - threshold)) {
            double[] w = { dataInertial.getX(), dataInertial.getY(), dataInertial.getZ() };
            if (inputIPhone) {
                double[] tmp = { dataInertial.getX() - lastInertial.getX(),
                        dataInertial.getY() - lastInertial.getY(), dataInertial.getZ() - lastInertial.getZ() };
                w = tmp;
                lastInertial = dataInertial.getClone();
            }

            wiigee.fireAccelerationEvent(w);
            //DataInertial tmp = new DataInertial(GestureRecognizerShake.class, (Float) w[0], (Float)w[1], (Float)w[2]);
            //return tmp;
        }

        return null;
    }

    /**
     * To Recognize with the ShakeSensor do following: 1. Click Shake-button and
     * hold. The Shake Sensor vibrates 2. Do gesture 3. Release Shake-button.
     * The Shake Sensor vibrates
     *
     * @param dataButton
     * @return
     */
    public IData process(DataDigital dataDigital) {
        if (dataDigital.hasAttribute(DataConstant.IDENTIFIER)) {
            if (dataDigital.getAttribute(DataConstant.IDENTIFIER).equals("ShakeSK7")) {
                if (dataDigital.getFlag())
                    startSampleRecognition();
                else
                    stopSampleRecognition();
            }
        }
        return dataDigital;

    }

    /**
     * To Recognize with ShakeAcceleromter and KeyboardInput do following: 1.
     * Learn gesture multiple times while holding the 't'-key on Keyboard-Input
     * Window. Releasing it marks the end of one recording process; 2. Finish
     * training of unique gesture by pressing 'return'-key 3. Recognize gesture
     * with 'space'-bar on Keyboard-Input Window 4. To save a gesture hit 's' on
     * Keyboard-Input Window and follow the instructions on the console. To be
     * done.
     *
     * @param dataButton
     * @return
     */
    public IData process(DataKey dataKey) {

        // keyType 84 for 't'; Hold 't' for learning a gesture. Releasing it
        // marks the end of the recording process
        if (dataKey.getKeyType() == 84) {
            if (dataKey.getFlag())
                startSampleLearning();
            else
                stopSampleLearning();
        }

        // keyType 10 for 'return-key'; finalizes learning process of a unique
        // gesture
        // NOTE: Gesture is not stored!
        else if (dataKey.getKeyType() == 10) {
            if (dataKey.getFlag()) {
                closeGesture();
            }
        }

        // keyType 32 for 'space-key'; hold to learn gesture
        // switch to learning mode and sample gesture
        else if (dataKey.getKeyType() == 32) {

            if (dataKey.getFlag()) {
                startSampleRecognition();
            } else {
                stopSampleRecognition();
            }
        }

        // keyType 83 for 's-key'; press to save gesture
        else if (dataKey.getKeyType() == 83 && dataKey.getFlag()) {
            saveGesture();
        }
        return null;
    }

    public void gestureReceived(GestureEvent event) {
        // DataGesture dataGesture = null;
        DataString dataString = null;

        DataKey dataKeyUp = null;
        DataKey dataKeyDown = null;
        DataButton dataButtonUp = null;
        DataButton dataButtonDown = null;
        if (event.isValid() && event.getProbability() > 0.8) {
            if (gesturesLoaded.containsKey(event.getId())) {
                System.out.println("New Gesture Event \"" + gesturesLoaded.get(event.getId()).getGesture()
                        + "\" with ID " + event.getId() + " and Probability " + event.getProbability()
                        + " from Source " + event.getSource());
                String gesture = gesturesLoaded.get(event.getId()).getGesture();
                if (gesture.contains("right")) {
                    dataKeyUp = new DataKey(GestureRecognizerShake.class, KeyEvent.VK_RIGHT, true);
                    dataKeyDown = new DataKey(GestureRecognizerShake.class, KeyEvent.VK_RIGHT, false);
                    dataButtonUp = new DataButton(GestureRecognizerShake.class, MouseEvent.BUTTON1, true);
                    dataButtonUp = new DataButton(GestureRecognizerShake.class, MouseEvent.BUTTON1, false);
                } else if (gesture.contains("left")) {
                    dataKeyUp = new DataKey(GestureRecognizerShake.class, KeyEvent.VK_LEFT, true);
                    dataKeyDown = new DataKey(GestureRecognizerShake.class, KeyEvent.VK_LEFT, false);
                } else if (gesture.contains("circle")) {
                    dataKeyUp = new DataKey(GestureRecognizerShake.class, KeyEvent.VK_F5, true);
                    dataKeyDown = new DataKey(GestureRecognizerShake.class, KeyEvent.VK_F5, false);
                }
                dataString = new DataString(GestureRecognizerShake.class,
                        gesturesLoaded.get(event.getId()).getGesture());
            } else {
                LOG.info("New Gesture Event (not loaded) with ID " + event.getId() + " and Probability "
                        + event.getProbability() + " from Source " + event.getSource());

                dataString = new DataString(GestureRecognizerShake.class,
                        gesturesLoaded.get(event.getId()).getGesture());
            }
            dataString.setAttribute(DataConstant.SESSION_ID, event.getId());

            if (dataString != null)
                publish(dataString);
            if (dataKeyUp != null)
                publish(dataKeyUp);
            if (dataKeyDown != null)
                publish(dataKeyDown);
        }
    }

    public void startSampleLearning() {
        fireButtonPressedEvent(4);
    }

    public void startSampleRecognition() {
        fireButtonPressedEvent(3);
    }

    public void closeGesture() {
        fireButtonPressedEvent(8);
    }

    public void stopSampleLearning() {
        fireButtonReleasedEvent(4);
    }

    public void stopSampleRecognition() {
        fireButtonReleasedEvent(3);
    }

    /**
     * Fires a button pressed event.
     *
     * @param button
     *            Integer value of the pressed button.
     */
    public void fireButtonPressedEvent(int button) {

        wiigee.fireButtonPressedEvent(button);
    }

    /**
     * Fires a button released event.
     */
    public void fireButtonReleasedEvent(int button) {
        wiigee.fireButtonReleasedEvent(button);

    }

    private void loadGestures() {
        new Thread() {
            public void run() {
                File f = new File(gestureFolder);
                String[] filenames = f.list();
                if (filenames == null) {
                    System.out.println("Failed to load gestures");
                    return;
                } else if (filenames.length == 0) {
                    System.out.println("No gestures found");
                    return;
                } else {
                    for (int i = 0; i < filenames.length; i++) {
                        int minus = filenames[i].lastIndexOf('-');
                        int dot = filenames[i].lastIndexOf('.');
                        String file = filenames[i].substring(0, dot);
                        if (file.isEmpty())
                            continue;
                        String gesture = filenames[i].substring(minus + 1, dot);
                        String idstr = filenames[i].substring(0, minus);

                        int id = Integer.parseInt(idstr);
                        Gestures g = new Gestures(id, gesture);
                        gesturesLoaded.put(id, g);

                        wiigee.loadGesture(gestureFolder + "/" + file);
                        System.out.println("Gesture " + gesture + " loaded");

                        // int minus = filenames[i].lastIndexOf('-');
                        // int dot = filenames[i].lastIndexOf('.');
                        // String file = filenames[i].substring(0, dot);
                        // String gesture = filenames[i].substring(0, minus);
                        // String idstr = filenames[i].substring(minus + 1,
                        // dot);
                        //
                        // int id = Integer.parseInt(idstr);
                        // Gestures g = new Gestures(id, gesture);
                        // gesturesLoaded.put(id, g);
                        //
                        // wiigee.loadGesture(gestureFolder + "/" + file);
                        // System.out.println("Gesture " + gesture + " loaded");
                    }
                }
            }
        }.start();
    }

    private void saveGesture() {
        new Thread() {
            public void run() {
                System.out.println("Do you want to save a Gesture? (y/n)");
                BufferedReader console = new BufferedReader(new InputStreamReader(System.in));
                String str = new String();
                try {
                    str = console.readLine();
                    if (str.equals("y")) {
                        System.out.println("Gesture ID: ");
                        String idstr = console.readLine();
                        int id = Integer.parseInt(idstr);

                        if (id < 10)
                            idstr = "0" + id;
                        System.out.println("Gesture Name (don't use '-' and '.'): ");
                        BufferedReader consoleF = new BufferedReader(new InputStreamReader(System.in));
                        String filename = new String();
                        filename = consoleF.readLine();

                        Gestures g = new Gestures(id, filename);
                        gesturesLoaded.put(g.id, g);
                        wiigee.saveGesture(id, gestureFolder + "/" + idstr + "-" + filename);
                        // wiigee.saveGesture(id, gestureFolder + "/" + filename
                        // + "-" + id);
                        System.out.println("Gesture " + g.getGesture() + " saved!");
                    }
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }.start();
    }

    private static class Gestures {
        public Gestures(int id, String gesture) {
            this.id = id;
            this.gesture = gesture;
        }

        private int id;
        private String gesture;

        public String getGesture() {
            return gesture;
        }

    }
}