diff --git a/AxibugEmuOnline.Client/Assets/Editors/CommandDispatcherEditor.cs b/AxibugEmuOnline.Client/Assets/Editors/CommandDispatcherEditor.cs
index 7077016a..37ff9da8 100644
--- a/AxibugEmuOnline.Client/Assets/Editors/CommandDispatcherEditor.cs
+++ b/AxibugEmuOnline.Client/Assets/Editors/CommandDispatcherEditor.cs
@@ -34,7 +34,7 @@ namespace AxibugEmuOnline.Editors
             }
             EditorGUILayout.EndVertical();
 
-            EditorGUILayout.LabelField(dispacather.Current.Name);
+            EditorGUILayout.LabelField(dispacather.Mode.ToString());
 
             Repaint();
         }
diff --git a/AxibugEmuOnline.Client/Assets/Resources/IMPORTENT.prefab b/AxibugEmuOnline.Client/Assets/Resources/IMPORTENT.prefab
index 441bd8fe..8e7c8dc7 100644
--- a/AxibugEmuOnline.Client/Assets/Resources/IMPORTENT.prefab
+++ b/AxibugEmuOnline.Client/Assets/Resources/IMPORTENT.prefab
@@ -10,7 +10,7 @@ GameObject:
   m_Component:
   - component: {fileID: 3186794564434009199}
   - component: {fileID: 1464475178787633862}
-  - component: {fileID: 2053226018124086955}
+  - component: {fileID: 3126747713153700628}
   m_Layer: 0
   m_Name: EventSystem
   m_TagString: Untagged
@@ -48,7 +48,7 @@ MonoBehaviour:
   m_FirstSelected: {fileID: 0}
   m_sendNavigationEvents: 0
   m_DragThreshold: 10
---- !u!114 &2053226018124086955
+--- !u!114 &3126747713153700628
 MonoBehaviour:
   m_ObjectHideFlags: 0
   m_CorrespondingSourceObject: {fileID: 0}
@@ -57,17 +57,28 @@ MonoBehaviour:
   m_GameObject: {fileID: 173080370084988713}
   m_Enabled: 1
   m_EditorHideFlags: 0
-  m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3}
+  m_Script: {fileID: 11500000, guid: 01614664b831546d2ae94a42149d80ac, type: 3}
   m_Name: 
   m_EditorClassIdentifier: 
   m_SendPointerHoverToParent: 1
-  m_HorizontalAxis: Horizontal
-  m_VerticalAxis: Vertical
-  m_SubmitButton: Submit
-  m_CancelButton: Cancel
-  m_InputActionsPerSecond: 10
-  m_RepeatDelay: 0.5
-  m_ForceModuleActive: 0
+  m_MoveRepeatDelay: 0.5
+  m_MoveRepeatRate: 0.1
+  m_XRTrackingOrigin: {fileID: 0}
+  m_ActionsAsset: {fileID: -944628639613478452, guid: ca9f5fa95ffab41fb9a615ab714db018, type: 3}
+  m_PointAction: {fileID: -1654692200621890270, guid: ca9f5fa95ffab41fb9a615ab714db018, type: 3}
+  m_MoveAction: {fileID: -8784545083839296357, guid: ca9f5fa95ffab41fb9a615ab714db018, type: 3}
+  m_SubmitAction: {fileID: 392368643174621059, guid: ca9f5fa95ffab41fb9a615ab714db018, type: 3}
+  m_CancelAction: {fileID: 7727032971491509709, guid: ca9f5fa95ffab41fb9a615ab714db018, type: 3}
+  m_LeftClickAction: {fileID: 3001919216989983466, guid: ca9f5fa95ffab41fb9a615ab714db018, type: 3}
+  m_MiddleClickAction: {fileID: -2185481485913320682, guid: ca9f5fa95ffab41fb9a615ab714db018, type: 3}
+  m_RightClickAction: {fileID: -4090225696740746782, guid: ca9f5fa95ffab41fb9a615ab714db018, type: 3}
+  m_ScrollWheelAction: {fileID: 6240969308177333660, guid: ca9f5fa95ffab41fb9a615ab714db018, type: 3}
+  m_TrackedDevicePositionAction: {fileID: 6564999863303420839, guid: ca9f5fa95ffab41fb9a615ab714db018, type: 3}
+  m_TrackedDeviceOrientationAction: {fileID: 7970375526676320489, guid: ca9f5fa95ffab41fb9a615ab714db018, type: 3}
+  m_DeselectOnBackgroundClick: 1
+  m_PointerBehavior: 0
+  m_CursorLockBehavior: 0
+  m_ScrollDeltaPerTick: 6
 --- !u!1 &261166211120060501
 GameObject:
   m_ObjectHideFlags: 0
diff --git a/AxibugEmuOnline.Client/Assets/Resources/UIPrefabs/OverlayUI/Overlay.prefab b/AxibugEmuOnline.Client/Assets/Resources/UIPrefabs/OverlayUI/Overlay.prefab
index 24025604..7fdf33b7 100644
--- a/AxibugEmuOnline.Client/Assets/Resources/UIPrefabs/OverlayUI/Overlay.prefab
+++ b/AxibugEmuOnline.Client/Assets/Resources/UIPrefabs/OverlayUI/Overlay.prefab
@@ -54,7 +54,7 @@ MonoBehaviour:
   m_EditorClassIdentifier: 
   m_InputUI: {fileID: 3531919739979819165}
   m_OptionUI: {fileID: 3531919738411886374}
-  m_Joystick: {fileID: 1479421568449666778}
+  m_screenGamepad: {fileID: 8310310311897327133}
   m_popTipsUI: {fileID: 5244143219655022973}
 --- !u!1001 &286598211728911619
 PrefabInstance:
@@ -924,6 +924,17 @@ RectTransform:
   m_CorrespondingSourceObject: {fileID: 3557960760441770044, guid: bb828a9e324f62649b40038f8cd3620a, type: 3}
   m_PrefabInstance: {fileID: 2731323643586367206}
   m_PrefabAsset: {fileID: 0}
+--- !u!114 &8310310311897327133 stripped
+MonoBehaviour:
+  m_CorrespondingSourceObject: {fileID: 6247543073642948859, guid: bb828a9e324f62649b40038f8cd3620a, type: 3}
+  m_PrefabInstance: {fileID: 2731323643586367206}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 0}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 1c6e60f499349d7479c565da795cde9b, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
 --- !u!1001 &6972157500961473863
 PrefabInstance:
   m_ObjectHideFlags: 0
diff --git a/AxibugEmuOnline.Client/Assets/Resources/UIPrefabs/ScreenKeyPad.prefab b/AxibugEmuOnline.Client/Assets/Resources/UIPrefabs/ScreenKeyPad.prefab
index 9ff64ea9..f2fa2f84 100644
--- a/AxibugEmuOnline.Client/Assets/Resources/UIPrefabs/ScreenKeyPad.prefab
+++ b/AxibugEmuOnline.Client/Assets/Resources/UIPrefabs/ScreenKeyPad.prefab
@@ -1452,6 +1452,7 @@ GameObject:
   serializedVersion: 6
   m_Component:
   - component: {fileID: 3557960760441770044}
+  - component: {fileID: 6247543073642948859}
   m_Layer: 5
   m_Name: ScreenKeyPad
   m_TagString: Untagged
@@ -1491,6 +1492,18 @@ RectTransform:
   m_AnchoredPosition: {x: 0, y: 0}
   m_SizeDelta: {x: 0, y: 0}
   m_Pivot: {x: 0.5, y: 0.5}
+--- !u!114 &6247543073642948859
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 3557960760441770047}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 1c6e60f499349d7479c565da795cde9b, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
 --- !u!1 &3557960760443913721
 GameObject:
   m_ObjectHideFlags: 0
diff --git a/AxibugEmuOnline.Client/Assets/Scene/AxibugEmuOnline.Client.unity b/AxibugEmuOnline.Client/Assets/Scene/AxibugEmuOnline.Client.unity
index eb2adf4c..a9ce8555 100644
--- a/AxibugEmuOnline.Client/Assets/Scene/AxibugEmuOnline.Client.unity
+++ b/AxibugEmuOnline.Client/Assets/Scene/AxibugEmuOnline.Client.unity
@@ -225,7 +225,7 @@ MonoBehaviour:
   bUseLocalWebApi: 0
   mLocalWebApi: http://localhost:5051
   bEditorUUID: 0
-  bEditorOpenGUIJoyStick: 0
+  bEditorOpenGUIJoyStick: 1
 --- !u!1 &1498586261
 GameObject:
   m_ObjectHideFlags: 3
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/App.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/App.cs
index 38b126aa..3b036644 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/App.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/App.cs
@@ -1,4 +1,5 @@
-using AxibugEmuOnline.Client.Manager;
+using AxibugEmuOnline.Client.InputDevices;
+using AxibugEmuOnline.Client.Manager;
 using AxibugEmuOnline.Client.Network;
 using AxibugProtobuf;
 using System;
@@ -22,14 +23,13 @@ namespace AxibugEmuOnline.Client.ClientCore
         public static AppLogin login;
         public static AppChat chat;
         public static UserDataManager user;
-        public static AppInput input;
+        public static InputDevicesManager input;
         public static AppEmu emu;
         public static HttpAPI httpAPI;
         public static CacheManager CacheMgr;
         public static AppRoom roomMgr;
         public static AppSettings settings;
         public static AppShare share;
-        public static GamePadManager gamePadMgr;
         public static SaveSlotManager SavMgr;
         public static FileDownloader FileDownloader;
         static bool bTest;
@@ -70,15 +70,14 @@ namespace AxibugEmuOnline.Client.ClientCore
             return s_romLibs[platform];
         }
 
