Index: trunk/autoquest-misc/src/main/java/de/ugoe/cs/autoquest/CommandHelpers.java
===================================================================
--- trunk/autoquest-misc/src/main/java/de/ugoe/cs/autoquest/CommandHelpers.java	(revision 922)
+++ trunk/autoquest-misc/src/main/java/de/ugoe/cs/autoquest/CommandHelpers.java	(revision 922)
@@ -0,0 +1,56 @@
+package de.ugoe.cs.autoquest;
+
+import java.util.logging.Level;
+
+import de.ugoe.cs.util.console.Console;
+
+/**
+ * <p>
+ * Helper class that collects methods that are often used by the commands.
+ * </p>
+ * 
+ * @author Steffen Herbold
+ * @version 1.0
+ */
+public class CommandHelpers {
+
+	/**
+	 * <p>
+	 * Prints a message to error stream of the {@link Console} that an object
+	 * has not been found in the storage.
+	 * </p>
+	 * 
+	 * @param objectName
+	 *            name of the object
+	 */
+	public static void objectNotFoundMessage(String objectName) {
+		Console.printerrln("Object " + objectName + " not found in storage.");
+	}
+
+	/**
+	 * <p>
+	 * Prints a message to the error stream of the {@link Console} that an
+	 * object is not of an expected type.
+	 * </p>
+	 * 
+	 * @param objectName
+	 *            name of the object
+	 * @param type
+	 *            expected type
+	 */
+	public static void objectNotType(String objectName, String type) {
+		Console.printerrln("Object " + objectName + "not of type " + type + ".");
+	}
+
+	/**
+	 * <p>
+	 * Prints a message to the trace stream of the {@link Console} that an
+	 * object in the storage has been overwritten.
+	 * </p>
+	 * 
+	 * @param objectName
+	 */
+	public static void dataOverwritten(String objectName) {
+		Console.traceln(Level.INFO, "Existing object " + objectName + " overwritten.");
+	}
+}
Index: trunk/autoquest-misc/src/main/java/de/ugoe/cs/autoquest/keyboardmaps/KeyStroke.java
===================================================================
--- trunk/autoquest-misc/src/main/java/de/ugoe/cs/autoquest/keyboardmaps/KeyStroke.java	(revision 922)
+++ trunk/autoquest-misc/src/main/java/de/ugoe/cs/autoquest/keyboardmaps/KeyStroke.java	(revision 922)
@@ -0,0 +1,243 @@
+
+package de.ugoe.cs.autoquest.keyboardmaps;
+
+/**
+ * <p>
+ * This class is used to define key strokes.
+ * </p>
+ * 
+ * @version 1.0
+ * @author Patrick Harms
+ */
+public class KeyStroke {
+
+    /**
+     * <p>
+     * Name of the key stroke.
+     * </p>
+     */
+    private String keyStrokeName;
+
+    /**
+     * <p>
+     * {@link VirtualKey} associated with the key stroke.
+     * </p>
+     */
+    private VirtualKey virtualKey;
+
+    /**
+     * <p>
+     * Defines whether numlock is pressed during the stroke.
+     * </p>
+     */
+    private boolean numlock;
+
+    /**
+     * <p>
+     * Defines whether localstate is pressed during the stroke.
+     * </p>
+     */
+    private boolean localstate;
+
+    /**
+     * <p>
+     * Defines whether shift is pressed during the stroke.
+     * </p>
+     */
+    private boolean shift;
+
+    /**
+     * <p>
+     * Defines whether altgr is pressed during the stroke.
+     * </p>
+     */
+    private boolean altgr;
+
+    /**
+     * <p>
+     * Defines whether inhibit is pressed during the stroke.
+     * </p>
+     */
+    private boolean inhibit;
+
+    /**
+     * <p>
+     * Defines the character in which the key stroke results.
+     * </p>
+     */
+    private char character;
+
+    /**
+     * <p>
+     * Constructor. Creates a new key stroke
+     * </p>
+     * 
+     * @param keyStrokeName
+     *            name of the key stroke
+     * @param virtualKey
+     *            virtual key associated with the key stroke
+     * @param numlock
+     *            defines whether numlock is pressed during the key stroke
+     * @param localstate
+     *            defines whether localstate is pressed during the key stroke
+     * @param shift
+     *            defines whether shift is pressed during the key stroke
+     * @param altgr
+     *            defines whether altgr is pressed during the key stroke
+     * @param inhibit
+     *            defines whether inhibit is pressed during the key stroke
+     * @param character
+     *            defines that character in which the key stroke results
+     */
+    public KeyStroke(String keyStrokeName,
+                     VirtualKey virtualKey,
+                     boolean numlock,
+                     boolean localstate,
+                     boolean shift,
+                     boolean altgr,
+                     boolean inhibit,
+                     char character)
+    {
+        this.keyStrokeName = keyStrokeName;
+        this.virtualKey = virtualKey;
+        this.numlock = numlock;
+        this.localstate = localstate;
+        this.shift = shift;
+        this.altgr = altgr;
+        this.inhibit = inhibit;
+        this.character = character;
+    }
+
+    /**
+     * <p>
+     * Returns the name of the key stroke.
+     * </p>
+     * 
+     * @return the name
+     */
+    public String getKeyStrokeName() {
+        return keyStrokeName;
+    }
+
+    /**
+     * <p>
+     * Returns the virtual key associated with the key stroke.
+     * </p>
+     * 
+     * @return the virtual key
+     */
+    public VirtualKey getVirtualKey() {
+        return virtualKey;
+    }
+
+    /**
+     * <p>
+     * Returns the character in which the key stroke results.
+     * </p>
+     * 
+     * @return the character
+     */
+    public char getCharacter() {
+        return character;
+    }
+
+    /**
+     * <p>
+     * Returns whether inhibit is pressed.
+     * </p>
+     * 
+     * @return true if pressed; false otherwise
+     */
+    public boolean getInhibit() {
+        return inhibit;
+    }
+
+    /**
+     * <p>
+     * Returns whether altgr is pressed.
+     * </p>
+     * 
+     * @return true if pressed; false otherwise
+     */
+    public boolean getAltgr() {
+        return altgr;
+    }
+
+    /**
+     * <p>
+     * Returns whether shift is pressed.
+     * </p>
+     * 
+     * @return true if pressed; false otherwise
+     */
+    public boolean getShift() {
+        return shift;
+    }
+
+    /**
+     * <p>
+     * Returns whether localstate is pressed.
+     * </p>
+     * 
+     * @return true if pressed; false otherwise
+     */
+    public boolean getLocalstate() {
+        return localstate;
+    }
+
+    /**
+     * <p>
+     * Returns whether numlock is pressed.
+     * </p>
+     * 
+     * @return true if pressed; false otherwise
+     */
+    public boolean getNumlock() {
+        return numlock;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see java.lang.Object#toString()
+     */
+    @Override
+    public String toString() {
+        StringBuffer toString = new StringBuffer();
+        toString.append("KeyStroke(");
+        toString.append(keyStrokeName);
+        toString.append(", ");
+        toString.append(virtualKey);
+
+        if (character != Character.UNASSIGNED) {
+            toString.append(", \'");
+            toString.append(character);
+            toString.append("\'");
+        }
+
+        if (shift) {
+            toString.append(", shift");
+        }
+
+        if (altgr) {
+            toString.append(", altgr");
+        }
+
+        if (numlock) {
+            toString.append(", numlock");
+        }
+
+        if (localstate) {
+            toString.append(", localstate");
+        }
+
+        if (inhibit) {
+            toString.append(", inhibit");
+        }
+
+        toString.append(")");
+
+        return toString.toString();
+    }
+
+}
Index: trunk/autoquest-misc/src/main/java/de/ugoe/cs/autoquest/keyboardmaps/KeyboardMap.java
===================================================================
--- trunk/autoquest-misc/src/main/java/de/ugoe/cs/autoquest/keyboardmaps/KeyboardMap.java	(revision 922)
+++ trunk/autoquest-misc/src/main/java/de/ugoe/cs/autoquest/keyboardmaps/KeyboardMap.java	(revision 922)
@@ -0,0 +1,2118 @@
+
+package de.ugoe.cs.autoquest.keyboardmaps;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.logging.Level;
+
+import de.ugoe.cs.util.console.Console;
+
+/**
+ * <p>
+ * Helper class that maps keyboard input based on a key map.
+ * </p>
+ * 
+ * @version 1.0
+ * @author Patrick Harms
+ */
+public class KeyboardMap {
+
+    /**
+     * <p>
+     * Locale used for the mapping.
+     * </p>
+     */
+    private Locale locale;
+
+    /**
+     * <p>
+     * Name of the mappings-file.
+     * </p>
+     */
+    private String fileName;
+
+    /**
+     * <p>
+     * Map that defines which key strokes define a virtual key.
+     * </p>
+     */
+    private Map<VirtualKey, List<KeyStroke>> keyStrokes =
+        new HashMap<VirtualKey, List<KeyStroke>>();
+
+    /**
+     * <p>
+     * Creates a new KeyboardMap.
+     * </p>
+     * 
+     * @param locale
+     *            Locale that is used for the keyboard map
+     */
+    KeyboardMap(Locale locale) {
+        this.locale = locale;
+
+        if ((this.locale == Locale.ENGLISH) || (this.locale == Locale.US) ||
+            (this.locale == Locale.CANADA))
+        {
+            fileName = "en-us";
+        }
+        else if (locale == Locale.UK) {
+            fileName = "en-gb";
+        }
+        else {
+            fileName = locale.getLanguage();
+        }
+    }
+
+    /**
+     * <p>
+     * Returns a character that is generated, given a {@link VirtualKey} is pressed while the
+     * respective modifiers are active.
+     * </p>
+     * 
+     * @param key
+     *            key that is pressed
+     * @param numlock
+     *            true, if numlock is pressed; false otherwise
+     * @param shift
+     *            true, if shift is pressed; false otherwise
+     * @param altgr
+     *            true, if altgr is pressed; false otherwise
+     * @param inhibit
+     *            true, if inhibit is pressed; false otherwise
+     * @return generated character
+     */
+    public char getCharacterFor(VirtualKey key,
+                                boolean numlock,
+                                boolean shift,
+                                boolean altgr,
+                                boolean inhibit)
+    {
+        List<KeyStroke> candidates = keyStrokes.get(key);
+
+        if (candidates == null) {
+            return Character.UNASSIGNED;
+        }
+
+        // try to find the key stroke
+        for (KeyStroke keyStroke : candidates) {
+            if ((numlock == keyStroke.getNumlock()) && (!keyStroke.getLocalstate()) &&
+                (shift == keyStroke.getShift()) && (altgr == keyStroke.getAltgr()) &&
+                (inhibit == keyStroke.getInhibit()))
+            {
+                return keyStroke.getCharacter();
+            }
+        }
+
+        // try to find the key stroke with a local state ignoring the other keys
+        for (KeyStroke keyStroke : candidates) {
+            if ((numlock == keyStroke.getNumlock()) && (keyStroke.getLocalstate()) &&
+                (inhibit == keyStroke.getInhibit()))
+            {
+                return keyStroke.getCharacter();
+            }
+        }
+
+        return Character.UNASSIGNED;
+    }
+
+    /**
+     * 
+     * <p>
+     * Initializes the keyboard map.
+     * </p>
+     * 
+     * @throws IllegalArgumentException thrown if there is a problem loading the keyboard map
+     */
+    void init() throws IllegalArgumentException {
+        Console.traceln(Level.FINE, "initializing keymap for locale " + locale);
+
+        List<String[]> deadKeySequences = new ArrayList<String[]>();
+        List<String[]> keyStrokes = new ArrayList<String[]>();
+        readStream(getStream(fileName), deadKeySequences, keyStrokes);
+
+        Console.traceln(Level.FINER, "read " + keyStrokes.size() + " key strokes and " +
+            deadKeySequences.size() + " dead key sequences");
+
+        VirtualKeySynonyms virtualKeySynonyms = determineVirtualKeySynonyms(keyStrokes);
+        processKeyStrokes(keyStrokes, virtualKeySynonyms);
+        // TODO still required? processDeadKeySequences(deadKeySequences);
+    }
+
+    /**
+     * <p>
+     * Returns a {@link InputStream} for a given filename.
+     * </p>
+     * 
+     * @param name
+     *            the filename
+     * @return the {@link InputStream}
+     */
+    private InputStream getStream(String name) {
+        Console.traceln(Level.FINER, "reading keymap for locale " + locale +
+            " from resource keymaps/" + name);
+
+        InputStream stream =
+            this.getClass().getClassLoader().getResourceAsStream("keymaps/" + name);
+
+        if (stream == null) {
+            throw new IllegalArgumentException("no keyboard map available for locale " + locale);
+        }
+
+        return stream;
+    }
+
+    /**
+     * <p>
+     * Reads a keyboard map from a input stream.
+     * </p>
+     * 
+     * @param stream
+     *            input stream with the keyboard map
+     * @param deadKeySequences
+     *            the dead key sequences
+     * @param keyStrokes
+     *            the keystrokes
+     * @throws IllegalArgumentException
+     *             thrown if there is an error reading the keyboard map
+     */
+    private void readStream(InputStream stream,
+                            List<String[]> deadKeySequences,
+                            List<String[]> keyStrokes) throws IllegalArgumentException
+    {
+        BufferedReader in = null;
+        try {
+            in = new BufferedReader(new InputStreamReader(stream, "UTF-8"));
+        }
+        catch (UnsupportedEncodingException e) {
+            Console.traceln(Level.WARNING, "no keyboard map available for locale " + locale);
+            throw new IllegalArgumentException("provided stream can not be read due to invalid encoding",
+                                               e);
+        }
+
+        try {
+            String line;
+            while ((line = in.readLine()) != null) {
+                if (!"".equals(line)) {
+                    processLine(line, deadKeySequences, keyStrokes);
+                }
+            }
+        }
+        catch (IOException e) {
+            Console.traceln(Level.WARNING, "no keyboard map available for locale " + locale);
+            throw new IllegalArgumentException("no keyboard map available for locale " + locale, e);
+        }
+        finally {
+            try {
+                in.close();
+            }
+            catch (IOException e) {
+                Console.traceln(Level.WARNING,
+                                "could not close input stream for reading keyboard map");
+            }
+        }
+    }
+
+    /**
+     * <p>
+     * Processes a line of a keyboard map file.
+     * </p>
+     * 
+     * @param line
+     *            the line in the keyboard map file
+     * @param deadKeySequences
+     *            the dead key sequences
+     * @param keyStrokes
+     *            the keystrokes
+     */
+    private void processLine(String line, List<String[]> deadKeySequences, List<String[]> keyStrokes)
+    {
+        String[] values = line.split(" ");
+
+        if (values.length <= 0) {
+            return;
+        }
+
+        // ignore comments
+        if (values[0].startsWith("#")) {
+            return;
+        }
+
+        if ("map".equals(values[0])) {
+            // this is the map id. Ignore it.
+        }
+        else if ("include".equals(values[0])) {
+            // process all includes
+            for (int i = 1; i < values.length; i++) {
+                if (!values[i].startsWith("#")) {
+                    readStream(getStream(values[i]), deadKeySequences, keyStrokes);
+                }
+                else {
+                    break;
+                }
+            }
+        }
+        else if ("sequence".equals(values[0])) {
+            deadKeySequences.add(values);
+        }
+        else {
+            boolean alreadyAdded = false;
+
+            // check, if there is a replacement
+            for (int i = 0; i < keyStrokes.size(); i++) {
+                if (keyStrokes.get(i)[0].equals(values[0])) {
+                    Console.traceln(Level.FINEST, "replacing key stroke " + values[0] +
+                                    " with former keyid " + keyStrokes.get(i)[1] +
+                                    " with new key id " + values[1]);
+                    keyStrokes.set(i, values);
+                    alreadyAdded = true;
+                    break;
+                }
+            }
+
+            if (!alreadyAdded) {
+                keyStrokes.add(values);
+            }
+        }
+    }
+
+    /**
+     * <p>
+     * Determines synonyms for virtual keys for the keyboard map.
+     * </p>
+     * 
+     * @param keyStrokes
+     *            the keystrokes
+     * @return the synonyms
+     */
+    private VirtualKeySynonyms determineVirtualKeySynonyms(List<String[]> keyStrokes) {
+        Console.traceln(Level.FINER, "determining virtual keys and synonyms for the keymap");
+
+        VirtualKeySynonyms virtualKeySynonyms = new VirtualKeySynonyms();
+
+        // for debugging purposes, determine which key strokes are not matched to virtual keys.
+        List<String[]> unmatchedKeyStrokes = new ArrayList<String[]>();
+
+        for (String[] keyStroke : keyStrokes) {
+            String keyStrokeName = keyStroke[0];
+            int keyId = getKeyId(keyStroke[1]);
+            // System.err.println(keyStrokeName + "  0x" + Integer.toHexString(keyId));
+
+            VirtualKey virtualKey = determineVirtualKey(keyStrokeName);
+
+            if (virtualKey != null) {
+                virtualKeySynonyms.add(keyId, virtualKey);
+            }
+            else {
+                unmatchedKeyStrokes.add(keyStroke);
+            }
+        }
+
+        for (String[] unmatchedKeyStroke : unmatchedKeyStrokes) {
+            if (!virtualKeySynonyms.containsKey(getKeyId(unmatchedKeyStroke[1]))) {
+                Console.traceln(Level.FINEST, "no virtual key mapped to key stroke " +
+                                unmatchedKeyStroke[0] + "(" + unmatchedKeyStroke[1] +
+                                ") of keyboard map for locale " + locale);
+            }
+        }
+
+        return virtualKeySynonyms;
+    }
+
+    /**
+     * <p>
+     * Converts a hexadecimal Id that is contained in a string into the integer Id of the key.
+     * </p>
+     * 
+     * @param keyIdString
+     *            the Id string
+     * @return the Id as integer
+     */
+    private int getKeyId(String keyIdString) {
+        if (keyIdString.startsWith("0x")) {
+            keyIdString = keyIdString.substring(2);
+        }
+
+        return Integer.parseInt(keyIdString, 16);
+    }
+
+    /**
+     * <p>
+     * Processes a list of key strokes.
+     * </p>
+     * 
+     * @param keyStrokes
+     *            the key strokes
+     * @param virtualKeySynonyms
+     *            synonyms of the involved virtual keys
+     */
+    private void processKeyStrokes(List<String[]> keyStrokes, VirtualKeySynonyms virtualKeySynonyms)
+    {
+        for (String[] keyStroke : keyStrokes) {
+            handleKeyStroke(keyStroke, virtualKeySynonyms);
+        }
+
+        addKeyStrokesIndependentOfNumLock();
+    }
+
+    /**
+     * <p>
+     * Handles a key stroke.
+     * </p>
+     * 
+     * @param values
+     *            contains the name, string Id, and modifiers of the key stroke
+     * @param virtualKeySynonyms
+     *            synonyms of the involved virtual keys
+     */
+    private void handleKeyStroke(String[] values, VirtualKeySynonyms virtualKeySynonyms) {
+        String keyStrokeName = values[0];
+        String keyIdString = values[1];
+        if (keyIdString.startsWith("0x")) {
+            keyIdString = keyIdString.substring(2);
+        }
+
+        int keyId = Integer.parseInt(keyIdString, 16);
+
+        // parse the conditions
+        boolean numlock = false;
+        boolean localstate = false;
+        boolean shift = false;
+        boolean altgr = false;
+        boolean addupper = false;
+        boolean inhibit = false;
+
+        for (int i = 2; i < values.length; i++) {
+            if (!values[i].startsWith("#")) {
+                if ("numlock".equals(values[i])) {
+                    numlock = true;
+                }
+                else if ("localstate".equals(values[i])) {
+                    localstate = true;
+                }
+                else if ("shift".equals(values[i])) {
+                    shift = true;
+                }
+                else if ("altgr".equals(values[i])) {
+                    altgr = true;
+                }
+                else if ("addupper".equals(values[i])) {
+                    addupper = true;
+                }
+                else if ("inhibit".equals(values[i])) {
+                    inhibit = true;
+                }
+                else {
+                    Console.traceln(Level.SEVERE, "unknown condition " + values[i] +
+                                    " specified for key stroke " + keyStrokeName +
+                                    " through keyboard map for locale " + locale);
+                    throw new IllegalArgumentException
+                        ("no keyboard map available for locale " + locale);
+                }
+            }
+            else {
+                break;
+            }
+        }
+
+        addAllRepresentedKeyStrokes(keyStrokeName, keyId, numlock, localstate, shift, altgr,
+                                    addupper, inhibit, virtualKeySynonyms);
+    }
+
+    /**
+     * <p>
+     * Adds a key stroke and all synonyms to the keyboard map.
+     * </p>
+     * 
+     * @param keyStrokeName
+     *            name of the key stroke
+     * @param keyId
+     *            id of the key stroke
+     * @param numlock
+     *            true, if numlock is pressed; false otherwise
+     * @param localstate
+     *            true, if localstate is pressed; false otherwise
+     * @param shift
+     *            true, if shift is pressed; false otherwise
+     * @param altgr
+     *            true, if altgr is pressed; false otherwise
+     * @param addupper
+     *            true, if addupper is pressed; false otherwise
+     * @param inhibit
+     *            true, if inhibit is pressed; false otherwise
+     * @param virtualKeySynonyms
+     *            synonyms of the involved virtual keys
+     */
+    private void addAllRepresentedKeyStrokes(String keyStrokeName,
+                                             int keyId,
+                                             boolean numlock,
+                                             boolean localstate,
+                                             boolean shift,
+                                             boolean altgr,
+                                             boolean addupper,
+                                             boolean inhibit,
+                                             VirtualKeySynonyms virtualKeySynonyms)
+    {
+        VirtualKey[] virtualKeys = virtualKeySynonyms.getVirtualKeySynonyms(keyId);
+
+        if (virtualKeys == null) {
+            Console.traceln(Level.SEVERE, "no virtual key mapped to key stroke " + keyStrokeName +
+                " of keyboard map for locale " + locale);
+            return;
+        }
+
+        for (VirtualKey virtualKey : virtualKeys) {
+            if (addupper) {
+                char c = determineCharacter(keyStrokeName, true);
+                addKeyStroke(keyStrokeName, virtualKey, numlock, localstate, true, altgr, inhibit,
+                             c);
+
+                c = determineCharacter(keyStrokeName, false);
+                addKeyStroke(keyStrokeName, virtualKey, numlock, localstate, false, altgr, inhibit,
+                             c);
+            }
+            else {
+                char c = determineCharacter(keyStrokeName, false);
+                addKeyStroke(keyStrokeName, virtualKey, numlock, localstate, shift, altgr, inhibit,
+                             c);
+            }
+        }
+    }
+
+    /**
+     * <p>
+     * Adds a key stroke and to the keyboard map.
+     * </p>
+     * 
+     * @param keyStrokeName
+     *            name of the key stroke
+     * @param virtualKey
+     *            the associated virtual key
+     * @param numlock
+     *            true, if numlock is pressed; false otherwise
+     * @param localstate
+     *            true, if localstate is pressed; false otherwise
+     * @param shift
+     *            true, if shift is pressed; false otherwise
+     * @param altgr
+     *            true, if altgr is pressed; false otherwise
+     * @param addupper
+     *            true, if addupper is pressed; false otherwise
+     * @param inhibit
+     *            true, if inhibit is pressed; false otherwise
+     * @param character
+     *            the resulting character
+     */
+    private void addKeyStroke(String keyStrokeName,
+                              VirtualKey virtualKey,
+                              boolean numlock,
+                              boolean localstate,
+                              boolean shift,
+                              boolean altgr,
+                              boolean inhibit,
+                              char character)
+    {
+        KeyStroke keyStroke =
+            new KeyStroke(keyStrokeName, virtualKey, numlock, localstate, shift, altgr, inhibit,
+                          character);
+
+        List<KeyStroke> keyStrokeList = keyStrokes.get(keyStroke.getVirtualKey());
+
+        if (keyStrokeList == null) {
+            keyStrokeList = new ArrayList<KeyStroke>();
+            keyStrokes.put(keyStroke.getVirtualKey(), keyStrokeList);
+        }
+
+        keyStrokeList.add(keyStroke);
+    }
+
+    /**
+     * <p>
+     * Adds key strokes independent of numlock.
+     * </p>
+     */
+    private void addKeyStrokesIndependentOfNumLock() {
+        for (Map.Entry<VirtualKey, List<KeyStroke>> entry : keyStrokes.entrySet()) {
+            List<KeyStroke> keyStrokesToAdd = new ArrayList<KeyStroke>();
+            for (KeyStroke keyStroke : entry.getValue()) {
+                if (!keyStroke.getNumlock()) {
+                    boolean foundPositiveNumlockVariant = false;
+                    for (KeyStroke candidate : entry.getValue()) {
+                        if ((candidate.getShift() == keyStroke.getShift()) &&
+                            (candidate.getAltgr() == keyStroke.getAltgr()) &&
+                            (candidate.getLocalstate() == keyStroke.getLocalstate()) &&
+                            (candidate.getInhibit() == keyStroke.getInhibit()) &&
+                            (candidate.getNumlock()))
+                        {
+                            foundPositiveNumlockVariant = true;
+                            break;
+                        }
+                    }
+
+                    if (!foundPositiveNumlockVariant) {
+                        keyStrokesToAdd.add(keyStroke);
+                    }
+                }
+            }
+
+            for (KeyStroke keyStroke : keyStrokesToAdd) {
+                addKeyStroke(keyStroke.getKeyStrokeName(), keyStroke.getVirtualKey(), true,
+                             keyStroke.getLocalstate(), keyStroke.getShift(), keyStroke.getAltgr(),
+                             keyStroke.getInhibit(), keyStroke.getCharacter());
+            }
+        }
+    }
+
+    /**
+     * <p>
+     * Determines a {@link VirtualKey} depending on a key stroke name
+     * </p>
+     * 
+     * @param keyStrokeName
+     *            name of the key stroke
+     * @return related virtual key
+     */
+    private VirtualKey determineVirtualKey(String keyStrokeName) {
+        if ("Shift_R".equals(keyStrokeName)) {
+            return VirtualKey.SHIFT;
+        }
+        else if ("Shift_L".equals(keyStrokeName)) {
+            return VirtualKey.SHIFT;
+        }
+        else if ("Alt_R".equals(keyStrokeName)) {
+            return VirtualKey.ALT_GRAPH;
+        }
+        else if ("Mode_switch".equals(keyStrokeName)) {
+            return VirtualKey.MODECHANGE;
+        }
+        else if ("ISO_Level3_Shift".equals(keyStrokeName)) {
+            return VirtualKey.SHIFT;
+        }
+        else if ("Alt_L".equals(keyStrokeName)) {
+            return VirtualKey.ALT;
+        }
+        else if ("Control_R".equals(keyStrokeName)) {
+            return VirtualKey.CONTROL;
+        }
+        else if ("Control_L".equals(keyStrokeName)) {
+            return VirtualKey.CONTROL;
+        }
+        else if ("Menu".equals(keyStrokeName)) {
+            return VirtualKey.WINDOWS;
+        }
+        else if ("1".equals(keyStrokeName)) {
+            return VirtualKey.DIGIT_1;
+        }
+        else if ("2".equals(keyStrokeName)) {
+            return VirtualKey.DIGIT_2;
+        }
+        else if ("3".equals(keyStrokeName)) {
+            return VirtualKey.DIGIT_3;
+        }
+        else if ("4".equals(keyStrokeName)) {
+            return VirtualKey.DIGIT_4;
+        }
+        else if ("5".equals(keyStrokeName)) {
+            return VirtualKey.DIGIT_5;
+        }
+        else if ("6".equals(keyStrokeName)) {
+            return VirtualKey.DIGIT_6;
+        }
+        else if ("7".equals(keyStrokeName)) {
+            return VirtualKey.DIGIT_7;
+        }
+        else if ("8".equals(keyStrokeName)) {
+            return VirtualKey.DIGIT_8;
+        }
+        else if ("9".equals(keyStrokeName)) {
+            return VirtualKey.DIGIT_9;
+        }
+        else if ("0".equals(keyStrokeName)) {
+            return VirtualKey.DIGIT_0;
+        }
+        else if ("BackSpace".equals(keyStrokeName)) {
+            return VirtualKey.BACK_SPACE;
+        }
+        else if ("Tab".equals(keyStrokeName)) {
+            return VirtualKey.TAB;
+        }
+        else if ("q".equals(keyStrokeName)) {
+            return VirtualKey.LETTER_Q;
+        }
+        else if ("w".equals(keyStrokeName)) {
+            return VirtualKey.LETTER_W;
+        }
+        else if ("e".equals(keyStrokeName)) {
+            return VirtualKey.LETTER_E;
+        }
+        else if ("r".equals(keyStrokeName)) {
+            return VirtualKey.LETTER_R;
+        }
+        else if ("t".equals(keyStrokeName)) {
+            return VirtualKey.LETTER_T;
+        }
+        else if ("y".equals(keyStrokeName)) {
+            return VirtualKey.LETTER_Y;
+        }
+        else if ("u".equals(keyStrokeName)) {
+            return VirtualKey.LETTER_U;
+        }
+        else if ("i".equals(keyStrokeName)) {
+            return VirtualKey.LETTER_I;
+        }
+        else if ("o".equals(keyStrokeName)) {
+            return VirtualKey.LETTER_O;
+        }
+        else if ("p".equals(keyStrokeName)) {
+            return VirtualKey.LETTER_P;
+        }
+        else if ("a".equals(keyStrokeName)) {
+            return VirtualKey.LETTER_A;
+        }
+        else if ("s".equals(keyStrokeName)) {
+            return VirtualKey.LETTER_S;
+        }
+        else if ("d".equals(keyStrokeName)) {
+            return VirtualKey.LETTER_D;
+        }
+        else if ("f".equals(keyStrokeName)) {
+            return VirtualKey.LETTER_F;
+        }
+        else if ("g".equals(keyStrokeName)) {
+            return VirtualKey.LETTER_G;
+        }
+        else if ("h".equals(keyStrokeName)) {
+            return VirtualKey.LETTER_H;
+        }
+        else if ("j".equals(keyStrokeName)) {
+            return VirtualKey.LETTER_J;
+        }
+        else if ("k".equals(keyStrokeName)) {
+            return VirtualKey.LETTER_K;
+        }
+        else if ("l".equals(keyStrokeName)) {
+            return VirtualKey.LETTER_L;
+        }
+        else if ("Return".equals(keyStrokeName)) {
+            return VirtualKey.ENTER;
+        }
+        else if ("z".equals(keyStrokeName)) {
+            return VirtualKey.LETTER_Z;
+        }
+        else if ("x".equals(keyStrokeName)) {
+            return VirtualKey.LETTER_X;
+        }
+        else if ("c".equals(keyStrokeName)) {
+            return VirtualKey.LETTER_C;
+        }
+        else if ("v".equals(keyStrokeName)) {
+            return VirtualKey.LETTER_V;
+        }
+        else if ("b".equals(keyStrokeName)) {
+            return VirtualKey.LETTER_B;
+        }
+        else if ("n".equals(keyStrokeName)) {
+            return VirtualKey.LETTER_N;
+        }
+        else if ("m".equals(keyStrokeName)) {
+            return VirtualKey.LETTER_M;
+        }
+        else if ("space".equals(keyStrokeName)) {
+            return VirtualKey.SPACE;
+        }
+        else if ("less".equals(keyStrokeName)) {
+            return VirtualKey.LESS;
+        }
+        else if ("greater".equals(keyStrokeName)) {
+            return VirtualKey.GREATER;
+        }
+        else if ("Escape".equals(keyStrokeName)) {
+            return VirtualKey.ESCAPE;
+        }
+        else if ("F1".equals(keyStrokeName)) {
+            return VirtualKey.F1;
+        }
+        else if ("F2".equals(keyStrokeName)) {
+            return VirtualKey.F2;
+        }
+        else if ("F3".equals(keyStrokeName)) {
+            return VirtualKey.F3;
+        }
+        else if ("F4".equals(keyStrokeName)) {
+            return VirtualKey.F4;
+        }
+        else if ("F5".equals(keyStrokeName)) {
+            return VirtualKey.F5;
+        }
+        else if ("F6".equals(keyStrokeName)) {
+            return VirtualKey.F6;
+        }
+        else if ("F7".equals(keyStrokeName)) {
+            return VirtualKey.F7;
+        }
+        else if ("F8".equals(keyStrokeName)) {
+            return VirtualKey.F8;
+        }
+        else if ("F9".equals(keyStrokeName)) {
+            return VirtualKey.F9;
+        }
+        else if ("F10".equals(keyStrokeName)) {
+            return VirtualKey.F10;
+        }
+        else if ("F11".equals(keyStrokeName)) {
+            return VirtualKey.F11;
+        }
+        else if ("F12".equals(keyStrokeName)) {
+            return VirtualKey.F12;
+        }
+        else if ("F13".equals(keyStrokeName)) {
+            return VirtualKey.F13;
+        }
+        else if ("F14".equals(keyStrokeName)) {
+            return VirtualKey.F14;
+        }
+        else if ("F15".equals(keyStrokeName)) {
+            return VirtualKey.F15;
+        }
+        else if ("F16".equals(keyStrokeName)) {
+            return VirtualKey.F16;
+        }
+        else if ("F17".equals(keyStrokeName)) {
+            return VirtualKey.F17;
+        }
+        else if ("F18".equals(keyStrokeName)) {
+            return VirtualKey.F18;
+        }
+        else if ("F19".equals(keyStrokeName)) {
+            return VirtualKey.F19;
+        }
+        else if ("F20".equals(keyStrokeName)) {
+            return VirtualKey.F20;
+        }
+        else if ("F21".equals(keyStrokeName)) {
+            return VirtualKey.F21;
+        }
+        else if ("F22".equals(keyStrokeName)) {
+            return VirtualKey.F22;
+        }
+        else if ("F23".equals(keyStrokeName)) {
+            return VirtualKey.F23;
+        }
+        else if ("F24".equals(keyStrokeName)) {
+            return VirtualKey.F24;
+        }
+        else if ("Print".equals(keyStrokeName)) {
+            return VirtualKey.PRINTSCREEN;
+        }
+        else if ("Scroll_Lock".equals(keyStrokeName)) {
+            return VirtualKey.SCROLL_LOCK;
+        }
+        else if ("Insert".equals(keyStrokeName)) {
+            return VirtualKey.INSERT;
+        }
+        else if ("Delete".equals(keyStrokeName)) {
+            return VirtualKey.DELETE;
+        }
+        else if ("Home".equals(keyStrokeName)) {
+            return VirtualKey.HOME;
+        }
+        else if ("End".equals(keyStrokeName)) {
+            return VirtualKey.END;
+        }
+        else if ("Page_Up".equals(keyStrokeName)) {
+            return VirtualKey.PAGE_UP;
+        }
+        else if ("Page_Down".equals(keyStrokeName)) {
+            return VirtualKey.PAGE_DOWN;
+        }
+        else if ("Left".equals(keyStrokeName)) {
+            return VirtualKey.LEFT;
+        }
+        else if ("Up".equals(keyStrokeName)) {
+            return VirtualKey.UP;
+        }
+        else if ("Down".equals(keyStrokeName)) {
+            return VirtualKey.DOWN;
+        }
+        else if ("Right".equals(keyStrokeName)) {
+            return VirtualKey.RIGHT;
+        }
+        else if ("Num_Lock".equals(keyStrokeName)) {
+            return VirtualKey.NUM_LOCK;
+        }
+        else if ("KP_Divide".equals(keyStrokeName)) {
+            return VirtualKey.SLASH;
+        }
+        else if ("KP_Multiply".equals(keyStrokeName)) {
+            return VirtualKey.ASTERISK;
+        }
+        else if ("KP_Subtract".equals(keyStrokeName)) {
+            return VirtualKey.MINUS;
+        }
+        else if ("KP_Add".equals(keyStrokeName)) {
+            return VirtualKey.PLUS;
+        }
+        else if ("KP_Enter".equals(keyStrokeName)) {
+            return VirtualKey.ENTER;
+        }
+        else if ("KP_Decimal".equals(keyStrokeName)) {
+            return VirtualKey.DECIMAL;
+        }
+        else if ("KP_Separator".equals(keyStrokeName)) {
+            return VirtualKey.SEPARATOR;
+        }
+        else if ("KP_Delete".equals(keyStrokeName)) {
+            return VirtualKey.DELETE;
+        }
+        else if ("KP_0".equals(keyStrokeName)) {
+            return VirtualKey.NUMPAD_0;
+        }
+        else if ("KP_Insert".equals(keyStrokeName)) {
+            return VirtualKey.INSERT;
+        }
+        else if ("KP_1".equals(keyStrokeName)) {
+            return VirtualKey.NUMPAD_1;
+        }
+        else if ("KP_End".equals(keyStrokeName)) {
+            return VirtualKey.END;
+        }
+        else if ("KP_2".equals(keyStrokeName)) {
+            return VirtualKey.NUMPAD_2;
+        }
+        else if ("KP_Down".equals(keyStrokeName)) {
+            return VirtualKey.KP_DOWN;
+        }
+        else if ("KP_3".equals(keyStrokeName)) {
+            return VirtualKey.NUMPAD_3;
+        }
+        else if ("KP_Next".equals(keyStrokeName)) {
+            return VirtualKey.PAGE_DOWN;
+        }
+        else if ("KP_4".equals(keyStrokeName)) {
+            return VirtualKey.NUMPAD_4;
+        }
+        else if ("KP_Left".equals(keyStrokeName)) {
+            return VirtualKey.KP_LEFT;
+        }
+        else if ("KP_5".equals(keyStrokeName)) {
+            return VirtualKey.NUMPAD_5;
+        }
+        else if ("KP_Begin".equals(keyStrokeName)) {
+            return VirtualKey.BEGIN;
+        }
+        else if ("KP_6".equals(keyStrokeName)) {
+            return VirtualKey.NUMPAD_6;
+        }
+        else if ("KP_Right".equals(keyStrokeName)) {
+            return VirtualKey.KP_RIGHT;
+        }
+        else if ("KP_7".equals(keyStrokeName)) {
+            return VirtualKey.NUMPAD_7;
+        }
+        else if ("KP_Home".equals(keyStrokeName)) {
+            return VirtualKey.HOME;
+        }
+        else if ("KP_8".equals(keyStrokeName)) {
+            return VirtualKey.NUMPAD_8;
+        }
+        else if ("KP_Up".equals(keyStrokeName)) {
+            return VirtualKey.KP_UP;
+        }
+        else if ("KP_9".equals(keyStrokeName)) {
+            return VirtualKey.NUMPAD_9;
+        }
+        else if ("KP_Prior".equals(keyStrokeName)) {
+            return VirtualKey.PAGE_UP;
+        }
+        else if ("Caps_Lock".equals(keyStrokeName)) {
+            return VirtualKey.CAPS_LOCK;
+        }
+        else if ("exclam".equals(keyStrokeName)) {
+            return VirtualKey.EXCLAMATION_MARK;
+        }
+        else if ("exclamdown".equals(keyStrokeName)) {
+            return VirtualKey.INVERTED_EXCLAMATION_MARK;
+        }
+        else if ("quotedbl".equals(keyStrokeName)) {
+            return VirtualKey.QUOTEDBL;
+        }
+        else if ("slash".equals(keyStrokeName)) {
+            return VirtualKey.SLASH;
+        }
+        else if ("backslash".equals(keyStrokeName)) {
+            return VirtualKey.BACK_SLASH;
+        }
+        else if ("dead_acute".equals(keyStrokeName)) {
+            return VirtualKey.DEAD_ACUTE;
+        }
+        else if ("dead_diaresis".equals(keyStrokeName)) {
+            return VirtualKey.DEAD_DIAERESIS;
+        }
+        else if ("dead_abovering".equals(keyStrokeName)) {
+            return VirtualKey.DEAD_ABOVERING;
+        }
+        else if ("plus".equals(keyStrokeName)) {
+            return VirtualKey.PLUS;
+        }
+        else if ("asterisk".equals(keyStrokeName)) {
+            return VirtualKey.ASTERISK;
+        }
+        else if ("dead_tilde".equals(keyStrokeName)) {
+            return VirtualKey.DEAD_TILDE;
+        }
+        else if ("dead_doubleacute".equals(keyStrokeName)) {
+            return VirtualKey.DEAD_DOUBLEACUTE;
+        }
+        else if ("dead_caron".equals(keyStrokeName)) {
+            return VirtualKey.DEAD_CARON;
+        }
+        else if ("dead_circumflex".equals(keyStrokeName)) {
+            return VirtualKey.DEAD_CIRCUMFLEX;
+        }
+        else if ("comma".equals(keyStrokeName)) {
+            return VirtualKey.COMMA;
+        }
+        else if ("semicolon".equals(keyStrokeName)) {
+            return VirtualKey.SEMICOLON;
+        }
+        else if ("multiply".equals(keyStrokeName)) {
+            return VirtualKey.MULTIPLY;
+        }
+        else if ("period".equals(keyStrokeName)) {
+            return VirtualKey.PERIOD;
+        }
+        else if ("colon".equals(keyStrokeName)) {
+            return VirtualKey.COLON;
+        }
+        else if ("dead_breve".equals(keyStrokeName)) {
+            return VirtualKey.DEAD_BREVE;
+        }
+        else if ("division".equals(keyStrokeName)) {
+            return VirtualKey.DIVIDE;
+        }
+        else if ("minus".equals(keyStrokeName)) {
+            return VirtualKey.MINUS;
+        }
+        else if ("underscore".equals(keyStrokeName)) {
+            return VirtualKey.UNDERSCORE;
+        }
+        else if ("dead_abovedot".equals(keyStrokeName)) {
+            return VirtualKey.DEAD_ABOVEDOT;
+        }
+        else if ("bracketleft".equals(keyStrokeName)) {
+            return VirtualKey.OPEN_BRACKET;
+        }
+        else if ("bracketright".equals(keyStrokeName)) {
+            return VirtualKey.CLOSE_BRACKET;
+        }
+        else if ("grave".equals(keyStrokeName)) {
+            return VirtualKey.DEAD_GRAVE;
+        }
+        else if ("equal".equals(keyStrokeName)) {
+            return VirtualKey.EQUALS;
+        }
+        else if ("dead_macron".equals(keyStrokeName)) {
+            return VirtualKey.DEAD_MACRON;
+        }
+        else if ("dead_ogonek".equals(keyStrokeName)) {
+            return VirtualKey.DEAD_OGONEK;
+        }
+        else if ("dead_cedilla".equals(keyStrokeName)) {
+            return VirtualKey.DEAD_CEDILLA;
+        }
+        else if ("ampersand".equals(keyStrokeName)) {
+            return VirtualKey.AMPERSAND;
+        }
+        else if ("parenleft".equals(keyStrokeName)) {
+            return VirtualKey.LEFT_PARENTHESIS;
+        }
+        else if ("parenright".equals(keyStrokeName)) {
+            return VirtualKey.RIGHT_PARENTHESIS;
+        }
+        else if ("braceleft".equals(keyStrokeName)) {
+            return VirtualKey.BRACELEFT;
+        }
+        else if ("braceright".equals(keyStrokeName)) {
+            return VirtualKey.BRACERIGHT;
+        }
+        else if ("at".equals(keyStrokeName)) {
+            return VirtualKey.AT;
+        }
+        else if ("dollar".equals(keyStrokeName)) {
+            return VirtualKey.DOLLAR;
+        }
+        else if ("EuroSign".equals(keyStrokeName)) {
+            return VirtualKey.EURO_SIGN;
+        }
+        else if ("Begin".equals(keyStrokeName)) {
+            return VirtualKey.BEGIN;
+        }
+        else if ("numbersign".equals(keyStrokeName)) {
+            return VirtualKey.NUMBER_SIGN;
+        }
+        else if ("asciicircum".equals(keyStrokeName)) {
+            return VirtualKey.CIRCUMFLEX;
+        }
+        else if ("Kanji".equals(keyStrokeName)) {
+            return VirtualKey.KANJI;
+        }
+        else if ("Katakana".equals(keyStrokeName)) {
+            return VirtualKey.KATAKANA;
+        }
+        else if ("Hiragana_Katakana".equals(keyStrokeName)) {
+            return VirtualKey.HIRAGANA;
+        }
+        else if ("Muhenkan".equals(keyStrokeName)) {
+            // I found this in the KeyEvent description
+            return VirtualKey.NONCONVERT;
+        }
+        else if ("kan".equals(keyStrokeName)) {
+            // I found this in the KeyEvent description
+            return VirtualKey.NONCONVERT;
+        }
+        else if ("Henkan_Mode".equals(keyStrokeName)) {
+            // I found this in the key event description
+            return VirtualKey.CONVERT;
+        }
+        else if ("voicedsound".equals(keyStrokeName)) {
+            return VirtualKey.DEAD_VOICED_SOUND;
+        }
+        else if ("semivoicedsound".equals(keyStrokeName)) {
+            return VirtualKey.DEAD_SEMIVOICED_SOUND;
+        }
+        else if ("Menu".equals(keyStrokeName)) {
+            return VirtualKey.CONTEXT_MENU;
+        }
+        else {
+            Console.traceln(Level.FINEST, "unknown virtual key for key stroke " + keyStrokeName +
+                " specified through " + "keyboard map for locale " + locale);
+
+            return null;
+        }
+
+        // for the following virtual keys no key stroke names are provided in the key maps
+        /*
+         * CANCEL(KeyEvent.VK_CANCEL), CLEAR(KeyEvent.VK_CLEAR), PAUSE(KeyEvent.VK_PAUSE),
+         * HELP(KeyEvent.VK_HELP), META(KeyEvent.VK_META),
+         * 
+         * BACK_QUOTE(KeyEvent.VK_BACK_QUOTE), QUOTE(KeyEvent.VK_QUOTE),
+         * 
+         * DEAD_IOTA(KeyEvent.VK_DEAD_IOTA),
+         * 
+         * FINAL(KeyEvent.VK_FINAL), CONVERT(KeyEvent.VK_CONVERT),
+         * NONCONVERT(KeyEvent.VK_NONCONVERT), ACCEPT(KeyEvent.VK_ACCEPT), KANA(KeyEvent.VK_KANA),
+         * ALPHANUMERIC(KeyEvent.VK_ALPHANUMERIC), FULL_WIDTH(KeyEvent.VK_FULL_WIDTH),
+         * HALF_WIDTH(KeyEvent.VK_HALF_WIDTH), ROMAN_CHARACTERS(KeyEvent.VK_ROMAN_CHARACTERS),
+         * ALL_CANDIDATES(KeyEvent.VK_ALL_CANDIDATES),
+         * PREVIOUS_CANDIDATE(KeyEvent.VK_PREVIOUS_CANDIDATE), CODE_INPUT(KeyEvent.VK_CODE_INPUT),
+         * JAPANESE_KATAKANA(KeyEvent.VK_JAPANESE_KATAKANA),
+         * JAPANESE_HIRAGANA(KeyEvent.VK_JAPANESE_HIRAGANA),
+         * JAPANESE_ROMAN(KeyEvent.VK_JAPANESE_ROMAN), KANA_LOCK(KeyEvent.VK_KANA_LOCK),
+         * INPUT_METHOD_ON_OFF(KeyEvent.VK_INPUT_METHOD_ON_OFF),
+         * 
+         * CUT(KeyEvent.VK_CUT), COPY(KeyEvent.VK_COPY), PASTE(KeyEvent.VK_PASTE),
+         * UNDO(KeyEvent.VK_UNDO), AGAIN(KeyEvent.VK_AGAIN), FIND(KeyEvent.VK_FIND),
+         * PROPS(KeyEvent.VK_PROPS), STOP(KeyEvent.VK_STOP), COMPOSE(KeyEvent.VK_COMPOSE),
+         */
+    }
+
+    /**
+     * <p>
+     * Determines the character that is generated by a key stroke.
+     * </p>
+     *
+     * @param keyStrokeName name of the key stroke
+     * @param getUpper defines whether the upper case version of the key stroke is returned or not
+     * @return the character
+     */
+    private char determineCharacter(String keyStrokeName, boolean getUpper) {
+        if ("Shift_R".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("Shift_L".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("Alt_R".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("Mode_switch".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("ISO_Level3_Shift".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("Alt_L".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("Control_R".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("Control_L".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("Menu".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("1".equals(keyStrokeName)) {
+            return '1';
+        }
+        else if ("2".equals(keyStrokeName)) {
+            return '2';
+        }
+        else if ("3".equals(keyStrokeName)) {
+            return '3';
+        }
+        else if ("4".equals(keyStrokeName)) {
+            return '4';
+        }
+        else if ("5".equals(keyStrokeName)) {
+            return '5';
+        }
+        else if ("6".equals(keyStrokeName)) {
+            return '6';
+        }
+        else if ("7".equals(keyStrokeName)) {
+            return '7';
+        }
+        else if ("8".equals(keyStrokeName)) {
+            return '8';
+        }
+        else if ("9".equals(keyStrokeName)) {
+            return '9';
+        }
+        else if ("0".equals(keyStrokeName)) {
+            return '0';
+        }
+        else if ("BackSpace".equals(keyStrokeName)) {
+            return '\b';
+        }
+        else if ("Tab".equals(keyStrokeName)) {
+            return '\t';
+        }
+        else if ("ISO_Left_Tab".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("q".equals(keyStrokeName)) {
+            return getUpper ? 'Q' : 'q';
+        }
+        else if ("w".equals(keyStrokeName)) {
+            return getUpper ? 'W' : 'w';
+        }
+        else if ("e".equals(keyStrokeName)) {
+            return getUpper ? 'E' : 'e';
+        }
+        else if ("r".equals(keyStrokeName)) {
+            return getUpper ? 'R' : 'r';
+        }
+        else if ("t".equals(keyStrokeName)) {
+            return getUpper ? 'T' : 't';
+        }
+        else if ("y".equals(keyStrokeName)) {
+            return getUpper ? 'Y' : 'y';
+        }
+        else if ("u".equals(keyStrokeName)) {
+            return getUpper ? 'U' : 'u';
+        }
+        else if ("i".equals(keyStrokeName)) {
+            return getUpper ? 'I' : 'i';
+        }
+        else if ("o".equals(keyStrokeName)) {
+            return getUpper ? 'O' : 'o';
+        }
+        else if ("p".equals(keyStrokeName)) {
+            return getUpper ? 'P' : 'p';
+        }
+        else if ("a".equals(keyStrokeName)) {
+            return getUpper ? 'A' : 'a';
+        }
+        else if ("s".equals(keyStrokeName)) {
+            return getUpper ? 'S' : 's';
+        }
+        else if ("d".equals(keyStrokeName)) {
+            return getUpper ? 'D' : 'd';
+        }
+        else if ("f".equals(keyStrokeName)) {
+            return getUpper ? 'F' : 'f';
+        }
+        else if ("g".equals(keyStrokeName)) {
+            return getUpper ? 'G' : 'g';
+        }
+        else if ("h".equals(keyStrokeName)) {
+            return getUpper ? 'H' : 'h';
+        }
+        else if ("j".equals(keyStrokeName)) {
+            return getUpper ? 'J' : 'j';
+        }
+        else if ("k".equals(keyStrokeName)) {
+            return getUpper ? 'K' : 'k';
+        }
+        else if ("l".equals(keyStrokeName)) {
+            return getUpper ? 'L' : 'l';
+        }
+        else if ("Return".equals(keyStrokeName)) {
+            return '\n';
+        }
+        else if ("z".equals(keyStrokeName)) {
+            return getUpper ? 'Z' : 'z';
+        }
+        else if ("x".equals(keyStrokeName)) {
+            return getUpper ? 'X' : 'x';
+        }
+        else if ("c".equals(keyStrokeName)) {
+            return getUpper ? 'C' : 'c';
+        }
+        else if ("v".equals(keyStrokeName)) {
+            return getUpper ? 'V' : 'v';
+        }
+        else if ("b".equals(keyStrokeName)) {
+            return getUpper ? 'B' : 'b';
+        }
+        else if ("n".equals(keyStrokeName)) {
+            return getUpper ? 'N' : 'n';
+        }
+        else if ("m".equals(keyStrokeName)) {
+            return getUpper ? 'M' : 'm';
+        }
+        else if ("space".equals(keyStrokeName)) {
+            return ' ';
+        }
+        else if ("less".equals(keyStrokeName)) {
+            return '<';
+        }
+        else if ("greater".equals(keyStrokeName)) {
+            return '>';
+        }
+        else if ("bar".equals(keyStrokeName)) {
+            return '|';
+        }
+        else if ("brokenbar".equals(keyStrokeName)) {
+            return '¦';
+        }
+        else if ("Escape".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("F1".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("F2".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("F3".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("F4".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("F5".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("F6".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("F7".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("F8".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("F9".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("F10".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("F11".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("SunF36".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("F12".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("SunF37".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("Print".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("Sys_Req".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("Execute".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("F22".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("Scroll_Lock".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("F23".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("Insert".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("Delete".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("Home".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("End".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("Page_Up".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("Page_Down".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("Left".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("Up".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("Down".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("Right".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("Num_Lock".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("KP_Divide".equals(keyStrokeName)) {
+            return '/';
+        }
+        else if ("KP_Multiply".equals(keyStrokeName)) {
+            return '*';
+        }
+        else if ("KP_Subtract".equals(keyStrokeName)) {
+            return '-';
+        }
+        else if ("KP_Add".equals(keyStrokeName)) {
+            return '+';
+        }
+        else if ("KP_Enter".equals(keyStrokeName)) {
+            return '\n';
+        }
+        else if ("KP_Decimal".equals(keyStrokeName)) {
+            return ',';
+        }
+        else if ("KP_Separator".equals(keyStrokeName)) {
+            return ',';
+        }
+        else if ("KP_Delete".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("KP_0".equals(keyStrokeName)) {
+            return '0';
+        }
+        else if ("KP_Insert".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("KP_1".equals(keyStrokeName)) {
+            return '1';
+        }
+        else if ("KP_End".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("KP_2".equals(keyStrokeName)) {
+            return '2';
+        }
+        else if ("KP_Down".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("KP_3".equals(keyStrokeName)) {
+            return '3';
+        }
+        else if ("KP_Next".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("KP_4".equals(keyStrokeName)) {
+            return '4';
+        }
+        else if ("KP_Left".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("KP_5".equals(keyStrokeName)) {
+            return '5';
+        }
+        else if ("KP_Begin".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("KP_6".equals(keyStrokeName)) {
+            return '6';
+        }
+        else if ("KP_Right".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("KP_7".equals(keyStrokeName)) {
+            return '7';
+        }
+        else if ("KP_Home".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("KP_8".equals(keyStrokeName)) {
+            return '8';
+        }
+        else if ("KP_Up".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("KP_9".equals(keyStrokeName)) {
+            return '9';
+        }
+        else if ("KP_Prior".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("Caps_Lock".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("Multi_key".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("exclam".equals(keyStrokeName)) {
+            return '!';
+        }
+        else if ("onesuperior".equals(keyStrokeName)) {
+            return '¹';
+        }
+        else if ("exclamdown".equals(keyStrokeName)) {
+            return '¡';
+        }
+        else if ("quotedbl".equals(keyStrokeName)) {
+            return '"';
+        }
+        else if ("twosuperior".equals(keyStrokeName)) {
+            return '²';
+        }
+        else if ("oneeighth".equals(keyStrokeName)) {
+            return '⅛';
+        }
+        else if ("section".equals(keyStrokeName)) {
+            return '§';
+        }
+        else if ("threesuperior".equals(keyStrokeName)) {
+            return '³';
+        }
+        else if ("sterling".equals(keyStrokeName)) {
+            return '£';
+        }
+        else if ("dollar".equals(keyStrokeName)) {
+            return '$';
+        }
+        else if ("onequarter".equals(keyStrokeName)) {
+            return '¼';
+        }
+        else if ("currency".equals(keyStrokeName)) {
+            return '¤';
+        }
+        else if ("percent".equals(keyStrokeName)) {
+            return '%';
+        }
+        else if ("onehalf".equals(keyStrokeName)) {
+            return '½';
+        }
+        else if ("threeeighths".equals(keyStrokeName)) {
+            return '⅜';
+        }
+        else if ("ampersand".equals(keyStrokeName)) {
+            return '&';
+        }
+        else if ("threequarters".equals(keyStrokeName)) {
+            return '¾';
+        }
+        else if ("fiveeighths".equals(keyStrokeName)) {
+            return '⅝';
+        }
+        else if ("slash".equals(keyStrokeName)) {
+            return '/';
+        }
+        else if ("braceleft".equals(keyStrokeName)) {
+            return '{';
+        }
+        else if ("seveneighths".equals(keyStrokeName)) {
+            return '⅞';
+        }
+        else if ("parenleft".equals(keyStrokeName)) {
+            return '(';
+        }
+        else if ("bracketleft".equals(keyStrokeName)) {
+            return '[';
+        }
+        else if ("trademark".equals(keyStrokeName)) {
+            return '™';
+        }
+        else if ("parenright".equals(keyStrokeName)) {
+            return ')';
+        }
+        else if ("bracketright".equals(keyStrokeName)) {
+            return ']';
+        }
+        else if ("plusminus".equals(keyStrokeName)) {
+            return '±';
+        }
+        else if ("equal".equals(keyStrokeName)) {
+            return '=';
+        }
+        else if ("braceright".equals(keyStrokeName)) {
+            return '}';
+        }
+        else if ("ssharp".equals(keyStrokeName)) {
+            return 'ß';
+        }
+        else if ("question".equals(keyStrokeName)) {
+            return '?';
+        }
+        else if ("backslash".equals(keyStrokeName)) {
+            return '\\';
+        }
+        else if ("questiondown".equals(keyStrokeName)) {
+            return '¿';
+        }
+        else if ("acute".equals(keyStrokeName)) {
+            return '´';
+        }
+        else if ("dead_acute".equals(keyStrokeName)) {
+            return 0x0301;
+        }
+        else if ("grave".equals(keyStrokeName)) {
+            return '`';
+        }
+        else if ("dead_grave".equals(keyStrokeName)) {
+            return 0x0300;
+        }
+        else if ("dead_cedilla".equals(keyStrokeName)) {
+            return 0x0327;
+        }
+        else if ("dead_ogonek".equals(keyStrokeName)) {
+            return 0x0328;
+        }
+        else if ("at".equals(keyStrokeName)) {
+            return '@';
+        }
+        else if ("Greek_OMEGA".equals(keyStrokeName)) {
+            return 'Ω';
+        }
+        else if ("EuroSign".equals(keyStrokeName)) {
+            return '€';
+        }
+        else if ("paragraph".equals(keyStrokeName)) {
+            return 0x2029;
+        }
+        else if ("registered".equals(keyStrokeName)) {
+            return '®';
+        }
+        else if ("tslash".equals(keyStrokeName)) {
+            return 'ŧ';
+        }
+        else if ("Tslash".equals(keyStrokeName)) {
+            return 'Ŧ';
+        }
+        else if ("z".equals(keyStrokeName)) {
+            return getUpper ? 'Z' : 'z';
+        }
+        else if ("leftarrow".equals(keyStrokeName)) {
+            return '←';
+        }
+        else if ("yen".equals(keyStrokeName)) {
+            return '¥';
+        }
+        else if ("downarrow".equals(keyStrokeName)) {
+            return '↓';
+        }
+        else if ("uparrow".equals(keyStrokeName)) {
+            return '↑';
+        }
+        else if ("rightarrow".equals(keyStrokeName)) {
+            return '→';
+        }
+        else if ("idotless".equals(keyStrokeName)) {
+            return 'ı';
+        }
+        else if ("oslash".equals(keyStrokeName)) {
+            return 'ø';
+        }
+        else if ("Ooblique".equals(keyStrokeName)) {
+            return 'Ø';
+        }
+        else if ("thorn".equals(keyStrokeName)) {
+            return 'þ';
+        }
+        else if ("THORN".equals(keyStrokeName)) {
+            return 'Þ';
+        }
+        else if ("udiaeresis".equals(keyStrokeName)) {
+            return getUpper ? 'Ü' : 'ü';
+        }
+        else if ("Udiaeresis".equals(keyStrokeName)) {
+            return getUpper ? 'Ü' : 'ü';
+        }
+        else if ("dead_diaeresis".equals(keyStrokeName)) {
+            return 0x0308;
+        }
+        else if ("dead_abovering".equals(keyStrokeName)) {
+            return 0x030A;
+        }
+        else if ("plus".equals(keyStrokeName)) {
+            return '+';
+        }
+        else if ("asterisk".equals(keyStrokeName)) {
+            return '*';
+        }
+        else if ("asciitilde".equals(keyStrokeName)) {
+            return '~';
+        }
+        else if ("dead_tilde".equals(keyStrokeName)) {
+            return 0x0303;
+        }
+        else if ("dead_macron".equals(keyStrokeName)) {
+            return 0x0304;
+        }
+        else if ("ae".equals(keyStrokeName)) {
+            return 'æ';
+        }
+        else if ("AE".equals(keyStrokeName)) {
+            return 'Æ';
+        }
+        else if ("eth".equals(keyStrokeName)) {
+            return 'ð';
+        }
+        else if ("ETH".equals(keyStrokeName)) {
+            return 'Ð';
+        }
+        else if ("dstroke".equals(keyStrokeName)) {
+            return getUpper ? 'Đ' : 'đ';
+        }
+        else if ("ordfeminine".equals(keyStrokeName)) {
+            return 'ª';
+        }
+        else if ("eng".equals(keyStrokeName)) {
+            return 'ŋ';
+        }
+        else if ("ENG".equals(keyStrokeName)) {
+            return 'Ŋ';
+        }
+        else if ("hstroke".equals(keyStrokeName)) {
+            return 'ħ';
+        }
+        else if ("Hstroke".equals(keyStrokeName)) {
+            return 'Ħ';
+        }
+        else if ("kra".equals(keyStrokeName)) {
+            return 'ĸ';
+        }
+        else if ("odiaeresis".equals(keyStrokeName)) {
+            return 'ö';
+        }
+        else if ("Odiaeresis".equals(keyStrokeName)) {
+            return 'Ö';
+        }
+        else if ("dead_doubleacute".equals(keyStrokeName)) {
+            return 0x030B;
+        }
+        else if ("adiaeresis".equals(keyStrokeName)) {
+            return 'ä';
+        }
+        else if ("Adiaeresis".equals(keyStrokeName)) {
+            return 'Ä';
+        }
+        else if ("dead_caron".equals(keyStrokeName)) {
+            return 0x030C;
+        }
+        else if ("asciicircum".equals(keyStrokeName)) {
+            return '^';
+        }
+        else if ("dead_circumflex".equals(keyStrokeName)) {
+            return 0x0302;
+        }
+        else if ("degree".equals(keyStrokeName)) {
+            return '°';
+        }
+        else if ("notsign".equals(keyStrokeName)) {
+            return '¬';
+        }
+        else if ("numbersign".equals(keyStrokeName)) {
+            return '#';
+        }
+        else if ("apostrophe".equals(keyStrokeName)) {
+            return '\'';
+        }
+        else if ("dead_breve".equals(keyStrokeName)) {
+            return 0x0306;
+        }
+        else if ("y".equals(keyStrokeName)) {
+            return getUpper ? 'Y' : 'y';
+        }
+        else if ("guillemotleft".equals(keyStrokeName)) {
+            return '»';
+        }
+        else if ("guillemotright".equals(keyStrokeName)) {
+            return '«';
+        }
+        else if ("cent".equals(keyStrokeName)) {
+            return '¢';
+        }
+        else if ("copyright".equals(keyStrokeName)) {
+            return '©';
+        }
+        else if ("leftdoublequotemark".equals(keyStrokeName)) {
+            return '„';
+        }
+        else if ("rightdoublequotemark".equals(keyStrokeName)) {
+            return '“';
+        }
+        else if ("mu".equals(keyStrokeName)) {
+            return 'µ';
+        }
+        else if ("masculine".equals(keyStrokeName)) {
+            return 'º';
+        }
+        else if ("comma".equals(keyStrokeName)) {
+            return ',';
+        }
+        else if ("semicolon".equals(keyStrokeName)) {
+            return ';';
+        }
+        else if ("horizconnector".equals(keyStrokeName)) {
+            return '·';
+        }
+        else if ("multiply".equals(keyStrokeName)) {
+            return '×';
+        }
+        else if ("period".equals(keyStrokeName)) {
+            return '.';
+        }
+        else if ("colon".equals(keyStrokeName)) {
+            return ':';
+        }
+        else if ("periodcentered".equals(keyStrokeName)) {
+            return '…';
+        }
+        else if ("division".equals(keyStrokeName)) {
+            return '÷';
+        }
+        else if ("minus".equals(keyStrokeName)) {
+            return '-';
+        }
+        else if ("underscore".equals(keyStrokeName)) {
+            return '_';
+        }
+        else if ("dead_belowdot".equals(keyStrokeName)) {
+            return 0x0323;
+        }
+        else if ("dead_abovedot".equals(keyStrokeName)) {
+            return 0x0307;
+        }
+        else if ("eacute".equals(keyStrokeName)) {
+            return getUpper ? 'É' : 'é';
+        }
+        else if ("Eacute".equals(keyStrokeName)) {
+            return getUpper ? 'É' : 'é';
+        }
+        else if ("egrave".equals(keyStrokeName)) {
+            return getUpper ? 'È' : 'è';
+        }
+        else if ("Egrave".equals(keyStrokeName)) {
+            return getUpper ? 'È' : 'è';
+        }
+        else if ("ccedilla".equals(keyStrokeName)) {
+            return getUpper ? 'Ç' : 'ç';
+        }
+        else if ("Ccedilla".equals(keyStrokeName)) {
+            return getUpper ? 'Ç' : 'ç';
+        }
+        else if ("agrave".equals(keyStrokeName)) {
+            return getUpper ? 'À' : 'à';
+        }
+        else if ("Agrave".equals(keyStrokeName)) {
+            return getUpper ? 'À' : 'à';
+        }
+        else if ("lstroke".equals(keyStrokeName)) {
+            return getUpper ? 'Ł' : 'ł';
+        }
+        else if ("Lstroke".equals(keyStrokeName)) {
+            return getUpper ? 'Ł' : 'ł';
+        }
+        else if ("ugrave".equals(keyStrokeName)) {
+            return getUpper ? 'Ù' : 'ù';
+        }
+        else if ("Ugrave".equals(keyStrokeName)) {
+            return getUpper ? 'Ù' : 'ù';
+        }
+        else if ("igrave".equals(keyStrokeName)) {
+            return getUpper ? 'Ì' : 'ì';
+        }
+        else if ("Igrave".equals(keyStrokeName)) {
+            return getUpper ? 'Ì' : 'ì';
+        }
+        else if ("ograve".equals(keyStrokeName)) {
+            return getUpper ? 'Ò' : 'ò';
+        }
+        else if ("ograve".equals(keyStrokeName)) {
+            return getUpper ? 'Ò' : 'ò';
+        }
+        else if ("keyboard_type".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("keyboard_subtype".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("keyboard_functionkeys".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("kana_NU".equals(keyStrokeName)) {
+            return 'ヌ';
+        }
+        else if ("kana_FU".equals(keyStrokeName)) {
+            return 'フ';
+        }
+        else if ("kana_A".equals(keyStrokeName)) {
+            return 'ア';
+        }
+        else if ("kana_a".equals(keyStrokeName)) {
+            return 'ァ';
+        }
+        else if ("kana_U".equals(keyStrokeName)) {
+            return 'ウ';
+        }
+        else if ("kana_u".equals(keyStrokeName)) {
+            return 'ゥ';
+        }
+        else if ("kana_E".equals(keyStrokeName)) {
+            return 'エ';
+        }
+        else if ("kana_e".equals(keyStrokeName)) {
+            return 'ェ';
+        }
+        else if ("kana_O".equals(keyStrokeName)) {
+            return 'オ';
+        }
+        else if ("kana_o".equals(keyStrokeName)) {
+            return 'ォ';
+        }
+        else if ("kana_YA".equals(keyStrokeName)) {
+            return 'ヤ';
+        }
+        else if ("kana_ya".equals(keyStrokeName)) {
+            return 'ャ';
+        }
+        else if ("kana_YU".equals(keyStrokeName)) {
+            return 'ユ';
+        }
+        else if ("kana_yu".equals(keyStrokeName)) {
+            return 'ュ';
+        }
+        else if ("kana_YO".equals(keyStrokeName)) {
+            return 'ヨ';
+        }
+        else if ("kana_yo".equals(keyStrokeName)) {
+            return 'ョ';
+        }
+        else if ("kana_WA".equals(keyStrokeName)) {
+            return 'ワ';
+        }
+        else if ("kana_WO".equals(keyStrokeName)) {
+            return 'ヲ';
+        }
+        else if ("kana_HO".equals(keyStrokeName)) {
+            return 'ホ';
+        }
+        else if ("kana_HE".equals(keyStrokeName)) {
+            return 'ヘ';
+        }
+        else if ("kana_TA".equals(keyStrokeName)) {
+            return 'タ';
+        }
+        else if ("kana_TE".equals(keyStrokeName)) {
+            return 'テ';
+        }
+        else if ("kana_I".equals(keyStrokeName)) {
+            return 'イ';
+        }
+        else if ("kana_i".equals(keyStrokeName)) {
+            return 'ィ';
+        }
+        else if ("kana_SU".equals(keyStrokeName)) {
+            return 'ス';
+        }
+        else if ("kana_KA".equals(keyStrokeName)) {
+            return 'カ';
+        }
+        else if ("kana_N".equals(keyStrokeName)) {
+            return 'ン';
+        }
+        else if ("kana_NA".equals(keyStrokeName)) {
+            return 'ナ';
+        }
+        else if ("kana_NI".equals(keyStrokeName)) {
+            return 'ニ';
+        }
+        else if ("kana_RA".equals(keyStrokeName)) {
+            return 'ラ';
+        }
+        else if ("kana_SE".equals(keyStrokeName)) {
+            return 'セ';
+        }
+        else if ("voicedsound".equals(keyStrokeName)) {
+            return 0x3099;
+        }
+        else if ("semivoicedsound".equals(keyStrokeName)) {
+            return 0x309A;
+        }
+        else if ("kana_openingbracket".equals(keyStrokeName)) {
+            return 0x04A2;
+        }
+        else if ("kana_closingbracket".equals(keyStrokeName)) {
+            return 0x04A3;
+        }
+        else if ("kana_CHI".equals(keyStrokeName)) {
+            return 'チ';
+        }
+        else if ("kana_TO".equals(keyStrokeName)) {
+            return 'ト';
+        }
+        else if ("kana_SHI".equals(keyStrokeName)) {
+            return 'シ';
+        }
+        else if ("kana_HA".equals(keyStrokeName)) {
+            return 'ハ';
+        }
+        else if ("kana_KI".equals(keyStrokeName)) {
+            return 'キ';
+        }
+        else if ("kana_KU".equals(keyStrokeName)) {
+            return 'ク';
+        }
+        else if ("kana_MA".equals(keyStrokeName)) {
+            return 'マ';
+        }
+        else if ("kana_NO".equals(keyStrokeName)) {
+            return 'ノ';
+        }
+        else if ("kana_RI".equals(keyStrokeName)) {
+            return 'リ';
+        }
+        else if ("kana_RE".equals(keyStrokeName)) {
+            return 'レ';
+        }
+        else if ("kana_KE".equals(keyStrokeName)) {
+            return 'ケ';
+        }
+        else if ("Zenkaku_Hankaku".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("Kanji".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("kana_MU".equals(keyStrokeName)) {
+            return 'ム';
+        }
+        else if ("kana_TSU".equals(keyStrokeName)) {
+            return 'ツ';
+        }
+        else if ("kana_tsu".equals(keyStrokeName)) {
+            return 'ッ';
+        }
+        else if ("kana_SA".equals(keyStrokeName)) {
+            return 'サ';
+        }
+        else if ("kana_SO".equals(keyStrokeName)) {
+            return 'ソ';
+        }
+        else if ("kana_HI".equals(keyStrokeName)) {
+            return 'ヒ';
+        }
+        else if ("kana_KO".equals(keyStrokeName)) {
+            return 'コ';
+        }
+        else if ("kana_MI".equals(keyStrokeName)) {
+            return 'ミ';
+        }
+        else if ("kana_MO".equals(keyStrokeName)) {
+            return 'モ';
+        }
+        else if ("kana_NE".equals(keyStrokeName)) {
+            return 'ネ';
+        }
+        else if ("kana_comma".equals(keyStrokeName)) {
+            return '､';
+        }
+        else if ("kana_RU".equals(keyStrokeName)) {
+            return 'ル';
+        }
+        else if ("kana_fullstop".equals(keyStrokeName)) {
+            return '｡';
+        }
+        else if ("kana_ME".equals(keyStrokeName)) {
+            return 'メ';
+        }
+        else if ("kana_conjunctive".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("Henkan_Mode".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("Hiragana_Katakana".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("Katakana".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("Romaji".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("Muhenkan".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("Eisu_toggle".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("Eisu_toggle".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("F13".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("Hangul".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else if ("Hangul_Hanja".equals(keyStrokeName)) {
+            return Character.UNASSIGNED;
+        }
+        else {
+            Console.traceln(Level.SEVERE, "unknown key stroke name " + keyStrokeName +
+                            " specified through keyboard map " + "for locale " + locale);
+
+            // if (shift)
+            // {
+            // System.err.println("    else if (\"" + keyStrokeName + "\".equals(keyStrokeName))");
+            // System.err.println("    {");
+            // System.err.println("      return shift ? '" +
+            // Character.toUpperCase(keyStrokeName.charAt(0)) +
+            // "' : '" + Character.toLowerCase(keyStrokeName.charAt(0)) + "';");
+            // System.err.println("    }");
+            // }
+            // else
+            // {
+            // System.err.println("    else if (\"" + keyStrokeName + "\".equals(keyStrokeName))");
+            // System.err.println("    {");
+            // System.err.println("      return '" + keyStrokeName + "';");
+            // System.err.println("    }");
+            // }
+            //
+            // return 0x0;
+            throw new IllegalArgumentException("no keyboard map available for locale " + locale);
+        }
+    }
+}
Index: trunk/autoquest-misc/src/main/java/de/ugoe/cs/autoquest/keyboardmaps/KeyboardMapFactory.java
===================================================================
--- trunk/autoquest-misc/src/main/java/de/ugoe/cs/autoquest/keyboardmaps/KeyboardMapFactory.java	(revision 922)
+++ trunk/autoquest-misc/src/main/java/de/ugoe/cs/autoquest/keyboardmaps/KeyboardMapFactory.java	(revision 922)
@@ -0,0 +1,36 @@
+package de.ugoe.cs.autoquest.keyboardmaps;
+
+import java.util.Locale;
+
+/**
+ * <p>
+ * Creates keyboard maps.
+ * </p>
+ * 
+ * @version 1.0
+ * @author Patrick Harms
+ */
+public class KeyboardMapFactory {
+
+    /**
+     * <p>
+     * Constructor. Private to prevent initialization of this class.
+     * </p>
+     */
+    private KeyboardMapFactory() {
+    }
+
+    /**
+     * <p>
+     * Returns a {@link KeyboardMap} for the given {@link Locale}.
+     * </p>
+     *
+     * @param locale the locale
+     * @return the keyboard map
+     */
+    public static KeyboardMap createKeyboardMap(Locale locale) {
+        KeyboardMap keyboardMap = new KeyboardMap(locale);
+        keyboardMap.init();
+        return keyboardMap;
+    }
+}
Index: trunk/autoquest-misc/src/main/java/de/ugoe/cs/autoquest/keyboardmaps/VirtualKey.java
===================================================================
--- trunk/autoquest-misc/src/main/java/de/ugoe/cs/autoquest/keyboardmaps/VirtualKey.java	(revision 922)
+++ trunk/autoquest-misc/src/main/java/de/ugoe/cs/autoquest/keyboardmaps/VirtualKey.java	(revision 922)
@@ -0,0 +1,483 @@
+package de.ugoe.cs.autoquest.keyboardmaps;
+
+import java.awt.event.KeyEvent;
+
+/**
+ * <p>
+ * Enumeration of virtual keys.
+ * </p>
+ * 
+ * @version 1.0
+ * @author Patrick Harms
+ */
+public enum VirtualKey {
+
+    ENTER(KeyEvent.VK_ENTER),
+    BACK_SPACE(KeyEvent.VK_BACK_SPACE),
+    TAB(KeyEvent.VK_TAB),
+    CANCEL(KeyEvent.VK_CANCEL),
+    CLEAR(KeyEvent.VK_CLEAR),
+    SHIFT(KeyEvent.VK_SHIFT),
+    CONTROL(KeyEvent.VK_CONTROL),
+    ALT(KeyEvent.VK_ALT),
+    PAUSE(KeyEvent.VK_PAUSE),
+    CAPS_LOCK(KeyEvent.VK_CAPS_LOCK),
+    ESCAPE(KeyEvent.VK_ESCAPE),
+    SPACE(KeyEvent.VK_SPACE),
+    PAGE_UP(KeyEvent.VK_PAGE_UP),
+    PAGE_DOWN(KeyEvent.VK_PAGE_DOWN),
+    END(KeyEvent.VK_END),
+    HOME(KeyEvent.VK_HOME),
+
+    LEFT(KeyEvent.VK_LEFT),
+    UP(KeyEvent.VK_UP),
+    RIGHT(KeyEvent.VK_RIGHT),
+    DOWN(KeyEvent.VK_DOWN),
+
+    COMMA(KeyEvent.VK_COMMA),
+    MINUS(KeyEvent.VK_MINUS),
+    PERIOD(KeyEvent.VK_PERIOD),
+    SLASH(KeyEvent.VK_SLASH),
+
+    DIGIT_0(KeyEvent.VK_0),
+    DIGIT_1(KeyEvent.VK_1),
+    DIGIT_2(KeyEvent.VK_2),
+    DIGIT_3(KeyEvent.VK_3),
+    DIGIT_4(KeyEvent.VK_4),
+    DIGIT_5(KeyEvent.VK_5),
+    DIGIT_6(KeyEvent.VK_6),
+    DIGIT_7(KeyEvent.VK_7),
+    DIGIT_8(KeyEvent.VK_8),
+    DIGIT_9(KeyEvent.VK_9),
+
+    SEMICOLON(KeyEvent.VK_SEMICOLON),
+    EQUALS(KeyEvent.VK_EQUALS),
+
+    LETTER_A(KeyEvent.VK_A),
+    LETTER_B(KeyEvent.VK_B),
+    LETTER_C(KeyEvent.VK_C),
+    LETTER_D(KeyEvent.VK_D),
+    LETTER_E(KeyEvent.VK_E),
+    LETTER_F(KeyEvent.VK_F),
+    LETTER_G(KeyEvent.VK_G),
+    LETTER_H(KeyEvent.VK_H),
+    LETTER_I(KeyEvent.VK_I),
+    LETTER_J(KeyEvent.VK_J),
+    LETTER_K(KeyEvent.VK_K),
+    LETTER_L(KeyEvent.VK_L),
+    LETTER_M(KeyEvent.VK_M),
+    LETTER_N(KeyEvent.VK_N),
+    LETTER_O(KeyEvent.VK_O),
+    LETTER_P(KeyEvent.VK_P),
+    LETTER_Q(KeyEvent.VK_Q),
+    LETTER_R(KeyEvent.VK_R),
+    LETTER_S(KeyEvent.VK_S),
+    LETTER_T(KeyEvent.VK_T),
+    LETTER_U(KeyEvent.VK_U),
+    LETTER_V(KeyEvent.VK_V),
+    LETTER_W(KeyEvent.VK_W),
+    LETTER_X(KeyEvent.VK_X),
+    LETTER_Y(KeyEvent.VK_Y),
+    LETTER_Z(KeyEvent.VK_Z),
+
+    OPEN_BRACKET(KeyEvent.VK_OPEN_BRACKET),
+    BACK_SLASH(KeyEvent.VK_BACK_SLASH),
+    CLOSE_BRACKET(KeyEvent.VK_CLOSE_BRACKET),
+
+    NUMPAD_0(KeyEvent.VK_NUMPAD0),
+    NUMPAD_1(KeyEvent.VK_NUMPAD1),
+    NUMPAD_2(KeyEvent.VK_NUMPAD2),
+    NUMPAD_3(KeyEvent.VK_NUMPAD3),
+    NUMPAD_4(KeyEvent.VK_NUMPAD4),
+    NUMPAD_5(KeyEvent.VK_NUMPAD5),
+    NUMPAD_6(KeyEvent.VK_NUMPAD6),
+    NUMPAD_7(KeyEvent.VK_NUMPAD7),
+    NUMPAD_8(KeyEvent.VK_NUMPAD8),
+    NUMPAD_9(KeyEvent.VK_NUMPAD9),
+    MULTIPLY(KeyEvent.VK_MULTIPLY),
+    ADD(KeyEvent.VK_ADD),
+
+    SEPARATOR(KeyEvent.VK_SEPARATOR),
+
+    SUBTRACT(KeyEvent.VK_SUBTRACT),
+    DECIMAL(KeyEvent.VK_DECIMAL),
+    DIVIDE(KeyEvent.VK_DIVIDE),
+    DELETE(KeyEvent.VK_DELETE),
+    NUM_LOCK(KeyEvent.VK_NUM_LOCK),
+    SCROLL_LOCK(KeyEvent.VK_SCROLL_LOCK),
+
+    F1(KeyEvent.VK_F1),
+    F2(KeyEvent.VK_F2),
+    F3(KeyEvent.VK_F3),
+    F4(KeyEvent.VK_F4),
+    F5(KeyEvent.VK_F5),
+    F6(KeyEvent.VK_F6),
+    F7(KeyEvent.VK_F7),
+    F8(KeyEvent.VK_F8),
+    F9(KeyEvent.VK_F9),
+    F10(KeyEvent.VK_F10),
+    F11(KeyEvent.VK_F11),
+    F12(KeyEvent.VK_F12),
+    F13(KeyEvent.VK_F13),
+    F14(KeyEvent.VK_F14),
+    F15(KeyEvent.VK_F15),
+    F16(KeyEvent.VK_F16),
+    F17(KeyEvent.VK_F17),
+    F18(KeyEvent.VK_F18),
+    F19(KeyEvent.VK_F19),
+    F20(KeyEvent.VK_F20),
+    F21(KeyEvent.VK_F21),
+    F22(KeyEvent.VK_F22),
+    F23(KeyEvent.VK_F23),
+    F24(KeyEvent.VK_F24),
+
+    PRINTSCREEN(KeyEvent.VK_PRINTSCREEN),
+    INSERT(KeyEvent.VK_INSERT),
+    HELP(KeyEvent.VK_HELP),
+    META(KeyEvent.VK_META),
+
+    BACK_QUOTE(KeyEvent.VK_BACK_QUOTE),
+    QUOTE(KeyEvent.VK_QUOTE),
+
+    KP_UP(KeyEvent.VK_KP_UP),
+    KP_DOWN(KeyEvent.VK_KP_DOWN),
+    KP_LEFT(KeyEvent.VK_KP_LEFT),
+    KP_RIGHT(KeyEvent.VK_KP_RIGHT),
+
+    DEAD_GRAVE(KeyEvent.VK_DEAD_GRAVE),
+    DEAD_ACUTE(KeyEvent.VK_DEAD_ACUTE),
+    DEAD_CIRCUMFLEX(KeyEvent.VK_DEAD_CIRCUMFLEX),
+    DEAD_TILDE(KeyEvent.VK_DEAD_TILDE),
+    DEAD_MACRON(KeyEvent.VK_DEAD_MACRON),
+    DEAD_BREVE(KeyEvent.VK_DEAD_BREVE),
+    DEAD_ABOVEDOT(KeyEvent.VK_DEAD_ABOVEDOT),
+    DEAD_DIAERESIS(KeyEvent.VK_DEAD_DIAERESIS),
+    DEAD_ABOVERING(KeyEvent.VK_DEAD_ABOVERING),
+    DEAD_DOUBLEACUTE(KeyEvent.VK_DEAD_DOUBLEACUTE),
+    DEAD_CARON(KeyEvent.VK_DEAD_CARON),
+    DEAD_CEDILLA(KeyEvent.VK_DEAD_CEDILLA),
+    DEAD_OGONEK(KeyEvent.VK_DEAD_OGONEK),
+    DEAD_IOTA(KeyEvent.VK_DEAD_IOTA),
+    DEAD_VOICED_SOUND(KeyEvent.VK_DEAD_VOICED_SOUND),
+    DEAD_SEMIVOICED_SOUND(KeyEvent.VK_DEAD_SEMIVOICED_SOUND),
+
+    AMPERSAND(KeyEvent.VK_AMPERSAND),
+    ASTERISK(KeyEvent.VK_ASTERISK),
+    QUOTEDBL(KeyEvent.VK_QUOTEDBL),
+    LESS(KeyEvent.VK_LESS),
+    GREATER(KeyEvent.VK_GREATER),
+    BRACELEFT(KeyEvent.VK_BRACELEFT),
+    BRACERIGHT(KeyEvent.VK_BRACERIGHT),
+
+    AT(KeyEvent.VK_AT),
+    COLON(KeyEvent.VK_COLON),
+    CIRCUMFLEX(KeyEvent.VK_CIRCUMFLEX),
+    DOLLAR(KeyEvent.VK_DOLLAR),
+    EURO_SIGN(KeyEvent.VK_EURO_SIGN),
+    EXCLAMATION_MARK(KeyEvent.VK_EXCLAMATION_MARK),
+    INVERTED_EXCLAMATION_MARK(KeyEvent.VK_INVERTED_EXCLAMATION_MARK),
+    LEFT_PARENTHESIS(KeyEvent.VK_LEFT_PARENTHESIS),
+    NUMBER_SIGN(KeyEvent.VK_NUMBER_SIGN),
+    PLUS(KeyEvent.VK_PLUS),
+    RIGHT_PARENTHESIS(KeyEvent.VK_RIGHT_PARENTHESIS),
+    UNDERSCORE(KeyEvent.VK_UNDERSCORE),
+
+    WINDOWS(KeyEvent.VK_WINDOWS),
+    CONTEXT_MENU(KeyEvent.VK_CONTEXT_MENU),
+
+    FINAL(KeyEvent.VK_FINAL),
+    CONVERT(KeyEvent.VK_CONVERT),
+    NONCONVERT(KeyEvent.VK_NONCONVERT),
+    ACCEPT(KeyEvent.VK_ACCEPT),
+    MODECHANGE(KeyEvent.VK_MODECHANGE),
+    KANA(KeyEvent.VK_KANA),
+    KANJI(KeyEvent.VK_KANJI),
+    ALPHANUMERIC(KeyEvent.VK_ALPHANUMERIC),
+    KATAKANA(KeyEvent.VK_KATAKANA),
+    HIRAGANA(KeyEvent.VK_HIRAGANA),
+    FULL_WIDTH(KeyEvent.VK_FULL_WIDTH),
+    HALF_WIDTH(KeyEvent.VK_HALF_WIDTH),
+    ROMAN_CHARACTERS(KeyEvent.VK_ROMAN_CHARACTERS),
+    ALL_CANDIDATES(KeyEvent.VK_ALL_CANDIDATES),
+    PREVIOUS_CANDIDATE(KeyEvent.VK_PREVIOUS_CANDIDATE),
+    CODE_INPUT(KeyEvent.VK_CODE_INPUT),
+    JAPANESE_KATAKANA(KeyEvent.VK_JAPANESE_KATAKANA),
+    JAPANESE_HIRAGANA(KeyEvent.VK_JAPANESE_HIRAGANA),
+    JAPANESE_ROMAN(KeyEvent.VK_JAPANESE_ROMAN),
+    KANA_LOCK(KeyEvent.VK_KANA_LOCK),
+    INPUT_METHOD_ON_OFF(KeyEvent.VK_INPUT_METHOD_ON_OFF),
+
+    CUT(KeyEvent.VK_CUT),
+    COPY(KeyEvent.VK_COPY),
+    PASTE(KeyEvent.VK_PASTE),
+    UNDO(KeyEvent.VK_UNDO),
+    AGAIN(KeyEvent.VK_AGAIN),
+    FIND(KeyEvent.VK_FIND),
+    PROPS(KeyEvent.VK_PROPS),
+    STOP(KeyEvent.VK_STOP),
+    COMPOSE(KeyEvent.VK_COMPOSE),
+    ALT_GRAPH(KeyEvent.VK_ALT_GRAPH),
+    BEGIN(KeyEvent.VK_BEGIN),
+
+    UNDEFINED(KeyEvent.VK_UNDEFINED);
+
+    /*
+     * BAR(KeyEvent.VK_UNDEFINED),
+     * APOSTROPHE(KeyEvent.VK_UNDEFINED),
+     * QUESTIONMARK(KeyEvent.VK_UNDEFINED),
+     * DEGREE(KeyEvent.VK_UNDEFINED),
+     * HENKAN_MODE(KeyEvent.VK_UNDEFINED),
+     * MUHENKAN(KeyEvent.VK_UNDEFINED),
+     * EISU_TOGGLE(KeyEvent.VK_UNDEFINED),
+     * HANGUL(KeyEvent.VK_UNDEFINED),
+     * HANGUL_HANJA(KeyEvent.VK_UNDEFINED),
+     * EXECUTE(KeyEvent.VK_UNDEFINED);
+     */
+
+    /**
+     * <p>
+     * Virtual key code of the virtual key.
+     * </p>
+     */
+    private int virtualKeyCode = -1;
+
+    /**
+     * <p>
+     * Description of the virtual key.
+     * </p>
+     */
+    private String description;
+
+    /**
+     * <p>
+     * Constructor. Creates a new VirtualKey.
+     * </p>
+     * 
+     * @param virtualKeyCode
+     *            key code of the virtual key
+     */
+    private VirtualKey(int virtualKeyCode) {
+        this.virtualKeyCode = virtualKeyCode;
+        this.description = KeyEvent.getKeyText(this.virtualKeyCode);
+    }
+
+    /**
+     * <p>
+     * Returns the description of the virtual key.
+     * </p>
+     * 
+     * @return the description.
+     */
+    String getDescription() {
+        return description;
+    }
+
+    /**
+     * <p>
+     * Returns whether the key is a combination key (e.g., shift, alt) or not.
+     * </p>
+     * 
+     * @return true, if the key is a combiniation key; false otherwise
+     */
+    public boolean isCombinationKey() {
+        switch (this)
+        {
+            case SHIFT:
+            case CONTROL:
+            case ALT:
+            case ALT_GRAPH:
+            case WINDOWS:
+                return true;
+
+            default:
+                return false;
+        }
+    }
+
+    /**
+     * <p>
+     * Returns whether the key is a lock key (e.g., caps lock, num lock) or not.
+     * </p>
+     * 
+     * @return true, if the key is a lock key; false otherwise
+     */
+    public boolean isLockKey() {
+        switch (this)
+        {
+            case CAPS_LOCK:
+            case NUM_LOCK:
+            case SCROLL_LOCK:
+                return true;
+
+            default:
+                return false;
+        }
+    }
+
+    /**
+     * <p>
+     * Returns whether the key is shift.
+     * </p>
+     * 
+     * @return true, if the key is shift; false otherwise
+     */
+    public boolean isShiftKey() {
+        switch (this)
+        {
+            case SHIFT:
+                return true;
+
+            default:
+                return false;
+        }
+    }
+
+    /**
+     * <p>
+     * Returns whether the is an alt key.
+     * </p>
+     * 
+     * @return true, if the key is alt or altgr; false otherwise
+     */
+    public boolean isAltKey() {
+        switch (this)
+        {
+            case ALT:
+            case ALT_GRAPH:
+                return true;
+
+            default:
+                return false;
+        }
+    }
+
+    /**
+     * <p>
+     * Returns whether the key is control.
+     * </p>
+     * 
+     * @return true, if the key is control; false otherwise
+     */
+    public boolean isControlKey() {
+        switch (this)
+        {
+            case CONTROL:
+                return true;
+
+            default:
+                return false;
+        }
+    }
+
+    /**
+     * <p>
+     * Returns whether the key is the windows key.
+     * </p>
+     * 
+     * @return true, if the key is the windows key; false otherwise
+     */
+    public boolean isWindowsKey() {
+        switch (this)
+        {
+            case WINDOWS:
+                return true;
+
+            default:
+                return false;
+        }
+    }
+
+    /**
+     * <p>
+     * Returns whether the key is the meta key.
+     * </p>
+     * 
+     * @return true, if the key is the meta key; false otherwise
+     */
+    public boolean isMetaKey() {
+        switch (this)
+        {
+            case META:
+                return true;
+
+            default:
+                return false;
+        }
+    }
+
+    /**
+     * <p>
+     * Returns whether the key is a letter.
+     * </p>
+     * 
+     * @return true, if the key is a letter; false otherwise
+     */
+    public boolean isLetter() {
+        if (virtualKeyCode > -1) {
+            return Character.isLetter((char) virtualKeyCode);
+        }
+        else {
+            return false;
+        }
+    }
+
+    /**
+     * <p>
+     * Returns whether the key is a digit.
+     * </p>
+     * 
+     * @return true, if the key is a digit; false otherwise
+     */
+    public boolean isDigit() {
+        if (virtualKeyCode > -1) {
+            return Character.isDigit(virtualKeyCode);
+        }
+        else {
+            return false;
+        }
+    }
+
+    /**
+     * <p>
+     * Parses an {@link String} and returns the respective VirtualKey if possible.
+     * </p>
+     * 
+     * @param numberString
+     *            String representation of the virtual key
+     * @return created VirtualKey
+     * @throws IllegalArgumentException
+     *             thrown if there is no VirtualKey that correlates to string
+     */
+    public static VirtualKey parseVirtualKey(String string) {
+        int virtualKeyCode = Integer.parseInt(string);
+        for (VirtualKey key1 : VirtualKey.values()) {
+            if (key1.virtualKeyCode == virtualKeyCode) {
+                return key1;
+            }
+        }
+
+        throw new IllegalArgumentException("there is no virtual key with id " + string);
+    }
+
+    /**
+     * <p>
+     * Returns the VirtualKey associated with an integer.
+     * </p>
+     * 
+     * @param number
+     *            integer to which the according VirtualKey is returned
+     * @return the VirtualKey
+     * @throws IllegalArgumentException
+     *             thrown if there is no VirtualKey that correlates to number
+     */
+    public static VirtualKey valueOf(int number) {
+        for (VirtualKey virtualKey : VirtualKey.values()) {
+            if (virtualKey.virtualKeyCode == number) {
+                return virtualKey;
+            }
+        }
+
+        throw new IllegalArgumentException("there is no virtual key with number " + number);
+    }
+
+}
Index: trunk/autoquest-misc/src/main/java/de/ugoe/cs/autoquest/keyboardmaps/VirtualKeySynonyms.java
===================================================================
--- trunk/autoquest-misc/src/main/java/de/ugoe/cs/autoquest/keyboardmaps/VirtualKeySynonyms.java	(revision 922)
+++ trunk/autoquest-misc/src/main/java/de/ugoe/cs/autoquest/keyboardmaps/VirtualKeySynonyms.java	(revision 922)
@@ -0,0 +1,103 @@
+
+package de.ugoe.cs.autoquest.keyboardmaps;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+
+import de.ugoe.cs.util.console.Console;
+
+/**
+ * <p>
+ * Helper class to handle synonymous {@link VirtualKey}s.
+ * </p>
+ * 
+ * @version 1.0
+ * @author Patrick Harms
+ */
+class VirtualKeySynonyms {
+
+    /**
+     * <p>
+     * Map of synonymous keys.
+     * </p>
+     */
+    private Map<Integer, List<VirtualKey>> synonyms = new HashMap<Integer, List<VirtualKey>>();
+
+    /**
+     * <p>
+     * Mapping of {@link VirtualKey}s to integer Ids.
+     * </p>
+     */
+    private Map<VirtualKey, Integer> keyIds = new HashMap<VirtualKey, Integer>();
+
+    /**
+     * <p>
+     * Adds a new synonymous key.
+     * </p>
+     * 
+     * @param keyId
+     *            id of the synonym
+     * @param virtualKey
+     *            the synonym
+     */
+    public void add(int keyId, VirtualKey virtualKey) {
+        List<VirtualKey> synonymList = synonyms.get(keyId);
+
+        if (synonymList == null) {
+            synonymList = new ArrayList<VirtualKey>();
+            synonyms.put(keyId, synonymList);
+        }
+
+        if (!synonymList.contains(virtualKey)) {
+            // ensure that the latest determined virtual keys are considered first
+            synonymList.add(0, virtualKey);
+        }
+
+        Integer existingKeyId = keyIds.get(virtualKey);
+
+        if ((existingKeyId != null) && (existingKeyId != keyId)) {
+            Console.traceln(Level.FINEST, "virtual key " + virtualKey + " is mapped to more " +
+                "than one key id (current is " + existingKeyId + ", new is " + keyId +
+                "). New key id will be used (" + keyId + ").");
+        }
+
+        keyIds.put(virtualKey, keyId);
+    }
+
+    /**
+     * <p>
+     * Returns whether a key is contained in the set of synonyms.
+     * </p>
+     * 
+     * @param keyId
+     *            id of the key
+     * @return true, if the key is contained; false otherwise
+     */
+    public boolean containsKey(int keyId) {
+        return synonyms.containsKey(keyId);
+    }
+
+    /**
+     * <p>
+     * Returns all synonyms known for a given key.
+     * </p>
+     * 
+     * @param keyId
+     *            the id of the key
+     * @return the synonyms
+     */
+    public VirtualKey[] getVirtualKeySynonyms(int keyId) {
+        List<VirtualKey> virtualKeys = synonyms.get(keyId);
+        if (virtualKeys != null) {
+            return virtualKeys.toArray(new VirtualKey[virtualKeys.size()]);
+        }
+        else {
+            Console.traceln(Level.WARNING, "no virtual key define for key id " + keyId);
+            return null;
+        }
+    }
+
+}
