diff --git a/engine/src/core-data/joystick-mapping.properties b/engine/src/core-data/joystick-mapping.properties
new file mode 100644
index 000000000..d3efbba11
--- /dev/null
+++ b/engine/src/core-data/joystick-mapping.properties
@@ -0,0 +1,22 @@
+#
+# Add compatibility entries for different joysticks
+# to map button and axis arrangments when possible.
+# This is keyed off of the reported joystick name and
+# reported button or axis name. The value half is
+# the new name as it will be reported through the Joystick
+# interface.
+#
+# Keys with spaces in them should have those spaces escaped.
+# Values do not need their spaces escaped. For example:
+#
+# Some\ Joystick.Button\ 0=Button 3
+#
+
+
+# Final Fantasy XIV mapping
+FF-GP1.Button\ 0=Button 3
+FF-GP1.Button\ 1=Button 2
+FF-GP1.Button\ 2=Button 1
+FF-GP1.Button\ 3=Button 0
+
+
diff --git a/engine/src/core/com/jme3/input/JoystickCompatibilityMappings.java b/engine/src/core/com/jme3/input/JoystickCompatibilityMappings.java
new file mode 100644
index 000000000..bae00e35d
--- /dev/null
+++ b/engine/src/core/com/jme3/input/JoystickCompatibilityMappings.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.jme3.input;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+
+/**
+ * Provides compatibility mapping to different joysticks
+ * that both report their name in a unique way and require
+ * remapping to achieve a proper default layout.
+ *
+ *
All mappings MUST be defined before the joystick support
+ * has been initialized in the InputManager.
+ *
+ * @author Paul Speed
+ */
+public class JoystickCompatibilityMappings {
+
+ private static final Logger logger = Logger.getLogger(JoystickCompatibilityMappings.class.getName());
+
+ // List of resource paths to check for the joystick-mapping.properties
+ // files.
+ private static String[] searchPaths = { "joystick-mapping.properties" };
+
+ private static Map> joystickMappings = new HashMap>();
+
+ static {
+ loadDefaultMappings();
+ }
+
+ protected static Map getMappings( String joystickName, boolean create ) {
+ Map result = joystickMappings.get(joystickName);
+ if( result == null && create ) {
+ result = new HashMap();
+ joystickMappings.put(joystickName,result);
+ }
+ return result;
+ }
+
+ /**
+ * Returns the remapped version of the axis/button name if there
+ * is a mapping for it otherwise it returns the original name.
+ */
+ public static String remapComponent( String joystickName, String componentName ) {
+ Map map = getMappings(joystickName.trim(), false);
+ if( map == null )
+ return componentName;
+ if( !map.containsKey(componentName) )
+ return componentName;
+ return map.get(componentName);
+ }
+
+ /**
+ * Returns a set of Joystick axis/button name remappings if they exist otherwise
+ * it returns an empty map.
+ */
+ public static Map getJoystickMappings( String joystickName ) {
+ Map result = getMappings(joystickName, false);
+ if( result == null )
+ return Collections.emptyMap();
+ return Collections.unmodifiableMap(result);
+ }
+
+ /**
+ * Adds a single Joystick axis or button remapping based on the
+ * joystick's name and axis/button name. The "remap" value will be
+ * used instead.
+ */
+ public static void addMapping( String stickName, String sourceComponent, String remap ) {
+ logger.log(Level.INFO, "addMapping(" + stickName + ", " + sourceComponent + ", " + remap + ")" );
+ getMappings(stickName, true).put( sourceComponent, remap );
+ }
+
+ /**
+ * Adds a preconfigured set of mappings in Properties object
+ * form where the names are dot notation "joystick"."axis/button"
+ * and the values are the remapped component name. This calls
+ * addMapping(stickName, sourceComponent, remap) for every property
+ * that it is able to parse.
+ */
+ public static void addMappings( Properties p ) {
+ for( Map.Entry