-        public static void Init(bool isTest = false,bool isUseGUIButton = false, string testSrvIP = "", bool bUseLocalWebApi = false, string mLocalWebApi = "")
+        public static void Init(bool isTest = false, bool isUseGUIButton = false, string testSrvIP = "", bool bUseLocalWebApi = false, string mLocalWebApi = "")
         {
             log = new LogManager(OnLogOut);
+
             //其他平台必要的初始化
-            if (UnityEngine.Application.platform == RuntimePlatform.PSP2)
-            {
-                PSP2Init();
-            }
-            input = new AppInput();
+            if (UnityEngine.Application.platform == RuntimePlatform.PSP2) PSP2Init();
+
+            input = new InputDevicesManager();
             FileDownloader = new FileDownloader();
             settings = new AppSettings();
             network = new NetworkHelper();
@@ -102,7 +101,6 @@ namespace AxibugEmuOnline.Client.ClientCore
             roomMgr = new AppRoom();
             share = new AppShare();
             SavMgr = new SaveSlotManager();
-            gamePadMgr = new GamePadManager();
 
 
             bTest = isTest;
@@ -232,8 +230,7 @@ namespace AxibugEmuOnline.Client.ClientCore
             foreach (var romLib in s_romLibs.Values) romLib.ExecuteFetchRomInfo();
             starRomLib.ExecuteFetchRomInfo();
             FileDownloader.Update();
-
-            gamePadMgr.Update();
+            input.Update();
         }
 
         public static Coroutine StartCoroutine(IEnumerator itor)
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/ColecoVisionMultiKeysSetting.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/ColecoVisionMultiKeysSetting.cs
deleted file mode 100644
index 543b83c0..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/ColecoVisionMultiKeysSetting.cs
+++ /dev/null
@@ -1,85 +0,0 @@
-using AxibugEmuOnline.Client.Manager;
-using UnityEngine;
-
-namespace AxiInputSP.Setting
-{
-    public class ColecoVisionMultiKeysSetting : MultiKeysSettingBase
-    {
-        public ColecoVisionMultiKeysSetting()
-        {
-            controllers = new ColecoVisionSingleKeysSeting[4];
-            for (int i = 0; i < controllers.Length; i++)
-                controllers[i] = new ColecoVisionSingleKeysSeting();
-        }
-
-        public override void LoadDefaultSetting()
-        {
-            ClearAll();
-
-#if UNITY_PSP2 && !UNITY_EDITOR
-            //PSV 摇杆
-            controllers[0].SetKey((ulong)EssgeeSingleKey.POTION_1, AxiInputEx.ByKeyCode(PSVitaKey.Start));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.POTION_2, AxiInputEx.ByKeyCode(PSVitaKey.Select));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.UP, AxiInputEx.ByKeyCode(PSVitaKey.Up));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.DOWN, AxiInputEx.ByKeyCode(PSVitaKey.Down));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.LEFT, AxiInputEx.ByKeyCode(PSVitaKey.Left));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.RIGHT, AxiInputEx.ByKeyCode(PSVitaKey.Right));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_1, AxiInputEx.ByKeyCode(PSVitaKey.Cross));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_2, AxiInputEx.ByKeyCode(PSVitaKey.Circle));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_3, AxiInputEx.ByKeyCode(PSVitaKey.Block));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_4, AxiInputEx.ByKeyCode(PSVitaKey.Triangle));
-            //PSV 摇杆
-            controllers[0].SetKey((ulong)EssgeeSingleKey.UP, AxiInputEx.ByAxis(AxiInputAxisType.UP));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.DOWN, AxiInputEx.ByAxis(AxiInputAxisType.DOWN));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.LEFT, AxiInputEx.ByAxis(AxiInputAxisType.LEFT));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.RIGHT, AxiInputEx.ByAxis(AxiInputAxisType.RIGHT));
-            controllers[0].ColletAllKey();
-            return;
-#endif
-            #region P1
-            //P1 键盘
-            controllers[0].SetKey((ulong)EssgeeSingleKey.OPTION_1, AxiInputEx.ByKeyCode(KeyCode.Return));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.OPTION_2, AxiInputEx.ByKeyCode(KeyCode.RightShift));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.UP, AxiInputEx.ByKeyCode(KeyCode.W));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.DOWN, AxiInputEx.ByKeyCode(KeyCode.S));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.LEFT, AxiInputEx.ByKeyCode(KeyCode.A));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.RIGHT, AxiInputEx.ByKeyCode(KeyCode.D));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_1, AxiInputEx.ByKeyCode(KeyCode.J));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_2, AxiInputEx.ByKeyCode(KeyCode.K));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_3, AxiInputEx.ByKeyCode(KeyCode.U));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_4, AxiInputEx.ByKeyCode(KeyCode.I));
-
-            //P1 UGUI
-            controllers[0].SetKey((ulong)EssgeeSingleKey.OPTION_1, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.POTION_1));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.OPTION_2, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.POTION_2));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.UP, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.UP));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.DOWN, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.DOWN));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.LEFT, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.LEFT));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.RIGHT, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.RIGHT));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_1, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.BTN_A));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_2, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.BTN_B));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_3, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.BTN_C));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_4, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.BTN_D));
-
-            //P2 键盘
-            controllers[1].SetKey((ulong)EssgeeSingleKey.OPTION_1, AxiInputEx.ByKeyCode(KeyCode.Keypad0));
-            controllers[1].SetKey((ulong)EssgeeSingleKey.OPTION_2, AxiInputEx.ByKeyCode(KeyCode.Delete));
-            controllers[1].SetKey((ulong)EssgeeSingleKey.UP, AxiInputEx.ByKeyCode(KeyCode.UpArrow));
-            controllers[1].SetKey((ulong)EssgeeSingleKey.DOWN, AxiInputEx.ByKeyCode(KeyCode.DownArrow));
-            controllers[1].SetKey((ulong)EssgeeSingleKey.LEFT, AxiInputEx.ByKeyCode(KeyCode.LeftArrow));
-            controllers[1].SetKey((ulong)EssgeeSingleKey.RIGHT, AxiInputEx.ByKeyCode(KeyCode.RightArrow));
-            controllers[1].SetKey((ulong)EssgeeSingleKey.BTN_1, AxiInputEx.ByKeyCode(KeyCode.Keypad1));
-            controllers[1].SetKey((ulong)EssgeeSingleKey.BTN_2, AxiInputEx.ByKeyCode(KeyCode.Keypad2));
-            controllers[1].SetKey((ulong)EssgeeSingleKey.BTN_3, AxiInputEx.ByKeyCode(KeyCode.Keypad3));
-            controllers[1].SetKey((ulong)EssgeeSingleKey.BTN_4, AxiInputEx.ByKeyCode(KeyCode.Keypad4));
-
-            controllers[0].ColletAllKey();
-            #endregion
-        }
-    }
-
-    public class ColecoVisionSingleKeysSeting : SingleKeySettingBase
-    {
-    }
-}
-
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/ColecoVisionMultiKeysSetting.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/ColecoVisionMultiKeysSetting.cs.meta
deleted file mode 100644
index bf2ae342..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/ColecoVisionMultiKeysSetting.cs.meta
+++ /dev/null
@@ -1,2 +0,0 @@
-fileFormatVersion: 2
-guid: 6febcf958b506d74aadb5e7ea35f1a9d
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GameBoyColorMultiKeysSetting.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GameBoyColorMultiKeysSetting.cs
deleted file mode 100644
index 052302ff..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GameBoyColorMultiKeysSetting.cs
+++ /dev/null
@@ -1,68 +0,0 @@
-using AxibugEmuOnline.Client.Manager;
-using UnityEngine;
-
-namespace AxiInputSP.Setting
-{
-    public class GameBoyColorMultiKeysSetting : MultiKeysSettingBase
-    {
-
-        public GameBoyColorMultiKeysSetting()
-        {
-            controllers = new GameBoyColorSingleKeysSeting[4];
-            for (int i = 0; i < controllers.Length; i++)
-                controllers[i] = new GameBoyColorSingleKeysSeting();
-        }
-
-        public override void LoadDefaultSetting()
-        {
-            ClearAll();
-
-#if UNITY_PSP2 && !UNITY_EDITOR
-            //PSV 摇杆
-            controllers[0].SetKey((ulong)EssgeeSingleKey.POTION_1, AxiInputEx.ByKeyCode(PSVitaKey.Start));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.POTION_2, AxiInputEx.ByKeyCode(PSVitaKey.Select));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.UP, AxiInputEx.ByKeyCode(PSVitaKey.Up));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.DOWN, AxiInputEx.ByKeyCode(PSVitaKey.Down));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.LEFT, AxiInputEx.ByKeyCode(PSVitaKey.Left));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.RIGHT, AxiInputEx.ByKeyCode(PSVitaKey.Right));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_1, AxiInputEx.ByKeyCode(PSVitaKey.Cross));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_2, AxiInputEx.ByKeyCode(PSVitaKey.Circle));
-            //PSV 摇杆
-            controllers[0].SetKey((ulong)EssgeeSingleKey.UP, AxiInputEx.ByAxis(AxiInputAxisType.UP));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.DOWN, AxiInputEx.ByAxis(AxiInputAxisType.DOWN));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.LEFT, AxiInputEx.ByAxis(AxiInputAxisType.LEFT));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.RIGHT, AxiInputEx.ByAxis(AxiInputAxisType.RIGHT));
-            controllers[0].ColletAllKey();
-            return;
-#endif
-            #region P1
-            //P1 键盘
-            controllers[0].SetKey((ulong)EssgeeSingleKey.OPTION_1, AxiInputEx.ByKeyCode(KeyCode.Return));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.OPTION_2, AxiInputEx.ByKeyCode(KeyCode.RightShift));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.UP, AxiInputEx.ByKeyCode(KeyCode.W));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.DOWN, AxiInputEx.ByKeyCode(KeyCode.S));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.LEFT, AxiInputEx.ByKeyCode(KeyCode.A));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.RIGHT, AxiInputEx.ByKeyCode(KeyCode.D));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_1, AxiInputEx.ByKeyCode(KeyCode.J));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_2, AxiInputEx.ByKeyCode(KeyCode.K));
-
-            //P1 UGUI
-            controllers[0].SetKey((ulong)EssgeeSingleKey.OPTION_1, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.POTION_1));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.OPTION_2, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.POTION_2));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.UP, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.UP));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.DOWN, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.DOWN));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.LEFT, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.LEFT));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.RIGHT, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.RIGHT));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_1, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.BTN_A));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_2, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.BTN_B));
-
-            controllers[0].ColletAllKey();
-            #endregion
-        }
-    }
-
-    public class GameBoyColorSingleKeysSeting : SingleKeySettingBase
-    {
-    }
-}
-
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GameBoyColorMultiKeysSetting.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GameBoyColorMultiKeysSetting.cs.meta
deleted file mode 100644
index 3021c891..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GameBoyColorMultiKeysSetting.cs.meta
+++ /dev/null
@@ -1,2 +0,0 @@
-fileFormatVersion: 2
-guid: 98e9f2994f6a07c4fb69339055653348
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GameBoyMultiKeysSetting.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GameBoyMultiKeysSetting.cs
deleted file mode 100644
index 8ee49ca6..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GameBoyMultiKeysSetting.cs
+++ /dev/null
@@ -1,68 +0,0 @@
-using AxibugEmuOnline.Client.Manager;
-using UnityEngine;
-
-namespace AxiInputSP.Setting
-{
-    public class GameBoyMultiKeysSetting : MultiKeysSettingBase
-    {
-
-        public GameBoyMultiKeysSetting()
-        {
-            controllers = new GameBoySingleKeysSeting[4];
-            for (int i = 0; i < controllers.Length; i++)
-                controllers[i] = new GameBoySingleKeysSeting();
-        }
-
-        public override void LoadDefaultSetting()
-        {
-            ClearAll();
-
-#if UNITY_PSP2 && !UNITY_EDITOR
-            //PSV 摇杆
-            controllers[0].SetKey((ulong)EssgeeSingleKey.POTION_1, AxiInputEx.ByKeyCode(PSVitaKey.Start));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.POTION_2, AxiInputEx.ByKeyCode(PSVitaKey.Select));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.UP, AxiInputEx.ByKeyCode(PSVitaKey.Up));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.DOWN, AxiInputEx.ByKeyCode(PSVitaKey.Down));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.LEFT, AxiInputEx.ByKeyCode(PSVitaKey.Left));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.RIGHT, AxiInputEx.ByKeyCode(PSVitaKey.Right));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_1, AxiInputEx.ByKeyCode(PSVitaKey.Cross));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_2, AxiInputEx.ByKeyCode(PSVitaKey.Circle));
-            //PSV 摇杆
-            controllers[0].SetKey((ulong)EssgeeSingleKey.UP, AxiInputEx.ByAxis(AxiInputAxisType.UP));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.DOWN, AxiInputEx.ByAxis(AxiInputAxisType.DOWN));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.LEFT, AxiInputEx.ByAxis(AxiInputAxisType.LEFT));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.RIGHT, AxiInputEx.ByAxis(AxiInputAxisType.RIGHT));
-            controllers[0].ColletAllKey();
-            return;
-#endif
-            #region P1
-            //P1 键盘
-            controllers[0].SetKey((ulong)EssgeeSingleKey.OPTION_1, AxiInputEx.ByKeyCode(KeyCode.Return));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.OPTION_2, AxiInputEx.ByKeyCode(KeyCode.RightShift));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.UP, AxiInputEx.ByKeyCode(KeyCode.W));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.DOWN, AxiInputEx.ByKeyCode(KeyCode.S));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.LEFT, AxiInputEx.ByKeyCode(KeyCode.A));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.RIGHT, AxiInputEx.ByKeyCode(KeyCode.D));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_1, AxiInputEx.ByKeyCode(KeyCode.J));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_2, AxiInputEx.ByKeyCode(KeyCode.K));
-
-            //P1 UGUI
-            controllers[0].SetKey((ulong)EssgeeSingleKey.OPTION_1, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.POTION_1));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.OPTION_2, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.POTION_2));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.UP, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.UP));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.DOWN, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.DOWN));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.LEFT, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.LEFT));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.RIGHT, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.RIGHT));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_1, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.BTN_A));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_2, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.BTN_B));
-
-            controllers[0].ColletAllKey();
-            #endregion
-        }
-    }
-
-    public class GameBoySingleKeysSeting : SingleKeySettingBase
-    {
-    }
-}
-
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GameBoyMultiKeysSetting.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GameBoyMultiKeysSetting.cs.meta
deleted file mode 100644
index 4347d222..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GameBoyMultiKeysSetting.cs.meta
+++ /dev/null
@@ -1,2 +0,0 @@
-fileFormatVersion: 2
-guid: 42485ea83f647924e9e8a8db04c8b351
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GameGearMultiKeysSetting.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GameGearMultiKeysSetting.cs
deleted file mode 100644
index 78da1487..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GameGearMultiKeysSetting.cs
+++ /dev/null
@@ -1,85 +0,0 @@
-using AxibugEmuOnline.Client.Manager;
-using UnityEngine;
-
-namespace AxiInputSP.Setting
-{
-    public class GameGearMultiKeysSetting : MultiKeysSettingBase
-    {
-        public GameGearMultiKeysSetting()
-        {
-            controllers = new GameGearSingleKeysSeting[4];
-            for (int i = 0; i < controllers.Length; i++)
-                controllers[i] = new GameGearSingleKeysSeting();
-        }
-
-        public override void LoadDefaultSetting()
-        {
-            ClearAll();
-
-#if UNITY_PSP2 && !UNITY_EDITOR
-            //PSV 摇杆
-            controllers[0].SetKey((ulong)EssgeeSingleKey.POTION_1, AxiInputEx.ByKeyCode(PSVitaKey.Start));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.POTION_2, AxiInputEx.ByKeyCode(PSVitaKey.Select));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.UP, AxiInputEx.ByKeyCode(PSVitaKey.Up));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.DOWN, AxiInputEx.ByKeyCode(PSVitaKey.Down));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.LEFT, AxiInputEx.ByKeyCode(PSVitaKey.Left));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.RIGHT, AxiInputEx.ByKeyCode(PSVitaKey.Right));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_1, AxiInputEx.ByKeyCode(PSVitaKey.Cross));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_2, AxiInputEx.ByKeyCode(PSVitaKey.Circle));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_3, AxiInputEx.ByKeyCode(PSVitaKey.Block));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_4, AxiInputEx.ByKeyCode(PSVitaKey.Triangle));
-            //PSV 摇杆
-            controllers[0].SetKey((ulong)EssgeeSingleKey.UP, AxiInputEx.ByAxis(AxiInputAxisType.UP));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.DOWN, AxiInputEx.ByAxis(AxiInputAxisType.DOWN));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.LEFT, AxiInputEx.ByAxis(AxiInputAxisType.LEFT));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.RIGHT, AxiInputEx.ByAxis(AxiInputAxisType.RIGHT));
-            controllers[0].ColletAllKey();
-            return;
-#endif
-            #region P1
-            //P1 键盘
-            controllers[0].SetKey((ulong)EssgeeSingleKey.OPTION_1, AxiInputEx.ByKeyCode(KeyCode.Return));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.OPTION_2, AxiInputEx.ByKeyCode(KeyCode.RightShift));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.UP, AxiInputEx.ByKeyCode(KeyCode.W));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.DOWN, AxiInputEx.ByKeyCode(KeyCode.S));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.LEFT, AxiInputEx.ByKeyCode(KeyCode.A));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.RIGHT, AxiInputEx.ByKeyCode(KeyCode.D));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_1, AxiInputEx.ByKeyCode(KeyCode.J));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_2, AxiInputEx.ByKeyCode(KeyCode.K));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_3, AxiInputEx.ByKeyCode(KeyCode.U));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_4, AxiInputEx.ByKeyCode(KeyCode.I));
-
-            //P1 UGUI
-            controllers[0].SetKey((ulong)EssgeeSingleKey.OPTION_1, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.POTION_1));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.OPTION_2, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.POTION_2));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.UP, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.UP));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.DOWN, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.DOWN));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.LEFT, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.LEFT));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.RIGHT, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.RIGHT));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_1, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.BTN_A));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_2, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.BTN_B));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_3, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.BTN_C));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_4, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.BTN_D));
-
-            //P2 键盘
-            controllers[1].SetKey((ulong)EssgeeSingleKey.OPTION_1, AxiInputEx.ByKeyCode(KeyCode.Keypad0));
-            controllers[1].SetKey((ulong)EssgeeSingleKey.OPTION_2, AxiInputEx.ByKeyCode(KeyCode.Delete));
-            controllers[1].SetKey((ulong)EssgeeSingleKey.UP, AxiInputEx.ByKeyCode(KeyCode.UpArrow));
-            controllers[1].SetKey((ulong)EssgeeSingleKey.DOWN, AxiInputEx.ByKeyCode(KeyCode.DownArrow));
-            controllers[1].SetKey((ulong)EssgeeSingleKey.LEFT, AxiInputEx.ByKeyCode(KeyCode.LeftArrow));
-            controllers[1].SetKey((ulong)EssgeeSingleKey.RIGHT, AxiInputEx.ByKeyCode(KeyCode.RightArrow));
-            controllers[1].SetKey((ulong)EssgeeSingleKey.BTN_1, AxiInputEx.ByKeyCode(KeyCode.Keypad1));
-            controllers[1].SetKey((ulong)EssgeeSingleKey.BTN_2, AxiInputEx.ByKeyCode(KeyCode.Keypad2));
-            controllers[1].SetKey((ulong)EssgeeSingleKey.BTN_3, AxiInputEx.ByKeyCode(KeyCode.Keypad3));
-            controllers[1].SetKey((ulong)EssgeeSingleKey.BTN_4, AxiInputEx.ByKeyCode(KeyCode.Keypad4));
-
-            controllers[0].ColletAllKey();
-            #endregion
-        }
-    }
-
-    public class GameGearSingleKeysSeting : SingleKeySettingBase
-    {
-    }
-}
-
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GameGearMultiKeysSetting.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GameGearMultiKeysSetting.cs.meta
deleted file mode 100644
index d0b9847a..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GameGearMultiKeysSetting.cs.meta
+++ /dev/null
@@ -1,2 +0,0 @@
-fileFormatVersion: 2
-guid: 1f1d4c32b29ac4740945cb36c4442f70
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GamingMultiKeysSetting.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GamingMultiKeysSetting.cs
deleted file mode 100644
index 979c3a9e..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GamingMultiKeysSetting.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-using AxibugEmuOnline.Client;
-using AxibugEmuOnline.Client.Common;
-using AxibugEmuOnline.Client.Manager;
-using UnityEngine;
-
-namespace AxiInputSP.Setting
-{
-    public class GamingMultiKeysSetting : MultiKeysSettingBase
-    {
-        public GamingMultiKeysSetting()
-        {
-            controllers = new GamingSingleKeysSeting[1];
-            for (int i = 0; i < controllers.Length; i++)
-                controllers[i] = new GamingSingleKeysSeting();
-        }
-
-        public override void LoadDefaultSetting()
-        {
-            ClearAll();
-
-#if UNITY_PSP2 && !UNITY_EDITOR
-            if (Application.platform == RuntimePlatform.PSP2)
-            {
-                controllers[0].SetKey((ulong)EnumCommand.OptionMenu, AxiInputEx.ByKeyCode(PSVitaKey.L));
-                controllers[0].SetKey((ulong)EnumCommand.OptionMenu, AxiInputEx.ByKeyCode(PSVitaKey.R));
-                controllers[0].ColletAllKey();
-            }
-#endif
-            controllers[0].SetKey((ulong)EnumCommand.OptionMenu, AxiInputEx.ByKeyCode(KeyCode.Escape));
-
-            //TODO 待补全
-            controllers[0].SetKey((ulong)EnumCommand.OptionMenu, AxiInputEx.ByKeyCode(PC_XBOXKEY.L));
-            controllers[0].SetKey((ulong)EnumCommand.OptionMenu, AxiInputEx.ByKeyCode(PC_XBOXKEY.R));
-            controllers[0].SetKey((ulong)EnumCommand.OptionMenu, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.HOME));
-
-            controllers[0].ColletAllKey();
-        }
-    }
-
-    public class GamingSingleKeysSeting : SingleKeySettingBase
-    {
-    }
-}
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GamingMultiKeysSetting.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GamingMultiKeysSetting.cs.meta
deleted file mode 100644
index 5a6854ca..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GamingMultiKeysSetting.cs.meta
+++ /dev/null
@@ -1,2 +0,0 @@
-fileFormatVersion: 2
-guid: 47f6f518d357c334c802a7aac4d507dc
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/MasterSystemMultiKeysSetting.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/MasterSystemMultiKeysSetting.cs
deleted file mode 100644
index 0faaf89a..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/MasterSystemMultiKeysSetting.cs
+++ /dev/null
@@ -1,102 +0,0 @@
-using AxibugEmuOnline.Client.Manager;
-using System;
-using UnityEngine;
-
-namespace AxiInputSP.Setting
-{
-    [Flags]
-    public enum EssgeeSingleKey : ushort
-    {
-        NONE = 0,
-        UP = 1,
-        DOWN = 1 << 1,
-        LEFT = 1 << 2,
-        RIGHT = 1 << 3,
-        BTN_1 = 1 << 4,
-        BTN_2 = 1 << 5,
-        BTN_3 = 1 << 6,
-        BTN_4 = 1 << 7,
-        OPTION_1 = 1 << 8,
-        OPTION_2 = 1 << 9,
-    }
-    public class MasterSystemMultiKeysSetting : MultiKeysSettingBase
-    {
-
-        public MasterSystemMultiKeysSetting()
-        {
-            controllers = new MasterSystemSingleKeysSeting[4];
-            for (int i = 0; i < controllers.Length; i++)
-                controllers[i] = new MasterSystemSingleKeysSeting();
-        }
-
-        public override void LoadDefaultSetting()
-        {
-            ClearAll();
-
-#if UNITY_PSP2 && !UNITY_EDITOR
-            //PSV 摇杆
-            controllers[0].SetKey((ulong)EssgeeSingleKey.POTION_1, AxiInputEx.ByKeyCode(PSVitaKey.Start));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.POTION_2, AxiInputEx.ByKeyCode(PSVitaKey.Select));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.UP, AxiInputEx.ByKeyCode(PSVitaKey.Up));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.DOWN, AxiInputEx.ByKeyCode(PSVitaKey.Down));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.LEFT, AxiInputEx.ByKeyCode(PSVitaKey.Left));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.RIGHT, AxiInputEx.ByKeyCode(PSVitaKey.Right));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_1, AxiInputEx.ByKeyCode(PSVitaKey.Cross));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_2, AxiInputEx.ByKeyCode(PSVitaKey.Circle));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_3, AxiInputEx.ByKeyCode(PSVitaKey.Block));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_4, AxiInputEx.ByKeyCode(PSVitaKey.Triangle));
-            //PSV 摇杆
-            controllers[0].SetKey((ulong)EssgeeSingleKey.UP, AxiInputEx.ByAxis(AxiInputAxisType.UP));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.DOWN, AxiInputEx.ByAxis(AxiInputAxisType.DOWN));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.LEFT, AxiInputEx.ByAxis(AxiInputAxisType.LEFT));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.RIGHT, AxiInputEx.ByAxis(AxiInputAxisType.RIGHT));
-            controllers[0].ColletAllKey();
-            return;
-#endif
-            #region P1
-            //P1 键盘
-            controllers[0].SetKey((ulong)EssgeeSingleKey.OPTION_1, AxiInputEx.ByKeyCode(KeyCode.Return));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.OPTION_2, AxiInputEx.ByKeyCode(KeyCode.RightShift));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.UP, AxiInputEx.ByKeyCode(KeyCode.W));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.DOWN, AxiInputEx.ByKeyCode(KeyCode.S));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.LEFT, AxiInputEx.ByKeyCode(KeyCode.A));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.RIGHT, AxiInputEx.ByKeyCode(KeyCode.D));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_1, AxiInputEx.ByKeyCode(KeyCode.J));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_2, AxiInputEx.ByKeyCode(KeyCode.K));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_3, AxiInputEx.ByKeyCode(KeyCode.U));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_4, AxiInputEx.ByKeyCode(KeyCode.I));
-
-            //P1 UGUI
-            controllers[0].SetKey((ulong)EssgeeSingleKey.OPTION_1, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.POTION_1));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.OPTION_2, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.POTION_2));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.UP, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.UP));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.DOWN, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.DOWN));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.LEFT, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.LEFT));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.RIGHT, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.RIGHT));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_1, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.BTN_A));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_2, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.BTN_B));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_3, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.BTN_C));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_4, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.BTN_D));
-
-            //P2 键盘
-            controllers[1].SetKey((ulong)EssgeeSingleKey.OPTION_1, AxiInputEx.ByKeyCode(KeyCode.Keypad0));
-            controllers[1].SetKey((ulong)EssgeeSingleKey.OPTION_2, AxiInputEx.ByKeyCode(KeyCode.Delete));
-            controllers[1].SetKey((ulong)EssgeeSingleKey.UP, AxiInputEx.ByKeyCode(KeyCode.UpArrow));
-            controllers[1].SetKey((ulong)EssgeeSingleKey.DOWN, AxiInputEx.ByKeyCode(KeyCode.DownArrow));
-            controllers[1].SetKey((ulong)EssgeeSingleKey.LEFT, AxiInputEx.ByKeyCode(KeyCode.LeftArrow));
-            controllers[1].SetKey((ulong)EssgeeSingleKey.RIGHT, AxiInputEx.ByKeyCode(KeyCode.RightArrow));
-            controllers[1].SetKey((ulong)EssgeeSingleKey.BTN_1, AxiInputEx.ByKeyCode(KeyCode.Keypad1));
-            controllers[1].SetKey((ulong)EssgeeSingleKey.BTN_2, AxiInputEx.ByKeyCode(KeyCode.Keypad2));
-            controllers[1].SetKey((ulong)EssgeeSingleKey.BTN_3, AxiInputEx.ByKeyCode(KeyCode.Keypad3));
-            controllers[1].SetKey((ulong)EssgeeSingleKey.BTN_4, AxiInputEx.ByKeyCode(KeyCode.Keypad4));
-
-            controllers[0].ColletAllKey();
-            #endregion
-        }
-    }
-
-    public class MasterSystemSingleKeysSeting : SingleKeySettingBase
-    {
-    }
-}
-
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/MasterSystemMultiKeysSetting.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/MasterSystemMultiKeysSetting.cs.meta
deleted file mode 100644
index 46440769..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/MasterSystemMultiKeysSetting.cs.meta
+++ /dev/null
@@ -1,2 +0,0 @@
-fileFormatVersion: 2
-guid: e3d5584a82b098141bf0c415938daf84
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/NESMultiKeysSetting.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/NESMultiKeysSetting.cs
deleted file mode 100644
index 7453d886..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/NESMultiKeysSetting.cs
+++ /dev/null
@@ -1,80 +0,0 @@
-using AxibugEmuOnline.Client.Manager;
-using AxiInputSP;
-using UnityEngine;
-using VirtualNes.Core;
-
-namespace AxiInputSP.Setting
-{
-    public class NESMultiKeysSetting : MultiKeysSettingBase
-    {
-        public NESMultiKeysSetting()
-        {
-            controllers = new NESSingleKeysSeting[4];
-            for (int i = 0; i < controllers.Length; i++)
-                controllers[i] = new NESSingleKeysSeting();
-        }
-
-        public override void LoadDefaultSetting()
-        {
-            ClearAll();
-#if UNITY_PSP2 && !UNITY_EDITOR
-            //PSV 摇杆
-            controllers[0].SetKey((ulong)EnumButtonType.START, AxiInputEx.ByKeyCode(PSVitaKey.Start));
-            controllers[0].SetKey((ulong)EnumButtonType.SELECT, AxiInputEx.ByKeyCode(PSVitaKey.Select));
-            controllers[0].SetKey((ulong)EnumButtonType.UP, AxiInputEx.ByKeyCode(PSVitaKey.Up));
-            controllers[0].SetKey((ulong)EnumButtonType.DOWN, AxiInputEx.ByKeyCode(PSVitaKey.Down));
-            controllers[0].SetKey((ulong)EnumButtonType.LEFT, AxiInputEx.ByKeyCode(PSVitaKey.Left));
-            controllers[0].SetKey((ulong)EnumButtonType.RIGHT, AxiInputEx.ByKeyCode(PSVitaKey.Right));
-            controllers[0].SetKey((ulong)EnumButtonType.A, AxiInputEx.ByKeyCode(PSVitaKey.Cross));
-            controllers[0].SetKey((ulong)EnumButtonType.B, AxiInputEx.ByKeyCode(PSVitaKey.Circle));
-            controllers[0].SetKey((ulong)EnumButtonType.MIC, AxiInputEx.ByKeyCode(PSVitaKey.Block));
-            //PSV 摇杆
-            controllers[0].SetKey((ulong)EnumButtonType.UP, AxiInputEx.ByAxis(AxiInputAxisType.UP));
-            controllers[0].SetKey((ulong)EnumButtonType.DOWN, AxiInputEx.ByAxis(AxiInputAxisType.DOWN));
-            controllers[0].SetKey((ulong)EnumButtonType.LEFT, AxiInputEx.ByAxis(AxiInputAxisType.LEFT));
-            controllers[0].SetKey((ulong)EnumButtonType.RIGHT, AxiInputEx.ByAxis(AxiInputAxisType.RIGHT));
-            controllers[0].ColletAllKey();
-            return;
-#endif
-            #region 
-            //P1 键盘
-            controllers[0].SetKey((ulong)EnumButtonType.START, AxiInputEx.ByKeyCode(KeyCode.Return));
-            controllers[0].SetKey((ulong)EnumButtonType.SELECT, AxiInputEx.ByKeyCode(KeyCode.RightShift));
-            controllers[0].SetKey((ulong)EnumButtonType.UP, AxiInputEx.ByKeyCode(KeyCode.W));
-            controllers[0].SetKey((ulong)EnumButtonType.DOWN, AxiInputEx.ByKeyCode(KeyCode.S));
-            controllers[0].SetKey((ulong)EnumButtonType.LEFT, AxiInputEx.ByKeyCode(KeyCode.A));
-            controllers[0].SetKey((ulong)EnumButtonType.RIGHT, AxiInputEx.ByKeyCode(KeyCode.D));
-            controllers[0].SetKey((ulong)EnumButtonType.A, AxiInputEx.ByKeyCode(KeyCode.K));
-            controllers[0].SetKey((ulong)EnumButtonType.B, AxiInputEx.ByKeyCode(KeyCode.J));
-            controllers[0].SetKey((ulong)EnumButtonType.MIC, AxiInputEx.ByKeyCode(KeyCode.U));
-
-            //P1 UGUI
-            controllers[0].SetKey((ulong)EnumButtonType.START, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.POTION_1));
-            controllers[0].SetKey((ulong)EnumButtonType.SELECT, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.POTION_2));
-            controllers[0].SetKey((ulong)EnumButtonType.UP, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.UP));
-            controllers[0].SetKey((ulong)EnumButtonType.DOWN, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.DOWN));
-            controllers[0].SetKey((ulong)EnumButtonType.LEFT, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.LEFT));
-            controllers[0].SetKey((ulong)EnumButtonType.RIGHT, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.RIGHT));
-            controllers[0].SetKey((ulong)EnumButtonType.A, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.BTN_B));
-            controllers[0].SetKey((ulong)EnumButtonType.B, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.BTN_A));
-            controllers[0].SetKey((ulong)EnumButtonType.MIC, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.BTN_C));
-
-            //P2 键盘
-            controllers[1].SetKey((ulong)EnumButtonType.START, AxiInputEx.ByKeyCode(KeyCode.Keypad0));
-            controllers[1].SetKey((ulong)EnumButtonType.SELECT, AxiInputEx.ByKeyCode(KeyCode.Delete));
-            controllers[1].SetKey((ulong)EnumButtonType.UP, AxiInputEx.ByKeyCode(KeyCode.UpArrow));
-            controllers[1].SetKey((ulong)EnumButtonType.DOWN, AxiInputEx.ByKeyCode(KeyCode.DownArrow));
-            controllers[1].SetKey((ulong)EnumButtonType.LEFT, AxiInputEx.ByKeyCode(KeyCode.LeftArrow));
-            controllers[1].SetKey((ulong)EnumButtonType.RIGHT, AxiInputEx.ByKeyCode(KeyCode.RightArrow));
-            controllers[1].SetKey((ulong)EnumButtonType.A, AxiInputEx.ByKeyCode(KeyCode.Keypad2));
-            controllers[1].SetKey((ulong)EnumButtonType.B, AxiInputEx.ByKeyCode(KeyCode.Keypad1));
-            controllers[1].SetKey((ulong)EnumButtonType.MIC, AxiInputEx.ByKeyCode(KeyCode.Keypad4));
-
-            controllers[0].ColletAllKey();
-            #endregion
-        }
-    }
-    public class NESSingleKeysSeting : SingleKeySettingBase
-    {
-    }
-}
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/NESMultiKeysSetting.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/NESMultiKeysSetting.cs.meta
deleted file mode 100644
index f0258e9f..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/NESMultiKeysSetting.cs.meta
+++ /dev/null
@@ -1,2 +0,0 @@
-fileFormatVersion: 2
-guid: 6556ff70f8cab73438e5fb7755808a3c
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/SC3000MultiKeysSetting.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/SC3000MultiKeysSetting.cs
deleted file mode 100644
index b4a2881f..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/SC3000MultiKeysSetting.cs
+++ /dev/null
@@ -1,85 +0,0 @@
-using AxibugEmuOnline.Client.Manager;
-using UnityEngine;
-
-namespace AxiInputSP.Setting
-{
-    public class SC3000MultiKeysSetting : MultiKeysSettingBase
-    {
-        public SC3000MultiKeysSetting()
-        {
-            controllers = new SC3000SingleKeysSeting[4];
-            for (int i = 0; i < controllers.Length; i++)
-                controllers[i] = new SC3000SingleKeysSeting();
-        }
-
-        public override void LoadDefaultSetting()
-        {
-            ClearAll();
-
-#if UNITY_PSP2 && !UNITY_EDITOR
-            //PSV 摇杆
-            controllers[0].SetKey((ulong)EssgeeSingleKey.POTION_1, AxiInputEx.ByKeyCode(PSVitaKey.Start));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.POTION_2, AxiInputEx.ByKeyCode(PSVitaKey.Select));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.UP, AxiInputEx.ByKeyCode(PSVitaKey.Up));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.DOWN, AxiInputEx.ByKeyCode(PSVitaKey.Down));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.LEFT, AxiInputEx.ByKeyCode(PSVitaKey.Left));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.RIGHT, AxiInputEx.ByKeyCode(PSVitaKey.Right));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_1, AxiInputEx.ByKeyCode(PSVitaKey.Cross));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_2, AxiInputEx.ByKeyCode(PSVitaKey.Circle));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_3, AxiInputEx.ByKeyCode(PSVitaKey.Block));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_4, AxiInputEx.ByKeyCode(PSVitaKey.Triangle));
-            //PSV 摇杆
-            controllers[0].SetKey((ulong)EssgeeSingleKey.UP, AxiInputEx.ByAxis(AxiInputAxisType.UP));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.DOWN, AxiInputEx.ByAxis(AxiInputAxisType.DOWN));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.LEFT, AxiInputEx.ByAxis(AxiInputAxisType.LEFT));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.RIGHT, AxiInputEx.ByAxis(AxiInputAxisType.RIGHT));
-            controllers[0].ColletAllKey();
-            return;
-#endif
-            #region P1
-            //P1 键盘
-            controllers[0].SetKey((ulong)EssgeeSingleKey.OPTION_1, AxiInputEx.ByKeyCode(KeyCode.Return));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.OPTION_2, AxiInputEx.ByKeyCode(KeyCode.RightShift));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.UP, AxiInputEx.ByKeyCode(KeyCode.W));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.DOWN, AxiInputEx.ByKeyCode(KeyCode.S));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.LEFT, AxiInputEx.ByKeyCode(KeyCode.A));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.RIGHT, AxiInputEx.ByKeyCode(KeyCode.D));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_1, AxiInputEx.ByKeyCode(KeyCode.J));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_2, AxiInputEx.ByKeyCode(KeyCode.K));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_3, AxiInputEx.ByKeyCode(KeyCode.U));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_4, AxiInputEx.ByKeyCode(KeyCode.I));
-
-            //P1 UGUI
-            controllers[0].SetKey((ulong)EssgeeSingleKey.OPTION_1, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.POTION_1));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.OPTION_2, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.POTION_2));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.UP, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.UP));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.DOWN, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.DOWN));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.LEFT, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.LEFT));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.RIGHT, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.RIGHT));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_1, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.BTN_A));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_2, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.BTN_B));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_3, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.BTN_C));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_4, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.BTN_D));
-
-            //P2 键盘
-            controllers[1].SetKey((ulong)EssgeeSingleKey.OPTION_1, AxiInputEx.ByKeyCode(KeyCode.Keypad0));
-            controllers[1].SetKey((ulong)EssgeeSingleKey.OPTION_2, AxiInputEx.ByKeyCode(KeyCode.Delete));
-            controllers[1].SetKey((ulong)EssgeeSingleKey.UP, AxiInputEx.ByKeyCode(KeyCode.UpArrow));
-            controllers[1].SetKey((ulong)EssgeeSingleKey.DOWN, AxiInputEx.ByKeyCode(KeyCode.DownArrow));
-            controllers[1].SetKey((ulong)EssgeeSingleKey.LEFT, AxiInputEx.ByKeyCode(KeyCode.LeftArrow));
-            controllers[1].SetKey((ulong)EssgeeSingleKey.RIGHT, AxiInputEx.ByKeyCode(KeyCode.RightArrow));
-            controllers[1].SetKey((ulong)EssgeeSingleKey.BTN_1, AxiInputEx.ByKeyCode(KeyCode.Keypad1));
-            controllers[1].SetKey((ulong)EssgeeSingleKey.BTN_2, AxiInputEx.ByKeyCode(KeyCode.Keypad2));
-            controllers[1].SetKey((ulong)EssgeeSingleKey.BTN_3, AxiInputEx.ByKeyCode(KeyCode.Keypad3));
-            controllers[1].SetKey((ulong)EssgeeSingleKey.BTN_4, AxiInputEx.ByKeyCode(KeyCode.Keypad4));
-
-            controllers[0].ColletAllKey();
-            #endregion
-        }
-    }
-
-    public class SC3000SingleKeysSeting : SingleKeySettingBase
-    {
-    }
-}
-
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/SC3000MultiKeysSetting.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/SC3000MultiKeysSetting.cs.meta
deleted file mode 100644
index 18f06e0f..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/SC3000MultiKeysSetting.cs.meta
+++ /dev/null
@@ -1,2 +0,0 @@
-fileFormatVersion: 2
-guid: bee2b8a3f5efaec47b9b363eeaa03160
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/SG1000MultiKeysSetting.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/SG1000MultiKeysSetting.cs
deleted file mode 100644
index 59aba56c..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/SG1000MultiKeysSetting.cs
+++ /dev/null
@@ -1,85 +0,0 @@
-using AxibugEmuOnline.Client.Manager;
-using UnityEngine;
-
-namespace AxiInputSP.Setting
-{
-    public class SG1000MultiKeysSetting : MultiKeysSettingBase
-    {
-        public SG1000MultiKeysSetting()
-        {
-            controllers = new SG1000SingleKeysSeting[4];
-            for (int i = 0; i < controllers.Length; i++)
-                controllers[i] = new SG1000SingleKeysSeting();
-        }
-
-        public override void LoadDefaultSetting()
-        {
-            ClearAll();
-
-#if UNITY_PSP2 && !UNITY_EDITOR
-            //PSV 摇杆
-            controllers[0].SetKey((ulong)EssgeeSingleKey.POTION_1, AxiInputEx.ByKeyCode(PSVitaKey.Start));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.POTION_2, AxiInputEx.ByKeyCode(PSVitaKey.Select));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.UP, AxiInputEx.ByKeyCode(PSVitaKey.Up));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.DOWN, AxiInputEx.ByKeyCode(PSVitaKey.Down));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.LEFT, AxiInputEx.ByKeyCode(PSVitaKey.Left));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.RIGHT, AxiInputEx.ByKeyCode(PSVitaKey.Right));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_1, AxiInputEx.ByKeyCode(PSVitaKey.Cross));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_2, AxiInputEx.ByKeyCode(PSVitaKey.Circle));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_3, AxiInputEx.ByKeyCode(PSVitaKey.Block));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_4, AxiInputEx.ByKeyCode(PSVitaKey.Triangle));
-            //PSV 摇杆
-            controllers[0].SetKey((ulong)EssgeeSingleKey.UP, AxiInputEx.ByAxis(AxiInputAxisType.UP));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.DOWN, AxiInputEx.ByAxis(AxiInputAxisType.DOWN));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.LEFT, AxiInputEx.ByAxis(AxiInputAxisType.LEFT));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.RIGHT, AxiInputEx.ByAxis(AxiInputAxisType.RIGHT));
-            controllers[0].ColletAllKey();
-            return;
-#endif
-            #region P1
-            //P1 键盘
-            controllers[0].SetKey((ulong)EssgeeSingleKey.OPTION_1, AxiInputEx.ByKeyCode(KeyCode.Return));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.OPTION_2, AxiInputEx.ByKeyCode(KeyCode.RightShift));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.UP, AxiInputEx.ByKeyCode(KeyCode.W));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.DOWN, AxiInputEx.ByKeyCode(KeyCode.S));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.LEFT, AxiInputEx.ByKeyCode(KeyCode.A));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.RIGHT, AxiInputEx.ByKeyCode(KeyCode.D));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_1, AxiInputEx.ByKeyCode(KeyCode.J));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_2, AxiInputEx.ByKeyCode(KeyCode.K));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_3, AxiInputEx.ByKeyCode(KeyCode.U));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_4, AxiInputEx.ByKeyCode(KeyCode.I));
-
-            //P1 UGUI
-            controllers[0].SetKey((ulong)EssgeeSingleKey.OPTION_1, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.POTION_1));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.OPTION_2, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.POTION_2));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.UP, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.UP));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.DOWN, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.DOWN));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.LEFT, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.LEFT));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.RIGHT, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.RIGHT));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_1, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.BTN_A));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_2, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.BTN_B));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_3, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.BTN_C));
-            controllers[0].SetKey((ulong)EssgeeSingleKey.BTN_4, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.BTN_D));
-
-            //P2 键盘
-            controllers[1].SetKey((ulong)EssgeeSingleKey.OPTION_1, AxiInputEx.ByKeyCode(KeyCode.Keypad0));
-            controllers[1].SetKey((ulong)EssgeeSingleKey.OPTION_2, AxiInputEx.ByKeyCode(KeyCode.Delete));
-            controllers[1].SetKey((ulong)EssgeeSingleKey.UP, AxiInputEx.ByKeyCode(KeyCode.UpArrow));
-            controllers[1].SetKey((ulong)EssgeeSingleKey.DOWN, AxiInputEx.ByKeyCode(KeyCode.DownArrow));
-            controllers[1].SetKey((ulong)EssgeeSingleKey.LEFT, AxiInputEx.ByKeyCode(KeyCode.LeftArrow));
-            controllers[1].SetKey((ulong)EssgeeSingleKey.RIGHT, AxiInputEx.ByKeyCode(KeyCode.RightArrow));
-            controllers[1].SetKey((ulong)EssgeeSingleKey.BTN_1, AxiInputEx.ByKeyCode(KeyCode.Keypad1));
-            controllers[1].SetKey((ulong)EssgeeSingleKey.BTN_2, AxiInputEx.ByKeyCode(KeyCode.Keypad2));
-            controllers[1].SetKey((ulong)EssgeeSingleKey.BTN_3, AxiInputEx.ByKeyCode(KeyCode.Keypad3));
-            controllers[1].SetKey((ulong)EssgeeSingleKey.BTN_4, AxiInputEx.ByKeyCode(KeyCode.Keypad4));
-
-            controllers[0].ColletAllKey();
-            #endregion
-        }
-    }
-
-    public class SG1000SingleKeysSeting : SingleKeySettingBase
-    {
-    }
-}
-
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/SG1000MultiKeysSetting.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/SG1000MultiKeysSetting.cs.meta
deleted file mode 100644
index 8840360a..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/SG1000MultiKeysSetting.cs.meta
+++ /dev/null
@@ -1,2 +0,0 @@
-fileFormatVersion: 2
-guid: 771225d8fe367ac42b6b91adf81ca27f
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/UMAMEMultiKeysSetting.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/UMAMEMultiKeysSetting.cs
deleted file mode 100644
index 9264b374..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/UMAMEMultiKeysSetting.cs
+++ /dev/null
@@ -1,97 +0,0 @@
-using AxibugEmuOnline.Client.Manager;
-using UnityEngine;
-
-namespace AxiInputSP.Setting
-{
-    public enum UMAMEKSingleKey
-    {
-        INSERT_COIN,
-        GAMESTART,
-        UP,
-        DOWN,
-        LEFT,
-        RIGHT,
-        BTN_A,
-        BTN_B,
-        BTN_C,
-        BTN_D,
-        BTN_E,
-        BTN_F
-    }
-    public class UMAMEMultiKeysSetting : MultiKeysSettingBase
-    {
-        public UMAMEMultiKeysSetting()
-        {
-            controllers = new UMAMEKSingleKeysSeting[4];
-            for (int i = 0; i < controllers.Length; i++)
-                controllers[i] = new UMAMEKSingleKeysSeting();
-        }
-
-        public override void LoadDefaultSetting()
-        {
-            ClearAll();
-#if UNITY_PSP2 && !UNITY_EDITOR
-            //PSV 摇杆
-            controllers[0].SetKey((ulong)MAMEKSingleKey.GAMESTART, AxiInputEx.ByKeyCode(PSVitaKey.Start));
-            controllers[0].SetKey((ulong)MAMEKSingleKey.INSERT_COIN, AxiInputEx.ByKeyCode(PSVitaKey.Select));
-            controllers[0].SetKey((ulong)MAMEKSingleKey.UP, AxiInputEx.ByKeyCode(PSVitaKey.Up));
-            controllers[0].SetKey((ulong)MAMEKSingleKey.DOWN, AxiInputEx.ByKeyCode(PSVitaKey.Down));
-            controllers[0].SetKey((ulong)MAMEKSingleKey.LEFT, AxiInputEx.ByKeyCode(PSVitaKey.Left));
-            controllers[0].SetKey((ulong)MAMEKSingleKey.RIGHT, AxiInputEx.ByKeyCode(PSVitaKey.Right));
-            controllers[0].SetKey((ulong)MAMEKSingleKey.BTN_A, AxiInputEx.ByKeyCode(PSVitaKey.Block));
-            controllers[0].SetKey((ulong)MAMEKSingleKey.BTN_B, AxiInputEx.ByKeyCode(PSVitaKey.Cross));
-            controllers[0].SetKey((ulong)MAMEKSingleKey.BTN_C, AxiInputEx.ByKeyCode(PSVitaKey.Circle));
-            controllers[0].SetKey((ulong)MAMEKSingleKey.BTN_D, AxiInputEx.ByKeyCode(PSVitaKey.Triangle));
-            controllers[0].SetKey((ulong)MAMEKSingleKey.BTN_E, AxiInputEx.ByKeyCode(PSVitaKey.L));
-            controllers[0].SetKey((ulong)MAMEKSingleKey.BTN_F, AxiInputEx.ByKeyCode(PSVitaKey.R));
-            //PSV 摇杆
-            controllers[0].SetKey((ulong)MAMEKSingleKey.UP, AxiInputEx.ByAxis(AxiInputAxisType.UP));
-            controllers[0].SetKey((ulong)MAMEKSingleKey.DOWN, AxiInputEx.ByAxis(AxiInputAxisType.DOWN));
-            controllers[0].SetKey((ulong)MAMEKSingleKey.LEFT, AxiInputEx.ByAxis(AxiInputAxisType.LEFT));
-            controllers[0].SetKey((ulong)MAMEKSingleKey.RIGHT, AxiInputEx.ByAxis(AxiInputAxisType.RIGHT));
-            controllers[0].ColletAllKey();
-            return;
-#endif
-            #region P1
-            //P1 键盘
-            controllers[0].SetKey((ulong)UMAMEKSingleKey.GAMESTART, AxiInputEx.ByKeyCode(KeyCode.Alpha1));
-            controllers[0].SetKey((ulong)UMAMEKSingleKey.INSERT_COIN, AxiInputEx.ByKeyCode(KeyCode.Alpha5));
-            controllers[0].SetKey((ulong)UMAMEKSingleKey.UP, AxiInputEx.ByKeyCode(KeyCode.W));
-            controllers[0].SetKey((ulong)UMAMEKSingleKey.DOWN, AxiInputEx.ByKeyCode(KeyCode.S));
-            controllers[0].SetKey((ulong)UMAMEKSingleKey.LEFT, AxiInputEx.ByKeyCode(KeyCode.A));
-            controllers[0].SetKey((ulong)UMAMEKSingleKey.RIGHT, AxiInputEx.ByKeyCode(KeyCode.D));
-            controllers[0].SetKey((ulong)UMAMEKSingleKey.BTN_A, AxiInputEx.ByKeyCode(KeyCode.J));
-            controllers[0].SetKey((ulong)UMAMEKSingleKey.BTN_B, AxiInputEx.ByKeyCode(KeyCode.K));
-            controllers[0].SetKey((ulong)UMAMEKSingleKey.BTN_C, AxiInputEx.ByKeyCode(KeyCode.L));
-            controllers[0].SetKey((ulong)UMAMEKSingleKey.BTN_D, AxiInputEx.ByKeyCode(KeyCode.U));
-            controllers[0].SetKey((ulong)UMAMEKSingleKey.BTN_E, AxiInputEx.ByKeyCode(KeyCode.I));
-            controllers[0].SetKey((ulong)UMAMEKSingleKey.BTN_F, AxiInputEx.ByKeyCode(KeyCode.O));
-
-            //Axis
-            controllers[0].SetKey((ulong)UMAMEKSingleKey.UP, AxiInputEx.ByAxis(AxiInputAxisType.UP));
-            controllers[0].SetKey((ulong)UMAMEKSingleKey.DOWN, AxiInputEx.ByAxis(AxiInputAxisType.DOWN));
-            controllers[0].SetKey((ulong)UMAMEKSingleKey.LEFT, AxiInputEx.ByAxis(AxiInputAxisType.LEFT));
-            controllers[0].SetKey((ulong)UMAMEKSingleKey.RIGHT, AxiInputEx.ByAxis(AxiInputAxisType.RIGHT));
-
-            //P1 UGUI
-            controllers[0].SetKey((ulong)UMAMEKSingleKey.GAMESTART, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.POTION_1));
-            controllers[0].SetKey((ulong)UMAMEKSingleKey.INSERT_COIN, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.POTION_2));
-            controllers[0].SetKey((ulong)UMAMEKSingleKey.UP, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.UP));
-            controllers[0].SetKey((ulong)UMAMEKSingleKey.DOWN, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.DOWN));
-            controllers[0].SetKey((ulong)UMAMEKSingleKey.LEFT, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.LEFT));
-            controllers[0].SetKey((ulong)UMAMEKSingleKey.RIGHT, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.RIGHT));
-            controllers[0].SetKey((ulong)UMAMEKSingleKey.BTN_A, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.BTN_A));
-            controllers[0].SetKey((ulong)UMAMEKSingleKey.BTN_B, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.BTN_B));
-            controllers[0].SetKey((ulong)UMAMEKSingleKey.BTN_C, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.BTN_C));
-            controllers[0].SetKey((ulong)UMAMEKSingleKey.BTN_D, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.BTN_D));
-            controllers[0].SetKey((ulong)UMAMEKSingleKey.BTN_E, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.BTN_E));
-            controllers[0].SetKey((ulong)UMAMEKSingleKey.BTN_F, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.BTN_F));
-
-            controllers[0].ColletAllKey();
-            #endregion
-        }
-    }
-    public class UMAMEKSingleKeysSeting : SingleKeySettingBase
-    {
-    }
-}
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/UMAMEMultiKeysSetting.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/UMAMEMultiKeysSetting.cs.meta
deleted file mode 100644
index 31eefb9e..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/UMAMEMultiKeysSetting.cs.meta
+++ /dev/null
@@ -1,2 +0,0 @@
-fileFormatVersion: 2
-guid: 486aed2afcba6b94f86c1ae4e4aeaf02
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/XMBMultiKeysSetting.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/XMBMultiKeysSetting.cs
deleted file mode 100644
index dd94b0a1..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/XMBMultiKeysSetting.cs
+++ /dev/null
@@ -1,72 +0,0 @@
-using AxibugEmuOnline.Client;
-using AxibugEmuOnline.Client.Common;
-using AxibugEmuOnline.Client.Manager;
-using UnityEngine;
-
-namespace AxiInputSP.Setting
-{
-    public class XMBMultiKeysSetting : MultiKeysSettingBase
-    {
-        public XMBMultiKeysSetting()
-        {
-            controllers = new XMBSingleKeysSeting[1];
-            for (int i = 0; i < controllers.Length; i++)
-                controllers[i] = new XMBSingleKeysSeting();
-        }
-
-        public override void LoadDefaultSetting()
-        {
-            ClearAll();
-
-#if UNITY_PSP2 && !UNITY_EDITOR
-            controllers[0].SetKey((ulong)EnumCommand.SelectItemUp, AxiInputEx.ByKeyCode(PSVitaKey.Up));
-            controllers[0].SetKey((ulong)EnumCommand.SelectItemDown, AxiInputEx.ByKeyCode(PSVitaKey.Down));
-            controllers[0].SetKey((ulong)EnumCommand.SelectItemLeft, AxiInputEx.ByKeyCode(PSVitaKey.Left));
-            controllers[0].SetKey((ulong)EnumCommand.SelectItemRight, AxiInputEx.ByKeyCode(PSVitaKey.Right));
-            controllers[0].SetKey((ulong)EnumCommand.Enter, AxiInputEx.ByKeyCode(PSVitaKey.Circle));
-            controllers[0].SetKey((ulong)EnumCommand.Back, AxiInputEx.ByKeyCode(PSVitaKey.Cross));
-            controllers[0].SetKey((ulong)EnumCommand.OptionMenu, AxiInputEx.ByKeyCode(PSVitaKey.Triangle));
-            controllers[0].ColletAllKey();
-            return;
-#endif
-            //键盘
-            controllers[0].SetKey((ulong)EnumCommand.SelectItemUp, AxiInputEx.ByKeyCode(KeyCode.W));
-            controllers[0].SetKey((ulong)EnumCommand.SelectItemDown, AxiInputEx.ByKeyCode(KeyCode.S));
-            controllers[0].SetKey((ulong)EnumCommand.SelectItemLeft, AxiInputEx.ByKeyCode(KeyCode.A));
-            controllers[0].SetKey((ulong)EnumCommand.SelectItemRight, AxiInputEx.ByKeyCode(KeyCode.D));
-            controllers[0].SetKey((ulong)EnumCommand.Enter, AxiInputEx.ByKeyCode(KeyCode.J));
-            controllers[0].SetKey((ulong)EnumCommand.Enter, AxiInputEx.ByKeyCode(KeyCode.Return));
-            controllers[0].SetKey((ulong)EnumCommand.Back, AxiInputEx.ByKeyCode(KeyCode.K));
-            controllers[0].SetKey((ulong)EnumCommand.Back, AxiInputEx.ByKeyCode(KeyCode.Escape));
-            controllers[0].SetKey((ulong)EnumCommand.OptionMenu, AxiInputEx.ByKeyCode(KeyCode.I));
-
-            //Axis
-            controllers[0].SetKey((ulong)EnumCommand.SelectItemUp, AxiInputEx.ByAxis(AxiInputAxisType.UP));
-            controllers[0].SetKey((ulong)EnumCommand.SelectItemDown, AxiInputEx.ByAxis(AxiInputAxisType.DOWN));
-            controllers[0].SetKey((ulong)EnumCommand.SelectItemLeft, AxiInputEx.ByAxis(AxiInputAxisType.LEFT));
-            controllers[0].SetKey((ulong)EnumCommand.SelectItemRight, AxiInputEx.ByAxis(AxiInputAxisType.RIGHT));
-
-            //P1 UGUI
-            controllers[0].SetKey((ulong)EnumCommand.SelectItemUp, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.UP));
-            controllers[0].SetKey((ulong)EnumCommand.SelectItemDown, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.DOWN));
-            controllers[0].SetKey((ulong)EnumCommand.SelectItemLeft, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.LEFT));
-            controllers[0].SetKey((ulong)EnumCommand.SelectItemRight, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.RIGHT));
-            controllers[0].SetKey((ulong)EnumCommand.Enter, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.BTN_A));
-            controllers[0].SetKey((ulong)EnumCommand.Back, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.BTN_B));
-            controllers[0].SetKey((ulong)EnumCommand.OptionMenu, AxiInputEx.ByUGUIBtn(AxiInputUGuiBtnType.HOME));
-
-            //PC XBOX
-
-            //TODO 待补全
-            controllers[0].SetKey((ulong)EnumCommand.Enter, AxiInputEx.ByKeyCode(PC_XBOXKEY.MenuBtn));
-            controllers[0].SetKey((ulong)EnumCommand.Back, AxiInputEx.ByKeyCode(PC_XBOXKEY.ViewBtn));
-            controllers[0].SetKey((ulong)EnumCommand.OptionMenu, AxiInputEx.ByKeyCode(PC_XBOXKEY.Y));
-
-            controllers[0].ColletAllKey();
-        }
-    }
-
-    public class XMBSingleKeysSeting : SingleKeySettingBase
-    {
-    }
-}
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/XMBMultiKeysSetting.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/XMBMultiKeysSetting.cs.meta
deleted file mode 100644
index 2333e4e7..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/XMBMultiKeysSetting.cs.meta
+++ /dev/null
@@ -1,2 +0,0 @@
-fileFormatVersion: 2
-guid: 90bd1ccb53a0ddd4b814030f1ae218a2
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/AxiInput.Struct.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/AxiInput.Struct.cs
index c3eee81c..e580c36a 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/AxiInput.Struct.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/AxiInput.Struct.cs
@@ -46,10 +46,10 @@ namespace AxiInputSP
         BTN_D,
         BTN_E,
         BTN_F,
