Index: /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/eventcore/gui/TextInput.java
===================================================================
--- /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/eventcore/gui/TextInput.java	(revision 686)
+++ /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/eventcore/gui/TextInput.java	(revision 687)
@@ -1,6 +1,13 @@
 package de.ugoe.cs.quest.eventcore.gui;
 
+import java.util.List;
+
+import de.ugoe.cs.quest.eventcore.Event;
+
 /**
- * TODO comment
+ * <p>
+ * A text input represents a list of key events that together represent entering text into a
+ * text field or text area.
+ * </p>
  * 
  * @version $Revision: $ $Date: $
@@ -11,4 +18,23 @@
     /**  */
     private static final long serialVersionUID = 1L;
+    
+    /** the text resulting from the text input events */
+    private String enteredText;
+
+    /** the text input events that caused the entering of the text */
+    private List<Event> textInputEvents;
+
+    /**
+     * <p>
+     * TODO: comment
+     * </p>
+     *
+     * @param enteredText
+     * @param textInputEvents
+     */
+    public TextInput(String enteredText, List<Event> textInputEvents) {
+        this.enteredText = enteredText;
+        this.textInputEvents = textInputEvents;
+    }
 
     /*
@@ -18,5 +44,5 @@
      */
     public String getName() {
-        return "TextInput";
+        return "TextInput(\"" + enteredText + "\")";
     }
 
@@ -28,5 +54,19 @@
     @Override
     public String toString() {
-        return "text input";
+        return "text input \"" + enteredText + "\"";
+    }
+
+    /**
+     * @return the enteredText
+     */
+    public String getEnteredText() {
+        return enteredText;
+    }
+
+    /**
+     * @return the textInputEvents
+     */
+    public List<Event> getTextInputEvents() {
+        return textInputEvents;
     }
 