-        POTION_1,
-        POTION_2,
-        POTION_3,
-        POTION_4,
+        OPTION_1,
+        OPTION_2,
+        OPTION_3,
+        OPTION_4,
         HOME,
     }
 }
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/AxiInputEx.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/AxiInputEx.cs
deleted file mode 100644
index 32b44d88..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/AxiInputEx.cs
+++ /dev/null
@@ -1,79 +0,0 @@
-using AxiInputSP.Axis;
-using AxiInputSP.UGUI;
-using UnityEngine;
-
-namespace AxiInputSP
-{
-    public static class AxiInputEx
-    {
-        public static AxiInput ByKeyCode(KeyCode keycode)
-        {
-            AxiInput data = new AxiInput();
-            data.all = 0;
-            data.type = AxiInputType.UNITY_KEYCODE;
-            data.KeyCodeValue = keycode;
-            return data;
-        }
-        public static AxiInput ByAxis(AxiInputAxisType axisType)
-        {
-            AxiInput data = new AxiInput();
-            data.all = 0;
-            data.type = AxiInputType.UNITY_AXIS;
-            data.AxisType = axisType;
-            return data;
-        }
-        public static AxiInput ByUGUIBtn(AxiInputUGuiBtnType btnType)
-        {
-            AxiInput data = new AxiInput();
-            data.all = 0;
-            data.type = AxiInputType.UNITY_UGUI_BTN;
-            data.UguiBtn = btnType;
-            return data;
-        }
-
-        public static bool GetKeyDown(this AxiInput axiInput)
-        {
-            switch (axiInput.type)
-            {
-                case AxiInputType.UNITY_KEYCODE:
-                    return Input.GetKeyDown(axiInput.KeyCodeValue);
-                case AxiInputType.UNITY_AXIS:
-                    return AxiInputAxisCenter.GetKeyDown(axiInput.AxisType);
-                case AxiInputType.UNITY_UGUI_BTN:
-                    return AxiInputUGUICenter.GetKeyDown(axiInput.UguiBtn);
-                default:
-                    return false;
-            }
-        }
-
-        public static bool GetKeyUp(this AxiInput axiInput)
-        {
-            switch (axiInput.type)
-            {
-                case AxiInputType.UNITY_KEYCODE:
-                    return Input.GetKeyUp(axiInput.KeyCodeValue);
-                case AxiInputType.UNITY_AXIS:
-                    return AxiInputAxisCenter.GetKeyUp(axiInput.AxisType);
-                case AxiInputType.UNITY_UGUI_BTN:
-                    return AxiInputUGUICenter.GetKeyUp(axiInput.UguiBtn);
-                default:
-                    return false;
-            }
-        }
-
-        public static bool GetKey(this AxiInput axiInput)
-        {
-            switch (axiInput.type)
-            {
-                case AxiInputType.UNITY_KEYCODE:
-                    return Input.GetKey(axiInput.KeyCodeValue);
-                case AxiInputType.UNITY_AXIS: 
-                    return AxiInputAxisCenter.GetKey(axiInput.AxisType);
-                case AxiInputType.UNITY_UGUI_BTN:
-                    return AxiInputUGUICenter.GetKey(axiInput.UguiBtn);
-                default:
-                    return false;
-            }
-        }
-    }
-}
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/AxiInputEx.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/AxiInputEx.cs.meta
deleted file mode 100644
index 0c1f91cf..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/AxiInputEx.cs.meta
+++ /dev/null
@@ -1,2 +0,0 @@
-fileFormatVersion: 2
-guid: f19df5371f3222747868da94fc86702f
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/UGUI/AxiInputUGUICenter.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/UGUI/AxiInputUGUICenter.cs
deleted file mode 100644
index e4974dd7..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/UGUI/AxiInputUGUICenter.cs
+++ /dev/null
@@ -1,78 +0,0 @@
-using System.Collections.Generic;
-
-namespace AxiInputSP.UGUI
-{
-    public static class AxiInputUGUICenter
-    {
-        static int handleSeed = 0;
-        static Dictionary<int, AxiInputUGUIHandle> dictHandle2AxiUgui = new Dictionary<int, AxiInputUGUIHandle>();
-        static Dictionary<AxiInputUGuiBtnType, List<AxiInputUGUIHandle>> dictBtnType2BtnList = new Dictionary<AxiInputUGuiBtnType, List<AxiInputUGUIHandle>>();
-
-        public static int GetNextSeed()
-        {
-            return ++handleSeed;
-        }
-        public static void RegHandle(AxiInputUGUIHandle uiHandle)
-        {
-            dictHandle2AxiUgui[uiHandle.Handle] = uiHandle;
-            List<AxiInputUGUIHandle> list;
-            if (!dictBtnType2BtnList.TryGetValue(uiHandle.UguiBtnType, out list))
-                list = dictBtnType2BtnList[uiHandle.UguiBtnType] = new List<AxiInputUGUIHandle>();
-
-            if (!list.Contains(uiHandle))
-                list.Add(uiHandle);
-        }
-        public static void UnregHandle(AxiInputUGUIHandle uiHandle)
-        {
-            if (!dictHandle2AxiUgui.ContainsKey(uiHandle.Handle))
-                return;
-            dictHandle2AxiUgui.Remove(uiHandle.Handle);
-
-            List<AxiInputUGUIHandle> list;
-            if (dictBtnType2BtnList.TryGetValue(uiHandle.UguiBtnType, out list))
-            {
-                if (list.Contains(uiHandle))
-                    list.Remove(uiHandle);
-            }
-        }
-
-        public static bool GetKeyUp(AxiInputUGuiBtnType btntype)
-        {
-            List<AxiInputUGUIHandle> list;
-            if (!dictBtnType2BtnList.TryGetValue(btntype, out list))
-                return false;
-            for (int i = 0; i < list.Count; i++)
-            {
-                if (list[i].GetKeyUp())
-                    return true;
-            }
-            return false;
-        }
-
-        public static bool GetKeyDown(AxiInputUGuiBtnType btntype)
-        {
-            List<AxiInputUGUIHandle> list;
-            if (!dictBtnType2BtnList.TryGetValue(btntype, out list))
-                return false;
-            for (int i = 0; i < list.Count; i++)
-            {
-                if (list[i].GetKeyDown())
-                    return true;
-            }
-            return false;
-        }
-
-        public static bool GetKey(AxiInputUGuiBtnType btntype)
-        {
-            List<AxiInputUGUIHandle> list;
-            if (!dictBtnType2BtnList.TryGetValue(btntype, out list))
-                return false;
-            for (int i = 0; i < list.Count; i++)
-            {
-                if (list[i].GetKey())
-                    return true;
-            }
-            return false;
-        }
-    }
-}
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/UGUI/AxiInputUGUICenter.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/UGUI/AxiInputUGUICenter.cs.meta
deleted file mode 100644
index 3836a184..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/UGUI/AxiInputUGUICenter.cs.meta
+++ /dev/null
@@ -1,2 +0,0 @@
-fileFormatVersion: 2
-guid: e41586af52faf33488c59e2608f9ff7b
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/UGUI/AxiInputUGUIHandle.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/UGUI/AxiInputUGUIHandle.cs
deleted file mode 100644
index d19baceb..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/UGUI/AxiInputUGUIHandle.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-using System;
-
-namespace AxiInputSP.UGUI
-{
-    public class AxiInputUGUIHandle
-    {
-        public int Handle { get; private set; }
-        public AxiInputUGuiBtnType UguiBtnType { get; private set; }
-
-        public AxiInputUGUIHandle(AxiInputUGuiBtnType uguiBtnType)
-        {
-            Handle = AxiInputUGUICenter.GetNextSeed();
-            this.UguiBtnType = uguiBtnType;
-            AxiInputUGUICenter.RegHandle(this);
-        }
-        public bool GetKey()
-        {
-            return GetKeyHandle != null ? GetKeyHandle.Invoke() : false;
-        }
-        public bool GetKeyUp()
-        {
-            return GetKeyUpHandle != null ? GetKeyUpHandle.Invoke() : false;
-        }
-        public bool GetKeyDown()
-        {
-            return GetKeyDownHandle != null ? GetKeyDownHandle.Invoke() : false;
-        }
-        public Func<bool> GetKeyHandle;
-        public Func<bool> GetKeyUpHandle;
-        public Func<bool> GetKeyDownHandle;
-
-        public void Dispose()
-        {
-            GetKeyHandle = null;
-            GetKeyUpHandle = null;
-            GetKeyDownHandle = null;
-            AxiInputUGUICenter.UnregHandle(this);
-        }
-    }
-}
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/UGUI/AxiInputUGUIHandle.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/UGUI/AxiInputUGUIHandle.cs.meta
deleted file mode 100644
index f11acfb4..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/UGUI/AxiInputUGUIHandle.cs.meta
+++ /dev/null
@@ -1,2 +0,0 @@
-fileFormatVersion: 2
-guid: e4ca40659ca235846b10ee28305147dd
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/UGUI/AxiIptButton.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/UGUI/AxiIptButton.cs
index 4819ba50..380f42b4 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/UGUI/AxiIptButton.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/UGUI/AxiIptButton.cs
@@ -13,59 +13,22 @@ namespace AxiInputSP.UGUI
             KeyHold
         }
 
-        AxiInputUGUIHandle[] handles;
         AxiButtonState m_state = AxiButtonState.None;
         /// <summary>
         /// 键值(支持组合键)
         /// </summary>
         [SerializeField]
         public AxiInputUGuiBtnType[] axiBtnTypeList;
-        protected override void Awake()
-        {
-            base.Awake();
-            if (axiBtnTypeList != null)
-            {
-                handles = new AxiInputUGUIHandle[axiBtnTypeList.Length];
-                for (int i = 0; i < axiBtnTypeList.Length; i++)
-                {
-                    handles[i] = new AxiInputUGUIHandle(axiBtnTypeList[i]);
-                    handles[i].GetKeyHandle = GetKey;
-                    handles[i].GetKeyUpHandle = GetKeyUp;
-                    handles[i].GetKeyDownHandle = GetKeyDown;
-                }
-            }
-        }
 
-        protected override void OnDestroy()
-        {
-            base.OnDestroy();
-            if (axiBtnTypeList != null)
-            {
-                handles = new AxiInputUGUIHandle[axiBtnTypeList.Length];
-                for (int i = 0; i < axiBtnTypeList.Length; i++)
-                {
-                    handles[i].Dispose();
-                    handles[i] = null;
-                }
-                axiBtnTypeList = null;
-                handles = null;
-            }
-
-        }
-        protected override void OnEnable()
-        {
-            base.OnEnable();
-        }
-
-        bool GetKey()
+        public bool GetKey()
         {
             return m_state >= AxiButtonState.KeyDown;
         }
-        bool GetKeyUp()
+        public bool GetKeyUp()
         {
             return m_state == AxiButtonState.KeyUp;
         }
-        bool GetKeyDown()
+        public bool GetKeyDown()
         {
             return m_state == AxiButtonState.KeyDown;
         }
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/UGUI/AxiIptJoystick.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/UGUI/AxiIptJoystick.cs
deleted file mode 100644
index 933d9c63..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/UGUI/AxiIptJoystick.cs
+++ /dev/null
@@ -1,121 +0,0 @@
-using System;
-using System.Collections.Generic;
-using UnityEngine;
-
-namespace AxiInputSP.UGUI
-{
-    public class AxiIptJoystick : IDisposable
-    {
-        enum AxiIptJoystickState
-        {
-            None,
-            KeyUp,
-            KeyDown,
-            KeyHold
-        }
-        static long LastCheckFrame = -1;
-        static Func<Vector2Int> RawJoy;
-        AxiInputUGUIHandle[] handles = new AxiInputUGUIHandle[4];
-        static Dictionary<AxiInputUGuiBtnType, AxiIptJoystickState> mAxis2State = new Dictionary<AxiInputUGuiBtnType, AxiIptJoystickState>();
-
-        public AxiIptJoystick(Func<Vector2Int> getRawJoy)
-        {
-            RawJoy = getRawJoy;
-            handles[0] = new AxiInputUGUIHandle(AxiInputUGuiBtnType.UP);
-            handles[0].GetKeyHandle = (() => { return GetKey(AxiInputUGuiBtnType.UP); });
-            handles[0].GetKeyUpHandle = (() => { return GetKeyUp(AxiInputUGuiBtnType.UP); });
-            handles[0].GetKeyDownHandle = (() => { return GetKeyDown(AxiInputUGuiBtnType.UP); });
-            mAxis2State[AxiInputUGuiBtnType.UP] = AxiIptJoystickState.None;
-
-            handles[1] = new AxiInputUGUIHandle(AxiInputUGuiBtnType.DOWN);
-            handles[1].GetKeyHandle = (() => { return GetKey(AxiInputUGuiBtnType.DOWN); });
-            handles[1].GetKeyUpHandle = (() => { return GetKeyUp(AxiInputUGuiBtnType.DOWN); });
-            handles[1].GetKeyDownHandle = (() => { return GetKeyDown(AxiInputUGuiBtnType.DOWN); });
-            mAxis2State[AxiInputUGuiBtnType.DOWN] = AxiIptJoystickState.None;
-
-            handles[2] = new AxiInputUGUIHandle(AxiInputUGuiBtnType.LEFT);
-            handles[2].GetKeyHandle = (() => { return GetKey(AxiInputUGuiBtnType.LEFT); });
-            handles[2].GetKeyUpHandle = (() => { return GetKeyUp(AxiInputUGuiBtnType.LEFT); });
-            handles[2].GetKeyDownHandle = (() => { return GetKeyDown(AxiInputUGuiBtnType.LEFT); });
-            mAxis2State[AxiInputUGuiBtnType.LEFT] = AxiIptJoystickState.None;
-
-            handles[3] = new AxiInputUGUIHandle(AxiInputUGuiBtnType.RIGHT);
-            handles[3].GetKeyHandle = (() => { return GetKey(AxiInputUGuiBtnType.RIGHT); });
-            handles[3].GetKeyUpHandle = (() => { return GetKeyUp(AxiInputUGuiBtnType.RIGHT); });
-            handles[3].GetKeyDownHandle = (() => { return GetKeyDown(AxiInputUGuiBtnType.RIGHT); });
-            mAxis2State[AxiInputUGuiBtnType.RIGHT] = AxiIptJoystickState.None;
-        }
-
-
-        public void Dispose()
-        {
-            for (int i = 0; i < handles.Length; i++)
-            {
-                handles[i].Dispose();
-                handles[i] = null;
-            }
-            mAxis2State.Clear();
-        }
-
-        public static void UpdateState()
-        {
-            if (LastCheckFrame == Time.frameCount)
-                return;
-            LastCheckFrame = Time.frameCount;
-            RecheckSingleState(AxiInputUGuiBtnType.RIGHT);
-            RecheckSingleState(AxiInputUGuiBtnType.LEFT);
-            RecheckSingleState(AxiInputUGuiBtnType.UP);
-            RecheckSingleState(AxiInputUGuiBtnType.DOWN);
-        }
-
-        static void RecheckSingleState(AxiInputUGuiBtnType axisType)
-        {
-            bool bKey = false;
-
-            Vector2Int inputV2 = RawJoy.Invoke();
-
-            switch (axisType)
-            {
-                case AxiInputUGuiBtnType.RIGHT: bKey = inputV2.x > 0; break;
-                case AxiInputUGuiBtnType.LEFT: bKey = inputV2.x < 0; break;
-                case AxiInputUGuiBtnType.UP: bKey = inputV2.y > 0; break;
-                case AxiInputUGuiBtnType.DOWN: bKey = inputV2.y < 0; break;
-            }
-            //按下
-            if (bKey)
-            {
-                //如果之前帧是KeyUp或None,则为KeyDown|KeyHold
-                if (mAxis2State[axisType] <= AxiIptJoystickState.KeyUp)
-                    mAxis2State[axisType] = AxiIptJoystickState.KeyDown;
-                //如果之前帧是KeyDown,则为KeyHold
-                else if (mAxis2State[axisType] == AxiIptJoystickState.KeyDown)
-                    mAxis2State[axisType] = AxiIptJoystickState.KeyHold;
-            }
-            //未按下
-            else
-            {
-                //如果之前帧是KeyDown|KeyHold,则为KeyUp|None
-                if (mAxis2State[axisType] >= AxiIptJoystickState.KeyDown)
-                    mAxis2State[axisType] = AxiIptJoystickState.KeyUp;
-                //如果之前帧是KeyUp,则为None
-                else if (mAxis2State[axisType] == AxiIptJoystickState.KeyUp)
-                    mAxis2State[axisType] = AxiIptJoystickState.None;
-            }
-        }
-        bool GetKey(AxiInputUGuiBtnType key)
-        {
-            UpdateState();
-            return mAxis2State[key] >= AxiIptJoystickState.KeyDown;
-        }
-        bool GetKeyUp(AxiInputUGuiBtnType key)
-        {
-            UpdateState();
-            return mAxis2State[key] == AxiIptJoystickState.KeyUp;
-        }
-        bool GetKeyDown(AxiInputUGuiBtnType key)
-        {
-            UpdateState();
-            return mAxis2State[key] == AxiIptJoystickState.KeyDown;
-        }
-    }
-}
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/UGUI/AxiIptJoystick.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/UGUI/AxiIptJoystick.cs.meta
deleted file mode 100644
index 36cefbcc..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/UGUI/AxiIptJoystick.cs.meta
+++ /dev/null
@@ -1,2 +0,0 @@
-fileFormatVersion: 2
-guid: 7194bc2da3bcaa747b87428fb3175009
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/UGUI/AxiScreenGamepad.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/UGUI/AxiScreenGamepad.cs
new file mode 100644
index 00000000..e9ae262f
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/UGUI/AxiScreenGamepad.cs
@@ -0,0 +1,62 @@
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace AxiInputSP.UGUI
+{
+    public class AxiScreenGamepad : MonoBehaviour
+    {
+        public delegate void OnAxiScreenGamepadActiveHandle(AxiScreenGamepad sender);
+        public delegate void OnAxiScreenGamepadDisactiveHandle(AxiScreenGamepad sender);
+
+        public static event OnAxiScreenGamepadActiveHandle OnGamepadActive;
+        public static event OnAxiScreenGamepadActiveHandle OnGamepadDisactive;
+
+        AxiIptButton[] m_buttons;
+        FloatingJoystick m_joystick;
+        HashSet<AxiInputUGuiBtnType> m_pressBtns = new HashSet<AxiInputUGuiBtnType>();
+        Vector2 m_joyStickRaw;
+
+        public bool GetKey(AxiInputUGuiBtnType btnType)
+        {
+            return m_pressBtns.Contains(btnType);
+        }
+
+        public Vector2 GetJoystickValue()
+        {
+            return m_joyStickRaw;
+        }
+
+        private void Update()
+        {
+            m_joyStickRaw = m_joystick.GetJoyRaw();
+            m_pressBtns.Clear();
+            foreach (var btn in m_buttons)
+            {
+                if (btn.GetKey())
+                {
+                    foreach (var btnType in btn.axiBtnTypeList)
+                        m_pressBtns.Add(btnType);
+                }
+            }
+        }
+
+        private void Awake()
+        {
+            m_buttons = GetComponentsInChildren<AxiIptButton>(true);
+            m_joystick = GetComponentInChildren<FloatingJoystick>(true);
+        }
+
+        private void OnEnable()
+        {
+            m_joyStickRaw = Vector2.zero;
+            m_pressBtns.Clear();
+
+            OnGamepadActive?.Invoke(this);
+        }
+
+        private void OnDisable()
+        {
+            OnGamepadDisactive?.Invoke(this);
+        }
+    }
+}
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/UGUI/AxiScreenGamepad.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/UGUI/AxiScreenGamepad.cs.meta
new file mode 100644
index 00000000..ca5ae78e
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/UGUI/AxiScreenGamepad.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 1c6e60f499349d7479c565da795cde9b
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxibugEmuOnline.Client.asmdef b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxibugEmuOnline.Client.asmdef
index 24d5e068..81c9246d 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxibugEmuOnline.Client.asmdef
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxibugEmuOnline.Client.asmdef
@@ -6,9 +6,9 @@
         "VirtualNes.Core",
         "UIEffect2018",
         "Mame.Core",
-        "Essgee.Unity",
-        "StoicGooseUnity"
-    ],
+        "Essgee.Unity"
+		"StoicGooseUnity"
+        "Unity.InputSystem"    ],
     "includePlatforms": [],
     "excludePlatforms": [],
     "allowUnsafeCode": true,
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/EssgeeEmulator/UEssgeeInterface/UEGKeyboard.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/EssgeeEmulator/UEssgeeInterface/UEGKeyboard.cs
index f4bcea1f..5b730853 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/EssgeeEmulator/UEssgeeInterface/UEGKeyboard.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/EssgeeEmulator/UEssgeeInterface/UEGKeyboard.cs
@@ -1,8 +1,7 @@
-using AxibugEmuOnline.Client;
+using AxibugEmuOnline.Client;
 using AxibugEmuOnline.Client.ClientCore;
 using AxibugEmuOnline.Client.Event;
-using AxibugEmuOnline.Client.Manager;
-using AxiInputSP.Setting;
+using AxibugEmuOnline.Client.Settings;
 using AxiReplay;
 using System;
 using System.Collections.Generic;
@@ -318,7 +317,7 @@ public class UEGKeyboard : MonoBehaviour
 
     public bool SampleInput()
     {
-        //Netģʽ
+        //Net模式
         if (InGameUI.Instance.IsNetPlay)
         {
             bool bHadNetData = false;
@@ -334,18 +333,18 @@ public class UEGKeyboard : MonoBehaviour
                 SetCurrKeyArr(CurrRemoteInpuAllData);
                 bHadNetData = true;
             }
-            else//������
+            else//无输入
             {
                 CurrRemoteInpuAllData = 0;
             }
 
-            //���ͱ��ز���
+            //发送本地操作
             App.roomMgr.SendRoomSingelPlayerInput(UEssgee.instance.Frame,
              DoLocalPressedKeys());
 
             return bHadNetData;
         }
-        //����ģʽ
+        //单机模式
         else
         {
             ulong inputData = DoLocalPressedKeys();
@@ -550,9 +549,9 @@ public class EssgssSingleController : IController
     uint? mConnectSlot;
 
     /// <summary>
-    /// ָʾ���ֱ����ӵ��ֱ����
-    /// <para><c>���ֵ�����˸��ֱ���ʵ����Ϸ�п��Ƶ�Player</c></para>
-    /// <value>[0,3] ����:Ϊ�մ���δ����</value>
+    /// 指示该手柄连接的手柄插槽
+    /// <para><c>这个值代表了该手柄在实际游戏中控制的Player</c></para>
+    /// <value>[0,3] 例外:为空代表未连接</value>
     /// </summary>
     public uint? ConnectSlot
     {
@@ -561,8 +560,8 @@ public class EssgssSingleController : IController
     }
 
     /// <summary>
-    /// ���������
-    /// <para><c>�˱�Ų��Ƕ�Ӧ��Ϸ�е�player1,player2,player3,player4,������Ϊ����4���ֱ���ʵ��</c></para>
+    /// 控制器编号
+    /// <para><c>此编号并非对应游戏中的player1,player2,player3,player4,仅仅作为本地4个手柄的实例</c></para>
     /// <value>[0,3]</value>
     /// </summary>
     public int ControllerIndex
@@ -578,34 +577,12 @@ public class EssgssSingleController : IController
 
     public bool AnyButtonDown()
     {
-        //if (Input.GetKeyDown(UP)) return true;
-        //if (Input.GetKeyDown(DOWN)) return true;
-        //if (Input.GetKeyDown(LEFT)) return true;
-        //if (Input.GetKeyDown(RIGHT)) return true;
-        //if (Input.GetKeyDown(BTN_1)) return true;
-        //if (Input.GetKeyDown(BTN_2)) return true;
-        //if (Input.GetKeyDown(BTN_3)) return true;
-        //if (Input.GetKeyDown(BTN_4)) return true;
-        //if (Input.GetKeyDown(OPTION_1)) return true;
-        //if (Input.GetKeyDown(OPTION_2)) return true;
-        //return false;
-
-        return GetSingleKeys().HadAnyKeyDown();
+        return GetKeyMapper().AnyKeyDown(mControllerIndex);
     }
 
-    public SingleKeySettingBase GetSingleKeys()
+    public EssgeeKeyBinding GetKeyMapper()
     {
-        switch (UEssgee.instance.Platform)
-        {
-            case AxibugProtobuf.RomPlatformType.MasterSystem: return App.input.sms.controllers[mControllerIndex];
-            case AxibugProtobuf.RomPlatformType.GameBoy: return App.input.gb.controllers[mControllerIndex];
-            case AxibugProtobuf.RomPlatformType.GameBoyColor: return App.input.gbc.controllers[mControllerIndex];
-            case AxibugProtobuf.RomPlatformType.ColecoVision: return App.input.cv.controllers[mControllerIndex];
-            case AxibugProtobuf.RomPlatformType.GameGear: return App.input.gg.controllers[mControllerIndex];
-            case AxibugProtobuf.RomPlatformType.Sc3000: return App.input.sc3000.controllers[mControllerIndex];
-            case AxibugProtobuf.RomPlatformType.Sg1000: return App.input.sg1000.controllers[mControllerIndex];
-            default: throw new NotImplementedException("err essgee platform");
-        }
+        return App.settings.KeyMapper.GetBinder<EssgeeKeyBinding>(UEssgee.instance.Platform);
     }
 
     public ulong GetSingleAllInput()
@@ -614,29 +591,19 @@ public class EssgssSingleController : IController
             return 0;
         CurrLocalSingleAllInput = 0;
 
-        SingleKeySettingBase essgeeKeys = GetSingleKeys();
+        EssgeeKeyBinding essgeeKeys = GetKeyMapper();
 
-        if (essgeeKeys.GetKey((ulong)EssgeeSingleKey.UP)) CurrLocalSingleAllInput |= (ulong)tg_UP;
-        if (essgeeKeys.GetKey((ulong)EssgeeSingleKey.DOWN)) CurrLocalSingleAllInput |= (ulong)tg_DOWN;
-        if (essgeeKeys.GetKey((ulong)EssgeeSingleKey.LEFT)) CurrLocalSingleAllInput |= (ulong)tg_LEFT;
-        if (essgeeKeys.GetKey((ulong)EssgeeSingleKey.RIGHT)) CurrLocalSingleAllInput |= (ulong)tg_RIGHT;
-        if (essgeeKeys.GetKey((ulong)EssgeeSingleKey.BTN_1)) CurrLocalSingleAllInput |= (ulong)tg_BTN_1;
-        if (essgeeKeys.GetKey((ulong)EssgeeSingleKey.BTN_2)) CurrLocalSingleAllInput |= (ulong)tg_BTN_2;
-        if (essgeeKeys.GetKey((ulong)EssgeeSingleKey.BTN_3)) CurrLocalSingleAllInput |= (ulong)tg_BTN_3;
-        if (essgeeKeys.GetKey((ulong)EssgeeSingleKey.BTN_4)) CurrLocalSingleAllInput |= (ulong)tg_BTN_4;
-        if (essgeeKeys.GetKey((ulong)EssgeeSingleKey.OPTION_1)) CurrLocalSingleAllInput |= (ulong)tg_OPTION_1;
-        if (essgeeKeys.GetKey((ulong)EssgeeSingleKey.OPTION_2)) CurrLocalSingleAllInput |= (ulong)tg_OPTION_2;
+        if (essgeeKeys.GetKey(EssgeeSingleKey.UP, mControllerIndex)) CurrLocalSingleAllInput |= tg_UP;
+        if (essgeeKeys.GetKey(EssgeeSingleKey.DOWN, mControllerIndex)) CurrLocalSingleAllInput |= tg_DOWN;
+        if (essgeeKeys.GetKey(EssgeeSingleKey.LEFT, mControllerIndex)) CurrLocalSingleAllInput |= tg_LEFT;
+        if (essgeeKeys.GetKey(EssgeeSingleKey.RIGHT, mControllerIndex)) CurrLocalSingleAllInput |= tg_RIGHT;
+        if (essgeeKeys.GetKey(EssgeeSingleKey.BTN_1, mControllerIndex)) CurrLocalSingleAllInput |= tg_BTN_1;
+        if (essgeeKeys.GetKey(EssgeeSingleKey.BTN_2, mControllerIndex)) CurrLocalSingleAllInput |= tg_BTN_2;
+        if (essgeeKeys.GetKey(EssgeeSingleKey.BTN_3, mControllerIndex)) CurrLocalSingleAllInput |= tg_BTN_3;
+        if (essgeeKeys.GetKey(EssgeeSingleKey.BTN_4, mControllerIndex)) CurrLocalSingleAllInput |= tg_BTN_4;
+        if (essgeeKeys.GetKey(EssgeeSingleKey.OPTION_1, mControllerIndex)) CurrLocalSingleAllInput |= tg_OPTION_1;
+        if (essgeeKeys.GetKey(EssgeeSingleKey.OPTION_2, mControllerIndex)) CurrLocalSingleAllInput |= tg_OPTION_2;
 
-        //if (Input.GetKey(UP)) CurrLocalSingleAllInput |= (ulong)tg_UP;
-        //if (Input.GetKey(DOWN)) CurrLocalSingleAllInput |= (ulong)tg_DOWN;
-        //if (Input.GetKey(LEFT)) CurrLocalSingleAllInput |= (ulong)tg_LEFT;
-        //if (Input.GetKey(RIGHT)) CurrLocalSingleAllInput |= (ulong)tg_RIGHT;
-        //if (Input.GetKey(BTN_1)) CurrLocalSingleAllInput |= (ulong)tg_BTN_1;
-        //if (Input.GetKey(BTN_2)) CurrLocalSingleAllInput |= (ulong)tg_BTN_2;
-        //if (Input.GetKey(BTN_3)) CurrLocalSingleAllInput |= (ulong)tg_BTN_3;
-        //if (Input.GetKey(BTN_4)) CurrLocalSingleAllInput |= (ulong)tg_BTN_4;
-        //if (Input.GetKey(OPTION_1)) CurrLocalSingleAllInput |= (ulong)tg_OPTION_1;
-        //if (Input.GetKey(OPTION_2)) CurrLocalSingleAllInput |= (ulong)tg_OPTION_1;
         return CurrLocalSingleAllInput;
     }
 }
@@ -646,7 +613,7 @@ public static class EssgssSingleControllerSetter
 {
     //public static void LoadControlKeyForConfig(this EssgssSingleController singlecontrol)
     //{
-    //    //TODO �ȴ�֧�����ã���ͳһ
+    //    //TODO 等待支持配置,或统一
     //    switch (singlecontrol.ControllerIndex)
     //    {
     //        case 0:
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/MameEmulator/UniInterface/UniKeyboard.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/MameEmulator/UniInterface/UniKeyboard.cs
index 2bec3163..20521e68 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/MameEmulator/UniInterface/UniKeyboard.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/MameEmulator/UniInterface/UniKeyboard.cs
@@ -1,7 +1,7 @@
-using AxibugEmuOnline.Client;
+using AxibugEmuOnline.Client;
 using AxibugEmuOnline.Client.ClientCore;
 using AxibugEmuOnline.Client.Event;
-using AxiInputSP.Setting;
+using AxibugEmuOnline.Client.Settings;
 using AxiReplay;
 using MAME.Core;
 using System;
@@ -25,9 +25,9 @@ public class UniKeyboard : MonoBehaviour, IKeyboard
     public ulong GetPressedKeys()
     {
         ulong InputData;
-        if (!bReplayMode)//����ģʽ��������������
+        if (!bReplayMode)//游玩模式(单机或联机)
             return mPlayMode.GetPressedKeys();
-        else//Replayģʽ
+        else//Replay模式
             return mReplayMode.GetPressedKeys();
     }
 
@@ -82,7 +82,7 @@ public class UniKeyboard : MonoBehaviour, IKeyboard
 
         public bool SampleInput()
         {
-            //Netģʽ
+            //Net模式
             if (InGameUI.Instance.IsNetPlay)
             {
                 bool bHadNetData = false;
@@ -98,15 +98,15 @@ public class UniKeyboard : MonoBehaviour, IKeyboard
 
                     bHadNetData = true;
                 }
-                else//������
+                else//无输入
                 {
                     CurrRemoteInpuAllData = 0;
                 }
-                //���ͱ��ز���
+                //发送本地操作
                 App.roomMgr.SendRoomSingelPlayerInput(UMAME.instance.Frame, DoLocalPressedKeys());
                 return bHadNetData;
             }
-            //����ģʽ
+            //单人模式
             else
             {
                 DoLocalPressedKeys();
@@ -135,7 +135,7 @@ public class UniKeyboard : MonoBehaviour, IKeyboard
 #endif
 
             CurrLocalInpuAllData = tempLocalInputAllData;
-            //�replay
+            //写入replay
             UMAME.instance.mReplayWriter.NextFramebyFrameIdx((int)UMAME.instance.mUniVideoPlayer.mFrame, CurrLocalInpuAllData);
 
             CheckPlayerSlotChanged();
@@ -146,16 +146,16 @@ public class UniKeyboard : MonoBehaviour, IKeyboard
 
         void CheckPlayerSlotChanged()
         {
-            if (!mUniKeyboard.ControllerMapper.Controller0.ConnectSlot.HasValue && mUniKeyboard.ControllerMapper.Controller0.AnyButtonDown()) 
+            if (!mUniKeyboard.ControllerMapper.Controller0.ConnectSlot.HasValue && mUniKeyboard.ControllerMapper.Controller0.AnyButtonDown())
                 Eventer.Instance.PostEvent(EEvent.OnLocalJoyDesireInvert, 0);
 
-            if (!mUniKeyboard.ControllerMapper.Controller1.ConnectSlot.HasValue && mUniKeyboard.ControllerMapper.Controller1.AnyButtonDown()) 
-                Eventer.Instance.PostEvent(EEvent.OnLocalJoyDesireInvert, 1);
-            
-            if (!mUniKeyboard.ControllerMapper.Controller2.ConnectSlot.HasValue && mUniKeyboard.ControllerMapper.Controller2.AnyButtonDown()) 
-                Eventer.Instance.PostEvent(EEvent.OnLocalJoyDesireInvert, 2);
-            
-            if (!mUniKeyboard.ControllerMapper.Controller3.ConnectSlot.HasValue && mUniKeyboard.ControllerMapper.Controller3.AnyButtonDown()) 
+            if (!mUniKeyboard.ControllerMapper.Controller1.ConnectSlot.HasValue && mUniKeyboard.ControllerMapper.Controller1.AnyButtonDown())
+                Eventer.Instance.PostEvent(EEvent.OnLocalJoyDesireInvert, 1);
+
+            if (!mUniKeyboard.ControllerMapper.Controller2.ConnectSlot.HasValue && mUniKeyboard.ControllerMapper.Controller2.AnyButtonDown())
+                Eventer.Instance.PostEvent(EEvent.OnLocalJoyDesireInvert, 2);
+
+            if (!mUniKeyboard.ControllerMapper.Controller3.ConnectSlot.HasValue && mUniKeyboard.ControllerMapper.Controller3.AnyButtonDown())
                 Eventer.Instance.PostEvent(EEvent.OnLocalJoyDesireInvert, 3);
         }
 
@@ -172,7 +172,7 @@ public class UniKeyboard : MonoBehaviour, IKeyboard
         {
             int targetFrame = (int)UMAME.instance.mUniVideoPlayer.mFrame;
             AxiReplay.ReplayStep stepData;
-            //�б仯
+            //有变化
             if (UMAME.instance.mReplayReader.NextFramebyFrameIdx(targetFrame, out stepData))
             {
 #if UNITY_EDITOR
@@ -265,7 +265,7 @@ public class MameControllerMapper : IControllerSetuper
 }
 
 /// <summary>
-/// MAME������
+/// MAME控制器
 /// </summary>
 public class MameSingleConoller : IController
 {
@@ -277,15 +277,16 @@ public class MameSingleConoller : IController
     tg_UP, tg_DOWN, tg_LEFT, tg_RIGHT,
     tg_BTN_A, tg_BTN_B, tg_BTN_C, tg_BTN_D, tg_BTN_E, tg_BTN_F;
 
-    public ulong CurrLocalSingleAllInput { get; private set; }
-
+    public ulong CurrLocalSingleAllInput { get; private set; }
+
+    private MAMEKeyBinding m_keyMapper;
     int mControllerIndex;
     uint? mConnectSlot;
 
     /// <summary>
-    /// ָʾ���ֱ����ӵ��ֱ����
-    /// <para><c>���ֵ�����˸��ֱ���ʵ����Ϸ�п��Ƶ�Player</c></para>
-    /// <value>[0,3] ����:Ϊ�մ���δ����</value>
+    /// 指示该手柄连接的手柄插槽
+    /// <para><c>这个值代表了该手柄在实际游戏中控制的Player</c></para>
+    /// <value>[0,3] 例外:为空代表未连接</value>
     /// </summary>
     public uint? ConnectSlot
     {
@@ -294,26 +295,29 @@ public class MameSingleConoller : IController
     }
 
     /// <summary>
-    /// ���������
-    /// <para><c>�˱�Ų��Ƕ�Ӧ��Ϸ�е�player1,player2,player3,player4,������Ϊ����4���ֱ���ʵ��</c></para>
+    /// 控制器编号
+    /// <para><c>此编号并非对应游戏中的player1,player2,player3,player4,仅仅作为本地4个手柄的实例</c></para>
     /// <value>[0,3]</value>
     /// </summary>
     public int ControllerIndex
     {
         get { return mControllerIndex; }
-        set { mControllerIndex = value; 
-            //this.LoadControlKeyForConfig();
-            //��ͳһ����
+        set
+        {
+            mControllerIndex = value;
+            //this.LoadControlKeyForConfig();
+            //走统一配置
         }
     }
     public MameSingleConoller(int controllerIndex)
     {
         ControllerIndex = controllerIndex;
+        m_keyMapper = App.settings.KeyMapper.GetBinder<MAMEKeyBinding>(UMAME.instance.Platform);
     }
 
     public bool AnyButtonDown()
     {
-        return App.input.mame.HadAnyKeyDown(ControllerIndex);
+        return m_keyMapper.AnyKeyDown(ControllerIndex);
         //if (Input.GetKeyDown(INSERT_COIN)) return true;
         //if (Input.GetKeyDown(GAMESTART)) return true;
         //if (Input.GetKeyDown(UP)) return true;
@@ -334,19 +338,19 @@ public class MameSingleConoller : IController
             return 0;
         CurrLocalSingleAllInput = 0;
 
-        var keys = App.input.mame.controllers[ControllerIndex];
-        if (keys.GetKey((ulong)UMAMEKSingleKey.INSERT_COIN)) CurrLocalSingleAllInput |= (ulong)tg_INSERT_COIN;
-        if (keys.GetKey((ulong)UMAMEKSingleKey.GAMESTART)) CurrLocalSingleAllInput |= (ulong)tg_GAMESTART;
-        if (keys.GetKey((ulong)UMAMEKSingleKey.UP)) CurrLocalSingleAllInput |= (ulong)tg_UP;
-        if (keys.GetKey((ulong)UMAMEKSingleKey.DOWN)) CurrLocalSingleAllInput |= (ulong)tg_DOWN;
-        if (keys.GetKey((ulong)UMAMEKSingleKey.LEFT)) CurrLocalSingleAllInput |= (ulong)tg_LEFT;
-        if (keys.GetKey((ulong)UMAMEKSingleKey.RIGHT)) CurrLocalSingleAllInput |= (ulong)tg_RIGHT;
-        if (keys.GetKey((ulong)UMAMEKSingleKey.BTN_A)) CurrLocalSingleAllInput |= (ulong)tg_BTN_A;
-        if (keys.GetKey((ulong)UMAMEKSingleKey.BTN_B)) CurrLocalSingleAllInput |= (ulong)tg_BTN_B;
-        if (keys.GetKey((ulong)UMAMEKSingleKey.BTN_C)) CurrLocalSingleAllInput |= (ulong)tg_BTN_C;
-        if (keys.GetKey((ulong)UMAMEKSingleKey.BTN_D)) CurrLocalSingleAllInput |= (ulong)tg_BTN_D;
-        if (keys.GetKey((ulong)UMAMEKSingleKey.BTN_E)) CurrLocalSingleAllInput |= (ulong)tg_BTN_E;
-        if (keys.GetKey((ulong)UMAMEKSingleKey.BTN_F)) CurrLocalSingleAllInput |= (ulong)tg_BTN_F;
+
+        if (m_keyMapper.GetKey(UMAMEKSingleKey.INSERT_COIN, ControllerIndex)) CurrLocalSingleAllInput |= (ulong)tg_INSERT_COIN;
+        if (m_keyMapper.GetKey(UMAMEKSingleKey.GAMESTART, ControllerIndex)) CurrLocalSingleAllInput |= (ulong)tg_GAMESTART;
+        if (m_keyMapper.GetKey(UMAMEKSingleKey.UP, ControllerIndex)) CurrLocalSingleAllInput |= (ulong)tg_UP;
+        if (m_keyMapper.GetKey(UMAMEKSingleKey.DOWN, ControllerIndex)) CurrLocalSingleAllInput |= (ulong)tg_DOWN;
+        if (m_keyMapper.GetKey(UMAMEKSingleKey.LEFT, ControllerIndex)) CurrLocalSingleAllInput |= (ulong)tg_LEFT;
+        if (m_keyMapper.GetKey(UMAMEKSingleKey.RIGHT, ControllerIndex)) CurrLocalSingleAllInput |= (ulong)tg_RIGHT;
+        if (m_keyMapper.GetKey(UMAMEKSingleKey.BTN_A, ControllerIndex)) CurrLocalSingleAllInput |= (ulong)tg_BTN_A;
+        if (m_keyMapper.GetKey(UMAMEKSingleKey.BTN_B, ControllerIndex)) CurrLocalSingleAllInput |= (ulong)tg_BTN_B;
+        if (m_keyMapper.GetKey(UMAMEKSingleKey.BTN_C, ControllerIndex)) CurrLocalSingleAllInput |= (ulong)tg_BTN_C;
+        if (m_keyMapper.GetKey(UMAMEKSingleKey.BTN_D, ControllerIndex)) CurrLocalSingleAllInput |= (ulong)tg_BTN_D;
+        if (m_keyMapper.GetKey(UMAMEKSingleKey.BTN_E, ControllerIndex)) CurrLocalSingleAllInput |= (ulong)tg_BTN_E;
+        if (m_keyMapper.GetKey(UMAMEKSingleKey.BTN_F, ControllerIndex)) CurrLocalSingleAllInput |= (ulong)tg_BTN_F;
 
         //if (Input.GetKey(INSERT_COIN)) CurrLocalSingleAllInput |= (ulong)tg_INSERT_COIN;
         //if (Input.GetKey(GAMESTART)) CurrLocalSingleAllInput |= (ulong)tg_GAMESTART;
@@ -367,10 +371,10 @@ public class MameSingleConoller : IController
 }
 public static class MameSingleControllSetter
 {
-    //������Ҫ
+    //不再需要
     //public static void LoadControlKeyForConfig(this MameSingleConoller singlecontrol)
     //{
-    //    //TODO �ȴ�֧�����ã���ͳһ
+    //    //TODO 等待支持配置,或统一
     //    switch (singlecontrol.ControllerIndex)
     //    {
     //        case 0:
@@ -456,7 +460,7 @@ public static class MameSingleControllSetter
                 singlecontrol.tg_BTN_E = MotionKey.P2_BTN_5;
                 singlecontrol.tg_BTN_F = MotionKey.P2_BTN_6;
                 break;
-            //�����޸ĺ� ֧��P3 P4
+            //后续修改后 支持P3 P4
             case 2:
                 singlecontrol.tg_INSERT_COIN = MotionKey.FinalKey;
                 singlecontrol.tg_GAMESTART = MotionKey.FinalKey;
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/NesEmulator/NesControllerMapper.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/NesEmulator/NesControllerMapper.cs
index c50b8f8b..5996a724 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/NesEmulator/NesControllerMapper.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/NesEmulator/NesControllerMapper.cs
@@ -1,7 +1,9 @@
 using AxibugEmuOnline.Client.ClientCore;
 using AxibugEmuOnline.Client.Common;
 using AxibugEmuOnline.Client.Event;
+using AxibugEmuOnline.Client.Settings;
 using NUnit.Framework.Internal;
+using System;
 using System.Collections.Generic;
 using System.Linq;
 using UnityEngine;
@@ -98,16 +100,7 @@ namespace AxibugEmuOnline.Client
                 case 3: targetController = Controller3; break;
                 default:
                     throw new System.Exception($"Not Allowed conIndex Range: {conIndex}");
-                    break;
             }
-            //var targetController = conIndex switch
-            //{
-            //    0 => Controller0,
-            //    1 => Controller1,
-            //    2 => Controller2,
-            //    3 => Controller3,
-            //    _ => throw new System.Exception($"Not Allowed conIndex Range: {conIndex}")
-            //};
 
             if (targetController.ConnectSlot.HasValue) return;
 
@@ -121,6 +114,7 @@ namespace AxibugEmuOnline.Client
         /// </summary>
         public class Controller : IController
         {
+            static Lazy<NesKeyBinding> s_keyBinder = new Lazy<NesKeyBinding>(() => App.settings.KeyMapper.GetBinder<NesKeyBinding>());
             /// <summary>
             /// 控制器编号
             /// <para><c>此编号并非对应游戏中的player1,player2,player3,player4,仅仅作为本地4个手柄的实例</c></para>
@@ -135,260 +129,32 @@ namespace AxibugEmuOnline.Client
             /// </summary>
             public uint? ConnectSlot { get; set; }
 
-            //public Button UP { get; }
-            //public Button DOWN { get; }
-            //public Button LEFT { get; }
-            //public Button RIGHT { get; }
-            //public Button A { get; }
-            //public Button B { get; }
-            //public Button SELECT { get; }
-            //public Button START { get; }
-            //public Button MIC { get; }
-
             public Controller(int controllerIndex)
             {
                 ControllerIndex = controllerIndex;
-                //UP = new Button(this, EnumButtonType.UP);
-                //DOWN = new Button(this, EnumButtonType.DOWN);
-                //LEFT = new Button(this, EnumButtonType.LEFT);
-                //RIGHT = new Button(this, EnumButtonType.RIGHT);
-                //A = new Button(this, EnumButtonType.A);
-                //B = new Button(this, EnumButtonType.B);
-                //SELECT = new Button(this, EnumButtonType.SELECT);
-                //START = new Button(this, EnumButtonType.START);
-                //MIC = new Button(this, EnumButtonType.MIC);
             }
 
             public EnumButtonType GetButtons()
             {
                 EnumButtonType res = 0;
-
-                if(App.input.nes.controllers[ControllerIndex].GetKey((ulong)EnumButtonType.UP)) res |= EnumButtonType.UP;
-                if(App.input.nes.controllers[ControllerIndex].GetKey((ulong)EnumButtonType.DOWN)) res |= EnumButtonType.DOWN;
-                if(App.input.nes.controllers[ControllerIndex].GetKey((ulong)EnumButtonType.LEFT)) res |= EnumButtonType.LEFT;
-                if(App.input.nes.controllers[ControllerIndex].GetKey((ulong)EnumButtonType.RIGHT)) res |= EnumButtonType.RIGHT;
-                if(App.input.nes.controllers[ControllerIndex].GetKey((ulong)EnumButtonType.A)) res |= EnumButtonType.A;
-                if(App.input.nes.controllers[ControllerIndex].GetKey((ulong)EnumButtonType.B)) res |= EnumButtonType.B;
-                if(App.input.nes.controllers[ControllerIndex].GetKey((ulong)EnumButtonType.SELECT)) res |= EnumButtonType.SELECT;
-                if(App.input.nes.controllers[ControllerIndex].GetKey((ulong)EnumButtonType.START)) res |= EnumButtonType.START;
-                if(App.input.nes.controllers[ControllerIndex].GetKey((ulong)EnumButtonType.MIC)) res |= EnumButtonType.MIC;
-
-                //res |= UP.SampleKey();
-                //res |= DOWN.SampleKey();
-                //res |= LEFT.SampleKey();
-                //res |= RIGHT.SampleKey();
-                //res |= A.SampleKey();
-                //res |= B.SampleKey();
-                //res |= SELECT.SampleKey();
-                //res |= START.SampleKey();
-                //res |= MIC.SampleKey();
+                if (s_keyBinder.Value.GetKey(EnumButtonType.UP, ControllerIndex)) res |= EnumButtonType.UP;
+                if (s_keyBinder.Value.GetKey(EnumButtonType.DOWN, ControllerIndex)) res |= EnumButtonType.DOWN;
+                if (s_keyBinder.Value.GetKey(EnumButtonType.LEFT, ControllerIndex)) res |= EnumButtonType.LEFT;
+                if (s_keyBinder.Value.GetKey(EnumButtonType.RIGHT, ControllerIndex)) res |= EnumButtonType.RIGHT;
+                if (s_keyBinder.Value.GetKey(EnumButtonType.A, ControllerIndex)) res |= EnumButtonType.A;
+                if (s_keyBinder.Value.GetKey(EnumButtonType.B, ControllerIndex)) res |= EnumButtonType.B;
+                if (s_keyBinder.Value.GetKey(EnumButtonType.SELECT, ControllerIndex)) res |= EnumButtonType.SELECT;
+                if (s_keyBinder.Value.GetKey(EnumButtonType.START, ControllerIndex)) res |= EnumButtonType.START;
+                if (s_keyBinder.Value.GetKey(EnumButtonType.MIC, ControllerIndex)) res |= EnumButtonType.MIC;
 
                 return res;
             }
 
             public bool AnyButtonDown()
             {
-                return App.input.nes.controllers[ControllerIndex].HadAnyKeyDown();
-                //return
-                //    UP.IsDown ||
-                //    DOWN.IsDown ||
-                //    LEFT.IsDown ||
-                //    RIGHT.IsDown ||
-                //    A.IsDown ||
-                //    B.IsDown ||
-                //    SELECT.IsDown ||
-                //    START.IsDown ||
-                //    MIC.IsDown;
+                return s_keyBinder.Value.AnyKeyDown(ControllerIndex);
             }
 
-            //public static KeyListener GetKey(int controllerInput, EnumButtonType nesConBtnType)
-            //{
-            //    string configKey = $"NES_{controllerInput}_{nesConBtnType}";
-
-            //    //PSV平台固定键值
-            //    if (UnityEngine.Application.platform == RuntimePlatform.PSP2)
-            //    {
-            //        return KeyListener.GetPSVitaKey(controllerInput, nesConBtnType);
-            //    }
-
-            //    if (PlayerPrefs.HasKey(configKey))
-            //    {
-            //        return new KeyListener(PlayerPrefs.GetString(configKey));
-            //    }
-            //    else
-            //    {
-            //        var defaultKeyCode = KeyListener.GetDefaultKey(controllerInput, nesConBtnType);
-            //        PlayerPrefs.SetString(configKey, defaultKeyCode.ToString());
-            //        return defaultKeyCode;
-            //    }
-            //}
         }
-
-        ///// <summary>
-        ///// NES控制器按键类
-        ///// </summary>
-        //public class Button
-        //{
-        //    /// <summary> 所属控制器 </summary>
-        //    readonly Controller m_hostController;
-
-        //    /// <summary> 按键 </summary>
-        //    readonly EnumButtonType m_buttonType;
-
-        //    /// <summary> 按键监听器 </summary>
-        //    KeyListener m_keyListener;
-
-        //    /// <summary> 指示按钮是否正在按下状态 </summary>
-        //    public bool IsPressing => m_keyListener.IsPressing();
-        //    /// <summary> 指示按钮是否被按下 </summary>
-        //    public bool IsDown => m_keyListener.IsDown();
-
-        //    public Button(Controller controller, EnumButtonType buttonType)
-        //    {
-        //        m_hostController = controller;
-        //        m_buttonType = buttonType;
-
-        //        CreateListener();
-        //    }
-
-        //    /// <summary>
-        //    /// 采集按钮按下状态
-        //    /// </summary>
-        //    /// <returns></returns>
-        //    public EnumButtonType SampleKey()
-        //    {
-        //        return IsPressing ? m_buttonType : 0;
-        //    }
-
-        //    private void CreateListener()
-        //    {
-        //        m_keyListener = Controller.GetKey(m_hostController.ControllerIndex, m_buttonType);
-        //    }
-        //}
-        //low C# readonly
-        //public readonly struct KeyListener
-
-        //public struct KeyListener
-        //{
-        //    private readonly KeyCode m_key;
-
-        //    public KeyListener(KeyCode key)
-        //    {
-        //        m_key = key;
-        //    }
-
-        //    /// <summary> 从配置字符串构建 </summary>
-        //    public KeyListener(string confStr)
-        //    {
-        //        m_key = KeyCode.None;
-
-        //        int result;
-        //        if (int.TryParse(confStr, out result))
-        //            m_key = (KeyCode)result;
-        //    }
-
-        //    public bool IsPressing()
-        //    {
-        //        return Input.GetKey(m_key);
-        //    }
-        //    public bool IsDown()
-        //    {
-        //        return Input.GetKeyDown(m_key);
-        //    }
-
-        //    public override string ToString()
-        //    {
-        //        return ((int)(m_key)).ToString();
-        //    }
-
-        //    public static KeyListener GetDefaultKey(int controllerIndex, EnumButtonType nesConBtnType)
-        //    {
-        //        switch (controllerIndex)
-        //        {
-        //            case 0:
-        //                switch (nesConBtnType)
-        //                {
-        //                    case EnumButtonType.LEFT:
-        //                        return new KeyListener(KeyCode.A);
-        //                    case EnumButtonType.RIGHT:
-        //                        return new KeyListener(KeyCode.D);
-        //                    case EnumButtonType.UP:
-        //                        return new KeyListener(KeyCode.W);
-        //                    case EnumButtonType.DOWN:
-        //                        return new KeyListener(KeyCode.S);
-        //                    case EnumButtonType.START:
-        //                        return new KeyListener(KeyCode.B);
-        //                    case EnumButtonType.SELECT:
-        //                        return new KeyListener(KeyCode.V);
-        //                    case EnumButtonType.A:
-        //                        return new KeyListener(KeyCode.K);
-        //                    case EnumButtonType.B:
-        //                        return new KeyListener(KeyCode.J);
-        //                    case EnumButtonType.MIC:
-        //                        return new KeyListener(KeyCode.M);
-        //                }
-
-        //                break;
-        //            case 1:
-        //                switch (nesConBtnType)
-        //                {
-        //                    case EnumButtonType.LEFT:
-        //                        return new KeyListener(KeyCode.Delete);
-        //                    case EnumButtonType.RIGHT:
-        //                        return new KeyListener(KeyCode.PageDown);
-        //                    case EnumButtonType.UP:
-        //                        return new KeyListener(KeyCode.Home);
-        //                    case EnumButtonType.DOWN:
-        //                        return new KeyListener(KeyCode.End);
-        //                    case EnumButtonType.START:
-        //                        return new KeyListener(KeyCode.PageUp);
-        //                    case EnumButtonType.SELECT:
-        //                        return new KeyListener(KeyCode.Insert);
-        //                    case EnumButtonType.A:
-        //                        return new KeyListener(KeyCode.Keypad5);
-        //                    case EnumButtonType.B:
-        //                        return new KeyListener(KeyCode.Keypad4);
-        //                    case EnumButtonType.MIC:
-        //                        return new KeyListener(KeyCode.KeypadPeriod);
-        //                }
-
-        //                break;
-        //        }
-
-        //        return default(KeyListener);
-        //    }
-
-
-        //    //public static KeyListener GetPSVitaKey(int controllerIndex, EnumButtonType nesConBtnType)
-        //    //{
-        //    //    switch (controllerIndex)
-        //    //    {
-        //    //        case 0:
-        //    //            switch (nesConBtnType)
-        //    //            {
-        //    //                case EnumButtonType.LEFT:
-        //    //                    return new KeyListener(PSVitaKey.Left);
-        //    //                case EnumButtonType.RIGHT:
-        //    //                    return new KeyListener(PSVitaKey.Right);
-        //    //                case EnumButtonType.UP:
-        //    //                    return new KeyListener(PSVitaKey.Up);
-        //    //                case EnumButtonType.DOWN:
-        //    //                    return new KeyListener(PSVitaKey.Down);
-        //    //                case EnumButtonType.START:
-        //    //                    return new KeyListener(PSVitaKey.Start);
-        //    //                case EnumButtonType.SELECT:
-        //    //                    return new KeyListener(PSVitaKey.Select);
-        //    //                case EnumButtonType.A:
-        //    //                    return new KeyListener(PSVitaKey.Circle);
-        //    //                case EnumButtonType.B:
-        //    //                    return new KeyListener(PSVitaKey.Cross);
-        //    //                case EnumButtonType.MIC:
-        //    //                    return new KeyListener(PSVitaKey.Block);
-        //    //            }
-        //    //            break;
-        //    //    }
-        //    //    return default(KeyListener);
-        //    //}
-        //}
     }
 }
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Event/EventInvoker.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Event/EventInvoker.cs
index 7f28e47e..3d9d1516 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Event/EventInvoker.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Event/EventInvoker.cs
@@ -1,3 +1,5 @@
+using AxibugEmuOnline.Client.Settings;
+
 namespace AxibugEmuOnline.Client
 {
     public static class EventInvoker
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/IkeyMapperChanger/CommandChanger.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/IkeyMapperChanger/CommandChanger.cs
deleted file mode 100644
index 1b183452..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/IkeyMapperChanger/CommandChanger.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using AxibugEmuOnline.Client.Manager;
-using System.Collections.Generic;
-
-namespace AxibugEmuOnline.Client
-{
-    public abstract class CommandChanger : IKeyMapperChanger
-    {
-        public string Name => GetType().Name;
-        public abstract EnumCommand[] GetConfig();
-
-        public abstract SingleKeysSetting GetKeySetting();
-    }
-}
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/IkeyMapperChanger/CommandChanger.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/IkeyMapperChanger/CommandChanger.cs.meta
deleted file mode 100644
index 8739d086..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/IkeyMapperChanger/CommandChanger.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: c29cb72b155d20a48a3a47a7a05160bd
-MonoImporter:
-  externalObjects: {}
-  serializedVersion: 2
-  defaultReferences: []
-  executionOrder: 0
-  icon: {instanceID: 0}
-  userData: 
-  assetBundleName: 
-  assetBundleVariant: 
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/IkeyMapperChanger/GamingChanger.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/IkeyMapperChanger/GamingChanger.cs
deleted file mode 100644
index 0029e267..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/IkeyMapperChanger/GamingChanger.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-using AxibugEmuOnline.Client.ClientCore;
-using AxibugEmuOnline.Client.Manager;
-
-namespace AxibugEmuOnline.Client
-{
-    public class GamingChanger : CommandChanger
-    {
-        public override EnumCommand[] GetConfig()
-        {
-            return App.input.gaming.controllers[0].GetAllCmd<EnumCommand>();
-        }
-
-        public override SingleKeysSetting GetKeySetting()
-        {
-            return App.input.gaming.controllers[0];
-        }
-
-        //Dictionary<KeyCode, EnumCommand> m_uiKeyMapper = new Dictionary<KeyCode, EnumCommand>();
-        //public GamingChanger()
-        //{
-        //    m_uiKeyMapper[KeyCode.Escape] = EnumCommand.OptionMenu;
-
-        //    if (Application.platform == RuntimePlatform.PSP2)
-        //    {
-        //        m_uiKeyMapper[Common.PSVitaKey.L] = EnumCommand.OptionMenu;
-        //        m_uiKeyMapper[Common.PSVitaKey.R] = EnumCommand.OptionMenu;
-        //    }
-
-        //    //PC XBOX
-        //    m_uiKeyMapper[Common.PC_XBOXKEY.Y] = EnumCommand.OptionMenu;
-        //}
-
-        //public override object GetConfig() => m_uiKeyMapper;
-    }
-}
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/IkeyMapperChanger/GamingChanger.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/IkeyMapperChanger/GamingChanger.cs.meta
deleted file mode 100644
index 014e1117..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/IkeyMapperChanger/GamingChanger.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: c8339ffab20bfea4cbc7d3aa440c3fdb
-MonoImporter:
-  externalObjects: {}
-  serializedVersion: 2
-  defaultReferences: []
-  executionOrder: 0
-  icon: {instanceID: 0}
-  userData: 
-  assetBundleName: 
-  assetBundleVariant: 
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/IkeyMapperChanger/NormalChanger.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/IkeyMapperChanger/NormalChanger.cs
deleted file mode 100644
index bba6c35f..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/IkeyMapperChanger/NormalChanger.cs
+++ /dev/null
@@ -1,64 +0,0 @@
-using AxibugEmuOnline.Client.ClientCore;
-using AxibugEmuOnline.Client.Manager;
-
-namespace AxibugEmuOnline.Client
-{
-
-    public class NormalChanger : CommandChanger
-    {
-        public override EnumCommand[] GetConfig()
-        {
-            return App.input.xmb.controllers[0].GetAllCmd<EnumCommand>();
-        }
-
-        public override SingleKeysSetting GetKeySetting()
-        {
-            return App.input.xmb.controllers[0];
-        }
-
-        //Dictionary<KeyCode, EnumCommand> m_uiKeyMapper = new Dictionary<KeyCode, EnumCommand>();
-        //public NormalChanger()
-        //{
-        //    m_uiKeyMapper[KeyCode.A] = EnumCommand.SelectItemLeft;
-        //    m_uiKeyMapper[KeyCode.D] = EnumCommand.SelectItemRight;
-        //    m_uiKeyMapper[KeyCode.W] = EnumCommand.SelectItemUp;
-        //    m_uiKeyMapper[KeyCode.S] = EnumCommand.SelectItemDown;
-        //    m_uiKeyMapper[KeyCode.K] = EnumCommand.Enter;
-        //    m_uiKeyMapper[KeyCode.L] = EnumCommand.Back;
-        //    m_uiKeyMapper[KeyCode.I] = EnumCommand.OptionMenu;
-
-        //    m_uiKeyMapper[KeyCode.LeftArrow] = EnumCommand.SelectItemLeft;
-        //    m_uiKeyMapper[KeyCode.RightArrow] = EnumCommand.SelectItemRight;
-        //    m_uiKeyMapper[KeyCode.UpArrow] = EnumCommand.SelectItemUp;
-        //    m_uiKeyMapper[KeyCode.DownArrow] = EnumCommand.SelectItemDown;
-        //    m_uiKeyMapper[KeyCode.Return] = EnumCommand.Enter;
-        //    m_uiKeyMapper[KeyCode.Escape] = EnumCommand.Back;
-        //    m_uiKeyMapper[KeyCode.RightShift] = EnumCommand.OptionMenu;
-        //    m_uiKeyMapper[KeyCode.LeftShift] = EnumCommand.OptionMenu;
-
-        //    if (Application.platform == RuntimePlatform.PSP2)
-        //    {
-        //        m_uiKeyMapper[Common.PSVitaKey.Left] = EnumCommand.SelectItemLeft;
-        //        m_uiKeyMapper[Common.PSVitaKey.Right] = EnumCommand.SelectItemRight;
-        //        m_uiKeyMapper[Common.PSVitaKey.Up] = EnumCommand.SelectItemUp;
-        //        m_uiKeyMapper[Common.PSVitaKey.Down] = EnumCommand.SelectItemDown;
-        //        m_uiKeyMapper[Common.PSVitaKey.Circle] = EnumCommand.Enter;
-        //        m_uiKeyMapper[Common.PSVitaKey.Cross] = EnumCommand.Back;
-        //        m_uiKeyMapper[Common.PSVitaKey.Triangle] = EnumCommand.OptionMenu;
-        //    }
-
-        //    //PC XBOX
-
-        //    //m_uiKeyMapper[Common.PC_XBOXKEY.Left] = EnumCommand.SelectItemLeft;
-        //    //m_uiKeyMapper[Common.PSVitaKey.Right] = EnumCommand.SelectItemRight;
-        //    //m_uiKeyMapper[Common.PSVitaKey.Up] = EnumCommand.SelectItemUp;
-        //    //m_uiKeyMapper[Common.PSVitaKey.Down] = EnumCommand.SelectItemDown;
-        //    m_uiKeyMapper[Common.PC_XBOXKEY.MenuBtn] = EnumCommand.Enter;
-        //    m_uiKeyMapper[Common.PC_XBOXKEY.ViewBtn] = EnumCommand.Back;
-        //    m_uiKeyMapper[Common.PC_XBOXKEY.Y] = EnumCommand.OptionMenu;
-        //}
-
-        //public override object GetConfig() => m_uiKeyMapper;
-    }
-
-}
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/IkeyMapperChanger/NormalChanger.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/IkeyMapperChanger/NormalChanger.cs.meta
deleted file mode 100644
index 2740c3f1..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/IkeyMapperChanger/NormalChanger.cs.meta
+++ /dev/null
@@ -1,11 +0,0 @@
-fileFormatVersion: 2
-guid: b8790f215d873d044aa8d00bacdee237
-MonoImporter:
-  externalObjects: {}
-  serializedVersion: 2
-  defaultReferences: []
-  executionOrder: 0
-  icon: {instanceID: 0}
-  userData: 
-  assetBundleName: 
-  assetBundleVariant: 
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppEmu.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppEmu.cs
index f92e144d..a46290aa 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppEmu.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppEmu.cs
@@ -83,7 +83,7 @@ namespace AxibugEmuOnline.Client.Manager
                 LaunchUI.Instance.HideMainMenu();
                 InGameUI.Instance.Show(romFile, m_emuCore);
 
-                CommandDispatcher.Instance.Current = CommandDispatcher.Instance.Gaming;
+                CommandDispatcher.Instance.Mode = CommandListener.ScheduleType.Gaming;
 
                 m_controllerSetuper = m_emuCore.GetControllerSetuper();
 
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppInput.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppInput.cs
deleted file mode 100644
index 1bde885a..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppInput.cs
+++ /dev/null
@@ -1,179 +0,0 @@
-using AxibugEmuOnline.Client.Common;
-using AxiInputSP;
-using AxiInputSP.Setting;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-namespace AxibugEmuOnline.Client.Manager
-{
-    public class AppInput
-    {
-        public XMBMultiKeysSetting xmb;
-        public GamingMultiKeysSetting gaming;
-        public UMAMEMultiKeysSetting mame;
-        public NESMultiKeysSetting nes;
-        public MasterSystemMultiKeysSetting sms;
-        public ColecoVisionMultiKeysSetting cv;
-        public GameBoyColorMultiKeysSetting gbc;
-        public GameBoyMultiKeysSetting gb;
-        public GameGearMultiKeysSetting gg;
-        public SC3000MultiKeysSetting sc3000;
-        public SG1000MultiKeysSetting sg1000;
-        public AppInput()
-        {
-            xmb = new XMBMultiKeysSetting();
-            gaming = new GamingMultiKeysSetting();
-            mame = new UMAMEMultiKeysSetting();
-            nes = new NESMultiKeysSetting();
-            sms = new MasterSystemMultiKeysSetting();
-            cv = new ColecoVisionMultiKeysSetting();
-            gbc = new GameBoyColorMultiKeysSetting();
-            gb = new GameBoyMultiKeysSetting();
-            gg = new GameGearMultiKeysSetting();
-            sc3000 = new SC3000MultiKeysSetting();
-            sg1000 = new SG1000MultiKeysSetting();
-            LoadDefaultSetting();
-        }
-
-        public void LoadDefaultSetting()
-        {
-            xmb.LoadDefaultSetting();
-            gaming.LoadDefaultSetting();
-            mame.LoadDefaultSetting();
-            nes.LoadDefaultSetting();
-            sms.LoadDefaultSetting();
-            cv.LoadDefaultSetting();
-            gbc.LoadDefaultSetting();
-            gb.LoadDefaultSetting();
-            gg.LoadDefaultSetting();
-            sc3000.LoadDefaultSetting();
-            sg1000.LoadDefaultSetting();
-        }
-    }
-
-    public interface MultiKeysSetting
-    {
-        bool HadAnyKeyDown(int index);
-        void ClearAll();
-        void LoadDefaultSetting();
-    }
-    public interface SingleKeysSetting
-    {
-        void ClearAll();
-        void SetKey(ulong Key, AxiInput input);
-        bool GetKey(ulong Key);
-        bool GetKeyDown(ulong Key);
-        bool GetKeyUp(ulong Key);
-        void ColletAllKey();
-        bool HadAnyKeyDown();
-    }
-
-    public abstract class MultiKeysSettingBase : MultiKeysSetting
-    {
-        public SingleKeySettingBase[] controllers;
-
-        public bool HadAnyKeyDown(int index)
-        {
-            if (index >= controllers.Length)
-                return false;
-            return controllers[index].HadAnyKeyDown();
-        }
-        public void ClearAll()
-        {
-            for (int i = 0; i < controllers.Length; i++)
-                controllers[i].ClearAll();
-        }
-
-        public abstract void LoadDefaultSetting();
-    }
-
-
-    public abstract class SingleKeySettingBase : SingleKeysSetting
-    {
-        protected Dictionary<ulong, List<AxiInput>> mDictSkey2AxiInput = new Dictionary<ulong, List<AxiInput>>();
-        protected AxiInput[] AxiInputArr = null;
-
-        public void SetKey(ulong Key, AxiInput input)
-        {
-            List<AxiInput> list;
-            if (!mDictSkey2AxiInput.TryGetValue(Key, out list))
-                list = mDictSkey2AxiInput[Key] = ObjectPoolAuto.AcquireList<AxiInput>();
-            list.Add(input);
-        }
-
-        public bool GetKey(ulong Key)
-        {
-            List<AxiInput> list;
-            if (!mDictSkey2AxiInput.TryGetValue(Key, out list))
-                return false;
-            for (int i = 0; i < list.Count; i++)
-            {
-                if (list[i].GetKey())
-                    return true;
-            }
-            return false;
-        }
-        public bool GetKeyUp(ulong Key)
-        {
-            List<AxiInput> list;
-            if (!mDictSkey2AxiInput.TryGetValue(Key, out list))
-                return false;
-            for (int i = 0; i < list.Count; i++)
-            {
-                if (list[i].GetKeyUp())
-                    return true;
-            }
-            return false;
-        }
-
-        public bool GetKeyDown(ulong Key)
-        {
-            List<AxiInput> list;
-            if (!mDictSkey2AxiInput.TryGetValue(Key, out list))
-                return false;
-            for (int i = 0; i < list.Count; i++)
-            {
-                if (list[i].GetKeyDown())
-                    return true;
-            }
-            return false;
-        }
-
-        public void ClearAll()
-        {
-            foreach (List<AxiInput> singlelist in mDictSkey2AxiInput.Values)
-                ObjectPoolAuto.Release(singlelist);
-            mDictSkey2AxiInput.Clear();
-            AxiInputArr = null;
-        }
-
-        public void ColletAllKey()
-        {
-            List<AxiInput> list = ObjectPoolAuto.AcquireList<AxiInput>();
-            foreach (List<AxiInput> singlelist in mDictSkey2AxiInput.Values)
-                list.AddRange(singlelist);
-            AxiInputArr = list.ToArray();
-            ObjectPoolAuto.Release(list);
-        }
-
-        public bool HadAnyKeyDown()
-        {
-            if (AxiInputArr == null)
-                return false;
-
-            for (int i = 0; i < AxiInputArr.Length; i++)
-            {
-                if (AxiInputArr[i].GetKey())
-                    return true;
-            }
-            return false;
-        }
-
-        public T[] GetAllCmd<T>()
-        {
-            return mDictSkey2AxiInput.Keys.Select(k => (T)Enum.ToObject(typeof(T), k)).ToArray();
-        }
-    }
-
-}
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppInput.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppInput.cs.meta
deleted file mode 100644
index 496e3f97..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppInput.cs.meta
+++ /dev/null
@@ -1,2 +0,0 @@
-fileFormatVersion: 2
-guid: 5c0bc1cf4f411aa4da3ffa218db2c2aa
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/AppSettings.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/AppSettings.cs
index 785b02d2..6cd99397 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/AppSettings.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/AppSettings.cs
@@ -1,4 +1,6 @@
-namespace AxibugEmuOnline.Client
+using AxibugEmuOnline.Client.Settings;
+
+namespace AxibugEmuOnline.Client
 {
     public class AppSettings
     {
@@ -7,13 +9,16 @@
         /// <summary> 滤镜设置 </summary>
         public FilterManager Filter { get; private set; }
         /// <summary> 画面比例设置 </summary>
-        public ScreenScaler ScreenScaler { get; private set; }
-
+        public ScreenScaler ScreenScaler { get; private set; }
+        /// <summary> 键位设置 </summary>
+        public KeyMapperSetting KeyMapper { get; private set; }
+
         public AppSettings()
         {
             BgColor = new BgColorSettings();
             Filter = new FilterManager();
             ScreenScaler = new ScreenScaler();
+            KeyMapper = new KeyMapperSetting();
         }
     }
 }
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/BgColorSettings.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/BgColorSettings.cs
index 14888817..5e5d59d1 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/BgColorSettings.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/BgColorSettings.cs
@@ -1,7 +1,7 @@
 using System.Collections.Generic;
 using UnityEngine;
 
-namespace AxibugEmuOnline.Client
+namespace AxibugEmuOnline.Client.Settings
 {
     /// <summary> 颜色设置 </summary>
     public class BgColorSettings
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/Filter/FilterManager.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/Filter/FilterManager.cs
index 325ca0b1..7c54a037 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/Filter/FilterManager.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/Filter/FilterManager.cs
@@ -8,7 +8,7 @@ using UnityEngine;
 using UnityEngine.UI;
 using static AxibugEmuOnline.Client.FilterEffect;
 
-namespace AxibugEmuOnline.Client
+namespace AxibugEmuOnline.Client.Settings
 {
     public class FilterManager
     {
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting.meta
similarity index 77%
rename from AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings.meta
rename to AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting.meta
index a924eaef..4cdc4aeb 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings.meta
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: 91746af636f351140a4796dc4e98be6d
+guid: 7c4a24e114240814a8587e2f90a2f6f0
 folderAsset: yes
 DefaultImporter:
   externalObjects: {}
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/EssgeeKeyBinding.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/EssgeeKeyBinding.cs
new file mode 100644
index 00000000..8e859bd7
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/EssgeeKeyBinding.cs
@@ -0,0 +1,192 @@
+using AxibugEmuOnline.Client.InputDevices;
+using AxibugProtobuf;
+using System;
+
+namespace AxibugEmuOnline.Client.Settings
+{
+    [Flags]
+    public enum EssgeeSingleKey : ushort
+    {
+        NONE = 0,
+        UP = 1,
+        DOWN = 1 << 1,
+        LEFT = 1 << 2,
+        RIGHT = 1 << 3,
+        BTN_1 = 1 << 4,
+        BTN_2 = 1 << 5,
+        BTN_3 = 1 << 6,
+        BTN_4 = 1 << 7,
+        OPTION_1 = 1 << 8,
+        OPTION_2 = 1 << 9,
+    }
+
+    public abstract class EssgeeKeyBinding : EmuCoreBinder<EssgeeSingleKey>
+    {
+        public override void Bind(Keyboard_D device, ControllerBinder controller)
+        {
+            switch (controller.ControllerIndex)
+            {
+                case 0:
+                    controller.SetBinding(EssgeeSingleKey.OPTION_1, device.Return, 0);
+                    controller.SetBinding(EssgeeSingleKey.OPTION_2, device.RightShift, 0);
+                    controller.SetBinding(EssgeeSingleKey.UP, device.W, 0);
+                    controller.SetBinding(EssgeeSingleKey.DOWN, device.S, 0);
+                    controller.SetBinding(EssgeeSingleKey.LEFT, device.A, 0);
+                    controller.SetBinding(EssgeeSingleKey.RIGHT, device.D, 0);
+                    controller.SetBinding(EssgeeSingleKey.BTN_1, device.J, 0);
+                    controller.SetBinding(EssgeeSingleKey.BTN_2, device.K, 0);
+                    controller.SetBinding(EssgeeSingleKey.BTN_3, device.U, 0);
+                    controller.SetBinding(EssgeeSingleKey.BTN_4, device.I, 0);
+                    break;
+                case 1:
+                    controller.SetBinding(EssgeeSingleKey.OPTION_1, device.Keypad0, 0);
+                    controller.SetBinding(EssgeeSingleKey.OPTION_2, device.Delete, 0);
+                    controller.SetBinding(EssgeeSingleKey.UP, device.UpArrow, 0);
+                    controller.SetBinding(EssgeeSingleKey.DOWN, device.DownArrow, 0);
+                    controller.SetBinding(EssgeeSingleKey.LEFT, device.LeftArrow, 0);
+                    controller.SetBinding(EssgeeSingleKey.RIGHT, device.RightArrow, 0);
+                    controller.SetBinding(EssgeeSingleKey.BTN_1, device.Keypad1, 0);
+                    controller.SetBinding(EssgeeSingleKey.BTN_2, device.Keypad2, 0);
+                    controller.SetBinding(EssgeeSingleKey.BTN_3, device.Keypad3, 0);
+                    controller.SetBinding(EssgeeSingleKey.BTN_4, device.Keypad4, 0);
+                    break;
+            }
+        }
+        public override void Bind(PSVController_D device, ControllerBinder controller)
+        {
+            switch (controller.ControllerIndex)
+            {
+                case 0:
+                    controller.SetBinding(EssgeeSingleKey.OPTION_1, device.Start, 0);
+                    controller.SetBinding(EssgeeSingleKey.OPTION_2, device.Select, 0);
+                    controller.SetBinding(EssgeeSingleKey.UP, device.Up, 0);
+                    controller.SetBinding(EssgeeSingleKey.DOWN, device.Down, 0);
+                    controller.SetBinding(EssgeeSingleKey.LEFT, device.Left, 0);
+                    controller.SetBinding(EssgeeSingleKey.RIGHT, device.Right, 0);
+                    controller.SetBinding(EssgeeSingleKey.BTN_1, device.Cross, 0);
+                    controller.SetBinding(EssgeeSingleKey.BTN_2, device.Circle, 0);
+                    controller.SetBinding(EssgeeSingleKey.BTN_3, device.Square, 0);
+                    controller.SetBinding(EssgeeSingleKey.BTN_4, device.Triangle, 0);
+
+                    controller.SetBinding(EssgeeSingleKey.UP, device.LeftStick.Up, 1);
+                    controller.SetBinding(EssgeeSingleKey.DOWN, device.LeftStick.Down, 1);
+                    controller.SetBinding(EssgeeSingleKey.LEFT, device.LeftStick.Left, 1);
+                    controller.SetBinding(EssgeeSingleKey.RIGHT, device.LeftStick.Right, 1);
+                    break;
+            }
+        }
+        public override void Bind(DualShockController_D device, ControllerBinder controller)
+        {
+            controller.SetBinding(EssgeeSingleKey.OPTION_1, device.Options, 0);
+            controller.SetBinding(EssgeeSingleKey.OPTION_2, device.Share, 0);
+            controller.SetBinding(EssgeeSingleKey.UP, device.Up, 0);
+            controller.SetBinding(EssgeeSingleKey.DOWN, device.Down, 0);
+            controller.SetBinding(EssgeeSingleKey.LEFT, device.Left, 0);
+            controller.SetBinding(EssgeeSingleKey.RIGHT, device.Right, 0);
+            controller.SetBinding(EssgeeSingleKey.BTN_1, device.Cross, 0);
+            controller.SetBinding(EssgeeSingleKey.BTN_2, device.Circle, 0);
+            controller.SetBinding(EssgeeSingleKey.BTN_3, device.Square, 0);
+            controller.SetBinding(EssgeeSingleKey.BTN_4, device.Triangle, 0);
+
+            controller.SetBinding(EssgeeSingleKey.UP, device.LeftStick.Up, 1);
+            controller.SetBinding(EssgeeSingleKey.DOWN, device.LeftStick.Down, 1);
+            controller.SetBinding(EssgeeSingleKey.LEFT, device.LeftStick.Left, 1);
+            controller.SetBinding(EssgeeSingleKey.RIGHT, device.LeftStick.Right, 1);
+        }
+        public override void Bind(GamePad_D device, ControllerBinder controller)
+        {
+            controller.SetBinding(EssgeeSingleKey.OPTION_1, device.Start, 0);
+            controller.SetBinding(EssgeeSingleKey.OPTION_2, device.Select, 0);
+            controller.SetBinding(EssgeeSingleKey.UP, device.Up, 0);
+            controller.SetBinding(EssgeeSingleKey.DOWN, device.Down, 0);
+            controller.SetBinding(EssgeeSingleKey.LEFT, device.Left, 0);
+            controller.SetBinding(EssgeeSingleKey.RIGHT, device.Right, 0);
+            controller.SetBinding(EssgeeSingleKey.BTN_1, device.South, 0);
+            controller.SetBinding(EssgeeSingleKey.BTN_2, device.East, 0);
+            controller.SetBinding(EssgeeSingleKey.BTN_3, device.West, 0);
+            controller.SetBinding(EssgeeSingleKey.BTN_4, device.North, 0);
+
+            controller.SetBinding(EssgeeSingleKey.UP, device.LeftStick.Up, 1);
+            controller.SetBinding(EssgeeSingleKey.DOWN, device.LeftStick.Down, 1);
+            controller.SetBinding(EssgeeSingleKey.LEFT, device.LeftStick.Left, 1);
+            controller.SetBinding(EssgeeSingleKey.RIGHT, device.LeftStick.Right, 1);
+        }
+        public override void Bind(XboxController_D device, ControllerBinder controller)
+        {
+            controller.SetBinding(EssgeeSingleKey.OPTION_1, device.Menu, 0);
+            controller.SetBinding(EssgeeSingleKey.OPTION_2, device.View, 0);
+            controller.SetBinding(EssgeeSingleKey.UP, device.Up, 0);
+            controller.SetBinding(EssgeeSingleKey.DOWN, device.Down, 0);
+            controller.SetBinding(EssgeeSingleKey.LEFT, device.Left, 0);
+            controller.SetBinding(EssgeeSingleKey.RIGHT, device.Right, 0);
+            controller.SetBinding(EssgeeSingleKey.BTN_1, device.A, 0);
+            controller.SetBinding(EssgeeSingleKey.BTN_2, device.B, 0);
+            controller.SetBinding(EssgeeSingleKey.BTN_3, device.X, 0);
+            controller.SetBinding(EssgeeSingleKey.BTN_4, device.Y, 0);
+
+            controller.SetBinding(EssgeeSingleKey.UP, device.LeftStick.Up, 1);
+            controller.SetBinding(EssgeeSingleKey.DOWN, device.LeftStick.Down, 1);
+            controller.SetBinding(EssgeeSingleKey.LEFT, device.LeftStick.Left, 1);
+            controller.SetBinding(EssgeeSingleKey.RIGHT, device.LeftStick.Right, 1);
+        }
+        public override void Bind(ScreenGamepad_D device, ControllerBinder controller)
+        {
+            controller.SetBinding(EssgeeSingleKey.OPTION_1, device.OPTION_1, 0);
+            controller.SetBinding(EssgeeSingleKey.OPTION_2, device.OPTION_2, 0);
+            controller.SetBinding(EssgeeSingleKey.UP, device.UP, 0);
+            controller.SetBinding(EssgeeSingleKey.DOWN, device.DOWN, 0);
+            controller.SetBinding(EssgeeSingleKey.LEFT, device.LEFT, 0);
+            controller.SetBinding(EssgeeSingleKey.RIGHT, device.RIGHT, 0);
+            controller.SetBinding(EssgeeSingleKey.BTN_1, device.BTN_A, 0);
+            controller.SetBinding(EssgeeSingleKey.BTN_2, device.BTN_B, 0);
+            controller.SetBinding(EssgeeSingleKey.BTN_3, device.BTN_C, 0);
+            controller.SetBinding(EssgeeSingleKey.BTN_4, device.BTN_D, 0);
+
+            controller.SetBinding(EssgeeSingleKey.UP, device.JOYSTICK.Up, 1);
+            controller.SetBinding(EssgeeSingleKey.DOWN, device.JOYSTICK.Down, 1);
+            controller.SetBinding(EssgeeSingleKey.LEFT, device.JOYSTICK.Left, 1);
+            controller.SetBinding(EssgeeSingleKey.RIGHT, device.JOYSTICK.Right, 1);
+        }
+    }
+
+    public class MasterSystemKeyBinding : EssgeeKeyBinding
+    {
+        public override RomPlatformType Platform => RomPlatformType.MasterSystem;
+        public override int ControllerCount => 2;
+    }
+
+    public class SG1000KeyBinding : EssgeeKeyBinding
+    {
+        public override RomPlatformType Platform => RomPlatformType.Sg1000;
+        public override int ControllerCount => 2;
+    }
+
+    public class ColecoVisionKeyBinding : EssgeeKeyBinding
+    {
+        public override RomPlatformType Platform => RomPlatformType.ColecoVision;
+        public override int ControllerCount => 2;
+    }
+
+    public class GameBoyColorKeyBinding : EssgeeKeyBinding
+    {
+        public override RomPlatformType Platform => RomPlatformType.GameBoyColor;
+        public override int ControllerCount => 1;
+    }
+    public class GameBoyKeyBinding : EssgeeKeyBinding
+    {
+        public override RomPlatformType Platform => RomPlatformType.GameBoy;
+        public override int ControllerCount => 1;
+    }
+
+    public class GameGearKeyBinding : EssgeeKeyBinding
+    {
+        public override RomPlatformType Platform => RomPlatformType.GameGear;
+        public override int ControllerCount => 2;
+    }
+
+    public class SC3000KeyBinding : EssgeeKeyBinding
+    {
+        public override RomPlatformType Platform => RomPlatformType.Sc3000;
+        public override int ControllerCount => 2;
+    }
+}
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/EssgeeKeyBinding.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/EssgeeKeyBinding.cs.meta
new file mode 100644
index 00000000..73ab7f17
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/EssgeeKeyBinding.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: f55743cde04853247be4bd9f7681edf4
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs
new file mode 100644
index 00000000..1447b390
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs
@@ -0,0 +1,40 @@
+using AxibugProtobuf;
+using System;
+using System.Collections.Generic;
+
+namespace AxibugEmuOnline.Client.Settings
+{
+    /// <summary>
+    /// 管理键位映射设置
+    /// </summary>
+    public class KeyMapperSetting
+    {
+        Dictionary<RomPlatformType, InternalEmuCoreBinder> m_binders = new Dictionary<RomPlatformType, InternalEmuCoreBinder>();
+        Dictionary<Type, InternalEmuCoreBinder> m_bindersByType = new Dictionary<Type, InternalEmuCoreBinder>();
+        public KeyMapperSetting()
+        {
+            var baseType = typeof(InternalEmuCoreBinder);
+            foreach (var t in baseType.Assembly.ExportedTypes)
+            {
+                if (t.IsAbstract) continue;
+                if (!baseType.IsAssignableFrom(t)) continue;
+
+                var binderIns = Activator.CreateInstance(t) as InternalEmuCoreBinder;
+                m_binders.Add(binderIns.Platform, binderIns);
+                m_bindersByType.Add(binderIns.GetType(), binderIns);
+            }
+        }
+
+        public T GetBinder<T>() where T : InternalEmuCoreBinder
+        {
+            m_bindersByType.TryGetValue(typeof(T), out var binder);
+            return binder as T;
+        }
+
+        public T GetBinder<T>(RomPlatformType romType) where T : InternalEmuCoreBinder
+        {
+            m_binders.TryGetValue(romType, out var binder);
+            return binder as T;
+        }
+    }
+}
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs.meta
new file mode 100644
index 00000000..bdeaa713
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 59504da02f065ec4e8e6905ab357badc
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/MAMEKeyBinding.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/MAMEKeyBinding.cs
new file mode 100644
index 00000000..7c6d6175
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/MAMEKeyBinding.cs
@@ -0,0 +1,187 @@
+using AxibugEmuOnline.Client.InputDevices;
+using AxibugProtobuf;
+using UnityEngine.UIElements;
+
+namespace AxibugEmuOnline.Client.Settings
+{
+    public enum UMAMEKSingleKey
+    {
+        INSERT_COIN,
+        GAMESTART,
+        UP,
+        DOWN,
+        LEFT,
+        RIGHT,
+        BTN_A,
+        BTN_B,
+        BTN_C,
+        BTN_D,
+        BTN_E,
+        BTN_F
+    }
+
+    public abstract class MAMEKeyBinding : EmuCoreBinder<UMAMEKSingleKey>
+    {
+        public override int ControllerCount => 4;
+
+        public override void Bind(Keyboard_D device, ControllerBinder controller)
+        {
+            switch (controller.ControllerIndex)
+            {
+                case 0:
+                    controller.SetBinding(UMAMEKSingleKey.INSERT_COIN, device.Q, 0);
+                    controller.SetBinding(UMAMEKSingleKey.GAMESTART, device.E, 0);
+                    controller.SetBinding(UMAMEKSingleKey.UP, device.W, 0);
+                    controller.SetBinding(UMAMEKSingleKey.DOWN, device.S, 0);
+                    controller.SetBinding(UMAMEKSingleKey.LEFT, device.A, 0);
+                    controller.SetBinding(UMAMEKSingleKey.RIGHT, device.D, 0);
+                    controller.SetBinding(UMAMEKSingleKey.BTN_A, device.J, 0);
+                    controller.SetBinding(UMAMEKSingleKey.BTN_B, device.K, 0);
+                    controller.SetBinding(UMAMEKSingleKey.BTN_C, device.L, 0);
+                    controller.SetBinding(UMAMEKSingleKey.BTN_D, device.U, 0);
+                    controller.SetBinding(UMAMEKSingleKey.BTN_E, device.I, 0);
+                    controller.SetBinding(UMAMEKSingleKey.BTN_F, device.O, 0);
+                    break;
+                case 1:
+                    controller.SetBinding(UMAMEKSingleKey.INSERT_COIN, device.Delete, 0);
+                    controller.SetBinding(UMAMEKSingleKey.GAMESTART, device.PageDown, 0);
+                    controller.SetBinding(UMAMEKSingleKey.UP, device.UpArrow, 0);
+                    controller.SetBinding(UMAMEKSingleKey.DOWN, device.DownArrow, 0);
+                    controller.SetBinding(UMAMEKSingleKey.LEFT, device.LeftArrow, 0);
+                    controller.SetBinding(UMAMEKSingleKey.RIGHT, device.RightArrow, 0);
+                    controller.SetBinding(UMAMEKSingleKey.BTN_A, device.Keypad1, 0);
+                    controller.SetBinding(UMAMEKSingleKey.BTN_B, device.Keypad2, 0);
+                    controller.SetBinding(UMAMEKSingleKey.BTN_C, device.Keypad3, 0);
+                    controller.SetBinding(UMAMEKSingleKey.BTN_D, device.Keypad4, 0);
+                    controller.SetBinding(UMAMEKSingleKey.BTN_E, device.Keypad5, 0);
+                    controller.SetBinding(UMAMEKSingleKey.BTN_F, device.Keypad6, 0);
+                    break;
+            }
+        }
+        public override void Bind(DualShockController_D device, ControllerBinder controller)
+        {
+            controller.SetBinding(UMAMEKSingleKey.INSERT_COIN, device.Share, 0);
+            controller.SetBinding(UMAMEKSingleKey.GAMESTART, device.Options, 0);
+            controller.SetBinding(UMAMEKSingleKey.UP, device.Up, 0);
+            controller.SetBinding(UMAMEKSingleKey.DOWN, device.Down, 0);
+            controller.SetBinding(UMAMEKSingleKey.LEFT, device.Left, 0);
+            controller.SetBinding(UMAMEKSingleKey.RIGHT, device.Right, 0);
+            controller.SetBinding(UMAMEKSingleKey.BTN_A, device.Square, 0);
+            controller.SetBinding(UMAMEKSingleKey.BTN_B, device.Cross, 0);
+            controller.SetBinding(UMAMEKSingleKey.BTN_C, device.Circle, 0);
+            controller.SetBinding(UMAMEKSingleKey.BTN_D, device.Triangle, 0);
+            controller.SetBinding(UMAMEKSingleKey.BTN_E, device.R1, 0);
+            controller.SetBinding(UMAMEKSingleKey.BTN_F, device.R2, 0);
+
+            controller.SetBinding(UMAMEKSingleKey.UP, device.LeftStick.Up, 1);
+            controller.SetBinding(UMAMEKSingleKey.DOWN, device.LeftStick.Down, 1);
+            controller.SetBinding(UMAMEKSingleKey.LEFT, device.LeftStick.Left, 1);
+            controller.SetBinding(UMAMEKSingleKey.RIGHT, device.LeftStick.Right, 1);
+        }
+        public override void Bind(GamePad_D device, ControllerBinder controller)
+        {
+            controller.SetBinding(UMAMEKSingleKey.INSERT_COIN, device.Select, 0);
+            controller.SetBinding(UMAMEKSingleKey.GAMESTART, device.Start, 0);
+            controller.SetBinding(UMAMEKSingleKey.UP, device.Up, 0);
+            controller.SetBinding(UMAMEKSingleKey.DOWN, device.Down, 0);
+            controller.SetBinding(UMAMEKSingleKey.LEFT, device.Left, 0);
+            controller.SetBinding(UMAMEKSingleKey.RIGHT, device.Right, 0);
+            controller.SetBinding(UMAMEKSingleKey.BTN_A, device.West, 0);
+            controller.SetBinding(UMAMEKSingleKey.BTN_B, device.South, 0);
+            controller.SetBinding(UMAMEKSingleKey.BTN_C, device.East, 0);
+            controller.SetBinding(UMAMEKSingleKey.BTN_D, device.North, 0);
+            controller.SetBinding(UMAMEKSingleKey.BTN_E, device.RightShoulder, 0);
+            controller.SetBinding(UMAMEKSingleKey.BTN_F, device.RightTrigger, 0);
+
+            controller.SetBinding(UMAMEKSingleKey.UP, device.LeftStick.Up, 1);
+            controller.SetBinding(UMAMEKSingleKey.DOWN, device.LeftStick.Down, 1);
+            controller.SetBinding(UMAMEKSingleKey.LEFT, device.LeftStick.Left, 1);
+            controller.SetBinding(UMAMEKSingleKey.RIGHT, device.LeftStick.Right, 1);
+        }
+        public override void Bind(PSVController_D device, ControllerBinder controller)
+        {
+            controller.SetBinding(UMAMEKSingleKey.INSERT_COIN, device.Select, 0);
+            controller.SetBinding(UMAMEKSingleKey.GAMESTART, device.Start, 0);
+            controller.SetBinding(UMAMEKSingleKey.UP, device.Up, 0);
+            controller.SetBinding(UMAMEKSingleKey.DOWN, device.Down, 0);
+            controller.SetBinding(UMAMEKSingleKey.LEFT, device.Left, 0);
+            controller.SetBinding(UMAMEKSingleKey.RIGHT, device.Right, 0);
+            controller.SetBinding(UMAMEKSingleKey.BTN_A, device.Square, 0);
+            controller.SetBinding(UMAMEKSingleKey.BTN_B, device.Cross, 0);
+            controller.SetBinding(UMAMEKSingleKey.BTN_C, device.Circle, 0);
+            controller.SetBinding(UMAMEKSingleKey.BTN_D, device.Triangle, 0);
+            controller.SetBinding(UMAMEKSingleKey.BTN_E, device.L, 0);
+            controller.SetBinding(UMAMEKSingleKey.BTN_F, device.R, 0);
+
+            controller.SetBinding(UMAMEKSingleKey.UP, device.LeftStick.Up, 1);
+            controller.SetBinding(UMAMEKSingleKey.DOWN, device.LeftStick.Down, 1);
+            controller.SetBinding(UMAMEKSingleKey.LEFT, device.LeftStick.Left, 1);
+            controller.SetBinding(UMAMEKSingleKey.RIGHT, device.LeftStick.Right, 1);
+        }
+        public override void Bind(XboxController_D device, ControllerBinder controller)
+        {
+            controller.SetBinding(UMAMEKSingleKey.INSERT_COIN, device.View, 0);
+            controller.SetBinding(UMAMEKSingleKey.GAMESTART, device.Menu, 0);
+            controller.SetBinding(UMAMEKSingleKey.UP, device.Up, 0);
+            controller.SetBinding(UMAMEKSingleKey.DOWN, device.Down, 0);
+            controller.SetBinding(UMAMEKSingleKey.LEFT, device.Left, 0);
+            controller.SetBinding(UMAMEKSingleKey.RIGHT, device.Right, 0);
+            controller.SetBinding(UMAMEKSingleKey.BTN_A, device.X, 0);
+            controller.SetBinding(UMAMEKSingleKey.BTN_B, device.A, 0);
+            controller.SetBinding(UMAMEKSingleKey.BTN_C, device.B, 0);
+            controller.SetBinding(UMAMEKSingleKey.BTN_D, device.Y, 0);
+            controller.SetBinding(UMAMEKSingleKey.BTN_E, device.RightBumper, 0);
+            controller.SetBinding(UMAMEKSingleKey.BTN_F, device.RightTrigger, 0);
+
+            controller.SetBinding(UMAMEKSingleKey.UP, device.LeftStick.Up, 1);
+            controller.SetBinding(UMAMEKSingleKey.DOWN, device.LeftStick.Down, 1);
+            controller.SetBinding(UMAMEKSingleKey.LEFT, device.LeftStick.Left, 1);
+            controller.SetBinding(UMAMEKSingleKey.RIGHT, device.LeftStick.Right, 1);
+        }
+        public override void Bind(ScreenGamepad_D device, ControllerBinder controller)
+        {
+            controller.SetBinding(UMAMEKSingleKey.INSERT_COIN, device.OPTION_1, 0);
+            controller.SetBinding(UMAMEKSingleKey.GAMESTART, device.OPTION_2, 0);
+            controller.SetBinding(UMAMEKSingleKey.UP, device.UP, 0);
+            controller.SetBinding(UMAMEKSingleKey.DOWN, device.DOWN, 0);
+            controller.SetBinding(UMAMEKSingleKey.LEFT, device.LEFT, 0);
+            controller.SetBinding(UMAMEKSingleKey.RIGHT, device.RIGHT, 0);
+            controller.SetBinding(UMAMEKSingleKey.BTN_A, device.BTN_A, 0);
+            controller.SetBinding(UMAMEKSingleKey.BTN_B, device.BTN_B, 0);
+            controller.SetBinding(UMAMEKSingleKey.BTN_C, device.BTN_C, 0);
+            controller.SetBinding(UMAMEKSingleKey.BTN_D, device.BTN_D, 0);
+            controller.SetBinding(UMAMEKSingleKey.BTN_E, device.BTN_E, 0);
+            controller.SetBinding(UMAMEKSingleKey.BTN_F, device.BTN_F, 0);
+
+            controller.SetBinding(UMAMEKSingleKey.UP, device.JOYSTICK.Up, 1);
+            controller.SetBinding(UMAMEKSingleKey.DOWN, device.JOYSTICK.Down, 1);
+            controller.SetBinding(UMAMEKSingleKey.LEFT, device.JOYSTICK.Left, 1);
+            controller.SetBinding(UMAMEKSingleKey.RIGHT, device.JOYSTICK.Right, 1);
+        }
+    }
+
+    public class NEOGEOKeyBinding : MAMEKeyBinding
+    {
+        public override RomPlatformType Platform => RomPlatformType.Neogeo;
+    }
+
+    public class CPS1KeyBinding : MAMEKeyBinding
+    {
+        public override RomPlatformType Platform => RomPlatformType.Cps1;
+    }
+
+    public class CPS2KeyBinding : MAMEKeyBinding
+    {
+        public override RomPlatformType Platform => RomPlatformType.Cps2;
+    }
+
+    public class IGSKeyBinding : MAMEKeyBinding
+    {
+        public override RomPlatformType Platform => RomPlatformType.Igs;
+    }
+
+    public class OldArcadeKeyBinding : MAMEKeyBinding
+    {
+        public override RomPlatformType Platform => RomPlatformType.ArcadeOld;
+    }
+}
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/MAMEKeyBinding.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/MAMEKeyBinding.cs.meta
new file mode 100644
index 00000000..e1dc72f5
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/MAMEKeyBinding.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: ef759672134881f4ca7df82e984a8c87
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/IkeyMapperChanger.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/Model.meta
similarity index 77%
rename from AxibugEmuOnline.Client/Assets/Script/AppMain/IkeyMapperChanger.meta
rename to AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/Model.meta
index e0fa40f3..b7a6eef8 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/IkeyMapperChanger.meta
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/Model.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: 04e926e140ae5bc4fa46bd64067261cf
+guid: d3e856501fe4be94db55b29fc9e4dfdb
 folderAsset: yes
 DefaultImporter:
   externalObjects: {}
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/Model/EmuCoreBinder.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/Model/EmuCoreBinder.cs
new file mode 100644
index 00000000..4fc1538e
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/Model/EmuCoreBinder.cs
@@ -0,0 +1,287 @@
+using AxibugEmuOnline.Client.ClientCore;
+using AxibugEmuOnline.Client.InputDevices;
+using AxibugEmuOnline.Client.Settings;
+using System;
+using System.Collections.Generic;
+using UnityEngine;
+
+/// <summary>
+/// 模拟器核心控制器键位绑定器
+/// </summary>
+/// <typeparam name="T"></typeparam>
+public abstract class EmuCoreBinder<T> : InternalEmuCoreBinder,
+    IDeviceBinder<T, Keyboard_D>,
+    IDeviceBinder<T, GamePad_D>,
+    IDeviceBinder<T, DualShockController_D>,
+    IDeviceBinder<T, XboxController_D>,
+    IDeviceBinder<T, PSVController_D>,
+    IDeviceBinder<T, ScreenGamepad_D>
+    where T : Enum
+{
+    //每一个实例代表一个对应模拟器平台的控制器索引
+    List<ControllerBinder> m_bindingPages = new List<ControllerBinder>();
+
+    public EmuCoreBinder()
+    {
+        var types = GetType().GetInterfaces();
+
+        for (int i = 0; i < ControllerCount; i++)
+        {
+            m_bindingPages.Add(new ControllerBinder(i, this));
+        }
+
+        foreach (var device in App.input.GetDevices())
+        {
+            foreach (var binding in m_bindingPages)
+            {
+                binding.RegistInputDevice(device);
+            }
+        }
+
+        App.input.OnDeviceLost += InputDevicesMgr_OnDeviceLost;
+        App.input.OnDeviceConnected += InputDevicesMgr_OnDeviceConnected;
+    }
+
+    private void InputDevicesMgr_OnDeviceConnected(InputDevice_D connectDevice)
+    {
+        foreach (var binding in m_bindingPages)
+        {
+            binding.RegistInputDevice(connectDevice);
+        }
+    }
+
+    private void InputDevicesMgr_OnDeviceLost(InputDevice_D lostDevice)
+    {
+        foreach (var binding in m_bindingPages)
+        {
+            binding.UnregistInputDevice(lostDevice);
+        }
+    }
+
+    internal void RaiseDeviceRegist(InputDevice_D device, ControllerBinder binding)
+    {
+        if (device is Keyboard_D keyboard) Bind(keyboard, binding);
+        else if (device is GamePad_D gamePad) Bind(gamePad, binding);
+        else if (device is DualShockController_D dsC) Bind(dsC, binding);
+        else if (device is XboxController_D xbC) Bind(xbC, binding);
+        else if (device is PSVController_D psvC) Bind(psvC, binding);
+        else if (device is ScreenGamepad_D screenGamepad) Bind(screenGamepad, binding);
+        else throw new NotImplementedException($"{device.GetType()}");
+    }
+
+    public bool Start(T emuControl, int controllerIndex)
+    {
+        var binding = m_bindingPages[controllerIndex];
+        foreach (var key in binding.GetBinding(emuControl))
+        {
+            if (key.Start) return true;
+        }
+
+        return false;
+    }
+
+    public bool Release(T emuControl, int controllerIndex)
+    {
+        var binding = m_bindingPages[controllerIndex];
+        foreach (var key in binding.GetBinding(emuControl))
+        {
+            if (key.Release) return true;
+        }
+
+        return false;
+    }
+
+    /// <summary>
+    /// 获取指定控件是否处于按下状态
+    /// <para>如果绑定了多个物理按键,则只有这多个物理按键全部不处于按下状态时,才会返回false</para>
+    /// </summary>
+    /// <param name="emuControl"></param>
+    /// <param name="controllerIndex"></param>
+    /// <returns></returns>
+    public bool GetKey(T emuControl, int controllerIndex)
+    {
+        var binding = m_bindingPages[controllerIndex];
+        foreach (var key in binding.GetBinding(emuControl))
+        {
+            if (key.Performing) return true;
+        }
+
+        return false;
+    }
+
+    /// <summary>
+    /// 获取调用帧是否有任意按键触发了按下操作
+    /// </summary>
+    /// <param name="controllerIndex"></param>
+    /// <returns></returns>
+    public bool AnyKeyDown(int controllerIndex)
+    {
+        var binding = m_bindingPages[controllerIndex];
+        return binding.AnyKeyDown();
+    }
+
+    /// <summary>
+    /// 获取指定控件的向量值
+    /// <para>通常用于摇杆类型的控件</para>
+    /// <para>如果同时绑定了多个物理输入设备,只会返回其中一个物理设备的向量值</para>
+    /// </summary>
+    /// <param name="emuControl">模拟器平台的具体键枚举</param>
+    /// <param name="controllerIndex">模拟器平台的控制器序号</param>
+    /// <returns></returns>
+    public Vector2 GetVector2(T emuControl, int controllerIndex)
+    {
+        var binding = m_bindingPages[controllerIndex];
+        foreach (var control in binding.GetBinding(emuControl))
+        {
+            if (!control.Performing) continue;
+
+            return control.GetVector2();
+        }
+
+        return default(Vector2);
+    }
+
+    /// <summary>
+    /// 获取指定控件的浮点值,取值范围为[0f,1f]
+    /// <para>通常用于线性类按键,例如PS手柄的扳机键</para>
+    /// <para>普通的按键也能读取这个值,但返回值只会有0f和1f两种值</para>
+    /// <para>如果同时绑定了多个物理控件,则会从所有处于按下状态的物理控件中取平均值</para>
+    /// </summary>
+    /// <param name="emuControl">模拟器平台的具体键枚举</param>
+    /// <param name="controllerIndex">模拟器平台的控制器序号</param>
+    /// <returns></returns>
+    public float GetFloat(T emuControl, int controllerIndex)
+    {
+        var totalFloat = 0f;
+        var totalControl = 0;
+
+        var binding = m_bindingPages[controllerIndex];
+        foreach (var key in binding.GetBinding(emuControl))
+        {
+            if (!key.Performing) continue;
+
+            totalControl++;
+            totalFloat += key.GetFlaot();
+        }
+
+        if (totalControl == 0) return default(float);
+        else return totalFloat / totalControl;
+    }
+
+    public class MapSetting : Dictionary<T, List<InputControl_C>> { }
+
+    public class ControllerBinder
+    {
+        Dictionary<Type, InputDevice_D> m_registedDevices = new Dictionary<Type, InputDevice_D>();
+        Dictionary<InputDevice_D, MapSetting> m_mapSetting = new Dictionary<InputDevice_D, MapSetting>();
+
+        public int ControllerIndex { get; }
+        public EmuCoreBinder<T> Host { get; }
+
+        internal ControllerBinder(int controllerIndex, EmuCoreBinder<T> host)
+        {
+            ControllerIndex = controllerIndex;
+            Host = host;
+        }
+
+        internal bool IsRegisted<DEVICE>() where DEVICE : InputDevice_D
+        {
+            var type = typeof(T);
+            return IsRegisted(type);
+        }
+        internal bool IsRegisted(Type deviceType)
+        {
+            return m_registedDevices.ContainsKey(deviceType);
+        }
+
+        internal void RegistInputDevice(InputDevice_D device)
+        {
+            var type = device.GetType();
+            if (IsRegisted(type)) return;
+
+            m_registedDevices.Add(type, device);
+            m_mapSetting[device] = new MapSetting();
+            Host.RaiseDeviceRegist(device, this);
+        }
+
+        internal void UnregistInputDevice(InputDevice_D device)
+        {
+            var type = device.GetType();
+            if (!IsRegisted(type)) return;
+
+            m_registedDevices.Remove(type);
+            m_mapSetting.Remove(device);
+        }
+
+        public void SetBinding(T emuBtn, InputControl_C key, int settingSlot)
+        {
+            var device = key.Device;
+            m_registedDevices.TryGetValue(device.GetType(), out var inputDevice);
+
+            Debug.Assert(inputDevice == device);
+
+            var setting = m_mapSetting[inputDevice];
+            if (!setting.TryGetValue(emuBtn, out var settingList))
+            {
+                settingList = new List<InputControl_C>();
+                setting[emuBtn] = settingList;
+            }
+
+            int needFixCount = settingSlot - settingList.Count + 1;
+            if (needFixCount > 0) for (int i = 0; i < needFixCount; i++) settingList.Add(null);
+
+            settingList[settingSlot] = key;
+        }
+
+        public InputControl_C GetBinding(T emuBtn, InputDevice_D device, int settingSlot)
+        {
+            m_mapSetting.TryGetValue(device, out var mapSetting);
+            if (mapSetting == null) return null;
+
+            mapSetting.TryGetValue(emuBtn, out var settingList);
+            if (settingList == null || settingSlot >= settingList.Count) return null;
+
+            return settingList[settingSlot];
+        }
+
+        private List<InputControl_C> m_caches = new List<InputControl_C>();
+        public IEnumerable<InputControl_C> GetBinding(T emuBtn)
+        {
+            m_caches.Clear();
+
+            foreach (var mapSettings in m_mapSetting.Values)
+            {
+                mapSettings.TryGetValue(emuBtn, out var bindControls);
+                if (bindControls != null)
+                {
+                    m_caches.AddRange(bindControls);
+                }
+            }
+
+            return m_caches;
+        }
+
+        public bool AnyKeyDown()
+        {
+            foreach (var mapSettings in m_mapSetting.Values)
+            {
+                foreach (var keys in mapSettings.Values)
+                {
+                    foreach (var key in keys)
+                    {
+                        if (key.Start) return true;
+                    }
+                }
+            }
+
+            return false;
+        }
+    }
+
+    public abstract void Bind(Keyboard_D device, ControllerBinder controller);
+    public abstract void Bind(GamePad_D device, ControllerBinder controller);
+    public abstract void Bind(DualShockController_D device, ControllerBinder controller);
+    public abstract void Bind(XboxController_D device, ControllerBinder controller);
+    public abstract void Bind(PSVController_D device, ControllerBinder controller);
+    public abstract void Bind(ScreenGamepad_D device, ControllerBinder controller);
+}
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/Model/EmuCoreBinder.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/Model/EmuCoreBinder.cs.meta
new file mode 100644
index 00000000..704c0a32
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/Model/EmuCoreBinder.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: c593acacf7f38e244aa08283266f1a2e
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/Model/IDeviceBinder.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/Model/IDeviceBinder.cs
new file mode 100644
index 00000000..424304d4
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/Model/IDeviceBinder.cs
@@ -0,0 +1,17 @@
+using AxibugEmuOnline.Client.InputDevices;
+using System;
+
+namespace AxibugEmuOnline.Client.Settings
+{
+    /// <summary>
+    /// 在所有<see cref="EmuCoreBinder{T}"/>的派生类中实现此接口以支持一种设备的绑定
+    /// <para>一种<see cref="EmuCoreBinder{T}"/>
+    /// 一个<see cref="EmuCoreBinder{T}.ControllerBinder"/>可以与多种设备建立绑定,但设备类型不可重复</para>
+    /// </summary>
+    public interface IDeviceBinder<ENUM, DEVICE>
+        where ENUM : Enum
+        where DEVICE : InputDevice_D
+    {
+        void Bind(DEVICE device, EmuCoreBinder<ENUM>.ControllerBinder controller);
+    }
+}
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/Model/IDeviceBinder.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/Model/IDeviceBinder.cs.meta
new file mode 100644
index 00000000..0533689b
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/Model/IDeviceBinder.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: b7c859b1adea6a5448ba60e43af3ccc6
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/Model/InternalEmuCoreBinder.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/Model/InternalEmuCoreBinder.cs
new file mode 100644
index 00000000..50d77b3e
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/Model/InternalEmuCoreBinder.cs
@@ -0,0 +1,12 @@
+using AxibugProtobuf;
+
+/// <summary>
+/// 此类为内部继承, 请勿继承此类
+/// </summary>
+public abstract class InternalEmuCoreBinder
+{
+    /// <summary> 所属核心 </summary>
+    public abstract RomPlatformType Platform { get; }
+    /// <summary> 控制器数量 </summary>
+    public abstract int ControllerCount { get; }
+}
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/Model/InternalEmuCoreBinder.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/Model/InternalEmuCoreBinder.cs.meta
new file mode 100644
index 00000000..22fa2e57
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/Model/InternalEmuCoreBinder.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 70fbaad26932617478d787c65e124da5
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/NesKeyBinding.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/NesKeyBinding.cs
new file mode 100644
index 00000000..8a743318
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/NesKeyBinding.cs
@@ -0,0 +1,125 @@
+using AxibugEmuOnline.Client.InputDevices;
+using AxibugProtobuf;
+using VirtualNes.Core;
+
+namespace AxibugEmuOnline.Client.Settings
+{
+    public class NesKeyBinding : EmuCoreBinder<EnumButtonType>
+    {
+        public override RomPlatformType Platform => RomPlatformType.Nes;
+        public override int ControllerCount => 4;
+
+        public override void Bind(Keyboard_D device, ControllerBinder controller)
+        {
+            switch (controller.ControllerIndex)
+            {
+                case 0:
+                    controller.SetBinding(EnumButtonType.LEFT, device.A, 0);
+                    controller.SetBinding(EnumButtonType.RIGHT, device.D, 0);
+                    controller.SetBinding(EnumButtonType.UP, device.W, 0);
+                    controller.SetBinding(EnumButtonType.DOWN, device.S, 0);
+                    controller.SetBinding(EnumButtonType.A, device.K, 0);
+                    controller.SetBinding(EnumButtonType.B, device.J, 0);
+                    controller.SetBinding(EnumButtonType.SELECT, device.V, 0);
+                    controller.SetBinding(EnumButtonType.START, device.B, 0);
+                    controller.SetBinding(EnumButtonType.MIC, device.M, 0);
+                    break;
+                case 1:
+                    controller.SetBinding(EnumButtonType.UP, device.UpArrow, 0);
+                    controller.SetBinding(EnumButtonType.DOWN, device.DownArrow, 0);
+                    controller.SetBinding(EnumButtonType.LEFT, device.LeftArrow, 0);
+                    controller.SetBinding(EnumButtonType.RIGHT, device.RightArrow, 0);
+                    controller.SetBinding(EnumButtonType.A, device.Keypad2, 0);
+                    controller.SetBinding(EnumButtonType.B, device.Keypad1, 0);
+                    controller.SetBinding(EnumButtonType.SELECT, device.Keypad0, 0);
+                    controller.SetBinding(EnumButtonType.START, device.KeypadPeriod, 0);
+                    break;
+            }
+        }
+        public override void Bind(DualShockController_D device, ControllerBinder controller)
+        {
+            controller.SetBinding(EnumButtonType.LEFT, device.Left, 0);
+            controller.SetBinding(EnumButtonType.RIGHT, device.Right, 0);
+            controller.SetBinding(EnumButtonType.UP, device.Up, 0);
+            controller.SetBinding(EnumButtonType.DOWN, device.Down, 0);
+            controller.SetBinding(EnumButtonType.A, device.Cross, 0);
+            controller.SetBinding(EnumButtonType.B, device.Square, 0);
+            controller.SetBinding(EnumButtonType.SELECT, device.Share, 0);
+            controller.SetBinding(EnumButtonType.START, device.Options, 0);
+            controller.SetBinding(EnumButtonType.MIC, device.L1, 0);
+
+            controller.SetBinding(EnumButtonType.LEFT, device.LeftStick.Left, 1);
+            controller.SetBinding(EnumButtonType.RIGHT, device.LeftStick.Right, 1);
+            controller.SetBinding(EnumButtonType.UP, device.LeftStick.Up, 1);
+            controller.SetBinding(EnumButtonType.DOWN, device.LeftStick.Down, 1);
+        }
+        public override void Bind(GamePad_D device, ControllerBinder controller)
+        {
+            controller.SetBinding(EnumButtonType.LEFT, device.Left, 0);
+            controller.SetBinding(EnumButtonType.RIGHT, device.Right, 0);
+            controller.SetBinding(EnumButtonType.UP, device.Up, 0);
+            controller.SetBinding(EnumButtonType.DOWN, device.Down, 0);
+            controller.SetBinding(EnumButtonType.A, device.South, 0);
+            controller.SetBinding(EnumButtonType.B, device.West, 0);
+            controller.SetBinding(EnumButtonType.SELECT, device.Select, 0);
+            controller.SetBinding(EnumButtonType.START, device.Start, 0);
+            controller.SetBinding(EnumButtonType.MIC, device.LeftShoulder, 0);
+
+            controller.SetBinding(EnumButtonType.LEFT, device.LeftStick.Left, 1);
+            controller.SetBinding(EnumButtonType.RIGHT, device.LeftStick.Right, 1);
+            controller.SetBinding(EnumButtonType.UP, device.LeftStick.Up, 1);
+            controller.SetBinding(EnumButtonType.DOWN, device.LeftStick.Down, 1);
+        }
+        public override void Bind(PSVController_D device, ControllerBinder controller)
+        {
+            controller.SetBinding(EnumButtonType.LEFT, device.Left, 0);
+            controller.SetBinding(EnumButtonType.RIGHT, device.Right, 0);
+            controller.SetBinding(EnumButtonType.UP, device.Up, 0);
+            controller.SetBinding(EnumButtonType.DOWN, device.Down, 0);
+            controller.SetBinding(EnumButtonType.A, device.Cross, 0);
+            controller.SetBinding(EnumButtonType.B, device.Square, 0);
+            controller.SetBinding(EnumButtonType.SELECT, device.Select, 0);
+            controller.SetBinding(EnumButtonType.START, device.Start, 0);
+            controller.SetBinding(EnumButtonType.MIC, device.L, 0);
+
+            controller.SetBinding(EnumButtonType.LEFT, device.LeftStick.Left, 1);
+            controller.SetBinding(EnumButtonType.RIGHT, device.LeftStick.Right, 1);
+            controller.SetBinding(EnumButtonType.UP, device.LeftStick.Up, 1);
+            controller.SetBinding(EnumButtonType.DOWN, device.LeftStick.Down, 1);
+        }
+        public override void Bind(XboxController_D device, ControllerBinder controller)
+        {
+            controller.SetBinding(EnumButtonType.LEFT, device.Left, 0);
+            controller.SetBinding(EnumButtonType.RIGHT, device.Right, 0);
+            controller.SetBinding(EnumButtonType.UP, device.Up, 0);
+            controller.SetBinding(EnumButtonType.DOWN, device.Down, 0);
+            controller.SetBinding(EnumButtonType.A, device.A, 0);
+            controller.SetBinding(EnumButtonType.B, device.X, 0);
+            controller.SetBinding(EnumButtonType.SELECT, device.View, 0);
+            controller.SetBinding(EnumButtonType.START, device.Menu, 0);
+            controller.SetBinding(EnumButtonType.MIC, device.LeftBumper, 0);
+
+            controller.SetBinding(EnumButtonType.LEFT, device.LeftStick.Left, 1);
+            controller.SetBinding(EnumButtonType.RIGHT, device.LeftStick.Right, 1);
+            controller.SetBinding(EnumButtonType.UP, device.LeftStick.Up, 1);
+            controller.SetBinding(EnumButtonType.DOWN, device.LeftStick.Down, 1);
+        }
+        public override void Bind(ScreenGamepad_D device, ControllerBinder controller)
+        {
+            controller.SetBinding(EnumButtonType.LEFT, device.LEFT, 0);
+            controller.SetBinding(EnumButtonType.RIGHT, device.RIGHT, 0);
+            controller.SetBinding(EnumButtonType.UP, device.UP, 0);
+            controller.SetBinding(EnumButtonType.DOWN, device.DOWN, 0);
+            controller.SetBinding(EnumButtonType.A, device.BTN_B, 0);
+            controller.SetBinding(EnumButtonType.B, device.BTN_A, 0);
+            controller.SetBinding(EnumButtonType.SELECT, device.OPTION_1, 0);
+            controller.SetBinding(EnumButtonType.START, device.OPTION_2, 0);
+            controller.SetBinding(EnumButtonType.MIC, device.OPTION_3, 0);
+
+            controller.SetBinding(EnumButtonType.LEFT, device.JOYSTICK.Left, 1);
+            controller.SetBinding(EnumButtonType.RIGHT, device.JOYSTICK.Right, 1);
+            controller.SetBinding(EnumButtonType.UP, device.JOYSTICK.Up, 1);
+            controller.SetBinding(EnumButtonType.DOWN, device.JOYSTICK.Down, 1);
+        }
+    }
+}
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/NesKeyBinding.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/NesKeyBinding.cs.meta
new file mode 100644
index 00000000..ae3e54e1
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/NesKeyBinding.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 65743da1d10d08d4d8a6485eb7fd7188
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/XMBKeyBinding.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/XMBKeyBinding.cs
new file mode 100644
index 00000000..a7bce802
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/XMBKeyBinding.cs
@@ -0,0 +1,116 @@
+using AxibugEmuOnline.Client.InputDevices;
+using AxibugProtobuf;
+
+namespace AxibugEmuOnline.Client
+{
+    public class XMBKeyBinding : EmuCoreBinder<EnumCommand>
+    {
+        public override RomPlatformType Platform => RomPlatformType.Invalid;
+        public override int ControllerCount => 2;
+
+        public override void Bind(Keyboard_D device, ControllerBinder controller)
+        {
+            switch (controller.ControllerIndex)
+            {
+                case 0://设置标准UI控制 //第一套控制布局 WSAD+JKLI
+                    controller.SetBinding(EnumCommand.Back, device.L, 0);
+                    controller.SetBinding(EnumCommand.Enter, device.K, 0);
+                    controller.SetBinding(EnumCommand.OptionMenu, device.I, 0);
+                    controller.SetBinding(EnumCommand.SelectItemDown, device.S, 0);
+                    controller.SetBinding(EnumCommand.SelectItemLeft, device.A, 0);
+                    controller.SetBinding(EnumCommand.SelectItemRight, device.D, 0);
+                    controller.SetBinding(EnumCommand.SelectItemUp, device.W, 0);
+
+                    //第二套控制布局 LOWB用
+                    controller.SetBinding(EnumCommand.Back, device.Escape, 1);
+                    controller.SetBinding(EnumCommand.Back, device.Backspace, 2);
+                    controller.SetBinding(EnumCommand.Enter, device.Return, 1);
+                    controller.SetBinding(EnumCommand.OptionMenu, device.LeftShift, 1);
+                    controller.SetBinding(EnumCommand.OptionMenu, device.RightShift, 2);
+                    controller.SetBinding(EnumCommand.SelectItemDown, device.DownArrow, 1);
+                    controller.SetBinding(EnumCommand.SelectItemLeft, device.LeftArrow, 1);
+                    controller.SetBinding(EnumCommand.SelectItemRight, device.RightArrow, 1);
+                    controller.SetBinding(EnumCommand.SelectItemUp, device.UpArrow, 1);
+                    break;
+                case 1://游戏中UI控制
+                    controller.SetBinding(EnumCommand.OptionMenu, device.Escape, 0);
+                    break;
+            }
+        }
+        public override void Bind(DualShockController_D device, ControllerBinder controller)
+        {
+            controller.SetBinding(EnumCommand.Back, device.Circle, 0);
+            controller.SetBinding(EnumCommand.Enter, device.Cross, 0);
+            controller.SetBinding(EnumCommand.OptionMenu, device.Options, 0);
+            controller.SetBinding(EnumCommand.SelectItemDown, device.Down, 0);
+            controller.SetBinding(EnumCommand.SelectItemLeft, device.Left, 0);
+            controller.SetBinding(EnumCommand.SelectItemRight, device.Right, 0);
+            controller.SetBinding(EnumCommand.SelectItemUp, device.Up, 0);
+
+            controller.SetBinding(EnumCommand.SelectItemDown, device.LeftStick.Down, 1);
+            controller.SetBinding(EnumCommand.SelectItemLeft, device.LeftStick.Left, 1);
+            controller.SetBinding(EnumCommand.SelectItemRight, device.LeftStick.Right, 1);
+            controller.SetBinding(EnumCommand.SelectItemUp, device.LeftStick.Up, 1);
+        }
+        public override void Bind(GamePad_D device, ControllerBinder controller)
+        {
+            controller.SetBinding(EnumCommand.Back, device.East, 0);
+            controller.SetBinding(EnumCommand.Enter, device.South, 0);
+            controller.SetBinding(EnumCommand.OptionMenu, device.Start, 0);
+            controller.SetBinding(EnumCommand.SelectItemDown, device.Down, 0);
+            controller.SetBinding(EnumCommand.SelectItemLeft, device.Left, 0);
+            controller.SetBinding(EnumCommand.SelectItemRight, device.Right, 0);
+            controller.SetBinding(EnumCommand.SelectItemUp, device.Up, 0);
+
+            controller.SetBinding(EnumCommand.SelectItemDown, device.LeftStick.Down, 1);
+            controller.SetBinding(EnumCommand.SelectItemLeft, device.LeftStick.Left, 1);
+            controller.SetBinding(EnumCommand.SelectItemRight, device.LeftStick.Right, 1);
+            controller.SetBinding(EnumCommand.SelectItemUp, device.LeftStick.Up, 1);
+        }
+        public override void Bind(PSVController_D device, ControllerBinder controller)
+        {
+            controller.SetBinding(EnumCommand.Back, device.Circle, 0);
+            controller.SetBinding(EnumCommand.Enter, device.Cross, 0);
+            controller.SetBinding(EnumCommand.OptionMenu, device.Start, 0);
+            controller.SetBinding(EnumCommand.SelectItemDown, device.Down, 0);
+            controller.SetBinding(EnumCommand.SelectItemLeft, device.Left, 0);
+            controller.SetBinding(EnumCommand.SelectItemRight, device.Right, 0);
+            controller.SetBinding(EnumCommand.SelectItemUp, device.Up, 0);
+
+            controller.SetBinding(EnumCommand.SelectItemDown, device.LeftStick.Down, 1);
+            controller.SetBinding(EnumCommand.SelectItemLeft, device.LeftStick.Left, 1);
+            controller.SetBinding(EnumCommand.SelectItemRight, device.LeftStick.Right, 1);
+            controller.SetBinding(EnumCommand.SelectItemUp, device.LeftStick.Up, 1);
+        }
+        public override void Bind(XboxController_D device, ControllerBinder controller)
+        {
+            controller.SetBinding(EnumCommand.Back, device.B, 0);
+            controller.SetBinding(EnumCommand.Enter, device.A, 0);
+            controller.SetBinding(EnumCommand.OptionMenu, device.Menu, 0);
+            controller.SetBinding(EnumCommand.SelectItemDown, device.Down, 0);
+            controller.SetBinding(EnumCommand.SelectItemLeft, device.Left, 0);
+            controller.SetBinding(EnumCommand.SelectItemRight, device.Right, 0);
+            controller.SetBinding(EnumCommand.SelectItemUp, device.Up, 0);
+
+            controller.SetBinding(EnumCommand.SelectItemDown, device.LeftStick.Down, 1);
+            controller.SetBinding(EnumCommand.SelectItemLeft, device.LeftStick.Left, 1);
+            controller.SetBinding(EnumCommand.SelectItemRight, device.LeftStick.Right, 1);
+            controller.SetBinding(EnumCommand.SelectItemUp, device.LeftStick.Up, 1);
+        }
+        public override void Bind(ScreenGamepad_D device, ControllerBinder controller)
+        {
+            controller.SetBinding(EnumCommand.Back, device.BTN_A, 0);
+            controller.SetBinding(EnumCommand.Enter, device.BTN_B, 0);
+            controller.SetBinding(EnumCommand.OptionMenu, device.OPTION_1, 0);
+            controller.SetBinding(EnumCommand.SelectItemDown, device.DOWN, 0);
+            controller.SetBinding(EnumCommand.SelectItemLeft, device.LEFT, 0);
+            controller.SetBinding(EnumCommand.SelectItemRight, device.RIGHT, 0);
+            controller.SetBinding(EnumCommand.SelectItemUp, device.UP, 0);
+
+            controller.SetBinding(EnumCommand.SelectItemDown, device.JOYSTICK.Down, 1);
+            controller.SetBinding(EnumCommand.SelectItemLeft, device.JOYSTICK.Left, 1);
+            controller.SetBinding(EnumCommand.SelectItemRight, device.JOYSTICK.Right, 1);
+            controller.SetBinding(EnumCommand.SelectItemUp, device.JOYSTICK.Up, 1);
+        }
+    }
+}
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/XMBKeyBinding.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/XMBKeyBinding.cs.meta
new file mode 100644
index 00000000..a65759fb
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/XMBKeyBinding.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 8605f13d4a077324b83a12938ee03721
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/ScreenScaler.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/ScreenScaler.cs
index 9e0ed065..9d1b7f16 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/ScreenScaler.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/ScreenScaler.cs
@@ -2,7 +2,7 @@
 using UnityEngine;
 using UnityEngine.UI;
 
-namespace AxibugEmuOnline.Client
+namespace AxibugEmuOnline.Client.Settings
 {
     /// <summary>
     /// 实现模拟器输出画面的比例调整类
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/GamePadManager/GamePad.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/GamePadManager/GamePad.cs
deleted file mode 100644
index 7f0a445b..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/GamePadManager/GamePad.cs
+++ /dev/null
@@ -1,26 +0,0 @@
-namespace AxibugEmuOnline.Client.Manager
-{
-    public partial class GamePadManager
-    {
-        /// <summary>
-        /// 被Unity所识别的通用GamePad类
-        /// </summary>
-        public class GamePad
-        {
-            internal GamePadInfo m_info;
-            public int Index => m_info.Index;
-            public string Name => m_info.Name;
-            public bool Offline { get; internal set; }
-
-            internal GamePad(GamePadInfo info)
-            {
-                m_info = info;
-            }
-
-            public override string ToString()
-            {
-                return $"{Index}:{Name}{(Offline ? "(Offline)" : string.Empty)}";
-            }
-        }
-    }
-}
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/GamePadManager/GamePad.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/GamePadManager/GamePad.cs.meta
deleted file mode 100644
index 531c8952..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/GamePadManager/GamePad.cs.meta
+++ /dev/null
@@ -1,2 +0,0 @@
-fileFormatVersion: 2
-guid: c2c0a06020f65a747af5490a6112361b
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/GamePadManager/GamePadManager.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/GamePadManager/GamePadManager.cs
deleted file mode 100644
index 6941e69f..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/GamePadManager/GamePadManager.cs
+++ /dev/null
@@ -1,121 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using UnityEngine;
-
-namespace AxibugEmuOnline.Client.Manager
-{
-    public partial class GamePadManager
-    {
-        #region Events
-        public delegate void GamePadConnectedHandle(GamePad newConnectGamePad);
-        /// <summary> 当一个手柄连接时触发 </summary>
-        public event GamePadConnectedHandle OnGamePadConnected;
-
-        public delegate void GamePadDisConnectedHandle(GamePad disConnectGamePad);
-        /// <summary> 当一个手柄断开时触发 </summary>
-        public event GamePadDisConnectedHandle OnGamePadDisConnected;
-        #endregion
-
-        Dictionary<GamePadInfo, GamePad> m_gamePads = new Dictionary<GamePadInfo, GamePad>();
-        HashSet<GamePadInfo> m_temp = new HashSet<GamePadInfo>();
-
-        public void Update()
-        {
-            m_temp.Clear();
-            foreach (var info in m_gamePads.Keys)
-                m_temp.Add(info); //记录需要被移除的手柄
-
-            var devices = Input.GetJoystickNames();
-            for (int i = 0; i < devices.Length; i++)
-            {
-                var info = new GamePadInfo { Index = i, Name = devices[i] };
-                m_temp.Remove(info);
-
-                if (!m_gamePads.ContainsKey(info))
-                {
-                    m_gamePads[info] = new GamePad(info);
-                    OnGamePadConnected?.Invoke(m_gamePads[info]);
-                };
-            }
-
-            foreach (var info in m_temp)
-            {
-                if (m_gamePads.TryGetValue(info, out GamePad gp))
-                {
-                    m_gamePads.Remove(info);
-                    gp.Offline = true;
-                    OnGamePadDisConnected?.Invoke(gp);
-                }
-            }
-        }
-
-        /// <summary>
-        /// 获取所有已连接的手柄,返回的结果顺序与手柄序号无关
-        /// </summary>
-        /// <returns></returns>
-        public GamePad[] GetGamePads()
-        {
-            return m_gamePads.Values.ToArray();
-        }
-
-        internal struct GamePadInfo : IEquatable<GamePadInfo>, IComparable<GamePadInfo>
-        {
-            internal int Index;
-            internal string Name;
-
-            public override bool Equals(object obj)
-            {
-                if (obj is GamePadInfo)
-                {
-                    return Equals((GamePadInfo)obj);
-                }
-                return false;
-            }
-
-            public bool Equals(GamePadInfo other)
-            {
-                return Index == other.Index && Name == other.Name;
-            }
-
-            public override int GetHashCode()
-            {
-                // Custom hash code implementation without HashCombine
-                int hash = 17;
-                hash = hash * 31 + Index.GetHashCode();
-                hash = hash * 31 + (Name != null ? Name.GetHashCode() : 0);
-                return hash;
-            }
-
-            public int CompareTo(GamePadInfo other)
-            {
-                int indexComparison = Index.CompareTo(other.Index);
-                if (indexComparison != 0)
-                {
-                    return indexComparison;
-                }
-                return string.Compare(Name, other.Name, StringComparison.Ordinal);
-            }
-
-            public static bool operator ==(GamePadInfo left, GamePadInfo right)
-            {
-                return left.Equals(right);
-            }
-
-            public static bool operator !=(GamePadInfo left, GamePadInfo right)
-            {
-                return !(left == right);
-            }
-
-            public static bool operator <(GamePadInfo left, GamePadInfo right)
-            {
-                return left.CompareTo(right) < 0;
-            }
-
-            public static bool operator >(GamePadInfo left, GamePadInfo right)
-            {
-                return left.CompareTo(right) > 0;
-            }
-        }
-    }
-}
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/GamePadManager/GamePadManager.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/GamePadManager/GamePadManager.cs.meta
deleted file mode 100644
index 38c4ba12..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/GamePadManager/GamePadManager.cs.meta
+++ /dev/null
@@ -1,2 +0,0 @@
-fileFormatVersion: 2
-guid: ce4d215abea527e4a8cf1103cbfecf6b
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/GamePadManager.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager.meta
similarity index 77%
rename from AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/GamePadManager.meta
rename to AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager.meta
index d9ee8b26..70175167 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/GamePadManager.meta
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: 5fe26f58ab822c44888b86305c5326e0
+guid: 7c141dadb47c8624c80c092e415ab621
 folderAsset: yes
 DefaultImporter:
   externalObjects: {}
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices.meta
new file mode 100644
index 00000000..c2499ed6
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: c72c157b8f11c634991ba09272065d1e
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/DualShockController_D.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/DualShockController_D.cs
new file mode 100644
index 00000000..fac26789
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/DualShockController_D.cs
@@ -0,0 +1,28 @@
+namespace AxibugEmuOnline.Client.InputDevices
+{
+    /// <summary> PS3,PS4控制器 </summary>
+    public class DualShockController_D : InputDevice_D
+    {
+        public Button_C Circle;
+        public Button_C Triangle;
+        public Button_C Cross;
+        public Button_C Square;
+        public Button_C Up;
+        public Button_C Down;
+        public Button_C Left;
+        public Button_C Right;
+        public Button_C L1;
+        public Button_C L2;
+        public Button_C L3;
+        public Button_C R1;
+        public Button_C R2;
+        public Button_C R3;
+        public Button_C Share;
+        public Button_C Options;
+        public Button_C TouchpadBtn;
+        public Stick_C LeftStick;
+        public Stick_C RightStick;
+
+        public DualShockController_D(InputResolver resolver) : base(resolver) { }
+    }
+}
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/DualShockController_D.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/DualShockController_D.cs.meta
new file mode 100644
index 00000000..b602453a
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/DualShockController_D.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: e1f707631f22b4843840696ce2f66471
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/GamePad_D.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/GamePad_D.cs
new file mode 100644
index 00000000..1834a25c
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/GamePad_D.cs
@@ -0,0 +1,29 @@
+namespace AxibugEmuOnline.Client.InputDevices
+{
+    /// <summary>
+    /// 通用游戏控制器
+    /// </summary>
+    public class GamePad_D : InputDevice_D
+    {
+        public Button_C Up;
+        public Button_C Down;
+        public Button_C Left;
+        public Button_C Right;
+        public Button_C Select;
+        public Button_C Start;
+        public Button_C North;
+        public Button_C South;
+        public Button_C West;
+        public Button_C East;
+        public Button_C LeftShoulder;
+        public Button_C RightShoulder;
+        public Button_C LeftTrigger;
+        public Button_C RightTrigger;
+        public Button_C LeftStickPress;
+        public Button_C RightStickPress;
+        public Stick_C LeftStick;
+        public Stick_C RightStick;
+
+        public GamePad_D(InputResolver resolver) : base(resolver) { }
+    }
+}
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/GamePad_D.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/GamePad_D.cs.meta
new file mode 100644
index 00000000..2ce54c6c
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/GamePad_D.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: adda9a9ea56de5742bc1b00ce85ce9e5
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls.meta
new file mode 100644
index 00000000..cac0156c
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: e098c1dc313c2d746b3a0c6a7f1a69f0
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/Button_C.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/Button_C.cs
new file mode 100644
index 00000000..3eaaa7bd
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/Button_C.cs
@@ -0,0 +1,12 @@
+namespace AxibugEmuOnline.Client.InputDevices
+{
+    /// <summary>
+    /// 按键类型的输入控件
+    /// </summary>
+    public class Button_C : InputControl_C
+    {
+        public Button_C(InputDevice_D device, string controlName) : base(device, controlName)
+        {
+        }
+    }
+}
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/Button_C.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/Button_C.cs.meta
new file mode 100644
index 00000000..dbb81e4a
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/Button_C.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 2106c0f7afa9b7647978373d7c6d5aae
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/InputControl_C.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/InputControl_C.cs
new file mode 100644
index 00000000..772d697e
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/InputControl_C.cs
@@ -0,0 +1,91 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using UnityEngine;
+
+namespace AxibugEmuOnline.Client.InputDevices
+{
+    /// <summary>
+    /// 输入设备的抽象控件接口
+    /// </summary>
+    public abstract class InputControl_C
+    {
+        /// <summary> 控件所属设备 </summary>
+        public InputDevice_D Device { get; internal set; }
+
+        /// <summary> 获取该控件是否在当前调用帧被激发 </summary>
+        public bool Start { get; private set; }
+        /// <summary> 获取该控件是否在当前调用帧被释放 </summary>
+        public bool Release { get; private set; }
+
+        bool m_performingLastFrame;
+        /// <summary> 获取该控件是否在当前调用帧是否处于活动状态 </summary>
+        public virtual bool Performing => Device.Resolver.CheckPerforming(this);
+
+        /// <summary> 获得该控件的以二维向量表达的值 </summary>
+        /// <returns></returns>
+        public virtual Vector2 GetVector2() => Device.Resolver.GetVector2(this);
+        /// <summary> 获得该控件的以浮点数表达的值 </summary>
+        public virtual float GetFlaot() => Device.Resolver.GetFloat(this);
+
+        internal void Update()
+        {
+            UpdateReleaseStartState();
+            OnUpdate();
+        }
+        private void UpdateReleaseStartState()
+        {
+            var oldPerforming = m_performingLastFrame;
+            var newPerforming = Performing;
+
+            Start = false;
+            Release = false;
+            if (oldPerforming != newPerforming)
+            {
+                if (oldPerforming == false) Start = true;
+                else Release = true;
+            }
+            m_performingLastFrame = Performing;
+        }
+
+        protected virtual void OnUpdate() { }
+
+        public InputControl_C Parent { get; private set; }
+        /// <summary> 控件名,这个控件名称必须是唯一的 </summary>
+        public string ControlName { get; private set; }
+        protected Dictionary<string, InputControl_C> m_controlMapper = new Dictionary<string, InputControl_C>();
+        internal InputControl_C(InputDevice_D device, string controlName)
+        {
+            Device = device;
+            ControlName = controlName;
+
+            DefineControls();
+        }
+
+        private void DefineControls()
+        {
+            foreach (var field in GetType().GetFields(BindingFlags.Instance | BindingFlags.Public))
+            {
+                if (!typeof(InputControl_C).IsAssignableFrom(field.FieldType)) continue;
+
+                var controlIns = Activator.CreateInstance(field.FieldType, Device, field.Name) as InputControl_C;
+                controlIns.Parent = this;
+                field.SetValue(this, controlIns);
+
+                m_controlMapper[field.Name] = controlIns;
+            }
+        }
+
+        public override string ToString()
+        {
+            if (Parent != null)
+            {
+                return $"{Parent}/{ControlName}";
+            }
+            else
+            {
+                return $"{Device}/{ControlName}";
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/InputControl_C.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/InputControl_C.cs.meta
new file mode 100644
index 00000000..f5b08af4
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/InputControl_C.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 0d3d88a49545f614184e3d5a59d2958e
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/Stick_C.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/Stick_C.cs
new file mode 100644
index 00000000..023b1146
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/Stick_C.cs
@@ -0,0 +1,57 @@
+using UnityEngine;
+
+namespace AxibugEmuOnline.Client.InputDevices
+{
+    /// <summary>
+    /// 摇杆类型的输入控件,支持的返回值为Vector2
+    /// </summary>
+    public class Stick_C : InputControl_C
+    {
+        public VirtualButton Up;
+        public VirtualButton Down;
+        public VirtualButton Left;
+        public VirtualButton Right;
+
+        public Stick_C(InputDevice_D device, string controlName) : base(device, controlName) { }
+
+        protected override void OnUpdate()
+        {
+            var axis = GetVector2();
+
+            Up.m_performing = axis.y > 0f;
+            Up.Update();
+
+            Down.m_performing = axis.y < 0f;
+            Down.Update();
+
+            Left.m_performing = axis.x < 0f;
+            Left.Update();
+
+            Right.m_performing = axis.x > 0f;
+            Right.Update();
+        }
+
+
+        public class VirtualButton : InputControl_C
+        {
+            internal bool m_performing;
+
+            public VirtualButton(InputDevice_D device, string controlName) : base(device, controlName) { }
+
+            public override bool Performing
+            {
+                get => m_performing;
+            }
+
+            public override Vector2 GetVector2()
+            {
+                return default;
+            }
+
+            public override float GetFlaot()
+            {
+                return Performing ? 1 : 0;
+            }
+        }
+    }
+}
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/Stick_C.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/Stick_C.cs.meta
new file mode 100644
index 00000000..2fa0f1e3
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/Stick_C.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 9091f3794f770294488695cd2cbbf7af
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputDevice_D.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputDevice_D.cs
new file mode 100644
index 00000000..b7d82bea
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputDevice_D.cs
@@ -0,0 +1,58 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+
+namespace AxibugEmuOnline.Client.InputDevices
+{
+    public abstract class InputDevice_D
+    {
+        public string UniqueName => m_resolver.GetDeviceName(this);
+
+        /// <summary> 指示该设备是否在线 </summary>
+        public bool Online => m_resolver.CheckOnline(this);
+        /// <summary> 指示该设备当前帧是否有任意控件被激发 </summary>
+        public bool AnyKeyDown { get; private set; }
+        /// <summary> 获得输入解决器 </summary>
+        internal InputResolver Resolver => m_resolver;
+
+        protected Dictionary<string, InputControl_C> m_controlMapper = new Dictionary<string, InputControl_C>();
+        protected InputResolver m_resolver;
+        public InputDevice_D(InputResolver resolver)
+        {
+            m_resolver = resolver;
+            DefineControls();
+        }
+
+        private void DefineControls()
+        {
+            foreach (var field in GetType().GetFields(BindingFlags.Instance | BindingFlags.Public))
+            {
+                if (!typeof(InputControl_C).IsAssignableFrom(field.FieldType)) continue;
+
+                var controlIns = Activator.CreateInstance(field.FieldType, this, field.Name) as InputControl_C;
+                field.SetValue(this, controlIns);
+
+                m_controlMapper[field.Name] = controlIns;
+            }
+        }
+
+        public void Update()
+        {
+            AnyKeyDown = false;
+
+            foreach (var control in m_controlMapper.Values)
+            {
+                control.Update();
+                if (control.Start)
+                {
+                    AnyKeyDown = true;
+                }
+            }
+        }
+
+        public override string ToString()
+        {
+            return Resolver.GetDeviceName(this);
+        }
+    }
+}
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputDevice_D.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputDevice_D.cs.meta
new file mode 100644
index 00000000..40a2f53f
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputDevice_D.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: eab247826950d024b8a5c7ade4142391
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/Keyboard_D.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/Keyboard_D.cs
new file mode 100644
index 00000000..35a28897
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/Keyboard_D.cs
@@ -0,0 +1,116 @@
+using System.Collections.Generic;
+
+namespace AxibugEmuOnline.Client.InputDevices
+{
+    /// <summary>
+    /// 通用键盘设备
+    /// </summary>
+    public class Keyboard_D : InputDevice_D
+    {
+        public Button_C A;
+        public Button_C B;
+        public Button_C C;
+        public Button_C D;
+        public Button_C E;
+        public Button_C F;
+        public Button_C G;
+        public Button_C H;
+        public Button_C I;
+        public Button_C J;
+        public Button_C K;
+        public Button_C L;
+        public Button_C M;
+        public Button_C N;
+        public Button_C O;
+        public Button_C P;
+        public Button_C Q;
+        public Button_C R;
+        public Button_C S;
+        public Button_C T;
+        public Button_C U;
+        public Button_C V;
+        public Button_C W;
+        public Button_C X;
+        public Button_C Y;
+        public Button_C Z;
+        public Button_C Alpha0;
+        public Button_C Alpha1;
+        public Button_C Alpha2;
+        public Button_C Alpha3;
+        public Button_C Alpha4;
+        public Button_C Alpha5;
+        public Button_C Alpha6;
+        public Button_C Alpha7;
+        public Button_C Alpha8;
+        public Button_C Alpha9;
+        public Button_C F1;
+        public Button_C F2;
+        public Button_C F3;
+        public Button_C F4;
+        public Button_C F5;
+        public Button_C F6;
+        public Button_C F7;
+        public Button_C F8;
+        public Button_C F9;
+        public Button_C F10;
+        public Button_C F11;
+        public Button_C F12;
+        public Button_C UpArrow;
+        public Button_C DownArrow;
+        public Button_C LeftArrow;
+        public Button_C RightArrow;
+        public Button_C Space;
+        public Button_C Return;
+        public Button_C Escape;
+        public Button_C Tab;
+        public Button_C Backspace;
+        public Button_C CapsLock;
+        public Button_C LeftShift;
+        public Button_C RightShift;
+        public Button_C LeftControl;
+        public Button_C RightControl;
+        public Button_C LeftAlt;
+        public Button_C RightAlt;
+        public Button_C LeftCommand;
+        public Button_C RightCommand;
+        public Button_C Comma;
+        public Button_C Period;
+        public Button_C Slash;
+        public Button_C BackQuote;
+        public Button_C Quote;
+        public Button_C Semicolon;
+        public Button_C LeftBracket;
+        public Button_C RightBracket;
+        public Button_C Backslash;
+        public Button_C Minus;
+        public Button_C Equals_k;
+        public Button_C Keypad0;
+        public Button_C Keypad1;
+        public Button_C Keypad2;
+        public Button_C Keypad3;
+        public Button_C Keypad4;
+        public Button_C Keypad5;
+        public Button_C Keypad6;
+        public Button_C Keypad7;
+        public Button_C Keypad8;
+        public Button_C Keypad9;
+        public Button_C KeypadPeriod;
+        public Button_C KeypadDivide;
+        public Button_C KeypadMultiply;
+        public Button_C KeypadMinus;
+        public Button_C KeypadPlus;
+        public Button_C KeypadEnter;
+        public Button_C Numlock;
+        public Button_C Print;
+        public Button_C Insert;
+        public Button_C Delete;
+        public Button_C Home;
+        public Button_C End;
+        public Button_C PageUp;
+        public Button_C PageDown;
+        public Button_C Pause;
+        public Button_C ScrollLock;
+
+        public Keyboard_D(InputResolver resolver) : base(resolver) { }
+    }
+}
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/Keyboard_D.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/Keyboard_D.cs.meta
new file mode 100644
index 00000000..aaa16d13
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/Keyboard_D.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: e75cd67769afcad4890be3acf0ac1330
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/PSVController_D.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/PSVController_D.cs
new file mode 100644
index 00000000..85a6e3c3
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/PSVController_D.cs
@@ -0,0 +1,22 @@
+namespace AxibugEmuOnline.Client.InputDevices
+{
+    public class PSVController_D : InputDevice_D
+    {
+        public Button_C Cross;
+        public Button_C Circle;
+        public Button_C Square;
+        public Button_C Triangle;
+        public Button_C L;
+        public Button_C R;
+        public Button_C Select;
+        public Button_C Start;
+        public Button_C Up;
+        public Button_C Right;
+        public Button_C Down;
+        public Button_C Left;
+        public Stick_C LeftStick;
+        public Stick_C RightStick;
+
+        public PSVController_D(InputResolver resolver) : base(resolver) { }
+    }
+}
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/PSVController_D.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/PSVController_D.cs.meta
new file mode 100644
index 00000000..d1ab8ba3
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/PSVController_D.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 5f5d8205d647a4741a9c4e8d7894f040
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/ScreenGamepad_D.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/ScreenGamepad_D.cs
new file mode 100644
index 00000000..7dd41c05
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/ScreenGamepad_D.cs
@@ -0,0 +1,74 @@
+using AxiInputSP;
+using AxiInputSP.UGUI;
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace AxibugEmuOnline.Client.InputDevices
+{
+    public class ScreenGamepad_D : InputDevice_D
+    {
+        public Button_C UP;
+        public Button_C DOWN;
+        public Button_C LEFT;
+        public Button_C RIGHT;
+        public Button_C BTN_A;
+        public Button_C BTN_B;
+        public Button_C BTN_C;
+        public Button_C BTN_D;
+        public Button_C BTN_E;
+        public Button_C BTN_F;
+        public Button_C OPTION_1;
+        public Button_C OPTION_2;
+        public Button_C OPTION_3;
+        public Button_C OPTION_4;
+        public Button_C HOME;
+        public Stick_C JOYSTICK;
+
+        AxiScreenGamepad m_linkUnityImpl;
+        Dictionary<Button_C, AxiInputUGuiBtnType> m_buttonTypes = new Dictionary<Button_C, AxiInputUGuiBtnType>();
+
+        public ScreenGamepad_D(AxiScreenGamepad linkMono, InputResolver resolver) : base(resolver)
+        {
+            m_linkUnityImpl = linkMono;
+            m_buttonTypes[UP] = AxiInputUGuiBtnType.UP;
+            m_buttonTypes[DOWN] = AxiInputUGuiBtnType.DOWN;
+            m_buttonTypes[LEFT] = AxiInputUGuiBtnType.LEFT;
+            m_buttonTypes[RIGHT] = AxiInputUGuiBtnType.RIGHT;
+            m_buttonTypes[BTN_A] = AxiInputUGuiBtnType.BTN_A;
+            m_buttonTypes[BTN_B] = AxiInputUGuiBtnType.BTN_B;
+            m_buttonTypes[BTN_C] = AxiInputUGuiBtnType.BTN_C;
+            m_buttonTypes[BTN_D] = AxiInputUGuiBtnType.BTN_D;
+            m_buttonTypes[BTN_E] = AxiInputUGuiBtnType.BTN_E;
+            m_buttonTypes[BTN_F] = AxiInputUGuiBtnType.BTN_F;
+            m_buttonTypes[OPTION_1] = AxiInputUGuiBtnType.OPTION_1;
+            m_buttonTypes[OPTION_2] = AxiInputUGuiBtnType.OPTION_2;
+            m_buttonTypes[OPTION_3] = AxiInputUGuiBtnType.OPTION_3;
+            m_buttonTypes[OPTION_4] = AxiInputUGuiBtnType.OPTION_4;
+            m_buttonTypes[HOME] = AxiInputUGuiBtnType.HOME;
+        }
+
+        public bool CheckPerforming<CONTROLLER>(CONTROLLER control) where CONTROLLER : InputControl_C
+        {
+            if (control is Button_C)
+            {
+                var type = m_buttonTypes[control as Button_C];
+                return m_linkUnityImpl.GetKey(type);
+            }
+            else if (control is Stick_C)
+            {
+                var vec2 = GetVector2(control);
+                return vec2.x != 0 || vec2.y != 0;
+            }
+            else return false;
+        }
+
+        public Vector2 GetVector2<CONTROLLER>(CONTROLLER control) where CONTROLLER : InputControl_C
+        {
+            if (control is Stick_C)
+            {
+                return m_linkUnityImpl.GetJoystickValue();
+            }
+            else return default;
+        }
+    }
+}
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/ScreenGamepad_D.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/ScreenGamepad_D.cs.meta
new file mode 100644
index 00000000..abca699f
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/ScreenGamepad_D.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: dbfeb8011d9b4a8429a35bc162c72c57
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/XboxController_D.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/XboxController_D.cs
new file mode 100644
index 00000000..41380b27
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/XboxController_D.cs
@@ -0,0 +1,27 @@
+namespace AxibugEmuOnline.Client.InputDevices
+{
+    public class XboxController_D : InputDevice_D
+    {
+        public Button_C X;
+        public Button_C Y;
+        public Button_C A;
+        public Button_C B;
+        public Button_C Up;
+        public Button_C Down;
+        public Button_C Left;
+        public Button_C Right;
+        public Button_C View;
+        public Button_C Menu;
+        public Button_C LeftBumper;
+        public Button_C LeftTrigger;
+        public Button_C LeftStickPress;
+        public Button_C RightBumper;
+        public Button_C RightTrigger;
+        public Button_C RightStickPress;
+        public Stick_C LeftStick;
+        public Stick_C RightStick;
+
+
+        public XboxController_D(InputResolver resolver) : base(resolver) { }
+    }
+}
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/XboxController_D.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/XboxController_D.cs.meta
new file mode 100644
index 00000000..fb344f7b
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/XboxController_D.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 5f0e5bba332725e45bb53ac32c4ee6d2
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/DualWayDictionary.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/DualWayDictionary.cs
new file mode 100644
index 00000000..3ab06251
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/DualWayDictionary.cs
@@ -0,0 +1,133 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace AxibugEmuOnline.Client.InputDevices
+{
+    /// <summary>
+    /// 双向字典
+    /// </summary>
+    /// <typeparam name="TKey"></typeparam>
+    /// <typeparam name="TValue"></typeparam>
+    public class DualWayDictionary<TKey, TValue> : IDictionary<TKey, TValue>, IDictionary
+        where TKey : notnull
+        where TValue : notnull
+    {
+        private readonly Dictionary<TKey, TValue> _forward = new();
+        private readonly Dictionary<TValue, TKey> _reverse = new();
+
+        // 显式实现非泛型接口
+        bool IDictionary.IsFixedSize => false;
+        bool IDictionary.IsReadOnly => false;
+        bool ICollection.IsSynchronized => false;
+        object ICollection.SyncRoot => ((ICollection)_forward).SyncRoot;
+
+        // 泛型接口实现
+        public TValue this[TKey key]
+        {
+            get => _forward[key];
+            set
+            {
+                if (_forward.TryGetValue(key, out var oldValue))
+                    _reverse.Remove(oldValue);
+                _forward[key] = value;
+                _reverse[value] = key;
+            }
+        }
+
+        object? IDictionary.this[object key]
+        {
+            get => key is TKey k ? _forward[k] : null;
+            set
+            {
+                if (key is TKey tk && value is TValue tv)
+                    this[tk] = tv;
+            }
+        }
+
+        public ICollection<TKey> Keys => _forward.Keys;
+        public ICollection<TValue> Values => _forward.Values;
+
+        ICollection IDictionary.Keys => _forward.Keys;
+        ICollection IDictionary.Values => _forward.Values;
+
+        public int Count => _forward.Count;
+        public bool IsReadOnly => false;
+
+        // 双向查询扩展
+        public bool TryGetKey(TValue value, out TKey key) => _reverse.TryGetValue(value, out key);
+        public bool TryGetValue(TKey key, out TValue value) => _forward.TryGetValue(key, out value);
+
+        // 接口方法实现
+        public void Add(TKey key, TValue value)
+        {
+            if (_forward.ContainsKey(key) || _reverse.ContainsKey(value))
+                throw new ArgumentException("键或值已存在");
+            _forward.Add(key, value);
+            _reverse.Add(value, key);
+        }
+
+        public void Add(KeyValuePair<TKey, TValue> item) => Add(item.Key, item.Value);
+
+        void IDictionary.Add(object key, object value)
+        {
+            if (key is TKey k && value is TValue v)
+                Add(k, v);
+            else
+                throw new ArgumentException("类型不匹配");
+        }
+
+        public bool Contains(object key) => key is TKey k && _forward.ContainsKey(k);
+        public bool Contains(KeyValuePair<TKey, TValue> item) => _forward.TryGetValue(item.Key, out var v) && v.Equals(item.Value);
+        public bool ContainsKey(TKey key) => _forward.ContainsKey(key);
+
+        public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
+        {
+            ((ICollection<KeyValuePair<TKey, TValue>>)_forward).CopyTo(array, arrayIndex);
+        }
+
+        public void CopyTo(Array array, int index)
+        {
+            ((ICollection)_forward).CopyTo(array, index);
+        }
+
+        public bool Remove(TKey key)
+        {
+            if (!_forward.Remove(key, out var value)) return false;
+            _reverse.Remove(value);
+            return true;
+        }
+
+        public bool Remove(KeyValuePair<TKey, TValue> item) => Remove(item.Key);
+
+        void IDictionary.Remove(object key)
+        {
+            if (key is TKey k) Remove(k);
+        }
+
+        public void Clear()
+        {
+            _forward.Clear();
+            _reverse.Clear();
+        }
+
+        // 枚举器实现
+        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() => _forward.GetEnumerator();
+        IDictionaryEnumerator IDictionary.GetEnumerator() => new DictionaryEnumerator(_forward.GetEnumerator());
+        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
+
+        // 非泛型枚举器适配器
+        private class DictionaryEnumerator : IDictionaryEnumerator
+        {
+            private readonly IEnumerator<KeyValuePair<TKey, TValue>> _enumerator;
+            public DictionaryEnumerator(IEnumerator<KeyValuePair<TKey, TValue>> enumerator) => _enumerator = enumerator;
+
+            public DictionaryEntry Entry => new(_enumerator.Current.Key, _enumerator.Current.Value);
+            public object Key => _enumerator.Current.Key;
+            public object? Value => _enumerator.Current.Value;
+            public object Current => Entry;
+            public bool MoveNext() => _enumerator.MoveNext();
+            public void Reset() => _enumerator.Reset();
+        }
+    }
+}
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/DualWayDictionary.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/DualWayDictionary.cs.meta
new file mode 100644
index 00000000..8346d0ac
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/DualWayDictionary.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: c1c60fee919bdf34983705af53c629f6
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs
new file mode 100644
index 00000000..eb323aa1
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs
@@ -0,0 +1,82 @@
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace AxibugEmuOnline.Client.InputDevices
+{
+    public class InputDevicesManager
+    {
+        InputResolver m_inputResolver = InputResolver.Create();
+        Dictionary<string, InputDevice_D> m_devices = new Dictionary<string, InputDevice_D>();
+
+        public delegate void OnDeviceConnectedHandle(InputDevice_D connectDevice);
+        public event OnDeviceConnectedHandle OnDeviceConnected;
+        public delegate void OnDeviceLostHandle(InputDevice_D lostDevice);
+        public event OnDeviceLostHandle OnDeviceLost;
+
+        bool m_quiting;
+        public InputDevicesManager()
+        {
+            Application.quitting += Application_quitting;
+            m_inputResolver.OnDeviceConnected += Resolver_OnDeviceConnected;
+            m_inputResolver.OnDeviceLost += Resolver_OnDeviceLost;
+            foreach (var device in m_inputResolver.GetDevices())
+                AddDevice(device);
+        }
+
+        private void Application_quitting()
+        {
+            m_quiting = true;
+        }
+
+        private void Resolver_OnDeviceLost(InputDevice_D lostDevice)
+        {
+            RemoveDevice(lostDevice);
+        }
+
+        private void Resolver_OnDeviceConnected(InputDevice_D connectDevice)
+        {
+            AddDevice(connectDevice);
+        }
+
+        void AddDevice(InputDevice_D device)
+        {
+            m_devices[device.UniqueName] = device;
+            OnDeviceConnected?.Invoke(device);
+        }
+
+        void RemoveDevice(InputDevice_D device)
+        {
+            if (m_quiting) return;
+
+            m_devices.Remove(device.UniqueName);
+            OnDeviceLost?.Invoke(device);
+        }
+
+        /// <summary>
+        /// 获得一个指定类型的设备
+        /// </summary>
+        public T GetDevice<T>() where T : InputDevice_D
+        {
+            foreach (var d in m_devices.Values)
+            {
+                if (d is T) return d as T;
+            }
+
+            return null;
+        }
+        /// <summary>
+        /// 获得所有存在的输入设备
+        /// </summary>
+        /// <returns></returns>
+        public IEnumerable<InputDevice_D> GetDevices()
+        {
+            return m_devices.Values;
+        }
+
+        /// <summary> 由外部驱动的逻辑更新入口 </summary>
+        public void Update()
+        {
+            foreach (var device in m_devices.Values) device.Update();
+        }
+    }
+}
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs.meta
new file mode 100644
index 00000000..30fbdabe
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 81cfc80679d76514d801eed124ffc356
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver.meta
new file mode 100644
index 00000000..5884599b
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 8fec275f55ad33a4fbe0ce724bc7274f
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputResolver.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputResolver.cs
new file mode 100644
index 00000000..c681bb0a
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputResolver.cs
@@ -0,0 +1,145 @@
+using AxiInputSP.UGUI;
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace AxibugEmuOnline.Client.InputDevices
+{
+    public abstract class InputResolver
+    {
+        public static InputResolver Create()
+        {
+#if ENABLE_INPUT_SYSTEM //InputSystem
+            return new ForInputSystem.InputSystemResolver();
+#elif UNITY_PSP2 //特化实现
+            return new ForPSV.PSVResolver();
+#elif UNITY_PS3 //SDK
+            throw new System.NotImplementedException();
+#else 
+            throw new System.NotImplementedException();    
+#endif
+        }
+
+        DualWayDictionary<AxiScreenGamepad, ScreenGamepad_D> m_devices = new DualWayDictionary<AxiScreenGamepad, ScreenGamepad_D>();
+
+        /// <summary> 禁止外部构造 </summary>
+        protected InputResolver()
+        {
+            AxiScreenGamepad.OnGamepadActive += AxiScreenGamepad_OnGamepadActive;
+            AxiScreenGamepad.OnGamepadDisactive += AxiScreenGamepad_OnGamepadDisactive;
+            OnInit();
+        }
+
+        private void AxiScreenGamepad_OnGamepadDisactive(AxiScreenGamepad sender)
+        {
+            if (m_devices.TryGetValue(sender, out var device))
+            {
+                m_devices.Remove(sender);
+                RaiseDeviceLost(device);
+            }
+        }
+
+        private void AxiScreenGamepad_OnGamepadActive(AxiScreenGamepad sender)
+        {
+            var newDevice = new ScreenGamepad_D(sender, this);
+            m_devices[sender] = newDevice;
+            RaiseDeviceConnected(newDevice);
+        }
+
+        protected abstract void OnInit();
+
+        List<InputDevice_D> m_devicesResultCache = new List<InputDevice_D>();
+        /// <summary>
+        /// 获得所有当前已连入的输入设备
+        /// </summary>
+        /// <returns></returns>
+        public IEnumerable<InputDevice_D> GetDevices()
+        {
+            m_devicesResultCache.Clear();
+            m_devicesResultCache.AddRange(m_devices.Values);
+            m_devicesResultCache.AddRange(OnGetDevices());
+            return m_devicesResultCache;
+        }
+        /// <inheritdoc cref="GetDevices"/>
+        protected abstract IEnumerable<InputDevice_D> OnGetDevices();
+
+        /// <summary> 检查指定输入设备是否还保持着连接 </summary>
+        public bool CheckOnline(InputDevice_D device)
+        {
+            if (device is ScreenGamepad_D)
+            {
+                return m_devices.TryGetKey(device as ScreenGamepad_D, out var _);
+            }
+            else
+            {
+                return OnCheckOnline(device);
+            }
+        }
+        /// <inheritdoc cref="CheckOnline(InputDevice_D)"/>
+        protected abstract bool OnCheckOnline(InputDevice_D device);
+
+        /// <param name="lostDevice">丢失的设备</param>
+        public delegate void OnDeviceLostHandle(InputDevice_D lostDevice);
+        /// <summary> 当设备丢失时触发 </summary>
+        public event OnDeviceLostHandle OnDeviceLost;
+        protected void RaiseDeviceLost(InputDevice_D lostDevice)
+        {
+            OnDeviceLost?.Invoke(lostDevice);
+        }
+
+        /// <param name="connectDevice">建立连接的设备</param>
+        public delegate void OnDeviceConnectedHandle(InputDevice_D connectDevice);
+        /// <summary> 当设备连接时触发 </summary>
+        public event OnDeviceConnectedHandle OnDeviceConnected;
+        protected void RaiseDeviceConnected(InputDevice_D connectDevice)
+        {
+            OnDeviceConnected?.Invoke(connectDevice);
+        }
+
+        public bool CheckPerforming<CONTROLLER>(CONTROLLER control) where CONTROLLER : InputControl_C
+        {
+            if (control.Device is ScreenGamepad_D)
+            {
+                ScreenGamepad_D device = control.Device as ScreenGamepad_D;
+
+                return device.CheckPerforming(control);
+            }
+            else return OnCheckPerforming(control);
+        }
+        protected abstract bool OnCheckPerforming<CONTROLLER>(CONTROLLER control) where CONTROLLER : InputControl_C;
+
+        public Vector2 GetVector2<CONTROLLER>(CONTROLLER control) where CONTROLLER : InputControl_C
+        {
+            if (control.Device is ScreenGamepad_D)
+            {
+                ScreenGamepad_D device = control.Device as ScreenGamepad_D;
+
+                return device.GetVector2(control);
+            }
+            return OnGetVector2(control);
+        }
+        protected abstract Vector2 OnGetVector2<CONTROLLER>(CONTROLLER control) where CONTROLLER : InputControl_C;
+
+        public float GetFloat<CONTROLLER>(CONTROLLER control) where CONTROLLER : InputControl_C
+        {
+            return OnGetFloat(control);
+        }
+        protected abstract float OnGetFloat<CONTROLLER>(CONTROLLER control) where CONTROLLER : InputControl_C;
+
+        /// <summary>
+        /// 获得输入设备的唯一名称
+        /// </summary>
+        /// <param name="inputDevice">这个设备必须是由resolver提供,并且保持着连接</param>
+        /// <returns></returns>
+        public string GetDeviceName(InputDevice_D inputDevice)
+        {
+            if (inputDevice is ScreenGamepad_D)
+            {
+                m_devices.TryGetKey(inputDevice as ScreenGamepad_D, out var realDeviceScript);
+                return $"{realDeviceScript.GetType().Name}_{realDeviceScript.GetHashCode()}";
+            }
+            else return OnGetDeviceName(inputDevice);
+        }
+        /// <inheritdoc cref="GetDeviceName(InputDevice_D)"/>
+        protected abstract string OnGetDeviceName(InputDevice_D inputDevice);
+    }
+}
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputResolver.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputResolver.cs.meta
new file mode 100644
index 00000000..fc7b2ce9
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputResolver.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 120c0ed2a5e098a4d84325be244aa9f3
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs
new file mode 100644
index 00000000..02eec3fd
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs
@@ -0,0 +1,302 @@
+#if ENABLE_INPUT_SYSTEM
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.InputSystem;
+using UnityEngine.InputSystem.DualShock;
+using UnityEngine.InputSystem.XInput;
+
+namespace AxibugEmuOnline.Client.InputDevices.ForInputSystem
+{
+    /// <summary> 基于UnityInputSystem实现的输入解决器 </summary>
+    public class InputSystemResolver : InputResolver
+    {
+        DualWayDictionary<InputDevice, InputDevice_D> m_devices = new DualWayDictionary<InputDevice, InputDevice_D>();
+
+        protected override void OnInit()
+        {
+            foreach (var device in InputSystem.devices) AddDevice(device);
+
+            InputSystem.onDeviceChange += IP_onDeviceChange;
+        }
+
+        private void AddDevice(InputDevice ipdev)
+        {
+            InputDevice_D newDevice = null;
+            if (ipdev is Keyboard) newDevice = new Keyboard_D(this);
+            else if (ipdev is DualShockGamepad) newDevice = new DualShockController_D(this);
+            else if (ipdev is XInputController) newDevice = new XboxController_D(this);
+            else if (ipdev is Gamepad) newDevice = new GamePad_D(this); //注意Gamepad的优先级,因为任何手柄,Inputsystem中的基类都是GamePad
+
+            if (newDevice != null)
+            {
+                m_devices.Add(ipdev, newDevice);
+                AddDeviceMapper(newDevice, ipdev);
+                RaiseDeviceConnected(newDevice);
+            }
+        }
+
+        private void RemoveDevice(InputDevice ipdev)
+        {
+            if (m_devices.TryGetValue(ipdev, out var device))
+            {
+                m_devices.Remove(ipdev);
+                RemoveDeviceMapper(device);
+                RaiseDeviceLost(device);
+            }
+        }
+
+        private T GetInputSystemDevice<T>(InputDevice_D device) where T : InputDevice
+        {
+            m_devices.TryGetKey(device, out var ipDev);
+            return ipDev as T;
+        }
+
+        protected override string OnGetDeviceName(InputDevice_D inputDevice)
+        {
+            var ipdev = GetInputSystemDevice<InputDevice>(inputDevice);
+            Debug.Assert(ipdev != null, "不能对已离线的设备获取名称");
+
+            return $"{ipdev.description.deviceClass}_{ipdev.description.interfaceName}_{ipdev.deviceId}";
+        }
+
+        protected override bool OnCheckOnline(InputDevice_D device)
+        {
+            return m_devices.TryGetKey(device, out var _);
+        }
+
+        private void IP_onDeviceChange(InputDevice device, InputDeviceChange changeType)
+        {
+            switch (changeType)
+            {
+                case InputDeviceChange.Added: AddDevice(device); break;
+                case InputDeviceChange.Removed: RemoveDevice(device); break;
+            }
+        }
+
+        protected override IEnumerable<InputDevice_D> OnGetDevices()
+        {
+            return m_devices.Values;
+        }
+
+        protected override bool OnCheckPerforming<CONTROLLER>(CONTROLLER control)
+        {
+            var ipControl = GetInputSystemControl(control);
+            return ipControl.IsPressed();
+        }
+
+        protected override Vector2 OnGetVector2<CONTROLLER>(CONTROLLER control)
+        {
+            var ipControl = GetInputSystemControl(control);
+            return (ipControl as InputControl<Vector2>).value;
+        }
+
+        protected override float OnGetFloat<CONTROLLER>(CONTROLLER control)
+        {
+            var ipControl = GetInputSystemControl(control);
+            return (ipControl as InputControl<float>).value;
+        }
+
+        InputControl GetInputSystemControl(InputControl_C key)
+        {
+            var device_d = key.Device;
+            var mapper = m_deviceMapper[device_d];
+            mapper.TryGetValue(key, out InputControl inputBtn);
+            if (inputBtn != null)
+                return inputBtn;
+            else
+            {
+                throw new System.Exception($"not found mapper setting : {key}");
+            }
+        }
+        Dictionary<InputDevice_D, Dictionary<InputControl_C, InputControl>> m_deviceMapper = new Dictionary<InputDevice_D, Dictionary<InputControl_C, InputControl>>();
+        void AddDeviceMapper(InputDevice_D device_d, InputDevice ipdevice)
+        {
+            m_deviceMapper.Add(device_d, new Dictionary<InputControl_C, InputControl>());
+            var mapper = m_deviceMapper[device_d];
+
+            if (device_d is Keyboard_D keyboard_d)
+            {
+                var ipKeyboard = ipdevice as Keyboard;
+
+                mapper[keyboard_d.A] = ipKeyboard.aKey;
+                mapper[keyboard_d.B] = ipKeyboard.bKey;
+                mapper[keyboard_d.C] = ipKeyboard.cKey;
+                mapper[keyboard_d.D] = ipKeyboard.dKey;
+                mapper[keyboard_d.E] = ipKeyboard.eKey;
+                mapper[keyboard_d.F] = ipKeyboard.fKey;
+                mapper[keyboard_d.G] = ipKeyboard.gKey;
+                mapper[keyboard_d.H] = ipKeyboard.hKey;
+                mapper[keyboard_d.I] = ipKeyboard.iKey;
+                mapper[keyboard_d.J] = ipKeyboard.jKey;
+                mapper[keyboard_d.K] = ipKeyboard.kKey;
+                mapper[keyboard_d.L] = ipKeyboard.lKey;
+                mapper[keyboard_d.M] = ipKeyboard.mKey;
+                mapper[keyboard_d.N] = ipKeyboard.nKey;
+                mapper[keyboard_d.O] = ipKeyboard.oKey;
+                mapper[keyboard_d.P] = ipKeyboard.pKey;
+                mapper[keyboard_d.Q] = ipKeyboard.qKey;
+                mapper[keyboard_d.R] = ipKeyboard.rKey;
+                mapper[keyboard_d.S] = ipKeyboard.sKey;
+                mapper[keyboard_d.T] = ipKeyboard.tKey;
+                mapper[keyboard_d.U] = ipKeyboard.uKey;
+                mapper[keyboard_d.V] = ipKeyboard.vKey;
+                mapper[keyboard_d.W] = ipKeyboard.wKey;
+                mapper[keyboard_d.X] = ipKeyboard.xKey;
+                mapper[keyboard_d.Y] = ipKeyboard.yKey;
+                mapper[keyboard_d.Z] = ipKeyboard.zKey;
+                mapper[keyboard_d.Alpha0] = ipKeyboard.digit0Key;
+                mapper[keyboard_d.Alpha1] = ipKeyboard.digit1Key;
+                mapper[keyboard_d.Alpha2] = ipKeyboard.digit2Key;
+                mapper[keyboard_d.Alpha3] = ipKeyboard.digit3Key;
+                mapper[keyboard_d.Alpha4] = ipKeyboard.digit4Key;
+                mapper[keyboard_d.Alpha5] = ipKeyboard.digit5Key;
+                mapper[keyboard_d.Alpha6] = ipKeyboard.digit6Key;
+                mapper[keyboard_d.Alpha7] = ipKeyboard.digit7Key;
+                mapper[keyboard_d.Alpha8] = ipKeyboard.digit8Key;
+                mapper[keyboard_d.Alpha9] = ipKeyboard.digit9Key;
+                mapper[keyboard_d.Keypad0] = ipKeyboard.numpad0Key;
+                mapper[keyboard_d.Keypad1] = ipKeyboard.numpad1Key;
+                mapper[keyboard_d.Keypad2] = ipKeyboard.numpad2Key;
+                mapper[keyboard_d.Keypad3] = ipKeyboard.numpad3Key;
+                mapper[keyboard_d.Keypad4] = ipKeyboard.numpad4Key;
+                mapper[keyboard_d.Keypad5] = ipKeyboard.numpad5Key;
+                mapper[keyboard_d.Keypad6] = ipKeyboard.numpad6Key;
+                mapper[keyboard_d.Keypad7] = ipKeyboard.numpad7Key;
+                mapper[keyboard_d.Keypad8] = ipKeyboard.numpad8Key;
+                mapper[keyboard_d.Keypad9] = ipKeyboard.numpad9Key;
+                mapper[keyboard_d.KeypadPeriod] = ipKeyboard.numpadPeriodKey;
+                mapper[keyboard_d.KeypadDivide] = ipKeyboard.numpadDivideKey;
+                mapper[keyboard_d.KeypadMultiply] = ipKeyboard.numpadMultiplyKey;
+                mapper[keyboard_d.KeypadMinus] = ipKeyboard.numpadMinusKey;
+                mapper[keyboard_d.KeypadPlus] = ipKeyboard.numpadPlusKey;
+                mapper[keyboard_d.KeypadEnter] = ipKeyboard.numpadEnterKey;
+                mapper[keyboard_d.F1] = ipKeyboard.f1Key;
+                mapper[keyboard_d.F2] = ipKeyboard.f2Key;
+                mapper[keyboard_d.F3] = ipKeyboard.f3Key;
+                mapper[keyboard_d.F4] = ipKeyboard.f4Key;
+                mapper[keyboard_d.F5] = ipKeyboard.f5Key;
+                mapper[keyboard_d.F6] = ipKeyboard.f6Key;
+                mapper[keyboard_d.F7] = ipKeyboard.f7Key;
+                mapper[keyboard_d.F8] = ipKeyboard.f8Key;
+                mapper[keyboard_d.F9] = ipKeyboard.f9Key;
+                mapper[keyboard_d.F10] = ipKeyboard.f10Key;
+                mapper[keyboard_d.F11] = ipKeyboard.f11Key;
+                mapper[keyboard_d.F12] = ipKeyboard.f12Key;
+                mapper[keyboard_d.UpArrow] = ipKeyboard.upArrowKey;
+                mapper[keyboard_d.DownArrow] = ipKeyboard.downArrowKey;
+                mapper[keyboard_d.LeftArrow] = ipKeyboard.leftArrowKey;
+                mapper[keyboard_d.RightArrow] = ipKeyboard.rightArrowKey;
+                mapper[keyboard_d.Space] = ipKeyboard.spaceKey;
+                mapper[keyboard_d.Backspace] = ipKeyboard.backspaceKey;
+                mapper[keyboard_d.Tab] = ipKeyboard.tabKey;
+                mapper[keyboard_d.Return] = ipKeyboard.enterKey;
+                mapper[keyboard_d.Escape] = ipKeyboard.escapeKey;
+                mapper[keyboard_d.LeftShift] = ipKeyboard.leftShiftKey;
+                mapper[keyboard_d.RightShift] = ipKeyboard.rightShiftKey;
+                mapper[keyboard_d.LeftControl] = ipKeyboard.leftCtrlKey;
+                mapper[keyboard_d.RightControl] = ipKeyboard.rightCtrlKey;
+                mapper[keyboard_d.LeftAlt] = ipKeyboard.leftAltKey;
+                mapper[keyboard_d.RightAlt] = ipKeyboard.rightAltKey;
+                mapper[keyboard_d.LeftCommand] = ipKeyboard.leftCommandKey;
+                mapper[keyboard_d.RightCommand] = ipKeyboard.rightCommandKey;
+                mapper[keyboard_d.CapsLock] = ipKeyboard.capsLockKey;
+                mapper[keyboard_d.Numlock] = ipKeyboard.numLockKey;
+                mapper[keyboard_d.ScrollLock] = ipKeyboard.scrollLockKey;
+                mapper[keyboard_d.Print] = ipKeyboard.printScreenKey;
+                mapper[keyboard_d.Pause] = ipKeyboard.pauseKey;
+                mapper[keyboard_d.Insert] = ipKeyboard.insertKey;
+                mapper[keyboard_d.Home] = ipKeyboard.homeKey;
+                mapper[keyboard_d.End] = ipKeyboard.endKey;
+                mapper[keyboard_d.PageUp] = ipKeyboard.pageUpKey;
+                mapper[keyboard_d.PageDown] = ipKeyboard.pageDownKey;
+                mapper[keyboard_d.Delete] = ipKeyboard.deleteKey;
+                mapper[keyboard_d.Comma] = ipKeyboard.commaKey;
+                mapper[keyboard_d.Period] = ipKeyboard.periodKey;
+                mapper[keyboard_d.Slash] = ipKeyboard.slashKey;
+                mapper[keyboard_d.BackQuote] = ipKeyboard.backquoteKey;
+                mapper[keyboard_d.Minus] = ipKeyboard.minusKey;
+                mapper[keyboard_d.Equals_k] = ipKeyboard.equalsKey;
+                mapper[keyboard_d.LeftBracket] = ipKeyboard.leftBracketKey;
+                mapper[keyboard_d.RightBracket] = ipKeyboard.rightBracketKey;
+                mapper[keyboard_d.Backslash] = ipKeyboard.backslashKey;
+                mapper[keyboard_d.Semicolon] = ipKeyboard.semicolonKey;
+                mapper[keyboard_d.Quote] = ipKeyboard.quoteKey;
+            }
+            else if (device_d is DualShockController_D ds_d)
+            {
+                var ipDsGamePad = ipdevice as DualShockGamepad;
+                mapper[ds_d.Circle] = ipDsGamePad.circleButton;
+                mapper[ds_d.Triangle] = ipDsGamePad.triangleButton;
+                mapper[ds_d.Cross] = ipDsGamePad.crossButton;
+                mapper[ds_d.Square] = ipDsGamePad.squareButton;
+                mapper[ds_d.Up] = ipDsGamePad.dpad.up;
+                mapper[ds_d.Down] = ipDsGamePad.dpad.down;
+                mapper[ds_d.Left] = ipDsGamePad.dpad.left;
+                mapper[ds_d.Right] = ipDsGamePad.dpad.right;
+                mapper[ds_d.L1] = ipDsGamePad.L1;
+                mapper[ds_d.L2] = ipDsGamePad.L2;
+                mapper[ds_d.L3] = ipDsGamePad.L3;
+                mapper[ds_d.R1] = ipDsGamePad.R1;
+                mapper[ds_d.R2] = ipDsGamePad.R2;
+                mapper[ds_d.R3] = ipDsGamePad.R3;
+                mapper[ds_d.Share] = ipDsGamePad.shareButton;
+                mapper[ds_d.Options] = ipDsGamePad.optionsButton;
+                mapper[ds_d.TouchpadBtn] = ipDsGamePad.touchpadButton;
+                mapper[ds_d.LeftStick] = ipDsGamePad.leftStick;
+                mapper[ds_d.RightStick] = ipDsGamePad.rightStick;
+            }
+            else if (device_d is XboxController_D xbox_d)
+            {
+                var ipXInputGamePad = ipdevice as XInputController;
+                mapper[xbox_d.X] = ipXInputGamePad.xButton;
+                mapper[xbox_d.Y] = ipXInputGamePad.yButton;
+                mapper[xbox_d.A] = ipXInputGamePad.aButton;
+                mapper[xbox_d.B] = ipXInputGamePad.bButton;
+                mapper[xbox_d.Up] = ipXInputGamePad.dpad.up;
+                mapper[xbox_d.Down] = ipXInputGamePad.dpad.down;
+                mapper[xbox_d.Left] = ipXInputGamePad.dpad.left;
+                mapper[xbox_d.Right] = ipXInputGamePad.dpad.right;
+                mapper[xbox_d.View] = ipXInputGamePad.view;
+                mapper[xbox_d.Menu] = ipXInputGamePad.menu;
+                mapper[xbox_d.LeftBumper] = ipXInputGamePad.leftShoulder;
+                mapper[xbox_d.LeftTrigger] = ipXInputGamePad.leftTrigger;
+                mapper[xbox_d.LeftStickPress] = ipXInputGamePad.leftStickButton;
+                mapper[xbox_d.RightBumper] = ipXInputGamePad.rightShoulder;
+                mapper[xbox_d.RightTrigger] = ipXInputGamePad.rightTrigger;
+                mapper[xbox_d.RightStickPress] = ipXInputGamePad.rightStickButton;
+                mapper[xbox_d.LeftStick] = ipXInputGamePad.leftStick;
+                mapper[xbox_d.RightStick] = ipXInputGamePad.rightStick;
+
+            }
+            else if (device_d is GamePad_D gamepad_d)
+            {
+                var ipGamepad = ipdevice as Gamepad;
+                mapper[gamepad_d.Up] = ipGamepad.dpad.up;
+                mapper[gamepad_d.Down] = ipGamepad.dpad.down;
+                mapper[gamepad_d.Left] = ipGamepad.dpad.left;
+                mapper[gamepad_d.Right] = ipGamepad.dpad.right;
+                mapper[gamepad_d.Select] = ipGamepad.selectButton;
+                mapper[gamepad_d.Start] = ipGamepad.startButton;
+                mapper[gamepad_d.North] = ipGamepad.buttonNorth;
+                mapper[gamepad_d.South] = ipGamepad.buttonSouth;
+                mapper[gamepad_d.West] = ipGamepad.buttonWest;
+                mapper[gamepad_d.East] = ipGamepad.buttonEast;
+                mapper[gamepad_d.LeftShoulder] = ipGamepad.leftShoulder;
+                mapper[gamepad_d.RightShoulder] = ipGamepad.rightShoulder;
+                mapper[gamepad_d.LeftTrigger] = ipGamepad.leftTrigger;
+                mapper[gamepad_d.RightTrigger] = ipGamepad.rightTrigger;
+                mapper[gamepad_d.LeftStickPress] = ipGamepad.leftStickButton;
+                mapper[gamepad_d.RightStickPress] = ipGamepad.rightStickButton;
+                mapper[gamepad_d.LeftStick] = ipGamepad.leftStick;
+                mapper[gamepad_d.RightStick] = ipGamepad.rightStick;
+            }
+            else throw new System.NotImplementedException($"初始化设备失败,未实现的物理按键映射 for {device_d.GetType()}");
+        }
+        void RemoveDeviceMapper(InputDevice_D keyboard_d)
+        {
+            m_deviceMapper.Remove(keyboard_d);
+        }
+    }
+
+}
+#endif
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs.meta
new file mode 100644
index 00000000..07098ed2
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: e56617975c158684eb627cfb4a1c3ebd
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/PSVResolver.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/PSVResolver.cs
new file mode 100644
index 00000000..b13ac075
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/PSVResolver.cs
@@ -0,0 +1,83 @@
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace AxibugEmuOnline.Client.InputDevices.ForPSV
+{
+    /// <summary> PSV特化输入解决器,只能用于PSV平台,并且只支持PSV控制器 </summary>
+    public class PSVResolver : InputResolver
+    {
+        List<InputDevice_D> m_devices = new List<InputDevice_D>();
+        PSVController_D m_psvController;
+
+        protected override void OnInit()
+        {
+            m_psvController = new PSVController_D(this);
+            m_devices.Add(m_psvController);
+        }
+
+        protected override IEnumerable<InputDevice_D> OnGetDevices()
+        {
+            return m_devices;
+        }
+
+        protected override bool OnCheckOnline(InputDevice_D device)
+        {
+            return device == m_psvController;
+        }
+
+        protected override string OnGetDeviceName(InputDevice_D inputDevice)
+        {
+            Debug.Assert(inputDevice == m_psvController, "只支持psv控制器");
+
+            return nameof(PSVController_D);
+        }
+
+        protected override bool OnCheckPerforming<CONTROLLER>(CONTROLLER control)
+        {
+            if (control.Device is PSVController_D psvCon)
+            {
+                if (control == psvCon.Cross) return Input.GetKey(KeyCode.Joystick1Button0);
+                else if (control == psvCon.Circle) return Input.GetKey(KeyCode.Joystick1Button1);
+                else if (control == psvCon.Square) return Input.GetKey(KeyCode.Joystick1Button2);
+                else if (control == psvCon.Triangle) return Input.GetKey(KeyCode.Joystick1Button3);
+                else if (control == psvCon.L) return Input.GetKey(KeyCode.Joystick1Button4);
+                else if (control == psvCon.R) return Input.GetKey(KeyCode.Joystick1Button5);
+                else if (control == psvCon.Select) return Input.GetKey(KeyCode.Joystick1Button6);
+                else if (control == psvCon.Start) return Input.GetKey(KeyCode.Joystick1Button7);
+                else if (control == psvCon.Up) return Input.GetKey(KeyCode.Joystick1Button8);
+                else if (control == psvCon.Right) return Input.GetKey(KeyCode.Joystick1Button9);
+                else if (control == psvCon.Down) return Input.GetKey(KeyCode.Joystick1Button10);
+                else if (control == psvCon.Left) return Input.GetKey(KeyCode.Joystick1Button11);
+                else if (control == psvCon.LeftStick || control == psvCon.RightStick)
+                {
+                    var vec2 = control.GetVector2();
+                    return vec2.x != 0 || vec2.y != 0;
+                }
+            }
+
+            throw new System.NotImplementedException();
+        }
+
+        protected override Vector2 OnGetVector2<CONTROLLER>(CONTROLLER control)
+        {
+            if (control.Device is PSVController_D psvCon)
+            {
+                if (control == psvCon.LeftStick)
+                {
+                    return new Vector2(Input.GetAxis("Joy1 Axis X"), Input.GetAxis("Joy1 Axis Y"));
+                }
+                else if (control == psvCon.RightStick)
+                {
+                    return new Vector2(Input.GetAxis("Joy1 Axis 4"), Input.GetAxis("Joy1 Axis 5"));
+                }
+            }
+
+            throw new System.NotImplementedException();
+        }
+
+        protected override float OnGetFloat<CONTROLLER>(CONTROLLER control)
+        {
+            throw new System.NotImplementedException();
+        }
+    }
+}
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/PSVResolver.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/PSVResolver.cs.meta
new file mode 100644
index 00000000..83539f59
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/PSVResolver.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 4347b81ba3ae8e148813290b685e8df0
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/BgSettingsUI/ScreenScalerListMenuItem.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/BgSettingsUI/ScreenScalerListMenuItem.cs
index b57268a4..4ad2b1fe 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/BgSettingsUI/ScreenScalerListMenuItem.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/BgSettingsUI/ScreenScalerListMenuItem.cs
@@ -1,4 +1,5 @@
 using AxibugEmuOnline.Client.ClientCore;
+using AxibugEmuOnline.Client.Settings;
 using System;
 using System.Collections.Generic;
 
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/BgSettingsUI/SettingItemSelector.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/BgSettingsUI/SettingItemSelector.cs
index 68421fbc..00c3e607 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/BgSettingsUI/SettingItemSelector.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/BgSettingsUI/SettingItemSelector.cs
@@ -1,3 +1,4 @@
+using AxibugEmuOnline.Client.Settings;
 using UnityEngine;
 
 namespace AxibugEmuOnline.Client
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/BgSettingsUI/UI_BgSettingItem_Color.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/BgSettingsUI/UI_BgSettingItem_Color.cs
index ee7b52bd..4632336a 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/BgSettingsUI/UI_BgSettingItem_Color.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/BgSettingsUI/UI_BgSettingItem_Color.cs
@@ -1,4 +1,5 @@
 using AxibugEmuOnline.Client.ClientCore;
+using AxibugEmuOnline.Client.Settings;
 using AxibugEmuOnline.Client.UI;
 using DG.Tweening;
 using DG.Tweening.Core;
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/BgSettingsUI/UI_FilterItem.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/BgSettingsUI/UI_FilterItem.cs
index eaa92acb..c93b4d5b 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/BgSettingsUI/UI_FilterItem.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/BgSettingsUI/UI_FilterItem.cs
@@ -4,7 +4,7 @@ using System;
 using System.Collections.Generic;
 using System.Linq;
 using UnityEngine;
-using static AxibugEmuOnline.Client.FilterManager;
+using static AxibugEmuOnline.Client.Settings.FilterManager;
 
 namespace AxibugEmuOnline.Client
 {
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/BgSettingsUI/UI_ScalerModeItem.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/BgSettingsUI/UI_ScalerModeItem.cs
index 094c8453..3a1e3a57 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/BgSettingsUI/UI_ScalerModeItem.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/BgSettingsUI/UI_ScalerModeItem.cs
@@ -1,4 +1,5 @@
 using AxibugEmuOnline.Client.ClientCore;
+using AxibugEmuOnline.Client.Settings;
 using AxibugEmuOnline.Client.UI;
 
 namespace AxibugEmuOnline.Client
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/CommandDispatcher/CommandDispatcher.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/CommandDispatcher/CommandDispatcher.cs
index 70765f45..4926fbdb 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/CommandDispatcher/CommandDispatcher.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/CommandDispatcher/CommandDispatcher.cs
@@ -1,4 +1,4 @@
-using System.Collections.Generic;
+using System.Collections.Generic;
 using UnityEngine;
 
 namespace AxibugEmuOnline.Client
@@ -7,39 +7,26 @@ namespace AxibugEmuOnline.Client
     {
         public static CommandDispatcher Instance { get; private set; }
 
-        /// <summary> ƽ��ע�����,������Ӧָ�� </summary>
+        /// <summary> 平级注册对象,都会响应指令 </summary>
         List<CommandExecuter> m_register = new List<CommandExecuter>();
-        /// <summary> ��ռע�����,ָ��ᱻ�б������һ�������ռ </summary>
+        /// <summary> 独占注册对象,指令会被列表中最后一个对象独占 </summary>
         List<CommandExecuter> m_registerHigh = new List<CommandExecuter>();
 
-        ICommandListener m_listener;
-        /// <summary> ��׼UI���� </summary>
-        public IKeyMapperChanger Normal { get; private set; }
-        /// <summary> ��Ϸ��UI���� </summary>
-        public IKeyMapperChanger Gaming { get; private set; }
+        CommandListener m_listener;
 
-        private IKeyMapperChanger m_current;
-        public IKeyMapperChanger Current
-        {
-            get => m_current;
-            set
-            {
-                m_current = value;
-
-                SetKeyMapper(m_current);
-            }
+        CommandListener.ScheduleType? m_waitMapperSetting = null;
+        public CommandListener.ScheduleType Mode
+        {
+            get => m_listener.Schedule;
+            set => m_waitMapperSetting = value;
         }
 
         private void Awake()
         {
             Instance = this;
 
-            //��ʼ��command������
+            //初始化command监视器
             m_listener = new CommandListener();
-
-            //��ʼ����λ�޸���
-            Normal = new NormalChanger();
-            Gaming = new GamingChanger();
         }
 
         private void OnDestroy()
@@ -85,20 +72,14 @@ namespace AxibugEmuOnline.Client
                 m_listener.Update(oneFrameRegister);
             }
 
-            //��λӳ���ڰ�����Ӧ�Ķ�ջ��������,��ֹ�������޸�����
+            //键位映射在按键响应的堆栈结束后处理,防止迭代器修改问题
             if (m_waitMapperSetting != null)
             {
-                m_listener.ApplyKeyMapper(m_waitMapperSetting);
+                m_listener.Schedule = m_waitMapperSetting.Value;
                 m_waitMapperSetting = null;
             }
         }
 
-        IKeyMapperChanger m_waitMapperSetting = null;
-        void SetKeyMapper(IKeyMapperChanger keyMapChanger)
-        {
-            m_waitMapperSetting = keyMapChanger;
-        }
-
         private List<CommandExecuter> peekRegister(List<CommandExecuter> results)
         {
             results.Clear();
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/CommandDispatcher/CommandListener.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/CommandDispatcher/CommandListener.cs
index b0920ed5..af565a5a 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/CommandDispatcher/CommandListener.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/CommandDispatcher/CommandListener.cs
@@ -1,89 +1,43 @@
 using AxibugEmuOnline.Client.ClientCore;
-using AxibugEmuOnline.Client.Manager;
+using System;
 using System.Collections.Generic;
-using System.Linq;
 using UnityEngine;
 
 namespace AxibugEmuOnline.Client
 {
-    public class CommandListener : ICommandListener
+    public class CommandListener
     {
-        //Dictionary<KeyCode, EnumCommand> m_keyMapper = new Dictionary<KeyCode, EnumCommand>();
-        SingleKeysSetting singleKeysSetting;
-        Dictionary<EnumCommand, bool> m_dictLastState = new Dictionary<EnumCommand, bool>();
         EnumCommand[] m_checkCmds;
         List<CommandState> m_commands = new List<CommandState>();
-        long CheckFrame = -1;
+        long CheckFrame = -1;
+        XMBKeyBinding m_keyBinder;
+        public ScheduleType Schedule { get; set; }
+
+        public CommandListener()
+        {
+            m_keyBinder = App.settings.KeyMapper.GetBinder<XMBKeyBinding>();
+            m_checkCmds = Enum.GetValues(typeof(EnumCommand)) as EnumCommand[];
+        }
+
         IEnumerable<CommandState> GetCommand()
         {
-            //foreach (var item in m_keyMapper)
-            //{
-            //    if (Input.GetKeyDown(item.Key)) m_commands.Add(new CommandState { Cmd = item.Value, Cancel = false });
-            //    if (Input.GetKeyUp(item.Key)) m_commands.Add(new CommandState { Cmd = item.Value, Cancel = true });
-            //}
-
             if (CheckFrame == Time.frameCount)
                 return m_commands;
             CheckFrame = Time.frameCount;
 
             m_commands.Clear();
 
-            //不再依赖KeyDown KeyUp的做法,兼容UGUI,或者Axis
-            if (m_checkCmds != null)
-            {
-                foreach (var cmd in m_checkCmds)
-                {
-                    if (singleKeysSetting.GetKeyDown((ulong)cmd)) m_commands.Add(new CommandState { Cmd = cmd, Cancel = false });
-                    if (singleKeysSetting.GetKeyUp((ulong)cmd)) m_commands.Add(new CommandState { Cmd = cmd, Cancel = true });
-
-                    //if (m_dictLastState[cmd] && !singleKeysSetting.GetKey((ulong)cmd))
-                    //{
-                    //    m_commands.Add(new CommandState { Cmd = cmd, Cancel = true });
-                    //    m_dictLastState[cmd] = false;
-                    //}
-                    //else if (!m_dictLastState[cmd] && singleKeysSetting.GetKey((ulong)cmd))
-                    //{ 
-                    //    m_commands.Add(new CommandState { Cmd = cmd, Cancel = false });
-                    //    m_dictLastState[cmd] = true;
-                    //}
-
-                    //bool oldstate = m_dictLastState[cmd];
-                    //bool newstate = singleKeysSetting.GetKey((ulong)cmd);
-                    //m_dictLastState[cmd] = newstate;
-                    //if (oldstate != newstate)
-                    //{
-                    //    m_commands.Add(new CommandState { Cmd = cmd, Cancel = !newstate });
-                    //}
-
-
-                }
-            }
-
-
-            //foreach (var item in m_keyMapper)
-            //{
-            //    if (Input.GetKeyDown(item.Key)) m_commands.Add(new CommandState { Cmd = item.Value, Cancel = false });
-            //    if (Input.GetKeyUp(item.Key)) m_commands.Add(new CommandState { Cmd = item.Value, Cancel = true });
-            //}
-
+            int controllerIndex = (int)Schedule;
+
+            foreach (var cmd in m_checkCmds)
+            {
+                if (m_keyBinder.Start(cmd, controllerIndex)) m_commands.Add(new CommandState { Cmd = cmd, Cancel = false });
+                if (m_keyBinder.Release(cmd, controllerIndex)) m_commands.Add(new CommandState { Cmd = cmd, Cancel = true });
+            }
+
+
             return m_commands;
         }
-        public void ApplyKeyMapper(IKeyMapperChanger changer)
-        {
-            //var cfg = (Dictionary<KeyCode, EnumCommand>)changer.GetConfig();
-            singleKeysSetting = changer.GetKeySetting();
-            App.log.Debug($"CommandListener ApplyKeyMapper | {Time.frameCount} {changer.Name}");
-            EnumCommand[] arr = changer.GetConfig();
-            //不要直接清m_dictLastState.Clear(),同样的Key维持状态,避免造成多余CommandState
-            EnumCommand[] temp = m_dictLastState.Keys.ToArray();
-            //仅添加新增
-            foreach (var cmd in arr)
-            {
-                if(!m_dictLastState.ContainsKey(cmd))
-                    m_dictLastState[cmd] = true;
-            }
-            m_checkCmds = arr;
-        }
 
         public void Update(IEnumerable<CommandExecuter> executers)
         {
@@ -96,5 +50,11 @@ namespace AxibugEmuOnline.Client
                 }
             }
         }
+
+        public enum ScheduleType
+        {
+            Normal,
+            Gaming
+        }
     }
 }
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/CommandDispatcher/ICommandListener.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/CommandDispatcher/ICommandListener.cs
index 118d987b..2a7122a8 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/CommandDispatcher/ICommandListener.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/CommandDispatcher/ICommandListener.cs
@@ -3,22 +3,6 @@ using System.Collections.Generic;
 
 namespace AxibugEmuOnline.Client
 {
-    public interface IKeyMapperChanger
-    {
-        string Name { get; }
-        EnumCommand[] GetConfig();
-        SingleKeysSetting GetKeySetting();
-    }
-    public interface ICommandListener
-    {
-        /// <summary>
-        /// 应用键位设置
-        /// </summary>
-        /// <param name="changer"></param>
-        void ApplyKeyMapper(IKeyMapperChanger changer);
-        void Update(IEnumerable<CommandExecuter> commands);
-    }
-
     public struct CommandState
     {
         public EnumCommand Cmd;
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/InGameUI/InGameUI_FilterSetting.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/InGameUI/InGameUI_FilterSetting.cs
index 14c684f2..aaf24689 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/InGameUI/InGameUI_FilterSetting.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/InGameUI/InGameUI_FilterSetting.cs
@@ -1,7 +1,7 @@
 using AxibugEmuOnline.Client.ClientCore;
 using System.Collections.Generic;
 using System.Linq;
-using static AxibugEmuOnline.Client.FilterManager;
+using static AxibugEmuOnline.Client.Settings.FilterManager;
 
 namespace AxibugEmuOnline.Client
 {
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/InGameUI/InGameUI_Scaler.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/InGameUI/InGameUI_Scaler.cs
index 4eb06201..6e86197e 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/InGameUI/InGameUI_Scaler.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/InGameUI/InGameUI_Scaler.cs
@@ -1,7 +1,7 @@
 using AxibugEmuOnline.Client.ClientCore;
 using System;
 using System.Collections.Generic;
-using static AxibugEmuOnline.Client.ScreenScaler;
+using static AxibugEmuOnline.Client.Settings.ScreenScaler;
 
 namespace AxibugEmuOnline.Client
 {
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/Joystick/FloatingJoystick.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/Joystick/FloatingJoystick.cs
index f0a05222..5df7fd7b 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/Joystick/FloatingJoystick.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/Joystick/FloatingJoystick.cs
@@ -1,5 +1,4 @@
-using AxiInputSP.UGUI;
-using UnityEngine;
+using UnityEngine;
 using UnityEngine.EventSystems;
 using UnityEngine.UI;
 
@@ -13,7 +12,6 @@ public class FloatingJoystick : Joystick
 
     readonly static Color ShowColor = new Color(1F, 1f, 1F, 0.7f);
     readonly static Color HideColor = new Color(1F, 1f, 1F, 0.3f);
-    AxiIptJoystick mAxiIptJoystick;
     //一次新的摇杆移动
     public static bool bNewTouchWithSkill = false;
 
@@ -34,24 +32,7 @@ public class FloatingJoystick : Joystick
         mIsMounseDown = false;
     }
 
-    void OnEnable()
-    {
-        if (mAxiIptJoystick == null)
-        {
-            mAxiIptJoystick = new AxiIptJoystick(GetJoyRaw);
-        }
-    }
-
-    private void OnDisable()
-    {
-        if (mAxiIptJoystick != null)
-        {
-            mAxiIptJoystick.Dispose();
-            mAxiIptJoystick = null;
-        }
-    }
-
-    private Vector2Int GetJoyRaw()
+    public Vector2Int GetJoyRaw()
     {
         return this.RawInputV2;
     }
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/LaunchUI.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/LaunchUI.cs
index 9b6beea2..4b1e0964 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/LaunchUI.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/LaunchUI.cs
@@ -44,13 +44,13 @@ namespace AxibugEmuOnline.Client
 
         private void Start()
         {
-            CommandDispatcher.Instance.Current = CommandDispatcher.Instance.Normal;
+            CommandDispatcher.Instance.Mode = CommandListener.ScheduleType.Normal;
         }
 
         private void Update()
         {
-            if (CommandDispatcher.Instance.Current == CommandDispatcher.Instance.Gaming && App.emu.Core.IsNull())
-                CommandDispatcher.Instance.Current = CommandDispatcher.Instance.Normal;
+            if (CommandDispatcher.Instance.Mode == CommandListener.ScheduleType.Gaming && App.emu.Core.IsNull())
+                CommandDispatcher.Instance.Mode = CommandListener.ScheduleType.Normal;
         }
 
         public void HideMainMenu()
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/OptionUI/OptionUI.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/OptionUI/OptionUI.cs
index 647d27b6..ec5ee71a 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/OptionUI/OptionUI.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/OptionUI/OptionUI.cs
@@ -147,7 +147,7 @@ namespace AxibugEmuOnline.Client
             return dirty;
         }
 
-        IKeyMapperChanger m_lastCS;
+        CommandListener.ScheduleType? m_lastCS;
         private Action m_onClose;
 
         /// <summary>
@@ -214,8 +214,8 @@ namespace AxibugEmuOnline.Client
                     0.3f
                     ).SetEase(Ease.OutCubic);
 
-                m_lastCS = CommandDispatcher.Instance.Current;
-                CommandDispatcher.Instance.Current = CommandDispatcher.Instance.Normal;
+                m_lastCS = CommandDispatcher.Instance.Mode;
+                CommandDispatcher.Instance.Mode = CommandListener.ScheduleType.Normal;
             }
 
         }
@@ -263,7 +263,7 @@ namespace AxibugEmuOnline.Client
 
                 m_bPoped = false;
 
-                CommandDispatcher.Instance.Current = m_lastCS;
+                CommandDispatcher.Instance.Mode = m_lastCS.Value;
 
                 m_onClose?.Invoke();
                 m_onClose = null;
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/OverlayUI/InputUI.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/OverlayUI/InputUI.cs
index a91b7c51..35514431 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/OverlayUI/InputUI.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/OverlayUI/InputUI.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
 using System.Collections;
 using UnityEngine;
 using UnityEngine.UI;
@@ -14,8 +14,6 @@ namespace AxibugEmuOnline.Client
 
         public static bool IsInputing { get; private set; }
 
-
-
         protected override void OnShow(object param)
         {
             ValueTuple<Action<string>, string, string> t = (ValueTuple<Action<string>, string, string>)param;
@@ -30,7 +28,7 @@ namespace AxibugEmuOnline.Client
             base.Update();
 
             IsInputing = m_input.isFocused;
-
+            
             if (IsInputing && Input.GetButtonDown("Submit"))
             {
                 OnCmdEnter();
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/OverlayUI/OverlayManager.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/OverlayUI/OverlayManager.cs
index ae613c67..08f2ad08 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/OverlayUI/OverlayManager.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/OverlayUI/OverlayManager.cs
@@ -1,4 +1,5 @@
 using AxibugEmuOnline.Client.ClientCore;
+using AxiInputSP.UGUI;
 using System;
 using System.Collections.Generic;
 using UnityEngine;
@@ -12,7 +13,7 @@ namespace AxibugEmuOnline.Client
 
         [SerializeField] InputUI m_InputUI;
         [SerializeField] OptionUI m_OptionUI;
-        [SerializeField] Transform m_Joystick;
+        [SerializeField] AxiScreenGamepad m_screenGamepad;
         [SerializeField] PopTipsUI m_popTipsUI;
 
         private void Awake()
@@ -21,7 +22,7 @@ namespace AxibugEmuOnline.Client
 
             m_InputUI.gameObject.SetActive(false);
 
-            m_Joystick.gameObject.SetActive(App.bUseGUIButton);
+            m_screenGamepad.gameObject.SetActive(App.bUseGUIButton);
         }
 
         public static void Input(Action<string> callback, string placeHolder, string defaultText)
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/XMBBgChanger.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/XMBBgChanger.cs
index 8f0e115c..9d23dc4c 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/XMBBgChanger.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/XMBBgChanger.cs
@@ -1,4 +1,5 @@
-using AxibugEmuOnline.Client.ClientCore;
+using AxibugEmuOnline.Client.ClientCore;
+using AxibugEmuOnline.Client.Settings;
 using UnityEngine;
 using UnityEngine.UI;
 
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/XMBOptionBgChanger.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/XMBOptionBgChanger.cs
index baa1c417..721ed63f 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/XMBOptionBgChanger.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/UI/XMBOptionBgChanger.cs
@@ -1,4 +1,5 @@
-using AxibugEmuOnline.Client.ClientCore;
+using AxibugEmuOnline.Client.ClientCore;
+using AxibugEmuOnline.Client.Settings;
 using Coffee.UIExtensions;
 using UnityEngine;
 
diff --git a/AxibugEmuOnline.Client/Packages/manifest.json b/AxibugEmuOnline.Client/Packages/manifest.json
index a91a4da7..cf2078f8 100644
--- a/AxibugEmuOnline.Client/Packages/manifest.json
+++ b/AxibugEmuOnline.Client/Packages/manifest.json
@@ -2,25 +2,20 @@
   "dependencies": {
     "com.unity.2d.sprite": "1.0.0",
     "com.unity.ide.visualstudio": "2.0.22",
+    "com.unity.inputsystem": "1.11.2",
+    "com.unity.test-framework": "1.4.5",
     "com.unity.ugui": "2.0.0",
     "com.unity.modules.accessibility": "1.0.0",
-    "com.unity.modules.ai": "1.0.0",
     "com.unity.modules.androidjni": "1.0.0",
     "com.unity.modules.animation": "1.0.0",
     "com.unity.modules.assetbundle": "1.0.0",
     "com.unity.modules.audio": "1.0.0",
-    "com.unity.modules.cloth": "1.0.0",
-    "com.unity.modules.director": "1.0.0",
     "com.unity.modules.imageconversion": "1.0.0",
     "com.unity.modules.imgui": "1.0.0",
     "com.unity.modules.jsonserialize": "1.0.0",
-    "com.unity.modules.particlesystem": "1.0.0",
     "com.unity.modules.physics": "1.0.0",
     "com.unity.modules.physics2d": "1.0.0",
     "com.unity.modules.screencapture": "1.0.0",
-    "com.unity.modules.terrain": "1.0.0",
-    "com.unity.modules.terrainphysics": "1.0.0",
-    "com.unity.modules.tilemap": "1.0.0",
     "com.unity.modules.ui": "1.0.0",
     "com.unity.modules.uielements": "1.0.0",
     "com.unity.modules.umbra": "1.0.0",
diff --git a/AxibugEmuOnline.Client/Packages/packages-lock.json b/AxibugEmuOnline.Client/Packages/packages-lock.json
index cfb15991..ce338603 100644
--- a/AxibugEmuOnline.Client/Packages/packages-lock.json
+++ b/AxibugEmuOnline.Client/Packages/packages-lock.json
@@ -8,10 +8,10 @@
     },
     "com.unity.ext.nunit": {
       "version": "2.0.5",
-      "depth": 2,
+      "depth": 1,
       "source": "registry",
       "dependencies": {},
-      "url": "https://packages.unity.cn"
+      "url": "https://packages.unity.com"
     },
     "com.unity.ide.visualstudio": {
       "version": "2.0.22",
@@ -20,18 +20,27 @@
       "dependencies": {
         "com.unity.test-framework": "1.1.9"
       },
-      "url": "https://packages.unity.cn"
+      "url": "https://packages.unity.com"
+    },
+    "com.unity.inputsystem": {
+      "version": "1.11.2",
+      "depth": 0,
+      "source": "registry",
+      "dependencies": {
+        "com.unity.modules.uielements": "1.0.0"
+      },
+      "url": "https://packages.unity.com"
     },
     "com.unity.test-framework": {
       "version": "1.4.5",
-      "depth": 1,
+      "depth": 0,
       "source": "registry",
       "dependencies": {
         "com.unity.ext.nunit": "2.0.3",
         "com.unity.modules.imgui": "1.0.0",
         "com.unity.modules.jsonserialize": "1.0.0"
       },
-      "url": "https://packages.unity.cn"
+      "url": "https://packages.unity.com"
     },
     "com.unity.ugui": {
       "version": "2.0.0",
@@ -48,12 +57,6 @@
       "source": "builtin",
       "dependencies": {}
     },
-    "com.unity.modules.ai": {
-      "version": "1.0.0",
-      "depth": 0,
-      "source": "builtin",
-      "dependencies": {}
-    },
     "com.unity.modules.androidjni": {
       "version": "1.0.0",
       "depth": 0,
@@ -78,23 +81,6 @@
       "source": "builtin",
       "dependencies": {}
     },
-    "com.unity.modules.cloth": {
-      "version": "1.0.0",
-      "depth": 0,
-      "source": "builtin",
-      "dependencies": {
-        "com.unity.modules.physics": "1.0.0"
-      }
-    },
-    "com.unity.modules.director": {
-      "version": "1.0.0",
-      "depth": 0,
-      "source": "builtin",
-      "dependencies": {
-        "com.unity.modules.audio": "1.0.0",
-        "com.unity.modules.animation": "1.0.0"
-      }
-    },
     "com.unity.modules.hierarchycore": {
       "version": "1.0.0",
       "depth": 1,
@@ -119,12 +105,6 @@
       "source": "builtin",
       "dependencies": {}
     },
-    "com.unity.modules.particlesystem": {
-      "version": "1.0.0",
-      "depth": 0,
-      "source": "builtin",
-      "dependencies": {}
-    },
     "com.unity.modules.physics": {
       "version": "1.0.0",
       "depth": 0,
@@ -153,29 +133,6 @@
         "com.unity.modules.jsonserialize": "1.0.0"
       }
     },
-    "com.unity.modules.terrain": {
-      "version": "1.0.0",
-      "depth": 0,
-      "source": "builtin",
-      "dependencies": {}
-    },
-    "com.unity.modules.terrainphysics": {
-      "version": "1.0.0",
-      "depth": 0,
-      "source": "builtin",
-      "dependencies": {
-        "com.unity.modules.physics": "1.0.0",
-        "com.unity.modules.terrain": "1.0.0"
-      }
-    },
-    "com.unity.modules.tilemap": {
-      "version": "1.0.0",
-      "depth": 0,
-      "source": "builtin",
-      "dependencies": {
-        "com.unity.modules.physics2d": "1.0.0"
-      }
-    },
     "com.unity.modules.ui": {
       "version": "1.0.0",
       "depth": 0,
diff --git a/AxibugEmuOnline.Client/ProjectSettings/EditorBuildSettings.asset b/AxibugEmuOnline.Client/ProjectSettings/EditorBuildSettings.asset
index 650f2575..017ad1ae 100644
--- a/AxibugEmuOnline.Client/ProjectSettings/EditorBuildSettings.asset
+++ b/AxibugEmuOnline.Client/ProjectSettings/EditorBuildSettings.asset
@@ -8,4 +8,6 @@ EditorBuildSettings:
   - enabled: 1
     path: Assets/Scene/AxibugEmuOnline.Client.unity
     guid: eb0c18a619175384d95147898a43054b
-  m_configObjects: {}
+  m_configObjects:
+    com.unity.input.settings.actions: {fileID: -944628639613478452, guid: ca9f5fa95ffab41fb9a615ab714db018, type: 3}
+  m_UseUCBPForAssetBundles: 0
diff --git a/AxibugEmuOnline.Client/ProjectSettings/InputManager.asset b/AxibugEmuOnline.Client/ProjectSettings/InputManager.asset
index db2c9bd8..89d3a3bb 100644
--- a/AxibugEmuOnline.Client/ProjectSettings/InputManager.asset
+++ b/AxibugEmuOnline.Client/ProjectSettings/InputManager.asset
@@ -37,6 +37,38 @@ InputManager:
     type: 0
     axis: 0
     joyNum: 0
+  - serializedVersion: 3
+    m_Name: Horizontal
+    descriptiveName: 
+    descriptiveNegativeName: 
+    negativeButton: 
+    positiveButton: 
+    altNegativeButton: 
+    altPositiveButton: 
+    gravity: 0
+    dead: 0
+    sensitivity: 0
+    snap: 0
+    invert: 0
+    type: 0
+    axis: 0
+    joyNum: 1
+  - serializedVersion: 3
+    m_Name: Vertical
+    descriptiveName: 
+    descriptiveNegativeName: 
+    negativeButton: 
+    positiveButton: 
+    altNegativeButton: 
+    altPositiveButton: 
+    gravity: 0
+    dead: 0
+    sensitivity: 0
+    snap: 0
+    invert: 0
+    type: 0
+    axis: 0
+    joyNum: 1
   - serializedVersion: 3
     m_Name: Horizontal
     descriptiveName: 
@@ -69,3 +101,36 @@ InputManager:
     type: 0
     axis: 0
     joyNum: 0
+  - serializedVersion: 3
+    m_Name: HorizontalR
+    descriptiveName: 
+    descriptiveNegativeName: 
+    negativeButton: 
+    positiveButton: 
+    altNegativeButton: 
+    altPositiveButton: 
+    gravity: 0
+    dead: 0
+    sensitivity: 0
+    snap: 0
+    invert: 0
+    type: 0
+    axis: 3
+    joyNum: 0
+  - serializedVersion: 3
+    m_Name: VerticalR
+    descriptiveName: 
+    descriptiveNegativeName: 
+    negativeButton: 
+    positiveButton: 
+    altNegativeButton: 
+    altPositiveButton: 
+    gravity: 0
+    dead: 0
+    sensitivity: 0
+    snap: 0
+    invert: 0
+    type: 0
+    axis: 4
+    joyNum: 0
+  m_UsePhysicalKeys: 1
diff --git a/AxibugEmuOnline.Client/ProjectSettings/PackageManagerSettings.asset b/AxibugEmuOnline.Client/ProjectSettings/PackageManagerSettings.asset
index 95c895df..626261bf 100644
--- a/AxibugEmuOnline.Client/ProjectSettings/PackageManagerSettings.asset
+++ b/AxibugEmuOnline.Client/ProjectSettings/PackageManagerSettings.asset
@@ -18,10 +18,11 @@ MonoBehaviour:
   m_SeeAllPackageVersions: 0
   m_DismissPreviewPackagesInUse: 0
   oneTimeWarningShown: 0
+  oneTimeDeprecatedPopUpShown: 0
   m_Registries:
   - m_Id: main
     m_Name: 
-    m_Url: https://packages.unity.cn
+    m_Url: https://packages.unity.com
     m_Scopes: []
     m_IsDefault: 1
     m_Capabilities: 7
@@ -31,6 +32,6 @@ MonoBehaviour:
   m_RegistryInfoDraft:
     m_Modified: 0
     m_ErrorMessage: 
-    m_UserModificationsInstanceId: -892
-    m_OriginalInstanceId: -894
+    m_UserModificationsInstanceId: -882
+    m_OriginalInstanceId: -884
   m_LoadAssets: 0