@@ -56,6 +96,11 @@
     @Override
     public boolean equals(Object obj) {
-        if (obj instanceof TextInput) {
+        if (this == obj) {
             return true;
+        }
+        else if (obj instanceof TextInput) {
+            return
+                enteredText.equals(((TextInput) obj).enteredText) &&
+                textInputEvents.equals(((TextInput) obj).textInputEvents);
         }
         return false;
@@ -69,5 +114,5 @@
     @Override
     public int hashCode() {
-        return getClass().hashCode();
+        return getClass().hashCode() + enteredText.hashCode() + textInputEvents.size();
     }
 
Index: /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/eventcore/gui/TextInputDetector.java
===================================================================
--- /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/eventcore/gui/TextInputDetector.java	(revision 687)
+++ /trunk/quest-core-events/src/main/java/de/ugoe/cs/quest/eventcore/gui/TextInputDetector.java	(revision 687)
@@ -0,0 +1,294 @@
+package de.ugoe.cs.quest.eventcore.gui;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+
+import de.ugoe.cs.quest.eventcore.Event;
+import de.ugoe.cs.quest.eventcore.IEventTarget;
+import de.ugoe.cs.quest.eventcore.gui.KeyInteraction;
+import de.ugoe.cs.quest.eventcore.gui.KeyPressed;
+import de.ugoe.cs.quest.eventcore.gui.KeyReleased;
+import de.ugoe.cs.quest.eventcore.guimodel.ITextArea;
+import de.ugoe.cs.quest.eventcore.guimodel.ITextField;
+import de.ugoe.cs.tasktree.keyboardmaps.KeyboardMap;
+import de.ugoe.cs.tasktree.keyboardmaps.KeyboardMapFactory;
+import de.ugoe.cs.tasktree.keyboardmaps.VirtualKey;
+
+/**
+ * <p>
+ * The text input detector iterates a list of events and searches for subsequent key events.
+ * Those are replaced by a single text input event representing the text entered through the key
+ * events. The replacement is only done, if the key events have a text field or text area as target
+ * </p>
+ * 
+ * @version $Revision: $ $Date: 18.03.2012$
+ * @author 2012, last modified by $Author: patrick$
+ */
+public class TextInputDetector {
+    
+    /** the keyboard map to use for character recognition*/
+    private KeyboardMap keyboardMap = KeyboardMapFactory.createKeyboardMap(Locale.GERMAN);
+    
+    /** the keys pressed in parallel */
+    List<VirtualKey> pressedKeys = new ArrayList<VirtualKey>();
+
+    /**
+     * <p>
+     * in the provided list of events, this method detects any event sequences that consists of
+     * key interactions and replaces them with a single text input interaction. This contains
+     * the entered text as well as the replaced key interaction events
+     * </p>
+     * 
+     * @param sequence the event sequence to search for text input events
+     * 
+     * @return the resulting sequence, in which key interactions on text fields and areas are
+     *         reduced to text input interactions
+     */
+    public List<Event> detectTextInputs(List<Event> sequence)
+    {
+        List<Event> resultingSequence = new LinkedList<Event>();
+        
+        int textEntryStartIndex = -1;
+        IEventTarget lastEventTarget = null;
+
+        int index = 0;
+        Event currentEvent = null;
+        Event textInputEvent = null;
+        while (index < sequence.size()) {
+            currentEvent = sequence.get(index);
+            textInputEvent = null;
+            
+            if (isKeyInteraction(currentEvent) && isDataInputEventTarget(currentEvent.getTarget()))
+            {
+                if (textEntryStartIndex < 0) {
+                    textEntryStartIndex = index;
+                    lastEventTarget = currentEvent.getTarget();
+                }
+                else if (!lastEventTarget.equals(currentEvent.getTarget())) {
+                    textInputEvent = handleTextEntrySequence
+                        (sequence, textEntryStartIndex, index - 1, lastEventTarget);
+                    
+                    textEntryStartIndex = index;
+                    lastEventTarget = currentEvent.getTarget();
+                }
+                currentEvent = null;
+            }
+            else {
+                if (textEntryStartIndex >= 0) {
+                    textInputEvent = handleTextEntrySequence
+                        (sequence, textEntryStartIndex, index - 1, lastEventTarget);
+                    
+                    textEntryStartIndex = -1;
+                    lastEventTarget = null;
+                }
+                
+            }
+
+            if (textInputEvent != null) {
+                resultingSequence.add(textInputEvent);
+            }
+            
+            if (currentEvent != null) {
+                resultingSequence.add(currentEvent);
+            }
+            
+            index++;
+        }
+
+        if (textEntryStartIndex >= 0) {
+            textInputEvent = handleTextEntrySequence
+                (sequence, textEntryStartIndex, sequence.size() - 1, lastEventTarget);
+            
+            if (textInputEvent != null) {
+                resultingSequence.add(textInputEvent);
+            }
+        }
+
+        return resultingSequence;
+    }
+
+    /**
+     * <p>
+     * returns true if the provide event is a key interaction; false else
+     * </p>
+     * 
+     * @param event the even to check
+     * 
+     * @return as described
+     */
+    private boolean isKeyInteraction(Event event) {
+        return (event.getType() instanceof KeyInteraction);
+    }
+
+    /**
+     * <p>
+     * creates a single text input event as replacement for key interactions being part of the
+     * subsequence of events denoted by the start and end index in the provide event sequence. If
+     * no text was entered, because the subsequence only contained key released events, then no
+     * text input event is generated (the method returns null).
+     * </p>
+     * 
+     * @param sequence
+     *            the event sequence of which the subsequence is analyzed
+     * @param startIndex
+     *            the start index in the event sequence from which the analysis should start
+     *            (inclusive)
+     * @param endIndex
+     *            the end index in the event sequence where the analysis should end (inclusive)
+     * @param eventTarget
+     *            the event target to be used for the new event
+     * 
+     * @return a text input event representing the text input resulting from the events of
+     *         the provided subsequence
+     * 
+     * @throws IllegalArgumentException
+     *             if the denoted subsequence contains other events than key interactions
+     */
+    private Event handleTextEntrySequence(List<Event>  sequence,
+                                          int          startIndex,
+                                          int          endIndex,
+                                          IEventTarget eventTarget)
+    {
+        List<Event> textInputEvents = new ArrayList<Event>();
+
+        String enteredText = determineEnteredText(sequence, startIndex, endIndex, textInputEvents);
+        
+        if ((enteredText != null) && (!"".equals(enteredText))) {
+            TextInput textInput = new TextInput(enteredText, textInputEvents);
+            return new Event(textInput, eventTarget);
+        }
+        else {
+            return null;
+        }
+    }
+
+    /**
+     * <p>
+     * check if an event target is a data input field, i.e. a text field or a text area
+     * </p>
+     * 
+     * @param eventTarget the event target to check
+     * 
+     * @return true, if it is a text field or a text area ; false else
+     */
+    private boolean isDataInputEventTarget(IEventTarget eventTarget) {
+        return ((eventTarget instanceof ITextField) || (eventTarget instanceof ITextArea));
+    }
+
+    /**
+     * <p>
+     * determines the text entered in the event subsequence denoted by the start and end index of
+     * the provided event sequence. The method records any pressed and released key interaction as
+     * well as combinations of pressed key interactions (such as shift + letter) and determines the
+     * respective character. All identified characters are then combined to the entered text. The
+     * method also identifies the usage of the back space. The enter key is ignored for text fields
+     * in which pressing the enter key results in finishing the text entry. All analyzed key
+     * interaction events are stored in the provided text input events result list. If the
+     * subsequence only contains key released events, no text was entered and the returned text is
+     * null.
+     * </p>
+     * 
+     * @param sequence
+     *            the event sequence of which the subsequence is analyzed
+     * @param startIndex
+     *            the start index in the event sequence from which the analysis should start
+     *            (inclusive)
+     * @param endIndex
+     *            the end index in the event sequence where the analysis should end (inclusive)
+     * @param textInputEvents
+     *            a buffer to contain any key interaction event analyzed (in out)
+     * 
+     * @return the text entered through the interaction events of the denoted subsequence
+     * 
+     * @throws IllegalArgumentException
+     *             if the denoted sequence contains other events than key interactions
+     */
+    private String determineEnteredText(List<Event> sequence,
+                                        int         startIndex,
+                                        int         endIndex,
+                                        List<Event> textInputEvents)
+        throws IllegalArgumentException
+    {
+        Event event;
+        StringBuffer enteredText = new StringBuffer();
+        
+        for (int i = startIndex; i <= endIndex; i++) {
+            event = sequence.get(i);
+            
+            if (event.getType() instanceof KeyPressed) {
+                VirtualKey key = ((KeyPressed) event.getType()).getKey();
+
+                pressedKeys.add(key);
+
+                if (key == VirtualKey.BACK_SPACE) {
+                    if (enteredText.length() > 0) {
+                        enteredText.deleteCharAt(enteredText.length() - 1);
+                    }
+                }
+                else if (key == VirtualKey.ENTER) {
+                    // text fields only contain one line of code. Therefore the return is ignored.
+                    if (!(event.getTarget() instanceof ITextField)) {
+                        enteredText.append(getCharacter(key, pressedKeys));
+                    }
+                }
+                else {
+                    char theChar = getCharacter(key, pressedKeys);
+                    if (theChar != Character.UNASSIGNED) {
+                        enteredText.append(theChar);
+                    }
+                }
+            }
+            else if (event.getType() instanceof KeyReleased) {
+                pressedKeys.remove(((KeyReleased) event.getType()).getKey());
+            }
+            else {
+                throw new IllegalArgumentException
+                    ("the subsequence denoted by the indexes contains other interactions than " +
+                     "just key strokes");
+            }
+            
+            textInputEvents.add(event);
+        }
+        
+        if (enteredText.length() > 0) {
+            return enteredText.toString();
+        }
+        else {
+            return null;
+        }
+    }
+
+    /**
+     * <p>
+     * determines the character matching the pressed key depending on other keys pressed in parallel
+     * such as the shift key.
+     * </p>
+     * 
+     * @param key         the key for which the character shall be determined
+     * @param pressedKeys the list of other keys pressed in parallel
+     * 
+     * @return the character resulting from the combination of pressed keys
+     */
+    private char getCharacter(VirtualKey key, List<VirtualKey> pressedKeys) {
+        boolean numlock = false;
+        boolean shift = false;
+        boolean altgr = false;
+
+        for (VirtualKey pressedKey : pressedKeys) {
+            if (pressedKey.isShiftKey()) {
+                shift = !shift;
+            }
+            else if (pressedKey == VirtualKey.ALT_GRAPH) {
+                altgr = !altgr;
+            }
+            else if (pressedKey == VirtualKey.NUM_LOCK) {
+                numlock = !numlock;
+            }
+        }
+
+        return keyboardMap.getCharacterFor(key, numlock, shift, altgr, false);
+    }
+
+}
