From 3c10873180ddc5a7feb56eaa1654610b3d10f130 Mon Sep 17 00:00:00 2001
From: "ALIENJACK\\alien" <alienjack@foxmail.com>
Date: Wed, 12 Mar 2025 20:09:11 +0800
Subject: [PATCH 01/20] =?UTF-8?q?=E8=BE=93=E5=85=A5=E8=AE=BE=E5=A4=87?=
 =?UTF-8?q?=E7=AE=A1=E7=90=86=E5=99=A8,=E4=BB=A5=E5=8F=8A=E6=8C=89?=
 =?UTF-8?q?=E9=94=AE=E6=98=A0=E5=B0=84=E8=AE=BE=E7=BD=AE=E5=9F=BA=E6=9C=AC?=
 =?UTF-8?q?=E6=A1=86=E6=9E=B6=E6=90=AD=E5=BB=BA?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../Assets/Script/AppMain/App.cs              |  17 +-
 .../NesEmulator/NesControllerMapper.cs        | 259 +-----------------
 .../Manager/AppSettings/AppSettings.cs        |   7 +-
 .../KeyMapperSetting.meta}                    |   2 +-
 .../KeyMapperSetting/KeyMapperSetting.cs      | 210 ++++++++++++++
 .../KeyMapperSetting/KeyMapperSetting.cs.meta |   2 +
 .../KeyMapperSetting/NesKeyBinding.cs         |  41 +++
 .../KeyMapperSetting/NesKeyBinding.cs.meta    |   2 +
 .../AppMain/Manager/GamePadManager/GamePad.cs |  26 --
 .../Manager/GamePadManager/GamePad.cs.meta    |   2 -
 .../Manager/GamePadManager/GamePadManager.cs  | 121 --------
 .../GamePadManager/GamePadManager.cs.meta     |   2 -
 .../AppMain/Manager/InputDevicesManager.meta  |   8 +
 .../InputDevicesManager.cs                    | 140 ++++++++++
 .../InputDevicesManager.cs.meta               |   2 +
 .../Manager/InputDevicesManager/Keyboard.cs   | 215 +++++++++++++++
 .../InputDevicesManager/Keyboard.cs.meta      |   2 +
 AxibugEmuOnline.Client/Packages/manifest.json |   8 +-
 .../Packages/packages-lock.json               |  62 +----
 .../PackageManagerSettings.asset              |   7 +-
 20 files changed, 658 insertions(+), 477 deletions(-)
 rename AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/{GamePadManager.meta => AppSettings/KeyMapperSetting.meta} (77%)
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs.meta
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/NesKeyBinding.cs
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/NesKeyBinding.cs.meta
 delete mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/GamePadManager/GamePad.cs
 delete mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/GamePadManager/GamePad.cs.meta
 delete mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/GamePadManager/GamePadManager.cs
 delete mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/GamePadManager/GamePadManager.cs.meta
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager.meta
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs.meta
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Keyboard.cs
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Keyboard.cs.meta

diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/App.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/App.cs
index 38b126aa..11171e22 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;
@@ -23,13 +24,13 @@ namespace AxibugEmuOnline.Client.ClientCore
         public static AppChat chat;
         public static UserDataManager user;
         public static AppInput input;
+        public static InputDevicesManager inputDevicesMgr;
         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 +71,15 @@ 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();
-            }
+            if (UnityEngine.Application.platform == RuntimePlatform.PSP2) PSP2Init();
+
             input = new AppInput();
+            inputDevicesMgr = new InputDevicesManager();
             FileDownloader = new FileDownloader();
             settings = new AppSettings();
             network = new NetworkHelper();
@@ -102,7 +103,6 @@ namespace AxibugEmuOnline.Client.ClientCore
             roomMgr = new AppRoom();
             share = new AppShare();
             SavMgr = new SaveSlotManager();
-            gamePadMgr = new GamePadManager();
 
 
             bTest = isTest;
@@ -233,7 +233,6 @@ namespace AxibugEmuOnline.Client.ClientCore
             starRomLib.ExecuteFetchRomInfo();
             FileDownloader.Update();
 
-            gamePadMgr.Update();
         }
 
         public static Coroutine StartCoroutine(IEnumerator itor)
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/NesEmulator/NesControllerMapper.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/NesEmulator/NesControllerMapper.cs
index c50b8f8b..d64d8c14 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/NesEmulator/NesControllerMapper.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/NesEmulator/NesControllerMapper.cs
@@ -2,6 +2,7 @@
 using AxibugEmuOnline.Client.Common;
 using AxibugEmuOnline.Client.Event;
 using NUnit.Framework.Internal;
+using System;
 using System.Collections.Generic;
 using System.Linq;
 using UnityEngine;
@@ -98,16 +99,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 +113,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 +128,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/Manager/AppSettings/AppSettings.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/AppSettings.cs
index 785b02d2..248a3c05 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/AppSettings.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/AppSettings.cs
@@ -7,13 +7,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/GamePadManager.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting.meta
similarity index 77%
rename from AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/GamePadManager.meta
rename to AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting.meta
index d9ee8b26..4cdc4aeb 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/GamePadManager.meta
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: 5fe26f58ab822c44888b86305c5326e0
+guid: 7c4a24e114240814a8587e2f90a2f6f0
 folderAsset: yes
 DefaultImporter:
   externalObjects: {}
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..158bd8a2
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs
@@ -0,0 +1,210 @@
+using AxibugEmuOnline.Client.InputDevices;
+using AxibugProtobuf;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine;
+
+namespace AxibugEmuOnline.Client
+{
+    /// <summary>
+    /// 管理键位映射设置
+    /// </summary>
+    public class KeyMapperSetting
+    {
+        Dictionary<RomPlatformType, EmuCoreControllerKeyBinding> m_binders = new Dictionary<RomPlatformType, EmuCoreControllerKeyBinding>();
+        Dictionary<Type, EmuCoreControllerKeyBinding> m_bindersByType = new Dictionary<Type, EmuCoreControllerKeyBinding>();
+        public KeyMapperSetting()
+        {
+            var baseType = typeof(EmuCoreControllerKeyBinding);
+            foreach (var t in baseType.Assembly.ExportedTypes)
+            {
+                if (t.IsAbstract) continue;
+                if (!baseType.IsAssignableFrom(t)) continue;
+
+                var binderIns = Activator.CreateInstance(t) as EmuCoreControllerKeyBinding;
+                m_binders.Add(binderIns.Platform, binderIns);
+                m_bindersByType.Add(binderIns.GetType(), binderIns);
+            }
+        }
+
+        public T GetBinder<T>() where T : EmuCoreControllerKeyBinding
+        {
+            m_bindersByType.TryGetValue(typeof(T), out var binder);
+            return binder as T;
+        }
+    }
+
+    /// <summary>
+    /// 此类为内部继承, 请勿继承此类
+    /// </summary>
+    public abstract class EmuCoreControllerKeyBinding
+    {
+        /// <summary> 所属核心 </summary>
+        public abstract RomPlatformType Platform { get; }
+        /// <summary> 控制器数量 </summary>
+        public abstract int ControllerCount { get; }
+    }
+
+    /// <summary>
+    /// 模拟器核心控制器键位绑定器
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    public abstract class EmuCoreControllerKeyBinding<T> : EmuCoreControllerKeyBinding
+        where T : Enum
+    {
+        List<BindingPage> m_bindingPages = new List<BindingPage>();
+
+        public EmuCoreControllerKeyBinding()
+        {
+            for (int i = 0; i < ControllerCount; i++)
+            {
+                m_bindingPages.Add(new BindingPage(i, this));
+            }
+
+            LoadDefaultMapper();
+        }
+
+        IEnumerable<T> DefineKeys()
+        {
+            return Enum.GetValues(typeof(T)).Cast<T>();
+        }
+
+        /// <summary>
+        /// 加载默认映射
+        /// </summary>
+        public void LoadDefaultMapper()
+        {
+            foreach (var binding in m_bindingPages)
+            {
+                binding.ClearBinding();
+                OnLoadDefaultMapper(binding);
+            }
+        }
+
+        protected abstract void OnLoadDefaultMapper(BindingPage binding);
+
+        /// <summary>
+        /// 获取指定按键是否处于按下状态
+        /// </summary>
+        /// <param name="emuBtn"></param>
+        /// <param name="controllerIndex"></param>
+        /// <returns></returns>
+        public bool GetKey(T emuBtn, int controllerIndex)
+        {
+            var binding = m_bindingPages[controllerIndex];
+            foreach (var key in binding.GetBinding(emuBtn))
+            {
+                if (key.IsPressing()) 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>
+        /// 获取指定按键的值
+        /// </summary>
+        /// <param name="emuBtn">模拟器平台的具体键枚举</param>
+        /// <param name="controllerIndex">模拟器平台的控制器序号</param>
+        /// <returns></returns>
+        public Vector2 GetVector2(T emuBtn, int controllerIndex)
+        {
+            var binding = m_bindingPages[controllerIndex];
+            foreach (var key in binding.GetBinding(emuBtn))
+            {
+                if (!key.IsPressing()) continue;
+
+                return key.GetVector2();
+            }
+
+            return default(Vector2);
+        }
+
+        /// <summary>
+        /// 获取指定按键的值
+        /// </summary>
+        /// <param name="emuBtn">模拟器平台的具体键枚举</param>
+        /// <param name="controllerIndex">模拟器平台的控制器序号</param>
+        /// <returns></returns>
+        public float GetFloat(T emuBtn, int controllerIndex)
+        {
+            var binding = m_bindingPages[controllerIndex];
+            foreach (var key in binding.GetBinding(emuBtn))
+            {
+                if (!key.IsPressing()) continue;
+
+                return key.GetFlaot();
+            }
+
+            return default(float);
+        }
+
+        public class BindingPage
+        {
+            Dictionary<T, List<InputDevice.KeyBase>> m_mapSetting = new Dictionary<T, List<InputDevice.KeyBase>>();
+
+            public int ControllerIndex { get; }
+            public EmuCoreControllerKeyBinding<T> Host { get; }
+
+            internal BindingPage(int controllerIndex, EmuCoreControllerKeyBinding<T> host)
+            {
+                ControllerIndex = controllerIndex;
+                Host = host;
+
+                foreach (var emuBtn in host.DefineKeys())
+                    m_mapSetting[emuBtn] = new List<InputDevice.KeyBase>();
+            }
+
+            public void ClearBinding()
+            {
+                foreach (var list in m_mapSetting.Values) list.Clear();
+            }
+
+            public void SetBinding(T emuBtn, InputDevice.KeyBase key, int settingSlot)
+            {
+                var settingList = m_mapSetting[emuBtn];
+
+                int needFixCount = settingSlot - settingList.Count + 1;
+                if (needFixCount > 0) for (int i = 0; i < needFixCount; i++) settingList.Add(null);
+
+                settingList[settingSlot] = key;
+            }
+
+            public InputDevice.KeyBase GetBinding(T emuBtn, int settingSlot)
+            {
+                var settingList = m_mapSetting[emuBtn];
+                if (settingSlot >= settingList.Count) return null;
+                return settingList[settingSlot];
+            }
+
+            public List<InputDevice.KeyBase> GetBinding(T emuBtn)
+            {
+                return m_mapSetting[emuBtn];
+            }
+
+            public bool AnyKeyDown()
+            {
+                foreach (var item in m_mapSetting)
+                {
+                    foreach (var key in item.Value)
+                    {
+                        if (key.GetButtonDown()) return true;
+                    }
+                }
+
+                return false;
+            }
+        }
+    }
+}
\ 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/NesKeyBinding.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/NesKeyBinding.cs
new file mode 100644
index 00000000..ef80d946
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/NesKeyBinding.cs
@@ -0,0 +1,41 @@
+using AxibugEmuOnline.Client.ClientCore;
+using AxibugProtobuf;
+using VirtualNes.Core;
+
+namespace AxibugEmuOnline.Client
+{
+    public class NesKeyBinding : EmuCoreControllerKeyBinding<EnumButtonType>
+    {
+        public override RomPlatformType Platform => RomPlatformType.Nes;
+        public override int ControllerCount => 4;
+
+        protected override void OnLoadDefaultMapper(BindingPage binding)
+        {
+            var keyboard = App.inputDevicesMgr.GetKeyboard();
+            switch (binding.ControllerIndex)
+            {
+                case 0:
+                    binding.SetBinding(EnumButtonType.LEFT, keyboard.A, 0);
+                    binding.SetBinding(EnumButtonType.RIGHT, keyboard.D, 0);
+                    binding.SetBinding(EnumButtonType.UP, keyboard.W, 0);
+                    binding.SetBinding(EnumButtonType.DOWN, keyboard.S, 0);
+                    binding.SetBinding(EnumButtonType.A, keyboard.K, 0);
+                    binding.SetBinding(EnumButtonType.B, keyboard.J, 0);
+                    binding.SetBinding(EnumButtonType.SELECT, keyboard.V, 0);
+                    binding.SetBinding(EnumButtonType.START, keyboard.B, 0);
+                    binding.SetBinding(EnumButtonType.MIC, keyboard.M, 0);
+                    break;
+                case 1:
+                    binding.SetBinding(EnumButtonType.UP, keyboard.UpArrow, 0);
+                    binding.SetBinding(EnumButtonType.DOWN, keyboard.DownArrow, 0);
+                    binding.SetBinding(EnumButtonType.LEFT, keyboard.LeftArrow, 0);
+                    binding.SetBinding(EnumButtonType.RIGHT, keyboard.RightArrow, 0);
+                    binding.SetBinding(EnumButtonType.A, keyboard.Keypad2, 0);
+                    binding.SetBinding(EnumButtonType.B, keyboard.Keypad1, 0);
+                    binding.SetBinding(EnumButtonType.SELECT, keyboard.Keypad0, 0);
+                    binding.SetBinding(EnumButtonType.START, keyboard.KeypadPeriod, 0);
+                    break;
+            }
+        }
+    }
+}
\ 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/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/InputDevicesManager.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager.meta
new file mode 100644
index 00000000..70175167
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 7c141dadb47c8624c80c092e415ab621
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
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..92d88d8a
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs
@@ -0,0 +1,140 @@
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace AxibugEmuOnline.Client.InputDevices
+{
+    public class InputDevicesManager
+    {
+        Dictionary<string, InputDevice> m_devices = new Dictionary<string, InputDevice>();
+
+        public InputDevicesManager()
+        {
+            AddDevice(new KeyBoard());
+        }
+
+        public void AddDevice(InputDevice device)
+        {
+            m_devices[device.UniqueName] = device;
+        }
+
+        public void RemoveDevice(InputDevice device)
+        {
+            m_devices.Remove(device.UniqueName);
+        }
+
+        public InputDevice.KeyBase GetKeyByPath(string path)
+        {
+            var temp = path.Split("/");
+            Debug.Assert(temp.Length == 2, "Invalid Path Format");
+
+            var deviceName = temp[0];
+            var keyName = temp[1];
+
+            var targetDevice = FindDeviceByName(deviceName);
+            if (targetDevice == null) return null;
+
+            var key = targetDevice.FindKeyByKeyName(keyName);
+            return key;
+        }
+
+        public InputDevice FindDeviceByName(string deviceName)
+        {
+            m_devices.TryGetValue(deviceName, out var device);
+            return device;
+        }
+
+        /// <summary>
+        /// 获得键盘设备
+        /// <para>键盘设备被设计为有且仅有一个,所以这里应该总是能获得键盘设备</para>
+        /// </summary>
+        public KeyBoard GetKeyboard()
+        {
+            foreach (var d in m_devices.Values)
+            {
+                if (d is KeyBoard kb) return kb;
+            }
+
+            return null;
+        }
+
+        /// <summary> 由外部驱动的逻辑更新入口 </summary>
+        public void Update()
+        {
+            foreach (var device in m_devices.Values) device.Update();
+        }
+    }
+
+    public abstract class InputDevice
+    {
+        public abstract string UniqueName { get; }
+
+        public delegate void OnKeyStateChangedHandle(KeyBase sender);
+        public event OnKeyStateChangedHandle OnKeyStateChanged;
+
+        /// <summary> 指示该设备是否在线 </summary>
+        public abstract bool Online { get; }
+        /// <summary> 指示该设备当前帧是否有任意键被按下 </summary>
+        public bool AnyKeyDown { get; private set; }
+
+        protected Dictionary<string, KeyBase> m_keyMapper = new Dictionary<string, KeyBase>();
+
+        public InputDevice()
+        {
+            foreach (var key in DefineKeys())
+            {
+                m_keyMapper[key.KeyName] = key;
+            }
+        }
+
+        public void Update()
+        {
+            AnyKeyDown = false;
+
+            foreach (var key in m_keyMapper.Values)
+            {
+                if (key.GetButtonDown())
+                {
+                    AnyKeyDown = true;
+                    RaiseKeyEvent(key);
+                }
+            }
+        }
+
+        protected abstract IEnumerable<KeyBase> DefineKeys();
+        protected void RaiseKeyEvent(KeyBase sender)
+        {
+            OnKeyStateChanged?.Invoke(sender);
+        }
+
+        public KeyBase FindKeyByKeyName(string keyName)
+        {
+            m_keyMapper.TryGetValue(keyName, out var key);
+            return key;
+        }
+
+        /// <summary>
+        /// 输入设备的键接口
+        /// </summary>
+        public abstract class KeyBase
+        {
+            public InputDevice HostDevice { get; internal set; }
+            /// <summary> 获取该键是否在当前调用帧被按下 </summary>
+            public abstract bool GetButtonDown();
+            /// <summary> 获取该键是否在当前调用帧被抬起 </summary>
+            public abstract bool GetButtonUp();
+            /// <summary> 获取该键是否在当前调用帧是否处于按下状态 </summary>
+            public abstract bool IsPressing();
+
+            public virtual Vector2 GetVector2() { throw new System.NotImplementedException(); }
+            public virtual float GetFlaot() { throw new System.NotImplementedException(); }
+
+            /// <summary> 键名 </summary>
+            public abstract string KeyName { get; }
+            public string GetPath()
+            {
+                return $"{HostDevice.UniqueName}/{KeyName}";
+            }
+        }
+
+    }
+}
\ 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/Keyboard.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Keyboard.cs
new file mode 100644
index 00000000..01a02ae0
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Keyboard.cs
@@ -0,0 +1,215 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine;
+
+namespace AxibugEmuOnline.Client.InputDevices
+{
+    public class KeyBoard : InputDevice
+    {
+        #region HardCodeForKeyboard
+        static readonly List<KeyCode> s_keyboardKeys = new List<KeyCode>
+        {
+            // 字母键 A-Z
+            KeyCode.A, KeyCode.B, KeyCode.C, KeyCode.D, KeyCode.E, KeyCode.F, KeyCode.G,
+            KeyCode.H, KeyCode.I, KeyCode.J, KeyCode.K, KeyCode.L, KeyCode.M, KeyCode.N,
+            KeyCode.O, KeyCode.P, KeyCode.Q, KeyCode.R, KeyCode.S, KeyCode.T, KeyCode.U,
+            KeyCode.V, KeyCode.W, KeyCode.X, KeyCode.Y, KeyCode.Z,
+
+            // 数字键 0-9
+            KeyCode.Alpha0, KeyCode.Alpha1, KeyCode.Alpha2, KeyCode.Alpha3, KeyCode.Alpha4,
+            KeyCode.Alpha5, KeyCode.Alpha6, KeyCode.Alpha7, KeyCode.Alpha8, KeyCode.Alpha9,
+
+            // 功能键 F1-F15
+            KeyCode.F1, KeyCode.F2, KeyCode.F3, KeyCode.F4, KeyCode.F5, KeyCode.F6,
+            KeyCode.F7, KeyCode.F8, KeyCode.F9, KeyCode.F10, KeyCode.F11, KeyCode.F12,
+            KeyCode.F13, KeyCode.F14, KeyCode.F15,
+
+            // 方向键
+            KeyCode.UpArrow, KeyCode.DownArrow, KeyCode.LeftArrow, KeyCode.RightArrow,
+
+            // 控制键
+            KeyCode.Space, KeyCode.Return, KeyCode.Escape, KeyCode.Tab, KeyCode.Backspace,
+            KeyCode.CapsLock, KeyCode.LeftShift, KeyCode.RightShift, KeyCode.LeftControl,
+            KeyCode.RightControl, KeyCode.LeftAlt, KeyCode.RightAlt, KeyCode.LeftCommand,
+            KeyCode.RightCommand, KeyCode.Menu,
+
+            // 符号键
+            KeyCode.Comma, KeyCode.Period, KeyCode.Slash, KeyCode.BackQuote, KeyCode.Quote,
+            KeyCode.Semicolon, KeyCode.LeftBracket, KeyCode.RightBracket, KeyCode.Backslash,
+            KeyCode.Minus, KeyCode.Equals, KeyCode.Tilde,
+
+            // 小键盘
+            KeyCode.Keypad0, KeyCode.Keypad1, KeyCode.Keypad2, KeyCode.Keypad3, KeyCode.Keypad4,
+            KeyCode.Keypad5, KeyCode.Keypad6, KeyCode.Keypad7, KeyCode.Keypad8, KeyCode.Keypad9,
+            KeyCode.KeypadPeriod, KeyCode.KeypadDivide, KeyCode.KeypadMultiply,
+            KeyCode.KeypadMinus, KeyCode.KeypadPlus, KeyCode.KeypadEnter, KeyCode.Numlock,
+
+            // 其他标准键
+            KeyCode.Print,  KeyCode.Insert, KeyCode.Delete, KeyCode.Home,
+            KeyCode.End, KeyCode.PageUp, KeyCode.PageDown, KeyCode.Pause, KeyCode.ScrollLock,
+            KeyCode.Clear
+        };
+        // 字母键 A-Z
+        public KeyboardKey A { get; private set; } = new KeyboardKey(KeyCode.A);
+        public KeyboardKey B { get; private set; } = new KeyboardKey(KeyCode.B);
+        public KeyboardKey C { get; private set; } = new KeyboardKey(KeyCode.C);
+        public KeyboardKey D { get; private set; } = new KeyboardKey(KeyCode.D);
+        public KeyboardKey E { get; private set; } = new KeyboardKey(KeyCode.E);
+        public KeyboardKey F { get; private set; } = new KeyboardKey(KeyCode.F);
+        public KeyboardKey G { get; private set; } = new KeyboardKey(KeyCode.G);
+        public KeyboardKey H { get; private set; } = new KeyboardKey(KeyCode.H);
+        public KeyboardKey I { get; private set; } = new KeyboardKey(KeyCode.I);
+        public KeyboardKey J { get; private set; } = new KeyboardKey(KeyCode.J);
+        public KeyboardKey K { get; private set; } = new KeyboardKey(KeyCode.K);
+        public KeyboardKey L { get; private set; } = new KeyboardKey(KeyCode.L);
+        public KeyboardKey M { get; private set; } = new KeyboardKey(KeyCode.M);
+        public KeyboardKey N { get; private set; } = new KeyboardKey(KeyCode.N);
+        public KeyboardKey O { get; private set; } = new KeyboardKey(KeyCode.O);
+        public KeyboardKey P { get; private set; } = new KeyboardKey(KeyCode.P);
+        public KeyboardKey Q { get; private set; } = new KeyboardKey(KeyCode.Q);
+        public KeyboardKey R { get; private set; } = new KeyboardKey(KeyCode.R);
+        public KeyboardKey S { get; private set; } = new KeyboardKey(KeyCode.S);
+        public KeyboardKey T { get; private set; } = new KeyboardKey(KeyCode.T);
+        public KeyboardKey U { get; private set; } = new KeyboardKey(KeyCode.U);
+        public KeyboardKey V { get; private set; } = new KeyboardKey(KeyCode.V);
+        public KeyboardKey W { get; private set; } = new KeyboardKey(KeyCode.W);
+        public KeyboardKey X { get; private set; } = new KeyboardKey(KeyCode.X);
+        public KeyboardKey Y { get; private set; } = new KeyboardKey(KeyCode.Y);
+        public KeyboardKey Z { get; private set; } = new KeyboardKey(KeyCode.Z);
+
+        // 数字键 0-9
+        public KeyboardKey Alpha0 { get; private set; } = new KeyboardKey(KeyCode.Alpha0);
+        public KeyboardKey Alpha1 { get; private set; } = new KeyboardKey(KeyCode.Alpha1);
+        public KeyboardKey Alpha2 { get; private set; } = new KeyboardKey(KeyCode.Alpha2);
+        public KeyboardKey Alpha3 { get; private set; } = new KeyboardKey(KeyCode.Alpha3);
+        public KeyboardKey Alpha4 { get; private set; } = new KeyboardKey(KeyCode.Alpha4);
+        public KeyboardKey Alpha5 { get; private set; } = new KeyboardKey(KeyCode.Alpha5);
+        public KeyboardKey Alpha6 { get; private set; } = new KeyboardKey(KeyCode.Alpha6);
+        public KeyboardKey Alpha7 { get; private set; } = new KeyboardKey(KeyCode.Alpha7);
+        public KeyboardKey Alpha8 { get; private set; } = new KeyboardKey(KeyCode.Alpha8);
+        public KeyboardKey Alpha9 { get; private set; } = new KeyboardKey(KeyCode.Alpha9);
+
+        // 功能键 F1-F15
+        public KeyboardKey F1 { get; private set; } = new KeyboardKey(KeyCode.F1);
+        public KeyboardKey F2 { get; private set; } = new KeyboardKey(KeyCode.F2);
+        public KeyboardKey F3 { get; private set; } = new KeyboardKey(KeyCode.F3);
+        public KeyboardKey F4 { get; private set; } = new KeyboardKey(KeyCode.F4);
+        public KeyboardKey F5 { get; private set; } = new KeyboardKey(KeyCode.F5);
+        public KeyboardKey F6 { get; private set; } = new KeyboardKey(KeyCode.F6);
+        public KeyboardKey F7 { get; private set; } = new KeyboardKey(KeyCode.F7);
+        public KeyboardKey F8 { get; private set; } = new KeyboardKey(KeyCode.F8);
+        public KeyboardKey F9 { get; private set; } = new KeyboardKey(KeyCode.F9);
+        public KeyboardKey F10 { get; private set; } = new KeyboardKey(KeyCode.F10);
+        public KeyboardKey F11 { get; private set; } = new KeyboardKey(KeyCode.F11);
+        public KeyboardKey F12 { get; private set; } = new KeyboardKey(KeyCode.F12);
+        public KeyboardKey F13 { get; private set; } = new KeyboardKey(KeyCode.F13);
+        public KeyboardKey F14 { get; private set; } = new KeyboardKey(KeyCode.F14);
+        public KeyboardKey F15 { get; private set; } = new KeyboardKey(KeyCode.F15);
+
+        // 方向键
+        public KeyboardKey UpArrow { get; private set; } = new KeyboardKey(KeyCode.UpArrow);
+        public KeyboardKey DownArrow { get; private set; } = new KeyboardKey(KeyCode.DownArrow);
+        public KeyboardKey LeftArrow { get; private set; } = new KeyboardKey(KeyCode.LeftArrow);
+        public KeyboardKey RightArrow { get; private set; } = new KeyboardKey(KeyCode.RightArrow);
+
+        // 控制键
+        public KeyboardKey Space { get; private set; } = new KeyboardKey(KeyCode.Space);
+        public KeyboardKey Return { get; private set; } = new KeyboardKey(KeyCode.Return);
+        public KeyboardKey Escape { get; private set; } = new KeyboardKey(KeyCode.Escape);
+        public KeyboardKey Tab { get; private set; } = new KeyboardKey(KeyCode.Tab);
+        public KeyboardKey Backspace { get; private set; } = new KeyboardKey(KeyCode.Backspace);
+        public KeyboardKey CapsLock { get; private set; } = new KeyboardKey(KeyCode.CapsLock);
+        public KeyboardKey LeftShift { get; private set; } = new KeyboardKey(KeyCode.LeftShift);
+        public KeyboardKey RightShift { get; private set; } = new KeyboardKey(KeyCode.RightShift);
+        public KeyboardKey LeftControl { get; private set; } = new KeyboardKey(KeyCode.LeftControl);
+        public KeyboardKey RightControl { get; private set; } = new KeyboardKey(KeyCode.RightControl);
+        public KeyboardKey LeftAlt { get; private set; } = new KeyboardKey(KeyCode.LeftAlt);
+        public KeyboardKey RightAlt { get; private set; } = new KeyboardKey(KeyCode.RightAlt);
+        public KeyboardKey LeftCommand { get; private set; } = new KeyboardKey(KeyCode.LeftCommand);
+        public KeyboardKey RightCommand { get; private set; } = new KeyboardKey(KeyCode.RightCommand);
+        public KeyboardKey Menu { get; private set; } = new KeyboardKey(KeyCode.Menu);
+
+        // 符号键
+        public KeyboardKey Comma { get; private set; } = new KeyboardKey(KeyCode.Comma);
+        public KeyboardKey Period { get; private set; } = new KeyboardKey(KeyCode.Period);
+        public KeyboardKey Slash { get; private set; } = new KeyboardKey(KeyCode.Slash);
+        public KeyboardKey BackQuote { get; private set; } = new KeyboardKey(KeyCode.BackQuote);
+        public KeyboardKey Quote { get; private set; } = new KeyboardKey(KeyCode.Quote);
+        public KeyboardKey Semicolon { get; private set; } = new KeyboardKey(KeyCode.Semicolon);
+        public KeyboardKey LeftBracket { get; private set; } = new KeyboardKey(KeyCode.LeftBracket);
+        public KeyboardKey RightBracket { get; private set; } = new KeyboardKey(KeyCode.RightBracket);
+        public KeyboardKey Backslash { get; private set; } = new KeyboardKey(KeyCode.Backslash);
+        public KeyboardKey Minus { get; private set; } = new KeyboardKey(KeyCode.Minus);
+        public KeyboardKey Equals_k { get; private set; } = new KeyboardKey(KeyCode.Equals);
+        public KeyboardKey Tilde { get; private set; } = new KeyboardKey(KeyCode.Tilde);
+
+        // 小键盘
+        public KeyboardKey Keypad0 { get; private set; } = new KeyboardKey(KeyCode.Keypad0);
+        public KeyboardKey Keypad1 { get; private set; } = new KeyboardKey(KeyCode.Keypad1);
+        public KeyboardKey Keypad2 { get; private set; } = new KeyboardKey(KeyCode.Keypad2);
+        public KeyboardKey Keypad3 { get; private set; } = new KeyboardKey(KeyCode.Keypad3);
+        public KeyboardKey Keypad4 { get; private set; } = new KeyboardKey(KeyCode.Keypad4);
+        public KeyboardKey Keypad5 { get; private set; } = new KeyboardKey(KeyCode.Keypad5);
+        public KeyboardKey Keypad6 { get; private set; } = new KeyboardKey(KeyCode.Keypad6);
+        public KeyboardKey Keypad7 { get; private set; } = new KeyboardKey(KeyCode.Keypad7);
+        public KeyboardKey Keypad8 { get; private set; } = new KeyboardKey(KeyCode.Keypad8);
+        public KeyboardKey Keypad9 { get; private set; } = new KeyboardKey(KeyCode.Keypad9);
+        public KeyboardKey KeypadPeriod { get; private set; } = new KeyboardKey(KeyCode.KeypadPeriod);
+        public KeyboardKey KeypadDivide { get; private set; } = new KeyboardKey(KeyCode.KeypadDivide);
+        public KeyboardKey KeypadMultiply { get; private set; } = new KeyboardKey(KeyCode.KeypadMultiply);
+        public KeyboardKey KeypadMinus { get; private set; } = new KeyboardKey(KeyCode.KeypadMinus);
+        public KeyboardKey KeypadPlus { get; private set; } = new KeyboardKey(KeyCode.KeypadPlus);
+        public KeyboardKey KeypadEnter { get; private set; } = new KeyboardKey(KeyCode.KeypadEnter);
+        public KeyboardKey Numlock { get; private set; } = new KeyboardKey(KeyCode.Numlock);
+
+        // 其他标准键
+        public KeyboardKey Print { get; private set; } = new KeyboardKey(KeyCode.Print);
+        public KeyboardKey Insert { get; private set; } = new KeyboardKey(KeyCode.Insert);
+        public KeyboardKey Delete { get; private set; } = new KeyboardKey(KeyCode.Delete);
+        public KeyboardKey Home { get; private set; } = new KeyboardKey(KeyCode.Home);
+        public KeyboardKey End { get; private set; } = new KeyboardKey(KeyCode.End);
+        public KeyboardKey PageUp { get; private set; } = new KeyboardKey(KeyCode.PageUp);
+        public KeyboardKey PageDown { get; private set; } = new KeyboardKey(KeyCode.PageDown);
+        public KeyboardKey Pause { get; private set; } = new KeyboardKey(KeyCode.Pause);
+        public KeyboardKey ScrollLock { get; private set; } = new KeyboardKey(KeyCode.ScrollLock);
+        public KeyboardKey Clear { get; private set; } = new KeyboardKey(KeyCode.Clear);
+        #endregion
+
+        public override string UniqueName => nameof(KeyBoard);
+        public override bool Online => true;
+
+        protected override IEnumerable<KeyBase> DefineKeys()
+        {
+            var keys = s_keyboardKeys.Select(kc => new KeyboardKey(kc) as KeyBase);
+            return keys;
+        }
+
+        public class KeyboardKey : KeyBase
+        {
+            internal KeyCode m_listenKey;
+
+            public KeyboardKey(KeyCode listenKey)
+            {
+                m_listenKey = listenKey;
+            }
+
+            public override bool GetButtonDown()
+            {
+                return Input.GetKeyDown(m_listenKey);
+            }
+
+            public override bool GetButtonUp()
+            {
+                return Input.GetKeyUp(m_listenKey);
+            }
+
+            public override bool IsPressing()
+            {
+                return Input.GetKey(m_listenKey);
+            }
+
+            public override string KeyName => m_listenKey.ToString();
+        }
+    }
+}
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Keyboard.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Keyboard.cs.meta
new file mode 100644
index 00000000..aaa16d13
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Keyboard.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: e75cd67769afcad4890be3acf0ac1330
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Packages/manifest.json b/AxibugEmuOnline.Client/Packages/manifest.json
index a91a4da7..655d4e84 100644
--- a/AxibugEmuOnline.Client/Packages/manifest.json
+++ b/AxibugEmuOnline.Client/Packages/manifest.json
@@ -2,25 +2,19 @@
   "dependencies": {
     "com.unity.2d.sprite": "1.0.0",
     "com.unity.ide.visualstudio": "2.0.22",
+    "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..c85b164b 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,18 @@
       "dependencies": {
         "com.unity.test-framework": "1.1.9"
       },
-      "url": "https://packages.unity.cn"
+      "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 +48,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 +72,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 +96,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 +124,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/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

From 955a35659a2c2de426e0cec62efdf323a1036346 Mon Sep 17 00:00:00 2001
From: "ALIENJACK\\alien" <alienjack@foxmail.com>
Date: Thu, 13 Mar 2025 17:38:12 +0800
Subject: [PATCH 02/20] =?UTF-8?q?=E5=BC=95=E5=85=A5InputSystem,=E8=BE=93?=
 =?UTF-8?q?=E5=85=A5=E8=AE=BE=E5=A4=87=E7=AE=A1=E7=90=86=E7=B3=BB=E7=BB=9F?=
 =?UTF-8?q?=E8=BF=AD=E4=BB=A3=E4=B8=AD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../Assets/Resources/IMPORTENT.prefab         |  31 ++--
 .../AppMain/AxibugEmuOnline.Client.asmdef     |   3 +-
 .../InputDevicesManager.cs                    |  22 ++-
 .../InputDevicesManager/InputResolver.meta    |   8 ++
 .../InputResolver/BiDirectionalDictionary.cs  | 133 ++++++++++++++++++
 .../BiDirectionalDictionary.cs.meta           |   2 +
 .../InputResolver/InputResolver.cs            |  57 ++++++++
 .../InputResolver/InputResolver.cs.meta       |   2 +
 .../InputResolver/InputSystemResolver.cs      |  65 +++++++++
 .../InputResolver/InputSystemResolver.cs.meta |   2 +
 .../Manager/InputDevicesManager/Keyboard.cs   |  87 ++++++------
 .../Script/AppMain/UI/OverlayUI/InputUI.cs    |   6 +-
 AxibugEmuOnline.Client/Packages/manifest.json |   1 +
 .../Packages/packages-lock.json               |   9 ++
 .../ProjectSettings/EditorBuildSettings.asset |   4 +-
 15 files changed, 372 insertions(+), 60 deletions(-)
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver.meta
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/BiDirectionalDictionary.cs
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/BiDirectionalDictionary.cs.meta
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputResolver.cs
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputResolver.cs.meta
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs.meta

diff --git a/AxibugEmuOnline.Client/Assets/Resources/IMPORTENT.prefab b/AxibugEmuOnline.Client/Assets/Resources/IMPORTENT.prefab
index b559c20e..038080ca 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/Script/AppMain/AxibugEmuOnline.Client.asmdef b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxibugEmuOnline.Client.asmdef
index b7f7eaf3..4c67b1ed 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxibugEmuOnline.Client.asmdef
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxibugEmuOnline.Client.asmdef
@@ -6,7 +6,8 @@
         "VirtualNes.Core",
         "UIEffect2018",
         "Mame.Core",
-        "Essgee.Unity"
+        "Essgee.Unity",
+        "Unity.InputSystem"
     ],
     "includePlatforms": [],
     "excludePlatforms": [],
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs
index 92d88d8a..8fff0861 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs
@@ -1,15 +1,30 @@
 using System.Collections.Generic;
 using UnityEngine;
+using UnityEngine.InputSystem;
 
 namespace AxibugEmuOnline.Client.InputDevices
 {
     public class InputDevicesManager
     {
+        InputResolver m_inputResolver = InputResolver.Create();
         Dictionary<string, InputDevice> m_devices = new Dictionary<string, InputDevice>();
 
         public InputDevicesManager()
         {
-            AddDevice(new KeyBoard());
+            m_inputResolver.OnDeviceConnected += OnDeviceConnected;
+            m_inputResolver.OnDeviceLost += OnDeviceLost;
+            foreach (var device in m_inputResolver.GetDevices())
+                AddDevice(device);
+        }
+
+        private void OnDeviceLost(InputDevice lostDevice)
+        {
+
+        }
+
+        private void OnDeviceConnected(InputDevice connectDevice)
+        {
+            throw new System.NotImplementedException();
         }
 
         public void AddDevice(InputDevice device)
@@ -77,9 +92,10 @@ namespace AxibugEmuOnline.Client.InputDevices
         public bool AnyKeyDown { get; private set; }
 
         protected Dictionary<string, KeyBase> m_keyMapper = new Dictionary<string, KeyBase>();
-
-        public InputDevice()
+        protected InputResolver m_resolver;
+        public InputDevice(InputResolver resolver)
         {
+            m_resolver = resolver;
             foreach (var key in DefineKeys())
             {
                 m_keyMapper[key.KeyName] = key;
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/BiDirectionalDictionary.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/BiDirectionalDictionary.cs
new file mode 100644
index 00000000..3ab06251
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/BiDirectionalDictionary.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/InputResolver/BiDirectionalDictionary.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/BiDirectionalDictionary.cs.meta
new file mode 100644
index 00000000..8346d0ac
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/BiDirectionalDictionary.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/InputResolver/InputResolver.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputResolver.cs
new file mode 100644
index 00000000..44fe1a91
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputResolver.cs
@@ -0,0 +1,57 @@
+using System.Collections.Generic;
+
+namespace AxibugEmuOnline.Client.InputDevices
+{
+    public abstract class InputResolver
+    {
+        public static InputResolver Create()
+        {
+#if ENABLE_INPUT_SYSTEM //InputSystem
+            return new InputSystemResolver();
+#elif UNITY_PSP2 //SDK
+            throw new System.NotImplementedException();
+#elif UNITY_PS3 //SDK
+            throw new System.NotImplementedException();
+#else //使用旧Input
+            throw new System.NotImplementedException();    
+#endif
+        }
+        /// <summary> 禁止外部构造 </summary>
+        protected InputResolver()
+        {
+            OnInit();
+        }
+
+        protected abstract void OnInit();
+
+        /// <summary>
+        /// 获得所有当前已连入的输入设备
+        /// </summary>
+        /// <returns></returns>
+        public abstract IEnumerable<InputDevice> GetDevices();
+
+        /// <summary>
+        /// 检查指定输入设备是否还保持着连接
+        /// </summary>
+        /// <returns></returns>
+        public abstract bool CheckOnline(InputDevice device);
+
+        /// <param name="lostDevice">丢失的设备</param>
+        public delegate void OnDeviceLostHandle(InputDevice lostDevice);
+        /// <summary> 当设备丢失时触发 </summary>
+        public event OnDeviceLostHandle OnDeviceLost;
+        protected void RaiseDeviceLost(InputDevice lostDevice)
+        {
+            OnDeviceLost?.Invoke(lostDevice);
+        }
+
+        /// <param name="connectDevice">建立连接的设备</param>
+        public delegate void OnDeviceConnectedHandle(InputDevice connectDevice);
+        /// <summary> 当设备连接时触发 </summary>
+        public event OnDeviceConnectedHandle OnDeviceConnected;
+        protected void RaiseDeviceConnected(InputDevice connectDevice)
+        {
+            OnDeviceConnected?.Invoke(connectDevice);
+        }
+    }
+}
\ 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..30ca2b2a
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs
@@ -0,0 +1,65 @@
+#if ENABLE_INPUT_SYSTEM
+using System.Collections.Generic;
+using IP = UnityEngine.InputSystem.InputSystem;
+using IPDevice = UnityEngine.InputSystem.InputDevice;
+using IPKeyboard = UnityEngine.InputSystem.Keyboard;
+
+namespace AxibugEmuOnline.Client.InputDevices
+{
+    /// <summary> InputSystem对接 </summary>
+    public class InputSystemResolver : InputResolver
+    {
+        DualWayDictionary<IPDevice, InputDevice> m_devices = new DualWayDictionary<IPDevice, InputDevice>();
+
+        protected override void OnInit()
+        {
+            foreach (var device in IP.devices)
+            {
+                AddDevice(device);
+            }
+
+            IP.onDeviceChange += IP_onDeviceChange;
+        }
+
+        private void AddDevice(IPDevice ipdev)
+        {
+            InputDevice newDevice = null;
+            if (ipdev is IPKeyboard) newDevice = new KeyBoard(this);
+
+            if (newDevice != null)
+            {
+                m_devices.Add(ipdev, newDevice);
+                RaiseDeviceConnected(newDevice);
+            }
+        }
+
+        private void RemoveDevice(IPDevice ipdev)
+        {
+            if (m_devices.TryGetValue(ipdev, out var device))
+            {
+                m_devices.Remove(ipdev);
+                RaiseDeviceLost(device);
+            }
+        }
+
+        public override bool CheckOnline(InputDevice device)
+        {
+            return m_devices.TryGetKey(device, out var _);
+        }
+
+        private void IP_onDeviceChange(IPDevice device, UnityEngine.InputSystem.InputDeviceChange changeType)
+        {
+            switch (changeType)
+            {
+                case UnityEngine.InputSystem.InputDeviceChange.Added: AddDevice(device); break;
+                case UnityEngine.InputSystem.InputDeviceChange.Removed: RemoveDevice(device); break;
+            }
+        }
+
+        public override IEnumerable<InputDevice> GetDevices()
+        {
+            return m_devices.Values;
+        }
+    }
+}
+#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/Keyboard.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Keyboard.cs
index 01a02ae0..b475b9c9 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Keyboard.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Keyboard.cs
@@ -1,13 +1,53 @@
-using System;
-using System.Collections.Generic;
+using System.Collections.Generic;
 using System.Linq;
 using UnityEngine;
 
 namespace AxibugEmuOnline.Client.InputDevices
 {
-    public class KeyBoard : InputDevice
+    public partial class KeyBoard : InputDevice
+    {
+        public override string UniqueName => nameof(KeyBoard);
+        public override bool Online => true;
+
+        public KeyBoard(InputResolver resolver) : base(resolver) { }
+
+        protected override IEnumerable<KeyBase> DefineKeys()
+        {
+            var keys = s_keyboardKeys.Select(kc => new KeyboardKey(kc) as KeyBase);
+            return keys;
+        }
+
+        public class KeyboardKey : KeyBase
+        {
+            internal KeyCode m_listenKey;
+
+            public KeyboardKey(KeyCode listenKey)
+            {
+                m_listenKey = listenKey;
+            }
+
+            public override bool GetButtonDown()
+            {
+                return Input.GetKeyDown(m_listenKey);
+            }
+
+            public override bool GetButtonUp()
+            {
+                return Input.GetKeyUp(m_listenKey);
+            }
+
+            public override bool IsPressing()
+            {
+                return Input.GetKey(m_listenKey);
+            }
+
+            public override string KeyName => m_listenKey.ToString();
+        }
+    }
+
+    #region HardCodeForKeyboard
+    public partial class KeyBoard : InputDevice
     {
-        #region HardCodeForKeyboard
         static readonly List<KeyCode> s_keyboardKeys = new List<KeyCode>
         {
             // 字母键 A-Z
@@ -50,6 +90,7 @@ namespace AxibugEmuOnline.Client.InputDevices
             KeyCode.End, KeyCode.PageUp, KeyCode.PageDown, KeyCode.Pause, KeyCode.ScrollLock,
             KeyCode.Clear
         };
+
         // 字母键 A-Z
         public KeyboardKey A { get; private set; } = new KeyboardKey(KeyCode.A);
         public KeyboardKey B { get; private set; } = new KeyboardKey(KeyCode.B);
@@ -174,42 +215,6 @@ namespace AxibugEmuOnline.Client.InputDevices
         public KeyboardKey Pause { get; private set; } = new KeyboardKey(KeyCode.Pause);
         public KeyboardKey ScrollLock { get; private set; } = new KeyboardKey(KeyCode.ScrollLock);
         public KeyboardKey Clear { get; private set; } = new KeyboardKey(KeyCode.Clear);
-        #endregion
-
-        public override string UniqueName => nameof(KeyBoard);
-        public override bool Online => true;
-
-        protected override IEnumerable<KeyBase> DefineKeys()
-        {
-            var keys = s_keyboardKeys.Select(kc => new KeyboardKey(kc) as KeyBase);
-            return keys;
-        }
-
-        public class KeyboardKey : KeyBase
-        {
-            internal KeyCode m_listenKey;
-
-            public KeyboardKey(KeyCode listenKey)
-            {
-                m_listenKey = listenKey;
-            }
-
-            public override bool GetButtonDown()
-            {
-                return Input.GetKeyDown(m_listenKey);
-            }
-
-            public override bool GetButtonUp()
-            {
-                return Input.GetKeyUp(m_listenKey);
-            }
-
-            public override bool IsPressing()
-            {
-                return Input.GetKey(m_listenKey);
-            }
-
-            public override string KeyName => m_listenKey.ToString();
-        }
     }
+    #endregion
 }
\ No newline at end of file
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/Packages/manifest.json b/AxibugEmuOnline.Client/Packages/manifest.json
index 655d4e84..cf2078f8 100644
--- a/AxibugEmuOnline.Client/Packages/manifest.json
+++ b/AxibugEmuOnline.Client/Packages/manifest.json
@@ -2,6 +2,7 @@
   "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",
diff --git a/AxibugEmuOnline.Client/Packages/packages-lock.json b/AxibugEmuOnline.Client/Packages/packages-lock.json
index c85b164b..ce338603 100644
--- a/AxibugEmuOnline.Client/Packages/packages-lock.json
+++ b/AxibugEmuOnline.Client/Packages/packages-lock.json
@@ -22,6 +22,15 @@
       },
       "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": 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

From 4e1f8fd045a26b839f3c8ae9eec76e54025dd7dd Mon Sep 17 00:00:00 2001
From: "ALIENJACK\\alien" <alienjack@foxmail.com>
Date: Fri, 14 Mar 2025 11:02:38 +0800
Subject: [PATCH 03/20] =?UTF-8?q?InputDevice=E4=B8=AD=E7=9A=84keybase?=
 =?UTF-8?q?=E5=9F=BA=E7=B1=BB=E6=94=B9=E4=B8=BAinputcontrol,=E7=AA=81?=
 =?UTF-8?q?=E5=87=BA=E5=9F=BA=E7=A1=80=E7=B1=BB=E5=9E=8B=E4=BD=9C=E4=B8=BA?=
 =?UTF-8?q?=E4=B8=80=E4=B8=AA=E8=BE=93=E5=85=A5=E6=8E=A7=E4=BB=B6=E7=9A=84?=
 =?UTF-8?q?=E6=A6=82=E5=BF=B5,=E4=BB=A5=E5=85=8D=E5=92=8C=E6=8C=89?=
 =?UTF-8?q?=E9=92=AE=E7=B1=BB=E6=8E=A7=E4=BB=B6=E6=B7=B7=E6=B7=86?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../KeyMapperSetting/KeyMapperSetting.cs      |  63 +++---
 .../InputDevicesManager.cs                    |  78 ++++----
 ...onalDictionary.cs => DualWayDictionary.cs} |   0
 ...nary.cs.meta => DualWayDictionary.cs.meta} |   0
 .../InputResolver/InputResolver.cs            |  22 +++
 .../InputResolver/InputSystemResolver.cs      | 180 +++++++++++++++++-
 .../Manager/InputDevicesManager/Keyboard.cs   |  33 ++--
 7 files changed, 289 insertions(+), 87 deletions(-)
 rename AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/{BiDirectionalDictionary.cs => DualWayDictionary.cs} (100%)
 rename AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/{BiDirectionalDictionary.cs.meta => DualWayDictionary.cs.meta} (100%)

diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs
index 158bd8a2..6a16325c 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs
@@ -85,17 +85,18 @@ namespace AxibugEmuOnline.Client
         protected abstract void OnLoadDefaultMapper(BindingPage binding);
 
         /// <summary>
-        /// 获取指定按键是否处于按下状态
+        /// 获取指定控件是否处于按下状态
+        /// <para>如果绑定了多个物理按键,则只有这多个物理按键全部不处于按下状态时,才会返回false</para>
         /// </summary>
-        /// <param name="emuBtn"></param>
+        /// <param name="emuControl"></param>
         /// <param name="controllerIndex"></param>
         /// <returns></returns>
-        public bool GetKey(T emuBtn, int controllerIndex)
+        public bool GetKey(T emuControl, int controllerIndex)
         {
             var binding = m_bindingPages[controllerIndex];
-            foreach (var key in binding.GetBinding(emuBtn))
+            foreach (var key in binding.GetBinding(emuControl))
             {
-                if (key.IsPressing()) return true;
+                if (key.Performing) return true;
             }
 
             return false;
@@ -113,46 +114,56 @@ namespace AxibugEmuOnline.Client
         }
 
         /// <summary>
-        /// 获取指定按键的值
+        /// 获取指定控件的向量值
+        /// <para>通常用于摇杆类型的控件</para>
+        /// <para>如果同时绑定了多个物理输入设备,只会返回其中一个物理设备的向量值</para>
         /// </summary>
-        /// <param name="emuBtn">模拟器平台的具体键枚举</param>
+        /// <param name="emuControl">模拟器平台的具体键枚举</param>
         /// <param name="controllerIndex">模拟器平台的控制器序号</param>
         /// <returns></returns>
-        public Vector2 GetVector2(T emuBtn, int controllerIndex)
+        public Vector2 GetVector2(T emuControl, int controllerIndex)
         {
             var binding = m_bindingPages[controllerIndex];
-            foreach (var key in binding.GetBinding(emuBtn))
+            foreach (var control in binding.GetBinding(emuControl))
             {
-                if (!key.IsPressing()) continue;
+                if (!control.Performing) continue;
 
-                return key.GetVector2();
+                return control.GetVector2();
             }
 
             return default(Vector2);
         }
 
         /// <summary>
-        /// 获取指定按键的值
+        /// 获取指定控件的浮点值,取值范围为[0f,1f]
+        /// <para>通常用于线性类按键,例如PS手柄的扳机键</para>
+        /// <para>普通的按键也能读取这个值,但返回值只会有0f和1f两种值</para>
+        /// <para>如果同时绑定了多个物理控件,则会从所有处于按下状态的物理控件中取平均值</para>
         /// </summary>
-        /// <param name="emuBtn">模拟器平台的具体键枚举</param>
+        /// <param name="emuControl">模拟器平台的具体键枚举</param>
         /// <param name="controllerIndex">模拟器平台的控制器序号</param>
         /// <returns></returns>
-        public float GetFloat(T emuBtn, int controllerIndex)
+        public float GetFloat(T emuControl, int controllerIndex)
         {
-            var binding = m_bindingPages[controllerIndex];
-            foreach (var key in binding.GetBinding(emuBtn))
-            {
-                if (!key.IsPressing()) continue;
+            var totalFloat = 0f;
+            var totalControl = 0;
 
-                return key.GetFlaot();
+            var binding = m_bindingPages[controllerIndex];
+            foreach (var key in binding.GetBinding(emuControl))
+            {
+                if (!key.Performing) continue;
+
+                totalControl++;
+                totalFloat += key.GetFlaot();
             }
 
-            return default(float);
+            if (totalControl == 0) return default(float);
+            else return totalFloat / totalControl;
         }
 
         public class BindingPage
         {
-            Dictionary<T, List<InputDevice.KeyBase>> m_mapSetting = new Dictionary<T, List<InputDevice.KeyBase>>();
+            Dictionary<T, List<InputDevice.InputControl>> m_mapSetting = new Dictionary<T, List<InputDevice.InputControl>>();
 
             public int ControllerIndex { get; }
             public EmuCoreControllerKeyBinding<T> Host { get; }
@@ -163,7 +174,7 @@ namespace AxibugEmuOnline.Client
                 Host = host;
 
                 foreach (var emuBtn in host.DefineKeys())
-                    m_mapSetting[emuBtn] = new List<InputDevice.KeyBase>();
+                    m_mapSetting[emuBtn] = new List<InputDevice.InputControl>();
             }
 
             public void ClearBinding()
@@ -171,7 +182,7 @@ namespace AxibugEmuOnline.Client
                 foreach (var list in m_mapSetting.Values) list.Clear();
             }
 
-            public void SetBinding(T emuBtn, InputDevice.KeyBase key, int settingSlot)
+            public void SetBinding(T emuBtn, InputDevice.InputControl key, int settingSlot)
             {
                 var settingList = m_mapSetting[emuBtn];
 
@@ -181,14 +192,14 @@ namespace AxibugEmuOnline.Client
                 settingList[settingSlot] = key;
             }
 
-            public InputDevice.KeyBase GetBinding(T emuBtn, int settingSlot)
+            public InputDevice.InputControl GetBinding(T emuBtn, int settingSlot)
             {
                 var settingList = m_mapSetting[emuBtn];
                 if (settingSlot >= settingList.Count) return null;
                 return settingList[settingSlot];
             }
 
-            public List<InputDevice.KeyBase> GetBinding(T emuBtn)
+            public List<InputDevice.InputControl> GetBinding(T emuBtn)
             {
                 return m_mapSetting[emuBtn];
             }
@@ -199,7 +210,7 @@ namespace AxibugEmuOnline.Client
                 {
                     foreach (var key in item.Value)
                     {
-                        if (key.GetButtonDown()) return true;
+                        if (key.Start) return true;
                     }
                 }
 
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs
index 8fff0861..97c4b06c 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs
@@ -1,6 +1,5 @@
 using System.Collections.Generic;
 using UnityEngine;
-using UnityEngine.InputSystem;
 
 namespace AxibugEmuOnline.Client.InputDevices
 {
@@ -19,12 +18,12 @@ namespace AxibugEmuOnline.Client.InputDevices
 
         private void OnDeviceLost(InputDevice lostDevice)
         {
-
+            RemoveDevice(lostDevice);
         }
 
         private void OnDeviceConnected(InputDevice connectDevice)
         {
-            throw new System.NotImplementedException();
+            AddDevice(connectDevice);
         }
 
         public void AddDevice(InputDevice device)
@@ -37,7 +36,7 @@ namespace AxibugEmuOnline.Client.InputDevices
             m_devices.Remove(device.UniqueName);
         }
 
-        public InputDevice.KeyBase GetKeyByPath(string path)
+        public InputDevice.InputControl GetKeyByPath(string path)
         {
             var temp = path.Split("/");
             Debug.Assert(temp.Length == 2, "Invalid Path Format");
@@ -48,7 +47,7 @@ namespace AxibugEmuOnline.Client.InputDevices
             var targetDevice = FindDeviceByName(deviceName);
             if (targetDevice == null) return null;
 
-            var key = targetDevice.FindKeyByKeyName(keyName);
+            var key = targetDevice.FindControlByName(keyName);
             return key;
         }
 
@@ -83,22 +82,22 @@ namespace AxibugEmuOnline.Client.InputDevices
     {
         public abstract string UniqueName { get; }
 
-        public delegate void OnKeyStateChangedHandle(KeyBase sender);
-        public event OnKeyStateChangedHandle OnKeyStateChanged;
-
         /// <summary> 指示该设备是否在线 </summary>
-        public abstract bool Online { get; }
-        /// <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, KeyBase> m_keyMapper = new Dictionary<string, KeyBase>();
+        protected Dictionary<string, InputControl> m_controlMapper = new Dictionary<string, InputControl>();
         protected InputResolver m_resolver;
         public InputDevice(InputResolver resolver)
         {
             m_resolver = resolver;
-            foreach (var key in DefineKeys())
+
+            foreach (var control in DefineControls())
             {
-                m_keyMapper[key.KeyName] = key;
+                m_controlMapper.Add(control.ControlName, control);
             }
         }
 
@@ -106,49 +105,54 @@ namespace AxibugEmuOnline.Client.InputDevices
         {
             AnyKeyDown = false;
 
-            foreach (var key in m_keyMapper.Values)
+            foreach (var control in m_controlMapper.Values)
             {
-                if (key.GetButtonDown())
+                if (control.Start)
                 {
                     AnyKeyDown = true;
-                    RaiseKeyEvent(key);
                 }
             }
         }
 
-        protected abstract IEnumerable<KeyBase> DefineKeys();
-        protected void RaiseKeyEvent(KeyBase sender)
-        {
-            OnKeyStateChanged?.Invoke(sender);
-        }
+        /// <summary> 用于列出这个输入设备的所有输入控件实例 </summary>
+        /// <returns></returns>
+        protected abstract IEnumerable<InputControl> DefineControls();
 
-        public KeyBase FindKeyByKeyName(string keyName)
+        /// <summary> 通过控件名称,找到对应的控件 </summary>
+        /// <param name="keyName"></param>
+        /// <returns></returns>
+        public InputControl FindControlByName(string controlName)
         {
-            m_keyMapper.TryGetValue(keyName, out var key);
+            m_controlMapper.TryGetValue(controlName, out var key);
             return key;
         }
 
         /// <summary>
-        /// 输入设备的键接口
+        /// 输入设备的抽象控件接口
         /// </summary>
-        public abstract class KeyBase
+        public abstract class InputControl
         {
-            public InputDevice HostDevice { get; internal set; }
-            /// <summary> 获取该键是否在当前调用帧被按下 </summary>
-            public abstract bool GetButtonDown();
-            /// <summary> 获取该键是否在当前调用帧被抬起 </summary>
-            public abstract bool GetButtonUp();
-            /// <summary> 获取该键是否在当前调用帧是否处于按下状态 </summary>
-            public abstract bool IsPressing();
+            /// <summary> 控件所属设备 </summary>
+            public InputDevice Device { get; internal set; }
 
-            public virtual Vector2 GetVector2() { throw new System.NotImplementedException(); }
-            public virtual float GetFlaot() { throw new System.NotImplementedException(); }
+            /// <summary> 获取该控件是否在当前调用帧被激发 </summary>
+            public abstract bool Start { get; }
+            /// <summary> 获取该控件是否在当前调用帧被释放 </summary>
+            public abstract bool Release { get; }
+            /// <summary> 获取该控件是否在当前调用帧是否处于活动状态 </summary>
+            public abstract bool Performing { get; }
 
-            /// <summary> 键名 </summary>
-            public abstract string KeyName { get; }
+            /// <summary> 获得该控件的以二维向量表达的值 </summary>
+            /// <returns></returns>
+            public abstract Vector2 GetVector2();
+            /// <summary> 获得该控件的以浮点数表达的值 </summary>
+            public abstract float GetFlaot();
+
+            /// <summary> 控件名,这个控件名称必须是唯一的 </summary>
+            public abstract string ControlName { get; }
             public string GetPath()
             {
-                return $"{HostDevice.UniqueName}/{KeyName}";
+                return $"{Device.UniqueName}/{ControlName}";
             }
         }
 
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/BiDirectionalDictionary.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/DualWayDictionary.cs
similarity index 100%
rename from AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/BiDirectionalDictionary.cs
rename to AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/DualWayDictionary.cs
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/BiDirectionalDictionary.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/DualWayDictionary.cs.meta
similarity index 100%
rename from AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/BiDirectionalDictionary.cs.meta
rename to AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/DualWayDictionary.cs.meta
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputResolver.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputResolver.cs
index 44fe1a91..3c098c5e 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputResolver.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputResolver.cs
@@ -1,4 +1,5 @@
 using System.Collections.Generic;
+using UnityEngine;
 
 namespace AxibugEmuOnline.Client.InputDevices
 {
@@ -53,5 +54,26 @@ namespace AxibugEmuOnline.Client.InputDevices
         {
             OnDeviceConnected?.Invoke(connectDevice);
         }
+
+        /// <summary>
+        /// 获取一个键盘设备的指定按键当前调用帧是否触发了按下动作
+        /// </summary>
+        /// <param name="keyboard">键盘设备实例,来自Resolver提供的设备实例</param>
+        /// <param name="key">键盘按键枚举值</param>
+        /// <returns></returns>
+        public abstract bool GetKeyDown(KeyBoard keyboard, KeyCode key);
+        /// <summary>
+        /// 获取一个键盘设备的指定按键当前调用帧是否触发了放开动作
+        /// </summary>
+        /// <param name="keyboard">键盘设备实例,来自Resolver提供的设备实例</param>
+        /// <param name="key">键盘按键枚举值</param>
+        public abstract bool GetKeyUp(KeyBoard keyboard, KeyCode key);
+        /// <summary>
+        /// 获取一个键盘设备的指定按键当前调用帧是否处于按下状态
+        /// </summary>
+        /// <param name="keyboard">键盘设备实例,来自Resolver提供的设备实例</param>
+        /// <param name="key">键盘按键枚举值</param>
+        public abstract bool GetKey(KeyBoard keyboard, KeyCode key);
+
     }
 }
\ 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
index 30ca2b2a..9917d1fa 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs
@@ -1,22 +1,21 @@
 #if ENABLE_INPUT_SYSTEM
 using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.InputSystem.Controls;
 using IP = UnityEngine.InputSystem.InputSystem;
 using IPDevice = UnityEngine.InputSystem.InputDevice;
 using IPKeyboard = UnityEngine.InputSystem.Keyboard;
 
 namespace AxibugEmuOnline.Client.InputDevices
 {
-    /// <summary> InputSystem对接 </summary>
-    public class InputSystemResolver : InputResolver
+    /// <summary> InputSystem对接类 </summary>
+    public partial class InputSystemResolver : InputResolver
     {
         DualWayDictionary<IPDevice, InputDevice> m_devices = new DualWayDictionary<IPDevice, InputDevice>();
 
         protected override void OnInit()
         {
-            foreach (var device in IP.devices)
-            {
-                AddDevice(device);
-            }
+            foreach (var device in IP.devices) AddDevice(device);
 
             IP.onDeviceChange += IP_onDeviceChange;
         }
@@ -60,6 +59,175 @@ namespace AxibugEmuOnline.Client.InputDevices
         {
             return m_devices.Values;
         }
+
+        public override bool GetKeyDown(KeyBoard keyboard, KeyCode key)
+        {
+            if (m_devices.TryGetKey(keyboard, out var ipdev))
+            {
+                var ipKeyboard = ipdev as IPKeyboard;
+                if (ipKeyboard == null) return false;
+
+                var k = GetIPKeyboardKey(ipKeyboard, key);
+                return k.wasPressedThisFrame;
+            }
+
+            return false;
+        }
+
+        public override bool GetKeyUp(KeyBoard keyboard, KeyCode key)
+        {
+            if (m_devices.TryGetKey(keyboard, out var ipdev))
+            {
+                var ipKeyboard = ipdev as IPKeyboard;
+                if (ipKeyboard == null) return false;
+
+                var k = GetIPKeyboardKey(ipKeyboard, key);
+                return k.wasReleasedThisFrame;
+            }
+
+            return false;
+        }
+
+        public override bool GetKey(KeyBoard keyboard, KeyCode key)
+        {
+            if (m_devices.TryGetKey(keyboard, out var ipdev))
+            {
+                var ipKeyboard = ipdev as IPKeyboard;
+                if (ipKeyboard == null) return false;
+
+                var k = GetIPKeyboardKey(ipKeyboard, key);
+                return k.isPressed;
+            }
+
+            return false;
+        }
+    }
+
+    public partial class InputSystemResolver : InputResolver
+    {
+        static ButtonControl GetIPKeyboardKey(IPKeyboard keyboard, KeyCode key)
+        {
+            switch (key)
+            {
+                // 字母键(A-Z)
+                case KeyCode.A: return keyboard.aKey;
+                case KeyCode.B: return keyboard.bKey;
+                case KeyCode.C: return keyboard.cKey;
+                case KeyCode.D: return keyboard.dKey;
+                case KeyCode.E: return keyboard.eKey;
+                case KeyCode.F: return keyboard.fKey;
+                case KeyCode.G: return keyboard.gKey;
+                case KeyCode.H: return keyboard.hKey;
+                case KeyCode.I: return keyboard.iKey;
+                case KeyCode.J: return keyboard.jKey;
+                case KeyCode.K: return keyboard.kKey;
+                case KeyCode.L: return keyboard.lKey;
+                case KeyCode.M: return keyboard.mKey;
+                case KeyCode.N: return keyboard.nKey;
+                case KeyCode.O: return keyboard.oKey;
+                case KeyCode.P: return keyboard.pKey;
+                case KeyCode.Q: return keyboard.qKey;
+                case KeyCode.R: return keyboard.rKey;
+                case KeyCode.S: return keyboard.sKey;
+                case KeyCode.T: return keyboard.tKey;
+                case KeyCode.U: return keyboard.uKey;
+                case KeyCode.V: return keyboard.vKey;
+                case KeyCode.W: return keyboard.wKey;
+                case KeyCode.X: return keyboard.xKey;
+                case KeyCode.Y: return keyboard.yKey;
+                case KeyCode.Z: return keyboard.zKey;
+
+                // 数字键(0-9)
+                case KeyCode.Alpha0: return keyboard.digit0Key;
+                case KeyCode.Alpha1: return keyboard.digit1Key;
+                case KeyCode.Alpha2: return keyboard.digit2Key;
+                case KeyCode.Alpha3: return keyboard.digit3Key;
+                case KeyCode.Alpha4: return keyboard.digit4Key;
+                case KeyCode.Alpha5: return keyboard.digit5Key;
+                case KeyCode.Alpha6: return keyboard.digit6Key;
+                case KeyCode.Alpha7: return keyboard.digit7Key;
+                case KeyCode.Alpha8: return keyboard.digit8Key;
+                case KeyCode.Alpha9: return keyboard.digit9Key;
+
+                // 小键盘
+                case KeyCode.Keypad0: return keyboard.numpad0Key;
+                case KeyCode.Keypad1: return keyboard.numpad1Key;
+                case KeyCode.Keypad2: return keyboard.numpad2Key;
+                case KeyCode.Keypad3: return keyboard.numpad3Key;
+                case KeyCode.Keypad4: return keyboard.numpad4Key;
+                case KeyCode.Keypad5: return keyboard.numpad5Key;
+                case KeyCode.Keypad6: return keyboard.numpad6Key;
+                case KeyCode.Keypad7: return keyboard.numpad7Key;
+                case KeyCode.Keypad8: return keyboard.numpad8Key;
+                case KeyCode.Keypad9: return keyboard.numpad9Key;
+                case KeyCode.KeypadPeriod: return keyboard.numpadPeriodKey;
+                case KeyCode.KeypadDivide: return keyboard.numpadDivideKey;
+                case KeyCode.KeypadMultiply: return keyboard.numpadMultiplyKey;
+                case KeyCode.KeypadMinus: return keyboard.numpadMinusKey;
+                case KeyCode.KeypadPlus: return keyboard.numpadPlusKey;
+                case KeyCode.KeypadEnter: return keyboard.numpadEnterKey;
+                case KeyCode.KeypadEquals: return keyboard.numpadEqualsKey;
+
+                // 功能键(F1-F15)
+                case KeyCode.F1: return keyboard.f1Key;
+                case KeyCode.F2: return keyboard.f2Key;
+                case KeyCode.F3: return keyboard.f3Key;
+                case KeyCode.F4: return keyboard.f4Key;
+                case KeyCode.F5: return keyboard.f5Key;
+                case KeyCode.F6: return keyboard.f6Key;
+                case KeyCode.F7: return keyboard.f7Key;
+                case KeyCode.F8: return keyboard.f8Key;
+                case KeyCode.F9: return keyboard.f9Key;
+                case KeyCode.F10: return keyboard.f10Key;
+                case KeyCode.F11: return keyboard.f11Key;
+                case KeyCode.F12: return keyboard.f12Key;
+
+                // 方向键
+                case KeyCode.UpArrow: return keyboard.upArrowKey;
+                case KeyCode.DownArrow: return keyboard.downArrowKey;
+                case KeyCode.LeftArrow: return keyboard.leftArrowKey;
+                case KeyCode.RightArrow: return keyboard.rightArrowKey;
+
+                // 符号键
+                case KeyCode.Space: return keyboard.spaceKey;
+                case KeyCode.Backspace: return keyboard.backspaceKey;
+                case KeyCode.Tab: return keyboard.tabKey;
+                case KeyCode.Return: return keyboard.enterKey;
+                case KeyCode.Escape: return keyboard.escapeKey;
+                case KeyCode.LeftShift: return keyboard.leftShiftKey;
+                case KeyCode.RightShift: return keyboard.rightShiftKey;
+                case KeyCode.LeftControl: return keyboard.leftCtrlKey;
+                case KeyCode.RightControl: return keyboard.rightCtrlKey;
+                case KeyCode.LeftAlt: return keyboard.leftAltKey;
+                case KeyCode.RightAlt: return keyboard.rightAltKey;
+                case KeyCode.LeftCommand: return keyboard.leftCommandKey; // macOS Command键
+                case KeyCode.RightCommand: return keyboard.rightCommandKey;
+                case KeyCode.CapsLock: return keyboard.capsLockKey;
+                case KeyCode.Numlock: return keyboard.numLockKey;
+                case KeyCode.ScrollLock: return keyboard.scrollLockKey;
+                case KeyCode.Print: return keyboard.printScreenKey;
+                case KeyCode.Pause: return keyboard.pauseKey;
+                case KeyCode.Insert: return keyboard.insertKey;
+                case KeyCode.Home: return keyboard.homeKey;
+                case KeyCode.End: return keyboard.endKey;
+                case KeyCode.PageUp: return keyboard.pageUpKey;
+                case KeyCode.PageDown: return keyboard.pageDownKey;
+                case KeyCode.Delete: return keyboard.deleteKey;
+                case KeyCode.Comma: return keyboard.commaKey;
+                case KeyCode.Period: return keyboard.periodKey;
+                case KeyCode.Slash: return keyboard.slashKey;
+                case KeyCode.BackQuote: return keyboard.backquoteKey;
+                case KeyCode.Minus: return keyboard.minusKey;
+                case KeyCode.Equals: return keyboard.equalsKey;
+                case KeyCode.LeftBracket: return keyboard.leftBracketKey;
+                case KeyCode.RightBracket: return keyboard.rightBracketKey;
+                case KeyCode.Backslash: return keyboard.backslashKey;
+                case KeyCode.Semicolon: return keyboard.semicolonKey;
+                case KeyCode.Quote: return keyboard.quoteKey;
+                default:
+                    throw new System.NotImplementedException($"Not Find KeyCode Mapper Code from {key}");
+            }
+        }
     }
 }
 #endif
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Keyboard.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Keyboard.cs
index b475b9c9..4c7b34ef 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Keyboard.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Keyboard.cs
@@ -7,41 +7,38 @@ namespace AxibugEmuOnline.Client.InputDevices
     public partial class KeyBoard : InputDevice
     {
         public override string UniqueName => nameof(KeyBoard);
-        public override bool Online => true;
-
         public KeyBoard(InputResolver resolver) : base(resolver) { }
 
-        protected override IEnumerable<KeyBase> DefineKeys()
+        protected override IEnumerable<InputControl> DefineControls()
         {
-            var keys = s_keyboardKeys.Select(kc => new KeyboardKey(kc) as KeyBase);
+            var keys = s_keyboardKeys.Select(kc => new KeyboardKey(kc) as InputControl);
             return keys;
         }
 
-        public class KeyboardKey : KeyBase
+        public class KeyboardKey : InputControl
         {
-            internal KeyCode m_listenKey;
+            KeyCode m_keycode;
+
+            public override bool Start => Device.Resolver.GetKeyDown(Device as KeyBoard, m_keycode);
+            public override bool Release => Device.Resolver.GetKeyUp(Device as KeyBoard, m_keycode);
+            public override bool Performing => Device.Resolver.GetKey(Device as KeyBoard, m_keycode);
 
             public KeyboardKey(KeyCode listenKey)
             {
-                m_listenKey = listenKey;
+                m_keycode = listenKey;
             }
 
-            public override bool GetButtonDown()
+            public override string ControlName => m_keycode.ToString();
+
+            public override Vector2 GetVector2()
             {
-                return Input.GetKeyDown(m_listenKey);
+                return default(Vector2);
             }
 
-            public override bool GetButtonUp()
+            public override float GetFlaot()
             {
-                return Input.GetKeyUp(m_listenKey);
+                return Performing ? 1 : 0;
             }
-
-            public override bool IsPressing()
-            {
-                return Input.GetKey(m_listenKey);
-            }
-
-            public override string KeyName => m_listenKey.ToString();
         }
     }
 

From 1c20707751d506e9c9a7e1f2c54143ad0a65334f Mon Sep 17 00:00:00 2001
From: "ALIENJACK\\alien" <alienjack@foxmail.com>
Date: Fri, 14 Mar 2025 15:27:26 +0800
Subject: [PATCH 04/20] =?UTF-8?q?=E8=BE=93=E5=85=A5=E7=B3=BB=E7=BB=9F?=
 =?UTF-8?q?=E8=BF=AD=E4=BB=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../Assets/Editors/CommandDispatcherEditor.cs |  2 +-
 .../Script/AppMain/IkeyMapperChanger.meta     |  8 --
 .../IkeyMapperChanger/CommandChanger.cs       | 13 ---
 .../IkeyMapperChanger/CommandChanger.cs.meta  | 11 ---
 .../IkeyMapperChanger/GamingChanger.cs        | 35 -------
 .../IkeyMapperChanger/GamingChanger.cs.meta   | 11 ---
 .../IkeyMapperChanger/NormalChanger.cs        | 64 -------------
 .../IkeyMapperChanger/NormalChanger.cs.meta   | 11 ---
 .../Assets/Script/AppMain/Manager/AppEmu.cs   |  2 +-
 .../KeyMapperSetting/KeyMapperSetting.cs      | 57 +++++++++--
 .../KeyMapperSetting/NesKeyBinding.cs         |  4 +-
 .../KeyMapperSetting/XMBKeyBinding.cs         | 44 +++++++++
 .../KeyMapperSetting/XMBKeyBinding.cs.meta    |  2 +
 .../InputDevicesManager.cs                    |  5 +-
 .../InputResolver/InputResolver.cs            |  8 +-
 .../InputResolver/InputSystemResolver.cs      | 10 +-
 .../Manager/InputDevicesManager/Keyboard.cs   |  7 +-
 .../UI/CommandDispatcher/CommandDispatcher.cs | 43 +++------
 .../UI/CommandDispatcher/CommandListener.cs   | 94 ++++++-------------
 .../UI/CommandDispatcher/ICommandListener.cs  | 16 ----
 .../Assets/Script/AppMain/UI/LaunchUI.cs      |  6 +-
 .../Script/AppMain/UI/OptionUI/OptionUI.cs    |  8 +-
 22 files changed, 167 insertions(+), 294 deletions(-)
 delete mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/IkeyMapperChanger.meta
 delete mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/IkeyMapperChanger/CommandChanger.cs
 delete mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/IkeyMapperChanger/CommandChanger.cs.meta
 delete mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/IkeyMapperChanger/GamingChanger.cs
 delete mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/IkeyMapperChanger/GamingChanger.cs.meta
 delete mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/IkeyMapperChanger/NormalChanger.cs
 delete mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/IkeyMapperChanger/NormalChanger.cs.meta
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/XMBKeyBinding.cs
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/XMBKeyBinding.cs.meta

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/Script/AppMain/IkeyMapperChanger.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/IkeyMapperChanger.meta
deleted file mode 100644
index e0fa40f3..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/IkeyMapperChanger.meta
+++ /dev/null
@@ -1,8 +0,0 @@
-fileFormatVersion: 2
-guid: 04e926e140ae5bc4fa46bd64067261cf
-folderAsset: yes
-DefaultImporter:
-  externalObjects: {}
-  userData: 
-  assetBundleName: 
-  assetBundleVariant: 
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 d28da729..117d33fd 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppEmu.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppEmu.cs
@@ -78,7 +78,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/AppSettings/KeyMapperSetting/KeyMapperSetting.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs
index 6a16325c..c18b21fa 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs
@@ -1,4 +1,5 @@
-using AxibugEmuOnline.Client.InputDevices;
+using AxibugEmuOnline.Client.ClientCore;
+using AxibugEmuOnline.Client.InputDevices;
 using AxibugProtobuf;
 using System;
 using System.Collections.Generic;
@@ -61,8 +62,7 @@ namespace AxibugEmuOnline.Client
             {
                 m_bindingPages.Add(new BindingPage(i, this));
             }
-
-            LoadDefaultMapper();
+            LoadDefaultKeyboardMapper();
         }
 
         IEnumerable<T> DefineKeys()
@@ -71,18 +71,41 @@ namespace AxibugEmuOnline.Client
         }
 
         /// <summary>
-        /// 加载默认映射
+        /// 加载默认键盘映射
         /// </summary>
-        public void LoadDefaultMapper()
+        public void LoadDefaultKeyboardMapper()
         {
             foreach (var binding in m_bindingPages)
             {
-                binding.ClearBinding();
-                OnLoadDefaultMapper(binding);
+                binding.ClearKeyboardBinding();
+                var keyboard = App.inputDevicesMgr.GetKeyboard();
+                if (keyboard != null) OnLoadDefaultKeyboardMapper(keyboard, binding);
             }
         }
 
-        protected abstract void OnLoadDefaultMapper(BindingPage binding);
+        protected abstract void OnLoadDefaultKeyboardMapper(KeyBoard keyboard, BindingPage binding);
+
+        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>
         /// 获取指定控件是否处于按下状态
@@ -177,9 +200,23 @@ namespace AxibugEmuOnline.Client
                     m_mapSetting[emuBtn] = new List<InputDevice.InputControl>();
             }
 
-            public void ClearBinding()
+            /// <summary>
+            /// 移除与键盘设备建立的绑定设置
+            /// </summary>
+            public void ClearKeyboardBinding()
             {
-                foreach (var list in m_mapSetting.Values) list.Clear();
+                foreach (var list in m_mapSetting.Values)
+                {
+                    for (int i = 0; i < list.Count; i++)
+                    {
+                        var inputControl = list[i];
+                        if (inputControl.Device is KeyBoard)
+                        {
+                            list.RemoveAt(i);
+                            i--;
+                        }
+                    }
+                }
             }
 
             public void SetBinding(T emuBtn, InputDevice.InputControl key, int settingSlot)
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/NesKeyBinding.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/NesKeyBinding.cs
index ef80d946..8258e202 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/NesKeyBinding.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/NesKeyBinding.cs
@@ -1,4 +1,5 @@
 using AxibugEmuOnline.Client.ClientCore;
+using AxibugEmuOnline.Client.InputDevices;
 using AxibugProtobuf;
 using VirtualNes.Core;
 
@@ -9,9 +10,8 @@ namespace AxibugEmuOnline.Client
         public override RomPlatformType Platform => RomPlatformType.Nes;
         public override int ControllerCount => 4;
 
-        protected override void OnLoadDefaultMapper(BindingPage binding)
+        protected override void OnLoadDefaultKeyboardMapper(KeyBoard keyboard, BindingPage binding)
         {
-            var keyboard = App.inputDevicesMgr.GetKeyboard();
             switch (binding.ControllerIndex)
             {
                 case 0:
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..a5525e65
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/XMBKeyBinding.cs
@@ -0,0 +1,44 @@
+using AxibugEmuOnline.Client.ClientCore;
+using AxibugEmuOnline.Client.InputDevices;
+using AxibugProtobuf;
+
+namespace AxibugEmuOnline.Client
+{
+    public class XMBKeyBinding : EmuCoreControllerKeyBinding<EnumCommand>
+    {
+        public override RomPlatformType Platform => RomPlatformType.Invalid;
+        public override int ControllerCount => 2;
+
+        protected override void OnLoadDefaultKeyboardMapper(KeyBoard keyboard, BindingPage binding)
+        {
+            switch (binding.ControllerIndex)
+            {
+                case 0://设置标准UI控制
+                    //第一套控制布局 WSAD+JKLI
+                    binding.SetBinding(EnumCommand.Back, keyboard.L, 0);
+                    binding.SetBinding(EnumCommand.Enter, keyboard.K, 0);
+                    binding.SetBinding(EnumCommand.OptionMenu, keyboard.I, 0);
+                    binding.SetBinding(EnumCommand.SelectItemDown, keyboard.S, 0);
+                    binding.SetBinding(EnumCommand.SelectItemLeft, keyboard.A, 0);
+                    binding.SetBinding(EnumCommand.SelectItemRight, keyboard.D, 0);
+                    binding.SetBinding(EnumCommand.SelectItemUp, keyboard.W, 0);
+
+                    //第二套控制布局 LOWB用
+                    binding.SetBinding(EnumCommand.Back, keyboard.Escape, 1);
+                    binding.SetBinding(EnumCommand.Back, keyboard.Backspace, 2);
+                    binding.SetBinding(EnumCommand.Enter, keyboard.Return, 1);
+                    binding.SetBinding(EnumCommand.OptionMenu, keyboard.LeftShift, 1);
+                    binding.SetBinding(EnumCommand.OptionMenu, keyboard.RightShift, 2);
+                    binding.SetBinding(EnumCommand.SelectItemDown, keyboard.DownArrow, 1);
+                    binding.SetBinding(EnumCommand.SelectItemLeft, keyboard.LeftArrow, 1);
+                    binding.SetBinding(EnumCommand.SelectItemRight, keyboard.RightArrow, 1);
+                    binding.SetBinding(EnumCommand.SelectItemUp, keyboard.UpArrow, 1);
+                    break;
+                case 1://游戏中UI控制
+                    binding.SetBinding(EnumCommand.OptionMenu, keyboard.Escape, 0);
+                    break;
+            }
+
+        }
+    }
+}
\ 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/InputDevicesManager/InputDevicesManager.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs
index 97c4b06c..45183e11 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs
@@ -58,8 +58,7 @@ namespace AxibugEmuOnline.Client.InputDevices
         }
 
         /// <summary>
-        /// 获得键盘设备
-        /// <para>键盘设备被设计为有且仅有一个,所以这里应该总是能获得键盘设备</para>
+        /// 获得一个键盘设备
         /// </summary>
         public KeyBoard GetKeyboard()
         {
@@ -80,7 +79,7 @@ namespace AxibugEmuOnline.Client.InputDevices
 
     public abstract class InputDevice
     {
-        public abstract string UniqueName { get; }
+        public string UniqueName => m_resolver.GetDeviceName(this);
 
         /// <summary> 指示该设备是否在线 </summary>
         public bool Online => m_resolver.CheckOnline(this);
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputResolver.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputResolver.cs
index 3c098c5e..d3f6c832 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputResolver.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputResolver.cs
@@ -8,7 +8,7 @@ namespace AxibugEmuOnline.Client.InputDevices
         public static InputResolver Create()
         {
 #if ENABLE_INPUT_SYSTEM //InputSystem
-            return new InputSystemResolver();
+            return new ForInputSystem.InputSystemResolver();
 #elif UNITY_PSP2 //SDK
             throw new System.NotImplementedException();
 #elif UNITY_PS3 //SDK
@@ -75,5 +75,11 @@ namespace AxibugEmuOnline.Client.InputDevices
         /// <param name="key">键盘按键枚举值</param>
         public abstract bool GetKey(KeyBoard keyboard, KeyCode key);
 
+        /// <summary>
+        /// 获得输入设备的唯一名称
+        /// </summary>
+        /// <param name="inputDevice">这个设备必须是由resolver提供,并且保持着连接</param>
+        /// <returns></returns>
+        public abstract string GetDeviceName(InputDevice inputDevice);
     }
 }
\ 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
index 9917d1fa..f7211d72 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs
@@ -6,7 +6,7 @@ using IP = UnityEngine.InputSystem.InputSystem;
 using IPDevice = UnityEngine.InputSystem.InputDevice;
 using IPKeyboard = UnityEngine.InputSystem.Keyboard;
 
-namespace AxibugEmuOnline.Client.InputDevices
+namespace AxibugEmuOnline.Client.InputDevices.ForInputSystem
 {
     /// <summary> InputSystem对接类 </summary>
     public partial class InputSystemResolver : InputResolver
@@ -41,6 +41,14 @@ namespace AxibugEmuOnline.Client.InputDevices
             }
         }
 
+        public override string GetDeviceName(InputDevice inputDevice)
+        {
+            m_devices.TryGetKey(inputDevice, out var ipdev);
+            Debug.Assert(ipdev != null, "不能对已离线的设备获取名称");
+
+            return $"{ipdev.description.deviceClass}_{ipdev.description.interfaceName}_{ipdev.deviceId}";
+        }
+
         public override bool CheckOnline(InputDevice device)
         {
             return m_devices.TryGetKey(device, out var _);
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Keyboard.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Keyboard.cs
index 4c7b34ef..01c0a84d 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Keyboard.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Keyboard.cs
@@ -4,9 +4,11 @@ using UnityEngine;
 
 namespace AxibugEmuOnline.Client.InputDevices
 {
+    /// <summary>
+    /// 通用键盘设备
+    /// </summary>
     public partial class KeyBoard : InputDevice
     {
-        public override string UniqueName => nameof(KeyBoard);
         public KeyBoard(InputResolver resolver) : base(resolver) { }
 
         protected override IEnumerable<InputControl> DefineControls()
@@ -156,6 +158,9 @@ namespace AxibugEmuOnline.Client.InputDevices
         public KeyboardKey Return { get; private set; } = new KeyboardKey(KeyCode.Return);
         public KeyboardKey Escape { get; private set; } = new KeyboardKey(KeyCode.Escape);
         public KeyboardKey Tab { get; private set; } = new KeyboardKey(KeyCode.Tab);
+        /// <summary>
+        /// <img src="./test.png" alt="test"/>
+        /// </summary>
         public KeyboardKey Backspace { get; private set; } = new KeyboardKey(KeyCode.Backspace);
         public KeyboardKey CapsLock { get; private set; } = new KeyboardKey(KeyCode.CapsLock);
         public KeyboardKey LeftShift { get; private set; } = new KeyboardKey(KeyCode.LeftShift);
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 54bb040c..9548927d 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/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;

From 3257e15ddad5ee2c8d429092a111673dade08cf3 Mon Sep 17 00:00:00 2001
From: "ALIENJACK\\alien" <alienjack@foxmail.com>
Date: Mon, 17 Mar 2025 10:33:23 +0800
Subject: [PATCH 05/20] =?UTF-8?q?=E9=94=AE=E7=9B=98=E6=98=A0=E5=B0=84?=
 =?UTF-8?q?=E9=85=8D=E7=BD=AE=E5=8A=A0=E8=BD=BD=E6=9C=BA=E5=88=B6=E4=BF=AE?=
 =?UTF-8?q?=E6=94=B9,=E7=8E=B0=E5=9C=A8=E5=9C=A8=E5=88=9D=E5=A7=8B?=
 =?UTF-8?q?=E5=8C=96=E4=BB=A5=E5=8F=8A=E4=BB=BB=E4=BD=95=E9=94=AE=E7=9B=98?=
 =?UTF-8?q?=E8=AE=BE=E5=A4=87=E6=96=AD=E5=BC=80=E5=92=8C=E8=BF=9E=E6=8E=A5?=
 =?UTF-8?q?=E6=97=B6,=E4=BC=9A=E6=A3=80=E6=9F=A5=E5=8F=AF=E7=94=A8?=
 =?UTF-8?q?=E9=94=AE=E7=9B=98=E8=AE=BE=E5=A4=87=E5=B9=B6=E4=B8=94=E8=B0=83?=
 =?UTF-8?q?=E7=94=A8=E9=85=8D=E7=BD=AE=E5=8A=A0=E8=BD=BD=E6=96=B9=E6=B3=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../KeyMapperSetting/KeyMapperSetting.cs      | 41 +++++++++++++++----
 .../KeyMapperSetting/NesKeyBinding.cs         |  2 +-
 .../KeyMapperSetting/XMBKeyBinding.cs         |  2 +-
 .../InputDevicesManager.cs                    | 40 ++++++------------
 4 files changed, 49 insertions(+), 36 deletions(-)

diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs
index c18b21fa..c6d6a001 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs
@@ -55,6 +55,7 @@ namespace AxibugEmuOnline.Client
         where T : Enum
     {
         List<BindingPage> m_bindingPages = new List<BindingPage>();
+        KeyBoard m_currentKeyboard;
 
         public EmuCoreControllerKeyBinding()
         {
@@ -62,7 +63,31 @@ namespace AxibugEmuOnline.Client
             {
                 m_bindingPages.Add(new BindingPage(i, this));
             }
-            LoadDefaultKeyboardMapper();
+            m_currentKeyboard = App.inputDevicesMgr.GetKeyboard();
+
+            if (m_currentKeyboard != null)
+                LoadKeyboardMapper();
+
+            App.inputDevicesMgr.OnDeviceLost += InputDevicesMgr_OnDeviceLost;
+            App.inputDevicesMgr.OnDeviceConnected += InputDevicesMgr_OnDeviceConnected;
+        }
+
+        private void InputDevicesMgr_OnDeviceConnected(InputDevice connectDevice)
+        {
+            if (m_currentKeyboard == null && connectDevice is KeyBoard) //未建立键盘按键映射设置时,并且有新的键盘连接时,建立键盘映射设置
+            {
+                m_currentKeyboard = connectDevice as KeyBoard;
+                LoadKeyboardMapper();
+            }
+        }
+
+        private void InputDevicesMgr_OnDeviceLost(InputDevice lostDevice)
+        {
+            if (lostDevice == m_currentKeyboard) //当前键盘设备丢失,与其他键盘重新建立连接
+            {
+                m_currentKeyboard = App.inputDevicesMgr.GetKeyboard();
+                LoadKeyboardMapper();
+            }
         }
 
         IEnumerable<T> DefineKeys()
@@ -71,19 +96,21 @@ namespace AxibugEmuOnline.Client
         }
 
         /// <summary>
-        /// 加载默认键盘映射
+        /// 加载键盘映射配置
         /// </summary>
-        public void LoadDefaultKeyboardMapper()
+        void LoadKeyboardMapper()
         {
             foreach (var binding in m_bindingPages)
             {
                 binding.ClearKeyboardBinding();
-                var keyboard = App.inputDevicesMgr.GetKeyboard();
-                if (keyboard != null) OnLoadDefaultKeyboardMapper(keyboard, binding);
+                if (m_currentKeyboard != null) OnLoadKeyboardMapper(m_currentKeyboard, binding);
             }
         }
 
-        protected abstract void OnLoadDefaultKeyboardMapper(KeyBoard keyboard, BindingPage binding);
+        /// <summary> 当加载键盘映射设置时触发 </summary>
+        /// <param name="keyboard"></param>
+        /// <param name="binding"></param>
+        protected abstract void OnLoadKeyboardMapper(KeyBoard keyboard, BindingPage binding);
 
         public bool Start(T emuControl, int controllerIndex)
         {
@@ -203,7 +230,7 @@ namespace AxibugEmuOnline.Client
             /// <summary>
             /// 移除与键盘设备建立的绑定设置
             /// </summary>
-            public void ClearKeyboardBinding()
+            internal void ClearKeyboardBinding()
             {
                 foreach (var list in m_mapSetting.Values)
                 {
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/NesKeyBinding.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/NesKeyBinding.cs
index 8258e202..b0632ffe 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/NesKeyBinding.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/NesKeyBinding.cs
@@ -10,7 +10,7 @@ namespace AxibugEmuOnline.Client
         public override RomPlatformType Platform => RomPlatformType.Nes;
         public override int ControllerCount => 4;
 
-        protected override void OnLoadDefaultKeyboardMapper(KeyBoard keyboard, BindingPage binding)
+        protected override void OnLoadKeyboardMapper(KeyBoard keyboard, BindingPage binding)
         {
             switch (binding.ControllerIndex)
             {
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/XMBKeyBinding.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/XMBKeyBinding.cs
index a5525e65..bd31c72e 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/XMBKeyBinding.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/XMBKeyBinding.cs
@@ -9,7 +9,7 @@ namespace AxibugEmuOnline.Client
         public override RomPlatformType Platform => RomPlatformType.Invalid;
         public override int ControllerCount => 2;
 
-        protected override void OnLoadDefaultKeyboardMapper(KeyBoard keyboard, BindingPage binding)
+        protected override void OnLoadKeyboardMapper(KeyBoard keyboard, BindingPage binding)
         {
             switch (binding.ControllerIndex)
             {
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs
index 45183e11..ad1a73f6 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs
@@ -8,53 +8,39 @@ namespace AxibugEmuOnline.Client.InputDevices
         InputResolver m_inputResolver = InputResolver.Create();
         Dictionary<string, InputDevice> m_devices = new Dictionary<string, InputDevice>();
 
+        public delegate void OnDeviceConnectedHandle(InputDevice connectDevice);
+        public event OnDeviceConnectedHandle OnDeviceConnected;
+        public delegate void OnDeviceLostHandle(InputDevice lostDevice);
+        public event OnDeviceLostHandle OnDeviceLost;
+
         public InputDevicesManager()
         {
-            m_inputResolver.OnDeviceConnected += OnDeviceConnected;
-            m_inputResolver.OnDeviceLost += OnDeviceLost;
+            m_inputResolver.OnDeviceConnected += Resolver_OnDeviceConnected;
+            m_inputResolver.OnDeviceLost += Resolver_OnDeviceLost;
             foreach (var device in m_inputResolver.GetDevices())
                 AddDevice(device);
         }
 
-        private void OnDeviceLost(InputDevice lostDevice)
+        private void Resolver_OnDeviceLost(InputDevice lostDevice)
         {
             RemoveDevice(lostDevice);
         }
 
-        private void OnDeviceConnected(InputDevice connectDevice)
+        private void Resolver_OnDeviceConnected(InputDevice connectDevice)
         {
             AddDevice(connectDevice);
         }
 
-        public void AddDevice(InputDevice device)
+        void AddDevice(InputDevice device)
         {
             m_devices[device.UniqueName] = device;
+            OnDeviceConnected?.Invoke(device);
         }
 
-        public void RemoveDevice(InputDevice device)
+        void RemoveDevice(InputDevice device)
         {
             m_devices.Remove(device.UniqueName);
-        }
-
-        public InputDevice.InputControl GetKeyByPath(string path)
-        {
-            var temp = path.Split("/");
-            Debug.Assert(temp.Length == 2, "Invalid Path Format");
-
-            var deviceName = temp[0];
-            var keyName = temp[1];
-
-            var targetDevice = FindDeviceByName(deviceName);
-            if (targetDevice == null) return null;
-
-            var key = targetDevice.FindControlByName(keyName);
-            return key;
-        }
-
-        public InputDevice FindDeviceByName(string deviceName)
-        {
-            m_devices.TryGetValue(deviceName, out var device);
-            return device;
+            OnDeviceLost?.Invoke(device);
         }
 
         /// <summary>

From a93f6449c807f3823dd9434809247e4a64b2d99c Mon Sep 17 00:00:00 2001
From: "ALIENJACK\\alien" <alienjack@foxmail.com>
Date: Mon, 17 Mar 2025 10:50:17 +0800
Subject: [PATCH 06/20] =?UTF-8?q?=E9=94=AE=E7=9B=98=E8=AE=BE=E5=A4=87?=
 =?UTF-8?q?=E9=94=AE=E5=80=BC=E5=AD=97=E6=AE=B5=E6=8E=A5=E5=8F=A3=E8=B0=83?=
 =?UTF-8?q?=E6=95=B4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../InputDevicesManager.cs                    |   5 +-
 .../Manager/InputDevicesManager/Keyboard.cs   | 249 +++++++++---------
 2 files changed, 122 insertions(+), 132 deletions(-)

diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs
index ad1a73f6..c0400f89 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs
@@ -135,9 +135,10 @@ namespace AxibugEmuOnline.Client.InputDevices
 
             /// <summary> 控件名,这个控件名称必须是唯一的 </summary>
             public abstract string ControlName { get; }
-            public string GetPath()
+
+            internal InputControl(InputDevice device)
             {
-                return $"{Device.UniqueName}/{ControlName}";
+                Device = device;
             }
         }
 
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Keyboard.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Keyboard.cs
index 01c0a84d..52870c9d 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Keyboard.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Keyboard.cs
@@ -9,23 +9,30 @@ namespace AxibugEmuOnline.Client.InputDevices
     /// </summary>
     public partial class KeyBoard : InputDevice
     {
+        Dictionary<KeyCode, KeyboardKey> m_keyControllerMap = new Dictionary<KeyCode, KeyboardKey>();
+
         public KeyBoard(InputResolver resolver) : base(resolver) { }
 
         protected override IEnumerable<InputControl> DefineControls()
         {
-            var keys = s_keyboardKeys.Select(kc => new KeyboardKey(kc) as InputControl);
+            var keys = s_keyboardKeys.Select(kc => new KeyboardKey(kc, this) as InputControl);
+            foreach (KeyboardKey key in keys)
+            {
+                m_keyControllerMap[key.m_keycode] = key;
+            }
             return keys;
         }
 
         public class KeyboardKey : InputControl
         {
-            KeyCode m_keycode;
+            internal KeyCode m_keycode;
 
             public override bool Start => Device.Resolver.GetKeyDown(Device as KeyBoard, m_keycode);
             public override bool Release => Device.Resolver.GetKeyUp(Device as KeyBoard, m_keycode);
             public override bool Performing => Device.Resolver.GetKey(Device as KeyBoard, m_keycode);
 
-            public KeyboardKey(KeyCode listenKey)
+            internal KeyboardKey(KeyCode listenKey, KeyBoard keyboard)
+                : base(keyboard)
             {
                 m_keycode = listenKey;
             }
@@ -90,133 +97,115 @@ namespace AxibugEmuOnline.Client.InputDevices
             KeyCode.Clear
         };
 
-        // 字母键 A-Z
-        public KeyboardKey A { get; private set; } = new KeyboardKey(KeyCode.A);
-        public KeyboardKey B { get; private set; } = new KeyboardKey(KeyCode.B);
-        public KeyboardKey C { get; private set; } = new KeyboardKey(KeyCode.C);
-        public KeyboardKey D { get; private set; } = new KeyboardKey(KeyCode.D);
-        public KeyboardKey E { get; private set; } = new KeyboardKey(KeyCode.E);
-        public KeyboardKey F { get; private set; } = new KeyboardKey(KeyCode.F);
-        public KeyboardKey G { get; private set; } = new KeyboardKey(KeyCode.G);
-        public KeyboardKey H { get; private set; } = new KeyboardKey(KeyCode.H);
-        public KeyboardKey I { get; private set; } = new KeyboardKey(KeyCode.I);
-        public KeyboardKey J { get; private set; } = new KeyboardKey(KeyCode.J);
-        public KeyboardKey K { get; private set; } = new KeyboardKey(KeyCode.K);
-        public KeyboardKey L { get; private set; } = new KeyboardKey(KeyCode.L);
-        public KeyboardKey M { get; private set; } = new KeyboardKey(KeyCode.M);
-        public KeyboardKey N { get; private set; } = new KeyboardKey(KeyCode.N);
-        public KeyboardKey O { get; private set; } = new KeyboardKey(KeyCode.O);
-        public KeyboardKey P { get; private set; } = new KeyboardKey(KeyCode.P);
-        public KeyboardKey Q { get; private set; } = new KeyboardKey(KeyCode.Q);
-        public KeyboardKey R { get; private set; } = new KeyboardKey(KeyCode.R);
-        public KeyboardKey S { get; private set; } = new KeyboardKey(KeyCode.S);
-        public KeyboardKey T { get; private set; } = new KeyboardKey(KeyCode.T);
-        public KeyboardKey U { get; private set; } = new KeyboardKey(KeyCode.U);
-        public KeyboardKey V { get; private set; } = new KeyboardKey(KeyCode.V);
-        public KeyboardKey W { get; private set; } = new KeyboardKey(KeyCode.W);
-        public KeyboardKey X { get; private set; } = new KeyboardKey(KeyCode.X);
-        public KeyboardKey Y { get; private set; } = new KeyboardKey(KeyCode.Y);
-        public KeyboardKey Z { get; private set; } = new KeyboardKey(KeyCode.Z);
-
-        // 数字键 0-9
-        public KeyboardKey Alpha0 { get; private set; } = new KeyboardKey(KeyCode.Alpha0);
-        public KeyboardKey Alpha1 { get; private set; } = new KeyboardKey(KeyCode.Alpha1);
-        public KeyboardKey Alpha2 { get; private set; } = new KeyboardKey(KeyCode.Alpha2);
-        public KeyboardKey Alpha3 { get; private set; } = new KeyboardKey(KeyCode.Alpha3);
-        public KeyboardKey Alpha4 { get; private set; } = new KeyboardKey(KeyCode.Alpha4);
-        public KeyboardKey Alpha5 { get; private set; } = new KeyboardKey(KeyCode.Alpha5);
-        public KeyboardKey Alpha6 { get; private set; } = new KeyboardKey(KeyCode.Alpha6);
-        public KeyboardKey Alpha7 { get; private set; } = new KeyboardKey(KeyCode.Alpha7);
-        public KeyboardKey Alpha8 { get; private set; } = new KeyboardKey(KeyCode.Alpha8);
-        public KeyboardKey Alpha9 { get; private set; } = new KeyboardKey(KeyCode.Alpha9);
-
-        // 功能键 F1-F15
-        public KeyboardKey F1 { get; private set; } = new KeyboardKey(KeyCode.F1);
-        public KeyboardKey F2 { get; private set; } = new KeyboardKey(KeyCode.F2);
-        public KeyboardKey F3 { get; private set; } = new KeyboardKey(KeyCode.F3);
-        public KeyboardKey F4 { get; private set; } = new KeyboardKey(KeyCode.F4);
-        public KeyboardKey F5 { get; private set; } = new KeyboardKey(KeyCode.F5);
-        public KeyboardKey F6 { get; private set; } = new KeyboardKey(KeyCode.F6);
-        public KeyboardKey F7 { get; private set; } = new KeyboardKey(KeyCode.F7);
-        public KeyboardKey F8 { get; private set; } = new KeyboardKey(KeyCode.F8);
-        public KeyboardKey F9 { get; private set; } = new KeyboardKey(KeyCode.F9);
-        public KeyboardKey F10 { get; private set; } = new KeyboardKey(KeyCode.F10);
-        public KeyboardKey F11 { get; private set; } = new KeyboardKey(KeyCode.F11);
-        public KeyboardKey F12 { get; private set; } = new KeyboardKey(KeyCode.F12);
-        public KeyboardKey F13 { get; private set; } = new KeyboardKey(KeyCode.F13);
-        public KeyboardKey F14 { get; private set; } = new KeyboardKey(KeyCode.F14);
-        public KeyboardKey F15 { get; private set; } = new KeyboardKey(KeyCode.F15);
-
-        // 方向键
-        public KeyboardKey UpArrow { get; private set; } = new KeyboardKey(KeyCode.UpArrow);
-        public KeyboardKey DownArrow { get; private set; } = new KeyboardKey(KeyCode.DownArrow);
-        public KeyboardKey LeftArrow { get; private set; } = new KeyboardKey(KeyCode.LeftArrow);
-        public KeyboardKey RightArrow { get; private set; } = new KeyboardKey(KeyCode.RightArrow);
-
-        // 控制键
-        public KeyboardKey Space { get; private set; } = new KeyboardKey(KeyCode.Space);
-        public KeyboardKey Return { get; private set; } = new KeyboardKey(KeyCode.Return);
-        public KeyboardKey Escape { get; private set; } = new KeyboardKey(KeyCode.Escape);
-        public KeyboardKey Tab { get; private set; } = new KeyboardKey(KeyCode.Tab);
-        /// <summary>
-        /// <img src="./test.png" alt="test"/>
-        /// </summary>
-        public KeyboardKey Backspace { get; private set; } = new KeyboardKey(KeyCode.Backspace);
-        public KeyboardKey CapsLock { get; private set; } = new KeyboardKey(KeyCode.CapsLock);
-        public KeyboardKey LeftShift { get; private set; } = new KeyboardKey(KeyCode.LeftShift);
-        public KeyboardKey RightShift { get; private set; } = new KeyboardKey(KeyCode.RightShift);
-        public KeyboardKey LeftControl { get; private set; } = new KeyboardKey(KeyCode.LeftControl);
-        public KeyboardKey RightControl { get; private set; } = new KeyboardKey(KeyCode.RightControl);
-        public KeyboardKey LeftAlt { get; private set; } = new KeyboardKey(KeyCode.LeftAlt);
-        public KeyboardKey RightAlt { get; private set; } = new KeyboardKey(KeyCode.RightAlt);
-        public KeyboardKey LeftCommand { get; private set; } = new KeyboardKey(KeyCode.LeftCommand);
-        public KeyboardKey RightCommand { get; private set; } = new KeyboardKey(KeyCode.RightCommand);
-        public KeyboardKey Menu { get; private set; } = new KeyboardKey(KeyCode.Menu);
-
-        // 符号键
-        public KeyboardKey Comma { get; private set; } = new KeyboardKey(KeyCode.Comma);
-        public KeyboardKey Period { get; private set; } = new KeyboardKey(KeyCode.Period);
-        public KeyboardKey Slash { get; private set; } = new KeyboardKey(KeyCode.Slash);
-        public KeyboardKey BackQuote { get; private set; } = new KeyboardKey(KeyCode.BackQuote);
-        public KeyboardKey Quote { get; private set; } = new KeyboardKey(KeyCode.Quote);
-        public KeyboardKey Semicolon { get; private set; } = new KeyboardKey(KeyCode.Semicolon);
-        public KeyboardKey LeftBracket { get; private set; } = new KeyboardKey(KeyCode.LeftBracket);
-        public KeyboardKey RightBracket { get; private set; } = new KeyboardKey(KeyCode.RightBracket);
-        public KeyboardKey Backslash { get; private set; } = new KeyboardKey(KeyCode.Backslash);
-        public KeyboardKey Minus { get; private set; } = new KeyboardKey(KeyCode.Minus);
-        public KeyboardKey Equals_k { get; private set; } = new KeyboardKey(KeyCode.Equals);
-        public KeyboardKey Tilde { get; private set; } = new KeyboardKey(KeyCode.Tilde);
-
-        // 小键盘
-        public KeyboardKey Keypad0 { get; private set; } = new KeyboardKey(KeyCode.Keypad0);
-        public KeyboardKey Keypad1 { get; private set; } = new KeyboardKey(KeyCode.Keypad1);
-        public KeyboardKey Keypad2 { get; private set; } = new KeyboardKey(KeyCode.Keypad2);
-        public KeyboardKey Keypad3 { get; private set; } = new KeyboardKey(KeyCode.Keypad3);
-        public KeyboardKey Keypad4 { get; private set; } = new KeyboardKey(KeyCode.Keypad4);
-        public KeyboardKey Keypad5 { get; private set; } = new KeyboardKey(KeyCode.Keypad5);
-        public KeyboardKey Keypad6 { get; private set; } = new KeyboardKey(KeyCode.Keypad6);
-        public KeyboardKey Keypad7 { get; private set; } = new KeyboardKey(KeyCode.Keypad7);
-        public KeyboardKey Keypad8 { get; private set; } = new KeyboardKey(KeyCode.Keypad8);
-        public KeyboardKey Keypad9 { get; private set; } = new KeyboardKey(KeyCode.Keypad9);
-        public KeyboardKey KeypadPeriod { get; private set; } = new KeyboardKey(KeyCode.KeypadPeriod);
-        public KeyboardKey KeypadDivide { get; private set; } = new KeyboardKey(KeyCode.KeypadDivide);
-        public KeyboardKey KeypadMultiply { get; private set; } = new KeyboardKey(KeyCode.KeypadMultiply);
-        public KeyboardKey KeypadMinus { get; private set; } = new KeyboardKey(KeyCode.KeypadMinus);
-        public KeyboardKey KeypadPlus { get; private set; } = new KeyboardKey(KeyCode.KeypadPlus);
-        public KeyboardKey KeypadEnter { get; private set; } = new KeyboardKey(KeyCode.KeypadEnter);
-        public KeyboardKey Numlock { get; private set; } = new KeyboardKey(KeyCode.Numlock);
-
-        // 其他标准键
-        public KeyboardKey Print { get; private set; } = new KeyboardKey(KeyCode.Print);
-        public KeyboardKey Insert { get; private set; } = new KeyboardKey(KeyCode.Insert);
-        public KeyboardKey Delete { get; private set; } = new KeyboardKey(KeyCode.Delete);
-        public KeyboardKey Home { get; private set; } = new KeyboardKey(KeyCode.Home);
-        public KeyboardKey End { get; private set; } = new KeyboardKey(KeyCode.End);
-        public KeyboardKey PageUp { get; private set; } = new KeyboardKey(KeyCode.PageUp);
-        public KeyboardKey PageDown { get; private set; } = new KeyboardKey(KeyCode.PageDown);
-        public KeyboardKey Pause { get; private set; } = new KeyboardKey(KeyCode.Pause);
-        public KeyboardKey ScrollLock { get; private set; } = new KeyboardKey(KeyCode.ScrollLock);
-        public KeyboardKey Clear { get; private set; } = new KeyboardKey(KeyCode.Clear);
+        public KeyboardKey A => m_keyControllerMap[KeyCode.A];
+        public KeyboardKey B => m_keyControllerMap[KeyCode.B];
+        public KeyboardKey C => m_keyControllerMap[KeyCode.C];
+        public KeyboardKey D => m_keyControllerMap[KeyCode.D];
+        public KeyboardKey E => m_keyControllerMap[KeyCode.E];
+        public KeyboardKey F => m_keyControllerMap[KeyCode.F];
+        public KeyboardKey G => m_keyControllerMap[KeyCode.G];
+        public KeyboardKey H => m_keyControllerMap[KeyCode.H];
+        public KeyboardKey I => m_keyControllerMap[KeyCode.I];
+        public KeyboardKey J => m_keyControllerMap[KeyCode.J];
+        public KeyboardKey K => m_keyControllerMap[KeyCode.K];
+        public KeyboardKey L => m_keyControllerMap[KeyCode.L];
+        public KeyboardKey M => m_keyControllerMap[KeyCode.M];
+        public KeyboardKey N => m_keyControllerMap[KeyCode.N];
+        public KeyboardKey O => m_keyControllerMap[KeyCode.O];
+        public KeyboardKey P => m_keyControllerMap[KeyCode.P];
+        public KeyboardKey Q => m_keyControllerMap[KeyCode.Q];
+        public KeyboardKey R => m_keyControllerMap[KeyCode.R];
+        public KeyboardKey S => m_keyControllerMap[KeyCode.S];
+        public KeyboardKey T => m_keyControllerMap[KeyCode.T];
+        public KeyboardKey U => m_keyControllerMap[KeyCode.U];
+        public KeyboardKey V => m_keyControllerMap[KeyCode.V];
+        public KeyboardKey W => m_keyControllerMap[KeyCode.W];
+        public KeyboardKey X => m_keyControllerMap[KeyCode.X];
+        public KeyboardKey Y => m_keyControllerMap[KeyCode.Y];
+        public KeyboardKey Z => m_keyControllerMap[KeyCode.Z];
+        public KeyboardKey Alpha0 => m_keyControllerMap[KeyCode.Alpha0];
+        public KeyboardKey Alpha1 => m_keyControllerMap[KeyCode.Alpha1];
+        public KeyboardKey Alpha2 => m_keyControllerMap[KeyCode.Alpha2];
+        public KeyboardKey Alpha3 => m_keyControllerMap[KeyCode.Alpha3];
+        public KeyboardKey Alpha4 => m_keyControllerMap[KeyCode.Alpha4];
+        public KeyboardKey Alpha5 => m_keyControllerMap[KeyCode.Alpha5];
+        public KeyboardKey Alpha6 => m_keyControllerMap[KeyCode.Alpha6];
+        public KeyboardKey Alpha7 => m_keyControllerMap[KeyCode.Alpha7];
+        public KeyboardKey Alpha8 => m_keyControllerMap[KeyCode.Alpha8];
+        public KeyboardKey Alpha9 => m_keyControllerMap[KeyCode.Alpha9];
+        public KeyboardKey F1 => m_keyControllerMap[KeyCode.F1];
+        public KeyboardKey F2 => m_keyControllerMap[KeyCode.F2];
+        public KeyboardKey F3 => m_keyControllerMap[KeyCode.F3];
+        public KeyboardKey F4 => m_keyControllerMap[KeyCode.F4];
+        public KeyboardKey F5 => m_keyControllerMap[KeyCode.F5];
+        public KeyboardKey F6 => m_keyControllerMap[KeyCode.F6];
+        public KeyboardKey F7 => m_keyControllerMap[KeyCode.F7];
+        public KeyboardKey F8 => m_keyControllerMap[KeyCode.F8];
+        public KeyboardKey F9 => m_keyControllerMap[KeyCode.F9];
+        public KeyboardKey F10 => m_keyControllerMap[KeyCode.F10];
+        public KeyboardKey F11 => m_keyControllerMap[KeyCode.F11];
+        public KeyboardKey F12 => m_keyControllerMap[KeyCode.F12];
+        public KeyboardKey F13 => m_keyControllerMap[KeyCode.F13];
+        public KeyboardKey F14 => m_keyControllerMap[KeyCode.F14];
+        public KeyboardKey F15 => m_keyControllerMap[KeyCode.F15];
+        public KeyboardKey UpArrow => m_keyControllerMap[KeyCode.UpArrow];
+        public KeyboardKey DownArrow => m_keyControllerMap[KeyCode.DownArrow];
+        public KeyboardKey LeftArrow => m_keyControllerMap[KeyCode.LeftArrow];
+        public KeyboardKey RightArrow => m_keyControllerMap[KeyCode.RightArrow];
+        public KeyboardKey Space => m_keyControllerMap[KeyCode.Space];
+        public KeyboardKey Return => m_keyControllerMap[KeyCode.Return];
+        public KeyboardKey Escape => m_keyControllerMap[KeyCode.Escape];
+        public KeyboardKey Tab => m_keyControllerMap[KeyCode.Tab];
+        public KeyboardKey Backspace => m_keyControllerMap[KeyCode.Backspace];
+        public KeyboardKey CapsLock => m_keyControllerMap[KeyCode.CapsLock];
+        public KeyboardKey LeftShift => m_keyControllerMap[KeyCode.LeftShift];
+        public KeyboardKey RightShift => m_keyControllerMap[KeyCode.RightShift];
+        public KeyboardKey LeftControl => m_keyControllerMap[KeyCode.LeftControl];
+        public KeyboardKey RightControl => m_keyControllerMap[KeyCode.RightControl];
+        public KeyboardKey LeftAlt => m_keyControllerMap[KeyCode.LeftAlt];
+        public KeyboardKey RightAlt => m_keyControllerMap[KeyCode.RightAlt];
+        public KeyboardKey LeftCommand => m_keyControllerMap[KeyCode.LeftCommand];
+        public KeyboardKey RightCommand => m_keyControllerMap[KeyCode.RightCommand];
+        public KeyboardKey Menu => m_keyControllerMap[KeyCode.Menu];
+        public KeyboardKey Comma => m_keyControllerMap[KeyCode.Comma];
+        public KeyboardKey Period => m_keyControllerMap[KeyCode.Period];
+        public KeyboardKey Slash => m_keyControllerMap[KeyCode.Slash];
+        public KeyboardKey BackQuote => m_keyControllerMap[KeyCode.BackQuote];
+        public KeyboardKey Quote => m_keyControllerMap[KeyCode.Quote];
+        public KeyboardKey Semicolon => m_keyControllerMap[KeyCode.Semicolon];
+        public KeyboardKey LeftBracket => m_keyControllerMap[KeyCode.LeftBracket];
+        public KeyboardKey RightBracket => m_keyControllerMap[KeyCode.RightBracket];
+        public KeyboardKey Backslash => m_keyControllerMap[KeyCode.Backslash];
+        public KeyboardKey Minus => m_keyControllerMap[KeyCode.Minus];
+        public KeyboardKey Equals_k => m_keyControllerMap[KeyCode.Equals];
+        public KeyboardKey Tilde => m_keyControllerMap[KeyCode.Tilde];
+        public KeyboardKey Keypad0 => m_keyControllerMap[KeyCode.Keypad0];
+        public KeyboardKey Keypad1 => m_keyControllerMap[KeyCode.Keypad1];
+        public KeyboardKey Keypad2 => m_keyControllerMap[KeyCode.Keypad2];
+        public KeyboardKey Keypad3 => m_keyControllerMap[KeyCode.Keypad3];
+        public KeyboardKey Keypad4 => m_keyControllerMap[KeyCode.Keypad4];
+        public KeyboardKey Keypad5 => m_keyControllerMap[KeyCode.Keypad5];
+        public KeyboardKey Keypad6 => m_keyControllerMap[KeyCode.Keypad6];
+        public KeyboardKey Keypad7 => m_keyControllerMap[KeyCode.Keypad7];
+        public KeyboardKey Keypad8 => m_keyControllerMap[KeyCode.Keypad8];
+        public KeyboardKey Keypad9 => m_keyControllerMap[KeyCode.Keypad9];
+        public KeyboardKey KeypadPeriod => m_keyControllerMap[KeyCode.KeypadPeriod];
+        public KeyboardKey KeypadDivide => m_keyControllerMap[KeyCode.KeypadDivide];
+        public KeyboardKey KeypadMultiply => m_keyControllerMap[KeyCode.KeypadMultiply];
+        public KeyboardKey KeypadMinus => m_keyControllerMap[KeyCode.KeypadMinus];
+        public KeyboardKey KeypadPlus => m_keyControllerMap[KeyCode.KeypadPlus];
+        public KeyboardKey KeypadEnter => m_keyControllerMap[KeyCode.KeypadEnter];
+        public KeyboardKey Numlock => m_keyControllerMap[KeyCode.Numlock];
+        public KeyboardKey Print => m_keyControllerMap[KeyCode.Print];
+        public KeyboardKey Insert => m_keyControllerMap[KeyCode.Insert];
+        public KeyboardKey Delete => m_keyControllerMap[KeyCode.Delete];
+        public KeyboardKey Home => m_keyControllerMap[KeyCode.Home];
+        public KeyboardKey End => m_keyControllerMap[KeyCode.End];
+        public KeyboardKey PageUp => m_keyControllerMap[KeyCode.PageUp];
+        public KeyboardKey PageDown => m_keyControllerMap[KeyCode.PageDown];
+        public KeyboardKey Pause => m_keyControllerMap[KeyCode.Pause];
+        public KeyboardKey ScrollLock => m_keyControllerMap[KeyCode.ScrollLock];
+        public KeyboardKey Clear => m_keyControllerMap[KeyCode.Clear];
     }
     #endregion
 }
\ No newline at end of file

From 811b0b2a48fb3c379c541c94773b5454324c8568 Mon Sep 17 00:00:00 2001
From: "ALIENJACK\\alien" <alienjack@foxmail.com>
Date: Mon, 17 Mar 2025 19:50:41 +0800
Subject: [PATCH 07/20] =?UTF-8?q?InputManager=E8=BF=AD=E4=BB=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../Assets/Script/AppMain/App.cs              |   8 +-
 .../ColecoVisionMultiKeysSetting.cs           |   1 +
 .../GameBoyColorMultiKeysSetting.cs           |   1 +
 .../GameBoyMultiKeysSetting.cs                |   1 +
 .../GameGearMultiKeysSetting.cs               |   1 +
 .../MasterSystemMultiKeysSetting.cs           |  16 +-
 .../SC3000MultiKeysSetting.cs                 |   1 +
 .../SG1000MultiKeysSetting.cs                 |   1 +
 .../UMAMEMultiKeysSetting.cs                  |  16 +-
 .../UEssgeeInterface/UEGKeyboard.cs           |  83 +++------
 .../MameEmulator/UniInterface/UniKeyboard.cs  |  95 +++++-----
 .../NesEmulator/NesControllerMapper.cs        |   1 +
 .../Script/AppMain/Event/EventInvoker.cs      |   2 +
 .../Manager/AppSettings/AppSettings.cs        |   4 +-
 .../Manager/AppSettings/BgColorSettings.cs    |   2 +-
 .../AppSettings/Filter/FilterManager.cs       |   2 +-
 .../KeyMapperSetting/EssgeeKeyBinding.cs      | 163 +++++++++++++++++
 .../KeyMapperSetting/EssgeeKeyBinding.cs.meta |   2 +
 .../KeyMapperSetting/KeyMapperSetting.cs      | 111 ++++++++----
 .../KeyMapperSetting/MAMEKeyBinding.cs        |  89 ++++++++++
 .../KeyMapperSetting/MAMEKeyBinding.cs.meta   |   2 +
 .../KeyMapperSetting/NesKeyBinding.cs         |  54 +++---
 .../KeyMapperSetting/XMBKeyBinding.cs         |  58 +++---
 .../Manager/AppSettings/ScreenScaler.cs       |   2 +-
 .../Manager/InputDevicesManager/Devices.meta  |   8 +
 .../{ => Devices}/Keyboard.cs                 |  17 +-
 .../{ => Devices}/Keyboard.cs.meta            |   0
 .../Devices/PSVController.cs                  | 167 ++++++++++++++++++
 .../Devices/PSVController.cs.meta             |   2 +
 .../InputDevicesManager.cs                    |  41 ++++-
 .../InputResolver/InputResolver.cs            |  19 +-
 .../InputResolver/InputSystemResolver.cs      |  28 ---
 .../InputResolver/PSVResolver.cs              |  39 ++++
 .../InputResolver/PSVResolver.cs.meta         |   2 +
 .../BgSettingsUI/ScreenScalerListMenuItem.cs  |   1 +
 .../UI/BgSettingsUI/SettingItemSelector.cs    |   1 +
 .../UI/BgSettingsUI/UI_BgSettingItem_Color.cs |   1 +
 .../AppMain/UI/BgSettingsUI/UI_FilterItem.cs  |   2 +-
 .../UI/BgSettingsUI/UI_ScalerModeItem.cs      |   1 +
 .../UI/InGameUI/InGameUI_FilterSetting.cs     |   2 +-
 .../AppMain/UI/InGameUI/InGameUI_Scaler.cs    |   2 +-
 .../Assets/Script/AppMain/UI/XMBBgChanger.cs  |   3 +-
 .../Script/AppMain/UI/XMBOptionBgChanger.cs   |   3 +-
 .../ProjectSettings/InputManager.asset        |  65 +++++++
 44 files changed, 825 insertions(+), 295 deletions(-)
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/EssgeeKeyBinding.cs
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/EssgeeKeyBinding.cs.meta
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/MAMEKeyBinding.cs
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/MAMEKeyBinding.cs.meta
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices.meta
 rename AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/{ => Devices}/Keyboard.cs (91%)
 rename AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/{ => Devices}/Keyboard.cs.meta (100%)
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/PSVController.cs
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/PSVController.cs.meta
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/PSVResolver.cs
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/PSVResolver.cs.meta

diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/App.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/App.cs
index 11171e22..3b036644 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/App.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/App.cs
@@ -23,8 +23,7 @@ namespace AxibugEmuOnline.Client.ClientCore
         public static AppLogin login;
         public static AppChat chat;
         public static UserDataManager user;
-        public static AppInput input;
-        public static InputDevicesManager inputDevicesMgr;
+        public static InputDevicesManager input;
         public static AppEmu emu;
         public static HttpAPI httpAPI;
         public static CacheManager CacheMgr;
@@ -78,8 +77,7 @@ namespace AxibugEmuOnline.Client.ClientCore
             //其他平台必要的初始化
             if (UnityEngine.Application.platform == RuntimePlatform.PSP2) PSP2Init();
 
-            input = new AppInput();
-            inputDevicesMgr = new InputDevicesManager();
+            input = new InputDevicesManager();
             FileDownloader = new FileDownloader();
             settings = new AppSettings();
             network = new NetworkHelper();
@@ -232,7 +230,7 @@ namespace AxibugEmuOnline.Client.ClientCore
             foreach (var romLib in s_romLibs.Values) romLib.ExecuteFetchRomInfo();
             starRomLib.ExecuteFetchRomInfo();
             FileDownloader.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
index 543b83c0..29ad615b 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/ColecoVisionMultiKeysSetting.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/ColecoVisionMultiKeysSetting.cs
@@ -1,4 +1,5 @@
 using AxibugEmuOnline.Client.Manager;
+using AxibugEmuOnline.Client.Settings;
 using UnityEngine;
 
 namespace AxiInputSP.Setting
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GameBoyColorMultiKeysSetting.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GameBoyColorMultiKeysSetting.cs
index 052302ff..71c4b648 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GameBoyColorMultiKeysSetting.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GameBoyColorMultiKeysSetting.cs
@@ -1,4 +1,5 @@
 using AxibugEmuOnline.Client.Manager;
+using AxibugEmuOnline.Client.Settings;
 using UnityEngine;
 
 namespace AxiInputSP.Setting
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GameBoyMultiKeysSetting.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GameBoyMultiKeysSetting.cs
index 8ee49ca6..74c553f8 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GameBoyMultiKeysSetting.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GameBoyMultiKeysSetting.cs
@@ -1,4 +1,5 @@
 using AxibugEmuOnline.Client.Manager;
+using AxibugEmuOnline.Client.Settings;
 using UnityEngine;
 
 namespace AxiInputSP.Setting
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GameGearMultiKeysSetting.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GameGearMultiKeysSetting.cs
index 78da1487..52a7c89f 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GameGearMultiKeysSetting.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GameGearMultiKeysSetting.cs
@@ -1,4 +1,5 @@
 using AxibugEmuOnline.Client.Manager;
+using AxibugEmuOnline.Client.Settings;
 using UnityEngine;
 
 namespace AxiInputSP.Setting
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/MasterSystemMultiKeysSetting.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/MasterSystemMultiKeysSetting.cs
index 0faaf89a..2c54db97 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/MasterSystemMultiKeysSetting.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/MasterSystemMultiKeysSetting.cs
@@ -1,24 +1,10 @@
 using AxibugEmuOnline.Client.Manager;
+using AxibugEmuOnline.Client.Settings;
 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
     {
 
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/SC3000MultiKeysSetting.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/SC3000MultiKeysSetting.cs
index b4a2881f..d305c562 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/SC3000MultiKeysSetting.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/SC3000MultiKeysSetting.cs
@@ -1,4 +1,5 @@
 using AxibugEmuOnline.Client.Manager;
+using AxibugEmuOnline.Client.Settings;
 using UnityEngine;
 
 namespace AxiInputSP.Setting
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/SG1000MultiKeysSetting.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/SG1000MultiKeysSetting.cs
index 59aba56c..316248d0 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/SG1000MultiKeysSetting.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/SG1000MultiKeysSetting.cs
@@ -1,4 +1,5 @@
 using AxibugEmuOnline.Client.Manager;
+using AxibugEmuOnline.Client.Settings;
 using UnityEngine;
 
 namespace AxiInputSP.Setting
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/UMAMEMultiKeysSetting.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/UMAMEMultiKeysSetting.cs
index 9264b374..4f35c774 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/UMAMEMultiKeysSetting.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/UMAMEMultiKeysSetting.cs
@@ -1,23 +1,9 @@
 using AxibugEmuOnline.Client.Manager;
+using AxibugEmuOnline.Client.Settings;
 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()
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..a8102448 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/EssgeeEmulator/UEssgeeInterface/UEGKeyboard.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/EssgeeEmulator/UEssgeeInterface/UEGKeyboard.cs
@@ -1,7 +1,8 @@
-using AxibugEmuOnline.Client;
+using AxibugEmuOnline.Client;
 using AxibugEmuOnline.Client.ClientCore;
 using AxibugEmuOnline.Client.Event;
 using AxibugEmuOnline.Client.Manager;
+using AxibugEmuOnline.Client.Settings;
 using AxiInputSP.Setting;
 using AxiReplay;
 using System;
@@ -318,7 +319,7 @@ public class UEGKeyboard : MonoBehaviour
 
     public bool SampleInput()
     {
-        //Netģʽ
+        //Net模式
         if (InGameUI.Instance.IsNetPlay)
         {
             bool bHadNetData = false;
@@ -334,18 +335,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 +551,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 +562,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 +579,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 +593,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 +615,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..c16a915a 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/MameEmulator/UniInterface/UniKeyboard.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/MameEmulator/UniInterface/UniKeyboard.cs
@@ -1,6 +1,7 @@
-using AxibugEmuOnline.Client;
+using AxibugEmuOnline.Client;
 using AxibugEmuOnline.Client.ClientCore;
 using AxibugEmuOnline.Client.Event;
+using AxibugEmuOnline.Client.Settings;
 using AxiInputSP.Setting;
 using AxiReplay;
 using MAME.Core;
@@ -25,9 +26,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 +83,7 @@ public class UniKeyboard : MonoBehaviour, IKeyboard
 
         public bool SampleInput()
         {
-            //Netģʽ
+            //Net模式
             if (InGameUI.Instance.IsNetPlay)
             {
                 bool bHadNetData = false;
@@ -98,15 +99,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 +136,7 @@ public class UniKeyboard : MonoBehaviour, IKeyboard
 #endif
 
             CurrLocalInpuAllData = tempLocalInputAllData;
-            //�replay
+            //写入replay
             UMAME.instance.mReplayWriter.NextFramebyFrameIdx((int)UMAME.instance.mUniVideoPlayer.mFrame, CurrLocalInpuAllData);
 
             CheckPlayerSlotChanged();
@@ -146,16 +147,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 +173,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 +266,7 @@ public class MameControllerMapper : IControllerSetuper
 }
 
 /// <summary>
-/// MAME������
+/// MAME控制器
 /// </summary>
 public class MameSingleConoller : IController
 {
@@ -277,15 +278,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 +296,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 +339,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 +372,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 +461,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 d64d8c14..5996a724 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/NesEmulator/NesControllerMapper.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/NesEmulator/NesControllerMapper.cs
@@ -1,6 +1,7 @@
 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;
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/Manager/AppSettings/AppSettings.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/AppSettings.cs
index 248a3c05..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
     {
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/Manager/AppSettings/KeyMapperSetting/EssgeeKeyBinding.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/EssgeeKeyBinding.cs
new file mode 100644
index 00000000..a32ebb71
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/EssgeeKeyBinding.cs
@@ -0,0 +1,163 @@
+using AxibugEmuOnline.Client.InputDevices;
+using AxibugProtobuf;
+using AxiInputSP;
+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 : EmuCoreControllerKeyBinding<EssgeeSingleKey>
+    {
+        protected override void OnRegistDevices(InputDevice device, BindingPage binding)
+        {
+            if (device is KeyBoard keyboard)
+            {
+                switch (binding.ControllerIndex)
+                {
+                    case 0:
+                        binding.SetBinding(EssgeeSingleKey.OPTION_1, keyboard.Return, 0);
+                        binding.SetBinding(EssgeeSingleKey.OPTION_2, keyboard.RightShift, 0);
+                        binding.SetBinding(EssgeeSingleKey.UP, keyboard.W, 0);
+                        binding.SetBinding(EssgeeSingleKey.DOWN, keyboard.S, 0);
+                        binding.SetBinding(EssgeeSingleKey.LEFT, keyboard.A, 0);
+                        binding.SetBinding(EssgeeSingleKey.RIGHT, keyboard.D, 0);
+                        binding.SetBinding(EssgeeSingleKey.BTN_1, keyboard.J, 0);
+                        binding.SetBinding(EssgeeSingleKey.BTN_2, keyboard.K, 0);
+                        binding.SetBinding(EssgeeSingleKey.BTN_3, keyboard.U, 0);
+                        binding.SetBinding(EssgeeSingleKey.BTN_4, keyboard.I, 0);
+                        break;
+                    case 1:
+                        binding.SetBinding(EssgeeSingleKey.OPTION_1, keyboard.Keypad0, 0);
+                        binding.SetBinding(EssgeeSingleKey.OPTION_2, keyboard.Delete, 0);
+                        binding.SetBinding(EssgeeSingleKey.UP, keyboard.UpArrow, 0);
+                        binding.SetBinding(EssgeeSingleKey.DOWN, keyboard.DownArrow, 0);
+                        binding.SetBinding(EssgeeSingleKey.LEFT, keyboard.LeftArrow, 0);
+                        binding.SetBinding(EssgeeSingleKey.RIGHT, keyboard.RightArrow, 0);
+                        binding.SetBinding(EssgeeSingleKey.BTN_1, keyboard.Keypad1, 0);
+                        binding.SetBinding(EssgeeSingleKey.BTN_2, keyboard.Keypad2, 0);
+                        binding.SetBinding(EssgeeSingleKey.BTN_3, keyboard.Keypad3, 0);
+                        binding.SetBinding(EssgeeSingleKey.BTN_4, keyboard.Keypad4, 0);
+                        break;
+                }
+            }
+            else if (device is PSVController psvCon && binding.ControllerIndex == 0)
+            {
+                binding.SetBinding(EssgeeSingleKey.OPTION_1, psvCon.Start, 0);
+                binding.SetBinding(EssgeeSingleKey.OPTION_2, psvCon.Select, 0);
+                binding.SetBinding(EssgeeSingleKey.UP, psvCon.Up, 0);
+                binding.SetBinding(EssgeeSingleKey.DOWN, psvCon.Down, 0);
+                binding.SetBinding(EssgeeSingleKey.LEFT, psvCon.Left, 0);
+                binding.SetBinding(EssgeeSingleKey.RIGHT, psvCon.Right, 0);
+                binding.SetBinding(EssgeeSingleKey.BTN_1, psvCon.Cross, 0);
+                binding.SetBinding(EssgeeSingleKey.BTN_2, psvCon.Circle, 0);
+                binding.SetBinding(EssgeeSingleKey.BTN_3, psvCon.Square, 0);
+                binding.SetBinding(EssgeeSingleKey.BTN_4, psvCon.Triangle, 0);
+                //PSV 摇杆
+                binding.SetBinding(EssgeeSingleKey.UP, psvCon.LeftStick.UP, 1);
+                binding.SetBinding(EssgeeSingleKey.DOWN, psvCon.LeftStick.Down, 1);
+                binding.SetBinding(EssgeeSingleKey.LEFT, psvCon.LeftStick.Left, 1);
+                binding.SetBinding(EssgeeSingleKey.RIGHT, psvCon.LeftStick.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;
+
+        protected override void OnRegistDevices(InputDevice device, BindingPage binding)
+        {
+            if (device is KeyBoard keyboard)
+            {
+                switch (binding.ControllerIndex)
+                {
+                    case 0:
+                        binding.SetBinding(EssgeeSingleKey.OPTION_1, keyboard.Return, 0);
+                        binding.SetBinding(EssgeeSingleKey.OPTION_2, keyboard.RightShift, 0);
+                        binding.SetBinding(EssgeeSingleKey.UP, keyboard.W, 0);
+                        binding.SetBinding(EssgeeSingleKey.DOWN, keyboard.S, 0);
+                        binding.SetBinding(EssgeeSingleKey.LEFT, keyboard.A, 0);
+                        binding.SetBinding(EssgeeSingleKey.RIGHT, keyboard.D, 0);
+                        binding.SetBinding(EssgeeSingleKey.BTN_1, keyboard.J, 0);
+                        binding.SetBinding(EssgeeSingleKey.BTN_2, keyboard.K, 0);
+                        binding.SetBinding(EssgeeSingleKey.BTN_3, keyboard.U, 0);
+                        binding.SetBinding(EssgeeSingleKey.BTN_4, keyboard.I, 0);
+                        break;
+                }
+            }
+        }
+    }
+    public class GameBoyKeyBinding : EssgeeKeyBinding
+    {
+        public override RomPlatformType Platform => RomPlatformType.GameBoy;
+        public override int ControllerCount => 1;
+
+        protected override void OnRegistDevices(InputDevice device, BindingPage binding)
+        {
+            if (device is KeyBoard keyboard)
+            {
+                switch (binding.ControllerIndex)
+                {
+                    case 0:
+                        binding.SetBinding(EssgeeSingleKey.OPTION_1, keyboard.Return, 0);
+                        binding.SetBinding(EssgeeSingleKey.OPTION_2, keyboard.RightShift, 0);
+                        binding.SetBinding(EssgeeSingleKey.UP, keyboard.W, 0);
+                        binding.SetBinding(EssgeeSingleKey.DOWN, keyboard.S, 0);
+                        binding.SetBinding(EssgeeSingleKey.LEFT, keyboard.A, 0);
+                        binding.SetBinding(EssgeeSingleKey.RIGHT, keyboard.D, 0);
+                        binding.SetBinding(EssgeeSingleKey.BTN_1, keyboard.J, 0);
+                        binding.SetBinding(EssgeeSingleKey.BTN_2, keyboard.K, 0);
+                        binding.SetBinding(EssgeeSingleKey.BTN_3, keyboard.U, 0);
+                        binding.SetBinding(EssgeeSingleKey.BTN_4, keyboard.I, 0);
+                        break;
+                }
+            }
+        }
+    }
+
+    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
index c6d6a001..10252195 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs
@@ -6,7 +6,7 @@ using System.Collections.Generic;
 using System.Linq;
 using UnityEngine;
 
-namespace AxibugEmuOnline.Client
+namespace AxibugEmuOnline.Client.Settings
 {
     /// <summary>
     /// 管理键位映射设置
@@ -34,6 +34,12 @@ namespace AxibugEmuOnline.Client
             m_bindersByType.TryGetValue(typeof(T), out var binder);
             return binder as T;
         }
+
+        public T GetBinder<T>(RomPlatformType romType) where T : EmuCoreControllerKeyBinding
+        {
+            m_binders.TryGetValue(romType, out var binder);
+            return binder as T;
+        }
     }
 
     /// <summary>
@@ -55,7 +61,6 @@ namespace AxibugEmuOnline.Client
         where T : Enum
     {
         List<BindingPage> m_bindingPages = new List<BindingPage>();
-        KeyBoard m_currentKeyboard;
 
         public EmuCoreControllerKeyBinding()
         {
@@ -63,30 +68,56 @@ namespace AxibugEmuOnline.Client
             {
                 m_bindingPages.Add(new BindingPage(i, this));
             }
-            m_currentKeyboard = App.inputDevicesMgr.GetKeyboard();
 
-            if (m_currentKeyboard != null)
-                LoadKeyboardMapper();
+            var keyboard = App.input.GetDevice<KeyBoard>();
+            if (keyboard != null)
+            {
+                foreach (var binding in m_bindingPages)
+                {
+                    binding.RegistInputDevice(keyboard);
+                }
+            }
 
-            App.inputDevicesMgr.OnDeviceLost += InputDevicesMgr_OnDeviceLost;
-            App.inputDevicesMgr.OnDeviceConnected += InputDevicesMgr_OnDeviceConnected;
+            var psvController = App.input.GetDevice<PSVController>();
+            if (psvController != null)
+            {
+                foreach (var binding in m_bindingPages)
+                {
+                    binding.RegistInputDevice(psvController);
+                }
+            }
+
+            App.input.OnDeviceLost += InputDevicesMgr_OnDeviceLost;
+            App.input.OnDeviceConnected += InputDevicesMgr_OnDeviceConnected;
         }
 
         private void InputDevicesMgr_OnDeviceConnected(InputDevice connectDevice)
         {
-            if (m_currentKeyboard == null && connectDevice is KeyBoard) //未建立键盘按键映射设置时,并且有新的键盘连接时,建立键盘映射设置
+            if (connectDevice is KeyBoard)
             {
-                m_currentKeyboard = connectDevice as KeyBoard;
-                LoadKeyboardMapper();
+                foreach (var binding in m_bindingPages)
+                {
+                    binding.RegistInputDevice(connectDevice);
+                }
             }
         }
 
         private void InputDevicesMgr_OnDeviceLost(InputDevice lostDevice)
         {
-            if (lostDevice == m_currentKeyboard) //当前键盘设备丢失,与其他键盘重新建立连接
+            foreach (var binding in m_bindingPages)
             {
-                m_currentKeyboard = App.inputDevicesMgr.GetKeyboard();
-                LoadKeyboardMapper();
+                binding.UnregistInputDevice(lostDevice);
+            }
+            if (lostDevice is KeyBoard) //键盘丢失,立即查找还存在的键盘并建立连接
+            {
+                var anotherKeyboard = App.input.GetDevice<KeyBoard>();
+                if (anotherKeyboard != null)
+                {
+                    foreach (var binding in m_bindingPages)
+                    {
+                        binding.UnregistInputDevice(lostDevice);
+                    }
+                }
             }
         }
 
@@ -95,22 +126,11 @@ namespace AxibugEmuOnline.Client
             return Enum.GetValues(typeof(T)).Cast<T>();
         }
 
-        /// <summary>
-        /// 加载键盘映射配置
-        /// </summary>
-        void LoadKeyboardMapper()
+        internal void RaiseDeviceRegist(InputDevice device, BindingPage binding)
         {
-            foreach (var binding in m_bindingPages)
-            {
-                binding.ClearKeyboardBinding();
-                if (m_currentKeyboard != null) OnLoadKeyboardMapper(m_currentKeyboard, binding);
-            }
+            OnRegistDevices(device, binding);
         }
-
-        /// <summary> 当加载键盘映射设置时触发 </summary>
-        /// <param name="keyboard"></param>
-        /// <param name="binding"></param>
-        protected abstract void OnLoadKeyboardMapper(KeyBoard keyboard, BindingPage binding);
+        protected abstract void OnRegistDevices(InputDevice device, BindingPage binding);
 
         public bool Start(T emuControl, int controllerIndex)
         {
@@ -214,6 +234,7 @@ namespace AxibugEmuOnline.Client
         public class BindingPage
         {
             Dictionary<T, List<InputDevice.InputControl>> m_mapSetting = new Dictionary<T, List<InputDevice.InputControl>>();
+            Dictionary<Type, InputDevice> m_registedDevices = new Dictionary<Type, InputDevice>();
 
             public int ControllerIndex { get; }
             public EmuCoreControllerKeyBinding<T> Host { get; }
@@ -227,17 +248,38 @@ namespace AxibugEmuOnline.Client
                     m_mapSetting[emuBtn] = new List<InputDevice.InputControl>();
             }
 
-            /// <summary>
-            /// 移除与键盘设备建立的绑定设置
-            /// </summary>
-            internal void ClearKeyboardBinding()
+            internal bool IsRegisted<DEVICE>() where DEVICE : InputDevice
             {
+                var type = typeof(T);
+                return IsRegisted(type);
+            }
+            internal bool IsRegisted(Type deviceType)
+            {
+                return m_registedDevices.ContainsKey(deviceType);
+            }
+
+            internal void RegistInputDevice(InputDevice device)
+            {
+                var type = device.GetType();
+                if (IsRegisted(type)) return;
+
+                m_registedDevices.Add(type, device);
+                Host.RaiseDeviceRegist(device, this);
+            }
+
+            internal void UnregistInputDevice(InputDevice device)
+            {
+                var type = device.GetType();
+                if (!IsRegisted(type)) return;
+
+                m_registedDevices.Remove(type);
+
                 foreach (var list in m_mapSetting.Values)
                 {
                     for (int i = 0; i < list.Count; i++)
                     {
                         var inputControl = list[i];
-                        if (inputControl.Device is KeyBoard)
+                        if (inputControl.Device == device)
                         {
                             list.RemoveAt(i);
                             i--;
@@ -248,6 +290,11 @@ namespace AxibugEmuOnline.Client
 
             public void SetBinding(T emuBtn, InputDevice.InputControl key, int settingSlot)
             {
+                var device = key.Device;
+                m_registedDevices.TryGetValue(device.GetType(), out var inputDevice);
+
+                Debug.Assert(inputDevice == device);
+
                 var settingList = m_mapSetting[emuBtn];
 
                 int needFixCount = settingSlot - settingList.Count + 1;
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..5fe780ab
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/MAMEKeyBinding.cs
@@ -0,0 +1,89 @@
+using AxibugEmuOnline.Client.InputDevices;
+using AxibugProtobuf;
+
+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 : EmuCoreControllerKeyBinding<UMAMEKSingleKey>
+    {
+        public override int ControllerCount => 4;
+
+        protected override void OnRegistDevices(InputDevice device, BindingPage binding)
+        {
+            if (device is KeyBoard keyboard)
+            {
+                switch (binding.ControllerIndex)
+                {
+                    case 0:
+                        binding.SetBinding(UMAMEKSingleKey.INSERT_COIN, keyboard.Q, 0);
+                        binding.SetBinding(UMAMEKSingleKey.GAMESTART, keyboard.E, 0);
+                        binding.SetBinding(UMAMEKSingleKey.UP, keyboard.W, 0);
+                        binding.SetBinding(UMAMEKSingleKey.DOWN, keyboard.S, 0);
+                        binding.SetBinding(UMAMEKSingleKey.LEFT, keyboard.A, 0);
+                        binding.SetBinding(UMAMEKSingleKey.RIGHT, keyboard.D, 0);
+                        binding.SetBinding(UMAMEKSingleKey.BTN_A, keyboard.J, 0);
+                        binding.SetBinding(UMAMEKSingleKey.BTN_B, keyboard.K, 0);
+                        binding.SetBinding(UMAMEKSingleKey.BTN_C, keyboard.L, 0);
+                        binding.SetBinding(UMAMEKSingleKey.BTN_D, keyboard.U, 0);
+                        binding.SetBinding(UMAMEKSingleKey.BTN_E, keyboard.I, 0);
+                        binding.SetBinding(UMAMEKSingleKey.BTN_F, keyboard.O, 0);
+                        break;
+                    case 1:
+                        binding.SetBinding(UMAMEKSingleKey.INSERT_COIN, keyboard.Delete, 0);
+                        binding.SetBinding(UMAMEKSingleKey.GAMESTART, keyboard.PageDown, 0);
+                        binding.SetBinding(UMAMEKSingleKey.UP, keyboard.UpArrow, 0);
+                        binding.SetBinding(UMAMEKSingleKey.DOWN, keyboard.DownArrow, 0);
+                        binding.SetBinding(UMAMEKSingleKey.LEFT, keyboard.LeftArrow, 0);
+                        binding.SetBinding(UMAMEKSingleKey.RIGHT, keyboard.RightArrow, 0);
+                        binding.SetBinding(UMAMEKSingleKey.BTN_A, keyboard.Keypad1, 0);
+                        binding.SetBinding(UMAMEKSingleKey.BTN_B, keyboard.Keypad2, 0);
+                        binding.SetBinding(UMAMEKSingleKey.BTN_C, keyboard.Keypad3, 0);
+                        binding.SetBinding(UMAMEKSingleKey.BTN_D, keyboard.Keypad4, 0);
+                        binding.SetBinding(UMAMEKSingleKey.BTN_E, keyboard.Keypad5, 0);
+                        binding.SetBinding(UMAMEKSingleKey.BTN_F, keyboard.Keypad6, 0);
+                        break;
+                }
+            }
+        }
+    }
+
+    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/Manager/AppSettings/KeyMapperSetting/NesKeyBinding.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/NesKeyBinding.cs
index b0632ffe..6c9d83ab 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/NesKeyBinding.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/NesKeyBinding.cs
@@ -1,40 +1,42 @@
-using AxibugEmuOnline.Client.ClientCore;
-using AxibugEmuOnline.Client.InputDevices;
+using AxibugEmuOnline.Client.InputDevices;
 using AxibugProtobuf;
 using VirtualNes.Core;
 
-namespace AxibugEmuOnline.Client
+namespace AxibugEmuOnline.Client.Settings
 {
     public class NesKeyBinding : EmuCoreControllerKeyBinding<EnumButtonType>
     {
         public override RomPlatformType Platform => RomPlatformType.Nes;
         public override int ControllerCount => 4;
 
-        protected override void OnLoadKeyboardMapper(KeyBoard keyboard, BindingPage binding)
+        protected override void OnRegistDevices(InputDevice device, BindingPage binding)
         {
-            switch (binding.ControllerIndex)
+            if (device is KeyBoard keyboard)
             {
-                case 0:
-                    binding.SetBinding(EnumButtonType.LEFT, keyboard.A, 0);
-                    binding.SetBinding(EnumButtonType.RIGHT, keyboard.D, 0);
-                    binding.SetBinding(EnumButtonType.UP, keyboard.W, 0);
-                    binding.SetBinding(EnumButtonType.DOWN, keyboard.S, 0);
-                    binding.SetBinding(EnumButtonType.A, keyboard.K, 0);
-                    binding.SetBinding(EnumButtonType.B, keyboard.J, 0);
-                    binding.SetBinding(EnumButtonType.SELECT, keyboard.V, 0);
-                    binding.SetBinding(EnumButtonType.START, keyboard.B, 0);
-                    binding.SetBinding(EnumButtonType.MIC, keyboard.M, 0);
-                    break;
-                case 1:
-                    binding.SetBinding(EnumButtonType.UP, keyboard.UpArrow, 0);
-                    binding.SetBinding(EnumButtonType.DOWN, keyboard.DownArrow, 0);
-                    binding.SetBinding(EnumButtonType.LEFT, keyboard.LeftArrow, 0);
-                    binding.SetBinding(EnumButtonType.RIGHT, keyboard.RightArrow, 0);
-                    binding.SetBinding(EnumButtonType.A, keyboard.Keypad2, 0);
-                    binding.SetBinding(EnumButtonType.B, keyboard.Keypad1, 0);
-                    binding.SetBinding(EnumButtonType.SELECT, keyboard.Keypad0, 0);
-                    binding.SetBinding(EnumButtonType.START, keyboard.KeypadPeriod, 0);
-                    break;
+                switch (binding.ControllerIndex)
+                {
+                    case 0:
+                        binding.SetBinding(EnumButtonType.LEFT, keyboard.A, 0);
+                        binding.SetBinding(EnumButtonType.RIGHT, keyboard.D, 0);
+                        binding.SetBinding(EnumButtonType.UP, keyboard.W, 0);
+                        binding.SetBinding(EnumButtonType.DOWN, keyboard.S, 0);
+                        binding.SetBinding(EnumButtonType.A, keyboard.K, 0);
+                        binding.SetBinding(EnumButtonType.B, keyboard.J, 0);
+                        binding.SetBinding(EnumButtonType.SELECT, keyboard.V, 0);
+                        binding.SetBinding(EnumButtonType.START, keyboard.B, 0);
+                        binding.SetBinding(EnumButtonType.MIC, keyboard.M, 0);
+                        break;
+                    case 1:
+                        binding.SetBinding(EnumButtonType.UP, keyboard.UpArrow, 0);
+                        binding.SetBinding(EnumButtonType.DOWN, keyboard.DownArrow, 0);
+                        binding.SetBinding(EnumButtonType.LEFT, keyboard.LeftArrow, 0);
+                        binding.SetBinding(EnumButtonType.RIGHT, keyboard.RightArrow, 0);
+                        binding.SetBinding(EnumButtonType.A, keyboard.Keypad2, 0);
+                        binding.SetBinding(EnumButtonType.B, keyboard.Keypad1, 0);
+                        binding.SetBinding(EnumButtonType.SELECT, keyboard.Keypad0, 0);
+                        binding.SetBinding(EnumButtonType.START, keyboard.KeypadPeriod, 0);
+                        break;
+                }
             }
         }
     }
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/XMBKeyBinding.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/XMBKeyBinding.cs
index bd31c72e..aa8e06fc 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/XMBKeyBinding.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/XMBKeyBinding.cs
@@ -1,5 +1,5 @@
-using AxibugEmuOnline.Client.ClientCore;
-using AxibugEmuOnline.Client.InputDevices;
+using AxibugEmuOnline.Client.InputDevices;
+using AxibugEmuOnline.Client.Settings;
 using AxibugProtobuf;
 
 namespace AxibugEmuOnline.Client
@@ -9,36 +9,38 @@ namespace AxibugEmuOnline.Client
         public override RomPlatformType Platform => RomPlatformType.Invalid;
         public override int ControllerCount => 2;
 
-        protected override void OnLoadKeyboardMapper(KeyBoard keyboard, BindingPage binding)
+        protected override void OnRegistDevices(InputDevice device, BindingPage binding)
         {
-            switch (binding.ControllerIndex)
+            if (device is KeyBoard keyboard)
             {
-                case 0://设置标准UI控制
-                    //第一套控制布局 WSAD+JKLI
-                    binding.SetBinding(EnumCommand.Back, keyboard.L, 0);
-                    binding.SetBinding(EnumCommand.Enter, keyboard.K, 0);
-                    binding.SetBinding(EnumCommand.OptionMenu, keyboard.I, 0);
-                    binding.SetBinding(EnumCommand.SelectItemDown, keyboard.S, 0);
-                    binding.SetBinding(EnumCommand.SelectItemLeft, keyboard.A, 0);
-                    binding.SetBinding(EnumCommand.SelectItemRight, keyboard.D, 0);
-                    binding.SetBinding(EnumCommand.SelectItemUp, keyboard.W, 0);
+                switch (binding.ControllerIndex)
+                {
+                    case 0://设置标准UI控制
+                           //第一套控制布局 WSAD+JKLI
+                        binding.SetBinding(EnumCommand.Back, keyboard.L, 0);
+                        binding.SetBinding(EnumCommand.Enter, keyboard.K, 0);
+                        binding.SetBinding(EnumCommand.OptionMenu, keyboard.I, 0);
+                        binding.SetBinding(EnumCommand.SelectItemDown, keyboard.S, 0);
+                        binding.SetBinding(EnumCommand.SelectItemLeft, keyboard.A, 0);
+                        binding.SetBinding(EnumCommand.SelectItemRight, keyboard.D, 0);
+                        binding.SetBinding(EnumCommand.SelectItemUp, keyboard.W, 0);
 
-                    //第二套控制布局 LOWB用
-                    binding.SetBinding(EnumCommand.Back, keyboard.Escape, 1);
-                    binding.SetBinding(EnumCommand.Back, keyboard.Backspace, 2);
-                    binding.SetBinding(EnumCommand.Enter, keyboard.Return, 1);
-                    binding.SetBinding(EnumCommand.OptionMenu, keyboard.LeftShift, 1);
-                    binding.SetBinding(EnumCommand.OptionMenu, keyboard.RightShift, 2);
-                    binding.SetBinding(EnumCommand.SelectItemDown, keyboard.DownArrow, 1);
-                    binding.SetBinding(EnumCommand.SelectItemLeft, keyboard.LeftArrow, 1);
-                    binding.SetBinding(EnumCommand.SelectItemRight, keyboard.RightArrow, 1);
-                    binding.SetBinding(EnumCommand.SelectItemUp, keyboard.UpArrow, 1);
-                    break;
-                case 1://游戏中UI控制
-                    binding.SetBinding(EnumCommand.OptionMenu, keyboard.Escape, 0);
-                    break;
+                        //第二套控制布局 LOWB用
+                        binding.SetBinding(EnumCommand.Back, keyboard.Escape, 1);
+                        binding.SetBinding(EnumCommand.Back, keyboard.Backspace, 2);
+                        binding.SetBinding(EnumCommand.Enter, keyboard.Return, 1);
+                        binding.SetBinding(EnumCommand.OptionMenu, keyboard.LeftShift, 1);
+                        binding.SetBinding(EnumCommand.OptionMenu, keyboard.RightShift, 2);
+                        binding.SetBinding(EnumCommand.SelectItemDown, keyboard.DownArrow, 1);
+                        binding.SetBinding(EnumCommand.SelectItemLeft, keyboard.LeftArrow, 1);
+                        binding.SetBinding(EnumCommand.SelectItemRight, keyboard.RightArrow, 1);
+                        binding.SetBinding(EnumCommand.SelectItemUp, keyboard.UpArrow, 1);
+                        break;
+                    case 1://游戏中UI控制
+                        binding.SetBinding(EnumCommand.OptionMenu, keyboard.Escape, 0);
+                        break;
+                }
             }
-
         }
     }
 }
\ 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 c6ae9483..62c0d2fd 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/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/Keyboard.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/Keyboard.cs
similarity index 91%
rename from AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Keyboard.cs
rename to AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/Keyboard.cs
index 52870c9d..7c5419f2 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Keyboard.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/Keyboard.cs
@@ -13,12 +13,12 @@ namespace AxibugEmuOnline.Client.InputDevices
 
         public KeyBoard(InputResolver resolver) : base(resolver) { }
 
-        protected override IEnumerable<InputControl> DefineControls()
+        protected override List<InputControl> DefineControls()
         {
-            var keys = s_keyboardKeys.Select(kc => new KeyboardKey(kc, this) as InputControl);
+            var keys = s_keyboardKeys.Select(kc => new KeyboardKey(kc, this) as InputControl).ToList();
             foreach (KeyboardKey key in keys)
             {
-                m_keyControllerMap[key.m_keycode] = key;
+                m_keyControllerMap.Add(key.m_keycode, key);
             }
             return keys;
         }
@@ -27,8 +27,6 @@ namespace AxibugEmuOnline.Client.InputDevices
         {
             internal KeyCode m_keycode;
 
-            public override bool Start => Device.Resolver.GetKeyDown(Device as KeyBoard, m_keycode);
-            public override bool Release => Device.Resolver.GetKeyUp(Device as KeyBoard, m_keycode);
             public override bool Performing => Device.Resolver.GetKey(Device as KeyBoard, m_keycode);
 
             internal KeyboardKey(KeyCode listenKey, KeyBoard keyboard)
@@ -69,7 +67,6 @@ namespace AxibugEmuOnline.Client.InputDevices
             // 功能键 F1-F15
             KeyCode.F1, KeyCode.F2, KeyCode.F3, KeyCode.F4, KeyCode.F5, KeyCode.F6,
             KeyCode.F7, KeyCode.F8, KeyCode.F9, KeyCode.F10, KeyCode.F11, KeyCode.F12,
-            KeyCode.F13, KeyCode.F14, KeyCode.F15,
 
             // 方向键
             KeyCode.UpArrow, KeyCode.DownArrow, KeyCode.LeftArrow, KeyCode.RightArrow,
@@ -78,12 +75,12 @@ namespace AxibugEmuOnline.Client.InputDevices
             KeyCode.Space, KeyCode.Return, KeyCode.Escape, KeyCode.Tab, KeyCode.Backspace,
             KeyCode.CapsLock, KeyCode.LeftShift, KeyCode.RightShift, KeyCode.LeftControl,
             KeyCode.RightControl, KeyCode.LeftAlt, KeyCode.RightAlt, KeyCode.LeftCommand,
-            KeyCode.RightCommand, KeyCode.Menu,
+            KeyCode.RightCommand,
 
             // 符号键
             KeyCode.Comma, KeyCode.Period, KeyCode.Slash, KeyCode.BackQuote, KeyCode.Quote,
             KeyCode.Semicolon, KeyCode.LeftBracket, KeyCode.RightBracket, KeyCode.Backslash,
-            KeyCode.Minus, KeyCode.Equals, KeyCode.Tilde,
+            KeyCode.Minus, KeyCode.Equals, 
 
             // 小键盘
             KeyCode.Keypad0, KeyCode.Keypad1, KeyCode.Keypad2, KeyCode.Keypad3, KeyCode.Keypad4,
@@ -94,7 +91,6 @@ namespace AxibugEmuOnline.Client.InputDevices
             // 其他标准键
             KeyCode.Print,  KeyCode.Insert, KeyCode.Delete, KeyCode.Home,
             KeyCode.End, KeyCode.PageUp, KeyCode.PageDown, KeyCode.Pause, KeyCode.ScrollLock,
-            KeyCode.Clear
         };
 
         public KeyboardKey A => m_keyControllerMap[KeyCode.A];
@@ -166,7 +162,6 @@ namespace AxibugEmuOnline.Client.InputDevices
         public KeyboardKey RightAlt => m_keyControllerMap[KeyCode.RightAlt];
         public KeyboardKey LeftCommand => m_keyControllerMap[KeyCode.LeftCommand];
         public KeyboardKey RightCommand => m_keyControllerMap[KeyCode.RightCommand];
-        public KeyboardKey Menu => m_keyControllerMap[KeyCode.Menu];
         public KeyboardKey Comma => m_keyControllerMap[KeyCode.Comma];
         public KeyboardKey Period => m_keyControllerMap[KeyCode.Period];
         public KeyboardKey Slash => m_keyControllerMap[KeyCode.Slash];
@@ -178,7 +173,6 @@ namespace AxibugEmuOnline.Client.InputDevices
         public KeyboardKey Backslash => m_keyControllerMap[KeyCode.Backslash];
         public KeyboardKey Minus => m_keyControllerMap[KeyCode.Minus];
         public KeyboardKey Equals_k => m_keyControllerMap[KeyCode.Equals];
-        public KeyboardKey Tilde => m_keyControllerMap[KeyCode.Tilde];
         public KeyboardKey Keypad0 => m_keyControllerMap[KeyCode.Keypad0];
         public KeyboardKey Keypad1 => m_keyControllerMap[KeyCode.Keypad1];
         public KeyboardKey Keypad2 => m_keyControllerMap[KeyCode.Keypad2];
@@ -205,7 +199,6 @@ namespace AxibugEmuOnline.Client.InputDevices
         public KeyboardKey PageDown => m_keyControllerMap[KeyCode.PageDown];
         public KeyboardKey Pause => m_keyControllerMap[KeyCode.Pause];
         public KeyboardKey ScrollLock => m_keyControllerMap[KeyCode.ScrollLock];
-        public KeyboardKey Clear => m_keyControllerMap[KeyCode.Clear];
     }
     #endregion
 }
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Keyboard.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/Keyboard.cs.meta
similarity index 100%
rename from AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Keyboard.cs.meta
rename to AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/Keyboard.cs.meta
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/PSVController.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/PSVController.cs
new file mode 100644
index 00000000..2183a0de
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/PSVController.cs
@@ -0,0 +1,167 @@
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace AxibugEmuOnline.Client.InputDevices
+{
+    public class PSVController : InputDevice
+    {
+        /// <summary> × </summary>
+        public Button Cross { get; private set; }
+        /// <summary> ○ </summary>
+        public Button Circle { get; private set; }
+        /// <summary> □ </summary>
+        public Button Square { get; private set; }
+        /// <summary> △ </summary>
+        public Button Triangle { get; private set; }
+        public Button L { get; private set; }
+        public Button R { get; private set; }
+        public Button Select { get; private set; }
+        public Button Start { get; private set; }
+        public Button Up { get; private set; }
+        public Button Right { get; private set; }
+        public Button Down { get; private set; }
+        public Button Left { get; private set; }
+
+        public Stick LeftStick { get; private set; }
+        public Stick RightStick { get; private set; }
+
+        public PSVController(InputResolver resolver) : base(resolver) { }
+
+        protected override List<InputControl> DefineControls()
+        {
+            List<InputControl> result = new List<InputControl>();
+
+            Cross = new Button(KeyCode.Joystick1Button0, this, "X");
+            Circle = new Button(KeyCode.Joystick1Button1, this, "⭕");
+            Square = new Button(KeyCode.Joystick1Button2, this, "□");
+            Triangle = new Button(KeyCode.Joystick1Button3, this, "△");
+
+            L = new Button(KeyCode.Joystick1Button4, this, "L");
+            R = new Button(KeyCode.Joystick1Button5, this, "R");
+
+            Select = new Button(KeyCode.Joystick1Button6, this, "SELECT");
+            Start = new Button(KeyCode.Joystick1Button7, this, "START");
+
+            Up = new Button(KeyCode.Joystick1Button8, this, "UP");
+            Right = new Button(KeyCode.Joystick1Button9, this, "RIGHT");
+            Down = new Button(KeyCode.Joystick1Button10, this, "DOWN");
+            Left = new Button(KeyCode.Joystick1Button11, this, "LEFT");
+
+            return result;
+        }
+
+        public class Button : InputControl
+        {
+            private KeyCode m_keyCode;
+            private string m_controlName;
+
+            public Button(KeyCode keycode, InputDevice device, string controlName) : base(device)
+            {
+                m_keyCode = keycode;
+                m_controlName = controlName;
+            }
+
+            public override bool Performing => Input.GetKey(m_keyCode);
+
+            public override Vector2 GetVector2()
+            {
+                return default;
+            }
+
+            public override float GetFlaot()
+            {
+                return Performing ? 1 : 0;
+            }
+
+            public override string ControlName => m_controlName;
+        }
+
+        public class Stick : InputControl
+        {
+            private bool m_left;
+
+            public VirtualButton UP { get; private set; }
+            public VirtualButton Down { get; private set; }
+            public VirtualButton Left { get; private set; }
+            public VirtualButton Right { get; private set; }
+
+            public Stick(InputDevice device, bool left) : base(device)
+            {
+                m_left = left;
+
+                UP = new VirtualButton(device);
+                Down = new VirtualButton(device);
+                Left = new VirtualButton(device);
+                Right = new VirtualButton(device);
+            }
+
+            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 override bool Performing => GetVector2().x != 0 || GetVector2().y != 0;
+
+            public override Vector2 GetVector2()
+            {
+                Vector2 result = Vector2.zero;
+
+                if (m_left)
+                {
+                    result.x = Input.GetAxis("Horizontal");
+                    result.y = Input.GetAxis("Vertical");
+                }
+                else
+                {
+                    result.x = Input.GetAxis("HorizontalR");
+                    result.y = Input.GetAxis("VerticalR");
+                }
+
+                return result;
+            }
+
+            public override float GetFlaot()
+            {
+                return Performing ? 1 : 0;
+            }
+
+            public override string ControlName => $"{nameof(Stick)}_{(m_left ? "left" : "right")}";
+
+            public class VirtualButton : InputControl
+            {
+                internal bool m_performing;
+
+                public VirtualButton(InputDevice device) : base(device) { }
+
+                public override bool Performing
+                {
+                    get => m_performing;
+                }
+
+                public override Vector2 GetVector2()
+                {
+                    return default;
+                }
+
+                public override float GetFlaot()
+                {
+                    return Performing ? 1 : 0;
+                }
+
+                public override string ControlName => "VirtualStickButton";
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/PSVController.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/PSVController.cs.meta
new file mode 100644
index 00000000..d1ab8ba3
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/PSVController.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/InputDevicesManager.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs
index c0400f89..9192e59a 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
 using UnityEngine;
 
 namespace AxibugEmuOnline.Client.InputDevices
@@ -44,13 +45,13 @@ namespace AxibugEmuOnline.Client.InputDevices
         }
 
         /// <summary>
-        /// 获得一个键盘设备
+        /// 获得一个指定类型的设备
         /// </summary>
-        public KeyBoard GetKeyboard()
+        public T GetDevice<T>() where T : InputDevice
         {
             foreach (var d in m_devices.Values)
             {
-                if (d is KeyBoard kb) return kb;
+                if (d is T) return d as T;
             }
 
             return null;
@@ -92,6 +93,7 @@ namespace AxibugEmuOnline.Client.InputDevices
 
             foreach (var control in m_controlMapper.Values)
             {
+                control.Update();
                 if (control.Start)
                 {
                     AnyKeyDown = true;
@@ -101,7 +103,7 @@ namespace AxibugEmuOnline.Client.InputDevices
 
         /// <summary> 用于列出这个输入设备的所有输入控件实例 </summary>
         /// <returns></returns>
-        protected abstract IEnumerable<InputControl> DefineControls();
+        protected abstract List<InputControl> DefineControls();
 
         /// <summary> 通过控件名称,找到对应的控件 </summary>
         /// <param name="keyName"></param>
@@ -121,9 +123,11 @@ namespace AxibugEmuOnline.Client.InputDevices
             public InputDevice Device { get; internal set; }
 
             /// <summary> 获取该控件是否在当前调用帧被激发 </summary>
-            public abstract bool Start { get; }
+            public bool Start { get; private set; }
             /// <summary> 获取该控件是否在当前调用帧被释放 </summary>
-            public abstract bool Release { get; }
+            public bool Release { get; private set; }
+
+            bool m_performingLastFrame;
             /// <summary> 获取该控件是否在当前调用帧是否处于活动状态 </summary>
             public abstract bool Performing { get; }
 
@@ -133,6 +137,29 @@ namespace AxibugEmuOnline.Client.InputDevices
             /// <summary> 获得该控件的以浮点数表达的值 </summary>
             public abstract float GetFlaot();
 
+            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() { }
+
             /// <summary> 控件名,这个控件名称必须是唯一的 </summary>
             public abstract string ControlName { get; }
 
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputResolver.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputResolver.cs
index d3f6c832..ff78f612 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputResolver.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputResolver.cs
@@ -9,11 +9,11 @@ namespace AxibugEmuOnline.Client.InputDevices
         {
 #if ENABLE_INPUT_SYSTEM //InputSystem
             return new ForInputSystem.InputSystemResolver();
-#elif UNITY_PSP2 //SDK
-            throw new System.NotImplementedException();
+#elif UNITY_PSP2 //特化实现
+            return new ForPSV.PSVResolver();
 #elif UNITY_PS3 //SDK
             throw new System.NotImplementedException();
-#else //使用旧Input
+#else 
             throw new System.NotImplementedException();    
 #endif
         }
@@ -55,19 +55,6 @@ namespace AxibugEmuOnline.Client.InputDevices
             OnDeviceConnected?.Invoke(connectDevice);
         }
 
-        /// <summary>
-        /// 获取一个键盘设备的指定按键当前调用帧是否触发了按下动作
-        /// </summary>
-        /// <param name="keyboard">键盘设备实例,来自Resolver提供的设备实例</param>
-        /// <param name="key">键盘按键枚举值</param>
-        /// <returns></returns>
-        public abstract bool GetKeyDown(KeyBoard keyboard, KeyCode key);
-        /// <summary>
-        /// 获取一个键盘设备的指定按键当前调用帧是否触发了放开动作
-        /// </summary>
-        /// <param name="keyboard">键盘设备实例,来自Resolver提供的设备实例</param>
-        /// <param name="key">键盘按键枚举值</param>
-        public abstract bool GetKeyUp(KeyBoard keyboard, KeyCode key);
         /// <summary>
         /// 获取一个键盘设备的指定按键当前调用帧是否处于按下状态
         /// </summary>
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs
index f7211d72..d70b2503 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs
@@ -68,34 +68,6 @@ namespace AxibugEmuOnline.Client.InputDevices.ForInputSystem
             return m_devices.Values;
         }
 
-        public override bool GetKeyDown(KeyBoard keyboard, KeyCode key)
-        {
-            if (m_devices.TryGetKey(keyboard, out var ipdev))
-            {
-                var ipKeyboard = ipdev as IPKeyboard;
-                if (ipKeyboard == null) return false;
-
-                var k = GetIPKeyboardKey(ipKeyboard, key);
-                return k.wasPressedThisFrame;
-            }
-
-            return false;
-        }
-
-        public override bool GetKeyUp(KeyBoard keyboard, KeyCode key)
-        {
-            if (m_devices.TryGetKey(keyboard, out var ipdev))
-            {
-                var ipKeyboard = ipdev as IPKeyboard;
-                if (ipKeyboard == null) return false;
-
-                var k = GetIPKeyboardKey(ipKeyboard, key);
-                return k.wasReleasedThisFrame;
-            }
-
-            return false;
-        }
-
         public override bool GetKey(KeyBoard keyboard, KeyCode key)
         {
             if (m_devices.TryGetKey(keyboard, out var ipdev))
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..cc8f5b4f
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/PSVResolver.cs
@@ -0,0 +1,39 @@
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace AxibugEmuOnline.Client.InputDevices.ForPSV
+{
+    public class PSVResolver : InputResolver
+    {
+        List<InputDevice> m_devices = new List<InputDevice>();
+        PSVController m_psvController;
+
+        protected override void OnInit()
+        {
+            m_psvController = new PSVController(this);
+            m_devices.Add(m_psvController);
+        }
+
+        public override IEnumerable<InputDevice> GetDevices()
+        {
+            return m_devices;
+        }
+
+        public override bool CheckOnline(InputDevice device)
+        {
+            return device == m_psvController;
+        }
+
+        public override bool GetKey(KeyBoard keyboard, KeyCode key)
+        {
+            return Input.GetKeyDown(key);
+        }
+
+        public override string GetDeviceName(InputDevice inputDevice)
+        {
+            Debug.Assert(inputDevice == m_psvController, "只支持psv控制器");
+
+            return nameof(PSVController);
+        }
+    }
+}
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/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/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/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

From 667089891a200d51f56ef17a069ab52197571c4e Mon Sep 17 00:00:00 2001
From: "ALIENJACK\\alien" <alienjack@foxmail.com>
Date: Mon, 17 Mar 2025 20:32:34 +0800
Subject: [PATCH 08/20] =?UTF-8?q?KeyMapper=E6=A0=B9=E6=8D=AE=E6=AF=8F?=
 =?UTF-8?q?=E7=A7=8D=E8=AE=BE=E5=A4=87=E5=8D=95=E7=8B=AC=E9=85=8D=E7=BD=AE?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../KeyMapperSetting/KeyMapperSetting.cs      | 62 +++++++++++--------
 1 file changed, 36 insertions(+), 26 deletions(-)

diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs
index 10252195..87e02443 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs
@@ -5,6 +5,7 @@ using System;
 using System.Collections.Generic;
 using System.Linq;
 using UnityEngine;
+using static AxibugEmuOnline.Client.Settings.EmuCoreControllerKeyBinding<T>;
 
 namespace AxibugEmuOnline.Client.Settings
 {
@@ -231,10 +232,12 @@ namespace AxibugEmuOnline.Client.Settings
             else return totalFloat / totalControl;
         }
 
+        public class MapSetting : Dictionary<T, List<InputDevice.InputControl>> { }
+
         public class BindingPage
         {
-            Dictionary<T, List<InputDevice.InputControl>> m_mapSetting = new Dictionary<T, List<InputDevice.InputControl>>();
             Dictionary<Type, InputDevice> m_registedDevices = new Dictionary<Type, InputDevice>();
+            Dictionary<InputDevice, MapSetting> m_mapSetting = new Dictionary<InputDevice, MapSetting>();
 
             public int ControllerIndex { get; }
             public EmuCoreControllerKeyBinding<T> Host { get; }
@@ -243,9 +246,6 @@ namespace AxibugEmuOnline.Client.Settings
             {
                 ControllerIndex = controllerIndex;
                 Host = host;
-
-                foreach (var emuBtn in host.DefineKeys())
-                    m_mapSetting[emuBtn] = new List<InputDevice.InputControl>();
             }
 
             internal bool IsRegisted<DEVICE>() where DEVICE : InputDevice
@@ -264,6 +264,7 @@ namespace AxibugEmuOnline.Client.Settings
                 if (IsRegisted(type)) return;
 
                 m_registedDevices.Add(type, device);
+                m_mapSetting[device] = new MapSetting();
                 Host.RaiseDeviceRegist(device, this);
             }
 
@@ -273,19 +274,7 @@ namespace AxibugEmuOnline.Client.Settings
                 if (!IsRegisted(type)) return;
 
                 m_registedDevices.Remove(type);
-
-                foreach (var list in m_mapSetting.Values)
-                {
-                    for (int i = 0; i < list.Count; i++)
-                    {
-                        var inputControl = list[i];
-                        if (inputControl.Device == device)
-                        {
-                            list.RemoveAt(i);
-                            i--;
-                        }
-                    }
-                }
+                m_mapSetting.Remove(device);
             }
 
             public void SetBinding(T emuBtn, InputDevice.InputControl key, int settingSlot)
@@ -295,7 +284,12 @@ namespace AxibugEmuOnline.Client.Settings
 
                 Debug.Assert(inputDevice == device);
 
-                var settingList = m_mapSetting[emuBtn];
+                var setting = m_mapSetting[inputDevice];
+                if (!setting.TryGetValue(emuBtn, out var settingList))
+                {
+                    settingList = new List<InputDevice.InputControl>();
+                    setting[emuBtn] = settingList;
+                }
 
                 int needFixCount = settingSlot - settingList.Count + 1;
                 if (needFixCount > 0) for (int i = 0; i < needFixCount; i++) settingList.Add(null);
@@ -303,25 +297,41 @@ namespace AxibugEmuOnline.Client.Settings
                 settingList[settingSlot] = key;
             }
 
-            public InputDevice.InputControl GetBinding(T emuBtn, int settingSlot)
+            public InputDevice.InputControl GetBinding(T emuBtn, InputDevice device, int settingSlot)
             {
-                var settingList = m_mapSetting[emuBtn];
-                if (settingSlot >= settingList.Count) return null;
+                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];
             }
 
-            public List<InputDevice.InputControl> GetBinding(T emuBtn)
+            public IEnumerable<InputDevice.InputControl> GetBinding(T emuBtn)
             {
-                return m_mapSetting[emuBtn];
+                foreach (var mapSettings in m_mapSetting.Values)
+                {
+                    mapSettings.TryGetValue(emuBtn, out var bindControls);
+                    if (bindControls != null)
+                    {
+                        return bindControls;
+                    }
+                }
+
+                return null;
             }
 
             public bool AnyKeyDown()
             {
-                foreach (var item in m_mapSetting)
+                foreach (var mapSettings in m_mapSetting.Values)
                 {
-                    foreach (var key in item.Value)
+                    foreach (var keys in mapSettings.Values)
                     {
-                        if (key.Start) return true;
+                        foreach (var key in keys)
+                        {
+                            if (key.Start) return true;
+                        }
                     }
                 }
 

From 49c893fdab59460fe18d34064bfdb03aea5d9b47 Mon Sep 17 00:00:00 2001
From: "ALIENJACK\\alien" <alienjack@foxmail.com>
Date: Tue, 18 Mar 2025 10:56:24 +0800
Subject: [PATCH 09/20] =?UTF-8?q?GetBinding=E6=96=B9=E6=B3=95=E4=BF=AE?=
 =?UTF-8?q?=E6=94=B9,=E5=9C=A8=E6=B2=A1=E6=9C=89=E7=BB=91=E5=AE=9A?=
 =?UTF-8?q?=E8=AE=BE=E5=A4=87=E6=97=B6=E8=BF=94=E5=9B=9E=E7=A9=BA=E8=BF=AD?=
 =?UTF-8?q?=E4=BB=A3=E5=99=A8=E8=80=8C=E4=B8=8D=E6=98=AFnull?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs   | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs
index 87e02443..36d1a1e1 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs
@@ -5,7 +5,6 @@ using System;
 using System.Collections.Generic;
 using System.Linq;
 using UnityEngine;
-using static AxibugEmuOnline.Client.Settings.EmuCoreControllerKeyBinding<T>;
 
 namespace AxibugEmuOnline.Client.Settings
 {
@@ -319,7 +318,7 @@ namespace AxibugEmuOnline.Client.Settings
                     }
                 }
 
-                return null;
+                return Enumerable.Empty<InputDevice.InputControl>();
             }
 
             public bool AnyKeyDown()

From cf8127c55350d5a67cef9d138eba66ffb12a111d Mon Sep 17 00:00:00 2001
From: "ALIENJACK\\alien" <alienjack@foxmail.com>
Date: Tue, 18 Mar 2025 11:23:08 +0800
Subject: [PATCH 10/20] =?UTF-8?q?=E4=BF=AE=E5=A4=8DGetBinding=E8=BF=94?=
 =?UTF-8?q?=E5=9B=9E=E7=9A=84InputControl=E5=AF=B9=E8=B1=A1=E5=B9=B6?=
 =?UTF-8?q?=E4=B8=8D=E5=AE=8C=E6=95=B4=E7=9A=84=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../AppSettings/KeyMapperSetting/KeyMapperSetting.cs     | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs
index 36d1a1e1..53ff6296 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs
@@ -2,6 +2,7 @@
 using AxibugEmuOnline.Client.InputDevices;
 using AxibugProtobuf;
 using System;
+using System.Collections;
 using System.Collections.Generic;
 using System.Linq;
 using UnityEngine;
@@ -307,18 +308,21 @@ namespace AxibugEmuOnline.Client.Settings
                 return settingList[settingSlot];
             }
 
+            private List<InputDevice.InputControl> m_caches = new List<InputDevice.InputControl>();
             public IEnumerable<InputDevice.InputControl> GetBinding(T emuBtn)
             {
+                m_caches.Clear();
+
                 foreach (var mapSettings in m_mapSetting.Values)
                 {
                     mapSettings.TryGetValue(emuBtn, out var bindControls);
                     if (bindControls != null)
                     {
-                        return bindControls;
+                        m_caches.AddRange(bindControls);
                     }
                 }
 
-                return Enumerable.Empty<InputDevice.InputControl>();
+                return m_caches;
             }
 
             public bool AnyKeyDown()
@@ -337,5 +341,6 @@ namespace AxibugEmuOnline.Client.Settings
                 return false;
             }
         }
+
     }
 }
\ No newline at end of file

From 924727eb7ce648133b4b91b91bbae5ca0b405e75 Mon Sep 17 00:00:00 2001
From: "ALIENJACK\\alien" <alienjack@foxmail.com>
Date: Wed, 26 Mar 2025 19:07:46 +0800
Subject: [PATCH 11/20] =?UTF-8?q?Input=E7=B3=BB=E7=BB=9F=E4=BB=A3=E7=A0=81?=
 =?UTF-8?q?=E8=BF=AD=E4=BB=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../InputDevicesManager/Devices/Keyboard.cs   | 12 ----
 .../Devices/PSVController.cs                  | 70 ++++---------------
 .../InputDevicesManager.cs                    |  9 ++-
 .../InputResolver/InputResolver.cs            | 11 ++-
 .../InputResolver/InputSystemResolver.cs      | 34 +++++++--
 .../InputResolver/PSVResolver.cs              | 70 +++++++++++++++++--
 6 files changed, 114 insertions(+), 92 deletions(-)

diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/Keyboard.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/Keyboard.cs
index 7c5419f2..5daa7d32 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/Keyboard.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/Keyboard.cs
@@ -27,8 +27,6 @@ namespace AxibugEmuOnline.Client.InputDevices
         {
             internal KeyCode m_keycode;
 
-            public override bool Performing => Device.Resolver.GetKey(Device as KeyBoard, m_keycode);
-
             internal KeyboardKey(KeyCode listenKey, KeyBoard keyboard)
                 : base(keyboard)
             {
@@ -36,16 +34,6 @@ namespace AxibugEmuOnline.Client.InputDevices
             }
 
             public override string ControlName => m_keycode.ToString();
-
-            public override Vector2 GetVector2()
-            {
-                return default(Vector2);
-            }
-
-            public override float GetFlaot()
-            {
-                return Performing ? 1 : 0;
-            }
         }
     }
 
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/PSVController.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/PSVController.cs
index 2183a0de..7b037956 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/PSVController.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/PSVController.cs
@@ -21,7 +21,6 @@ namespace AxibugEmuOnline.Client.InputDevices
         public Button Right { get; private set; }
         public Button Down { get; private set; }
         public Button Left { get; private set; }
-
         public Stick LeftStick { get; private set; }
         public Stick RightStick { get; private set; }
 
@@ -31,54 +30,40 @@ namespace AxibugEmuOnline.Client.InputDevices
         {
             List<InputControl> result = new List<InputControl>();
 
-            Cross = new Button(KeyCode.Joystick1Button0, this, "X");
-            Circle = new Button(KeyCode.Joystick1Button1, this, "⭕");
-            Square = new Button(KeyCode.Joystick1Button2, this, "□");
-            Triangle = new Button(KeyCode.Joystick1Button3, this, "△");
+            Cross = new Button(this, "X");
+            Circle = new Button(this, "⭕");
+            Square = new Button(this, "□");
+            Triangle = new Button(this, "△");
 
-            L = new Button(KeyCode.Joystick1Button4, this, "L");
-            R = new Button(KeyCode.Joystick1Button5, this, "R");
+            L = new Button(this, "L");
+            R = new Button(this, "R");
 
-            Select = new Button(KeyCode.Joystick1Button6, this, "SELECT");
-            Start = new Button(KeyCode.Joystick1Button7, this, "START");
+            Select = new Button(this, "SELECT");
+            Start = new Button(this, "START");
 
-            Up = new Button(KeyCode.Joystick1Button8, this, "UP");
-            Right = new Button(KeyCode.Joystick1Button9, this, "RIGHT");
-            Down = new Button(KeyCode.Joystick1Button10, this, "DOWN");
-            Left = new Button(KeyCode.Joystick1Button11, this, "LEFT");
+            Up = new Button(this, "UP");
+            Right = new Button(this, "RIGHT");
+            Down = new Button(this, "DOWN");
+            Left = new Button(this, "LEFT");
 
             return result;
         }
 
         public class Button : InputControl
         {
-            private KeyCode m_keyCode;
-            private string m_controlName;
+            internal string m_controlName;
 
-            public Button(KeyCode keycode, InputDevice device, string controlName) : base(device)
+            public Button(InputDevice device, string controlName) : base(device)
             {
-                m_keyCode = keycode;
                 m_controlName = controlName;
             }
 
-            public override bool Performing => Input.GetKey(m_keyCode);
-
-            public override Vector2 GetVector2()
-            {
-                return default;
-            }
-
-            public override float GetFlaot()
-            {
-                return Performing ? 1 : 0;
-            }
-
             public override string ControlName => m_controlName;
         }
 
         public class Stick : InputControl
         {
-            private bool m_left;
+            internal bool m_left;
 
             public VirtualButton UP { get; private set; }
             public VirtualButton Down { get; private set; }
@@ -112,31 +97,6 @@ namespace AxibugEmuOnline.Client.InputDevices
                 Right.Update();
             }
 
-            public override bool Performing => GetVector2().x != 0 || GetVector2().y != 0;
-
-            public override Vector2 GetVector2()
-            {
-                Vector2 result = Vector2.zero;
-
-                if (m_left)
-                {
-                    result.x = Input.GetAxis("Horizontal");
-                    result.y = Input.GetAxis("Vertical");
-                }
-                else
-                {
-                    result.x = Input.GetAxis("HorizontalR");
-                    result.y = Input.GetAxis("VerticalR");
-                }
-
-                return result;
-            }
-
-            public override float GetFlaot()
-            {
-                return Performing ? 1 : 0;
-            }
-
             public override string ControlName => $"{nameof(Stick)}_{(m_left ? "left" : "right")}";
 
             public class VirtualButton : InputControl
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs
index 9192e59a..b4fff468 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs
@@ -1,5 +1,4 @@
-using System;
-using System.Collections.Generic;
+using System.Collections.Generic;
 using UnityEngine;
 
 namespace AxibugEmuOnline.Client.InputDevices
@@ -129,13 +128,13 @@ namespace AxibugEmuOnline.Client.InputDevices
 
             bool m_performingLastFrame;
             /// <summary> 获取该控件是否在当前调用帧是否处于活动状态 </summary>
-            public abstract bool Performing { get; }
+            public virtual bool Performing => Device.Resolver.CheckPerforming(this);
 
             /// <summary> 获得该控件的以二维向量表达的值 </summary>
             /// <returns></returns>
-            public abstract Vector2 GetVector2();
+            public virtual Vector2 GetVector2() => Device.Resolver.GetVector2(this);
             /// <summary> 获得该控件的以浮点数表达的值 </summary>
-            public abstract float GetFlaot();
+            public virtual float GetFlaot() => Device.Resolver.GetFloat(this);
 
             internal void Update()
             {
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputResolver.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputResolver.cs
index ff78f612..390eafbd 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputResolver.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputResolver.cs
@@ -1,5 +1,6 @@
 using System.Collections.Generic;
 using UnityEngine;
+using UnityEngine.InputSystem;
 
 namespace AxibugEmuOnline.Client.InputDevices
 {
@@ -55,13 +56,9 @@ namespace AxibugEmuOnline.Client.InputDevices
             OnDeviceConnected?.Invoke(connectDevice);
         }
 
-        /// <summary>
-        /// 获取一个键盘设备的指定按键当前调用帧是否处于按下状态
-        /// </summary>
-        /// <param name="keyboard">键盘设备实例,来自Resolver提供的设备实例</param>
-        /// <param name="key">键盘按键枚举值</param>
-        public abstract bool GetKey(KeyBoard keyboard, KeyCode key);
-
+        public abstract bool CheckPerforming<CONTROLLER>(CONTROLLER control) where CONTROLLER : InputDevice.InputControl;
+        public abstract Vector2 GetVector2<CONTROLLER>(CONTROLLER control) where CONTROLLER : InputDevice.InputControl;
+        public abstract float GetFloat<CONTROLLER>(CONTROLLER control) where CONTROLLER : InputDevice.InputControl;
         /// <summary>
         /// 获得输入设备的唯一名称
         /// </summary>
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs
index d70b2503..49a03c53 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs
@@ -1,6 +1,7 @@
 #if ENABLE_INPUT_SYSTEM
 using System.Collections.Generic;
 using UnityEngine;
+using UnityEngine.InputSystem;
 using UnityEngine.InputSystem.Controls;
 using IP = UnityEngine.InputSystem.InputSystem;
 using IPDevice = UnityEngine.InputSystem.InputDevice;
@@ -68,18 +69,37 @@ namespace AxibugEmuOnline.Client.InputDevices.ForInputSystem
             return m_devices.Values;
         }
 
-        public override bool GetKey(KeyBoard keyboard, KeyCode key)
+        public override bool CheckPerforming<CONTROLLER>(CONTROLLER control)
         {
-            if (m_devices.TryGetKey(keyboard, out var ipdev))
+            if (control.Device is KeyBoard keyboard)
             {
-                var ipKeyboard = ipdev as IPKeyboard;
-                if (ipKeyboard == null) return false;
+                if (control is KeyBoard.KeyboardKey key)
+                {
+                    if (m_devices.TryGetKey(keyboard, out var ipdev))
+                    {
+                        var ipKeyboard = ipdev as IPKeyboard;
+                        if (ipKeyboard == null) return false;
 
-                var k = GetIPKeyboardKey(ipKeyboard, key);
-                return k.isPressed;
+                        var k = GetIPKeyboardKey(ipKeyboard, key.m_keycode);
+                        return k.isPressed;
+                    }
+
+                    return false;
+                }
             }
 
-            return false;
+
+            throw new System.NotImplementedException();
+        }
+
+        public override Vector2 GetVector2<CONTROLLER>(CONTROLLER control)
+        {
+            throw new System.NotImplementedException();
+        }
+
+        public override float GetFloat<CONTROLLER>(CONTROLLER control)
+        {
+            throw new System.NotImplementedException();
         }
     }
 
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/PSVResolver.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/PSVResolver.cs
index cc8f5b4f..1c7ee738 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/PSVResolver.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/PSVResolver.cs
@@ -1,5 +1,8 @@
-using System.Collections.Generic;
+using NUnit.Framework.Internal;
+using System.Collections.Generic;
 using UnityEngine;
+using static Essgee.Emulation.Audio.DMGAudio;
+using static VirtualNes.Core.APU_INTERNAL;
 
 namespace AxibugEmuOnline.Client.InputDevices.ForPSV
 {
@@ -24,16 +27,71 @@ namespace AxibugEmuOnline.Client.InputDevices.ForPSV
             return device == m_psvController;
         }
 
-        public override bool GetKey(KeyBoard keyboard, KeyCode key)
-        {
-            return Input.GetKeyDown(key);
-        }
-
         public override string GetDeviceName(InputDevice inputDevice)
         {
             Debug.Assert(inputDevice == m_psvController, "只支持psv控制器");
 
             return nameof(PSVController);
         }
+
+        public override bool CheckPerforming<CONTROLLER>(CONTROLLER control)
+        {
+            if (control.Device is PSVController psvCon)
+            {
+                if (control is PSVController.Button button)
+                {
+                    if (button == psvCon.Cross) return Input.GetKey(KeyCode.Joystick1Button0);
+                    else if (button == psvCon.Circle) return Input.GetKey(KeyCode.Joystick1Button1);
+                    else if (button == psvCon.Square) return Input.GetKey(KeyCode.Joystick1Button2);
+                    else if (button == psvCon.Triangle) return Input.GetKey(KeyCode.Joystick1Button3);
+                    else if (button == psvCon.L) return Input.GetKey(KeyCode.Joystick1Button4);
+                    else if (button == psvCon.R) return Input.GetKey(KeyCode.Joystick1Button5);
+                    else if (button == psvCon.Select) return Input.GetKey(KeyCode.Joystick1Button6);
+                    else if (button == psvCon.Start) return Input.GetKey(KeyCode.Joystick1Button7);
+                    else if (button == psvCon.Up) return Input.GetKey(KeyCode.Joystick1Button8);
+                    else if (button == psvCon.Right) return Input.GetKey(KeyCode.Joystick1Button9);
+                    else if (button == psvCon.Down) return Input.GetKey(KeyCode.Joystick1Button10);
+                    else if (button == psvCon.Left) return Input.GetKey(KeyCode.Joystick1Button11);
+                }
+                else if (control is PSVController.Stick stick)
+                {
+                    var vec2 = stick.GetVector2();
+                    return vec2.x != 0 || vec2.y != 0;
+                }
+            }
+
+            throw new System.NotImplementedException();
+        }
+
+        public override Vector2 GetVector2<CONTROLLER>(CONTROLLER control)
+        {
+            if (control.Device is PSVController)
+            {
+                if (control is PSVController.Stick stick)
+                {
+                    Vector2 result = Vector2.zero;
+
+                    if (stick.m_left)
+                    {
+                        result.x = Input.GetAxis("Joy1 Axis X");
+                        result.y = Input.GetAxis("Joy1 Axis Y");
+                    }
+                    else
+                    {
+                        result.x = Input.GetAxis("Joy1 Axis 4");
+                        result.y = Input.GetAxis("Joy1 Axis 5");
+                    }
+
+                    return result;
+                }
+            }
+
+            throw new System.NotImplementedException();
+        }
+
+        public override float GetFloat<CONTROLLER>(CONTROLLER control)
+        {
+            throw new System.NotImplementedException();
+        }
     }
 }

From 8007af0bc54dbed7f4ce79f9838c0fb41110b882 Mon Sep 17 00:00:00 2001
From: "ALIENJACK\\alien" <alienjack@foxmail.com>
Date: Thu, 27 Mar 2025 11:54:10 +0800
Subject: [PATCH 12/20] =?UTF-8?q?InputControl=E7=9A=84=E5=AE=9E=E7=8E=B0?=
 =?UTF-8?q?=E7=B1=BB=E6=8C=AA=E5=85=A5=E5=9F=BA=E6=9C=AC=E7=B1=BB=E5=9E=8B?=
 =?UTF-8?q?,=E4=B8=8D=E5=86=8D=E6=AF=8F=E4=B8=AA=E8=AE=BE=E5=A4=87?=
 =?UTF-8?q?=E5=8D=95=E7=8B=AC=E5=AE=9E=E7=8E=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../KeyMapperSetting/EssgeeKeyBinding.cs      |   1 -
 .../KeyMapperSetting/KeyMapperSetting.cs      |  12 +-
 .../Devices/InputControls/Button.cs           |  17 +++
 .../Devices/InputControls/InputControl.cs     |  59 ++++++++++
 .../Devices/InputControls/Stick.cs            |  70 ++++++++++++
 .../Devices/InputDevice.cs                    |  56 +++++++++
 .../InputDevicesManager/Devices/Keyboard.cs   |   6 +-
 .../Devices/PSVController.cs                  |  79 +------------
 .../{InputResolver => }/DualWayDictionary.cs  |   0
 .../DualWayDictionary.cs.meta                 |   0
 .../InputDevicesManager.cs                    | 107 ------------------
 .../InputResolver/InputResolver.cs            |   6 +-
 .../InputResolver/InputSystemResolver.cs      |   9 +-
 .../InputResolver/PSVResolver.cs              |  60 ++++------
 14 files changed, 242 insertions(+), 240 deletions(-)
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/Button.cs
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/InputControl.cs
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/Stick.cs
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputDevice.cs
 rename AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/{InputResolver => }/DualWayDictionary.cs (100%)
 rename AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/{InputResolver => }/DualWayDictionary.cs.meta (100%)

diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/EssgeeKeyBinding.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/EssgeeKeyBinding.cs
index a32ebb71..5423edc2 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/EssgeeKeyBinding.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/EssgeeKeyBinding.cs
@@ -1,6 +1,5 @@
 using AxibugEmuOnline.Client.InputDevices;
 using AxibugProtobuf;
-using AxiInputSP;
 using System;
 
 namespace AxibugEmuOnline.Client.Settings
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs
index 53ff6296..bfb5a1ba 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs
@@ -232,7 +232,7 @@ namespace AxibugEmuOnline.Client.Settings
             else return totalFloat / totalControl;
         }
 
-        public class MapSetting : Dictionary<T, List<InputDevice.InputControl>> { }
+        public class MapSetting : Dictionary<T, List<InputControl>> { }
 
         public class BindingPage
         {
@@ -277,7 +277,7 @@ namespace AxibugEmuOnline.Client.Settings
                 m_mapSetting.Remove(device);
             }
 
-            public void SetBinding(T emuBtn, InputDevice.InputControl key, int settingSlot)
+            public void SetBinding(T emuBtn, InputControl key, int settingSlot)
             {
                 var device = key.Device;
                 m_registedDevices.TryGetValue(device.GetType(), out var inputDevice);
@@ -287,7 +287,7 @@ namespace AxibugEmuOnline.Client.Settings
                 var setting = m_mapSetting[inputDevice];
                 if (!setting.TryGetValue(emuBtn, out var settingList))
                 {
-                    settingList = new List<InputDevice.InputControl>();
+                    settingList = new List<InputControl>();
                     setting[emuBtn] = settingList;
                 }
 
@@ -297,7 +297,7 @@ namespace AxibugEmuOnline.Client.Settings
                 settingList[settingSlot] = key;
             }
 
-            public InputDevice.InputControl GetBinding(T emuBtn, InputDevice device, int settingSlot)
+            public InputControl GetBinding(T emuBtn, InputDevice device, int settingSlot)
             {
                 m_mapSetting.TryGetValue(device, out var mapSetting);
                 if (mapSetting == null) return null;
@@ -308,8 +308,8 @@ namespace AxibugEmuOnline.Client.Settings
                 return settingList[settingSlot];
             }
 
-            private List<InputDevice.InputControl> m_caches = new List<InputDevice.InputControl>();
-            public IEnumerable<InputDevice.InputControl> GetBinding(T emuBtn)
+            private List<InputControl> m_caches = new List<InputControl>();
+            public IEnumerable<InputControl> GetBinding(T emuBtn)
             {
                 m_caches.Clear();
 
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/Button.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/Button.cs
new file mode 100644
index 00000000..cc166856
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/Button.cs
@@ -0,0 +1,17 @@
+namespace AxibugEmuOnline.Client.InputDevices
+{
+    /// <summary>
+    /// 按键类型的输入控件
+    /// </summary>
+    public class Button : InputControl
+    {
+        string m_controlName;
+
+        public Button(InputDevice device, string controlName) : base(device)
+        {
+            m_controlName = controlName;
+        }
+
+        public override string ControlName => m_controlName;
+    }
+}
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/InputControl.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/InputControl.cs
new file mode 100644
index 00000000..9f8f811d
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/InputControl.cs
@@ -0,0 +1,59 @@
+using UnityEngine;
+
+namespace AxibugEmuOnline.Client.InputDevices
+{
+    /// <summary>
+    /// 输入设备的抽象控件接口
+    /// </summary>
+    public abstract class InputControl
+    {
+        /// <summary> 控件所属设备 </summary>
+        public InputDevice 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() { }
+
+        /// <summary> 控件名,这个控件名称必须是唯一的 </summary>
+        public abstract string ControlName { get; }
+
+        internal InputControl(InputDevice device)
+        {
+            Device = device;
+        }
+    }
+}
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/Stick.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/Stick.cs
new file mode 100644
index 00000000..227647c6
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/Stick.cs
@@ -0,0 +1,70 @@
+using UnityEngine;
+
+namespace AxibugEmuOnline.Client.InputDevices
+{
+    /// <summary>
+    /// 摇杆类型的输入控件,支持的返回值为Vector2
+    /// </summary>
+    public class Stick : InputControl
+    {
+        string m_controlName;
+        public override string ControlName => m_controlName;
+
+        public VirtualButton UP { get; private set; }
+        public VirtualButton Down { get; private set; }
+        public VirtualButton Left { get; private set; }
+        public VirtualButton Right { get; private set; }
+
+        public Stick(InputDevice device, string controlName) : base(device)
+        {
+            m_controlName = controlName;
+
+            UP = new VirtualButton(device);
+            Down = new VirtualButton(device);
+            Left = new VirtualButton(device);
+            Right = new VirtualButton(device);
+        }
+
+        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
+        {
+            internal bool m_performing;
+
+            public VirtualButton(InputDevice device) : base(device) { }
+
+            public override bool Performing
+            {
+                get => m_performing;
+            }
+
+            public override Vector2 GetVector2()
+            {
+                return default;
+            }
+
+            public override float GetFlaot()
+            {
+                return Performing ? 1 : 0;
+            }
+
+            public override string ControlName => "VirtualStickButton";
+        }
+    }
+}
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputDevice.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputDevice.cs
new file mode 100644
index 00000000..e8f17bc6
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputDevice.cs
@@ -0,0 +1,56 @@
+using System.Collections.Generic;
+
+namespace AxibugEmuOnline.Client.InputDevices
+{
+    public abstract class InputDevice
+    {
+        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> m_controlMapper = new Dictionary<string, InputControl>();
+        protected InputResolver m_resolver;
+        public InputDevice(InputResolver resolver)
+        {
+            m_resolver = resolver;
+
+            foreach (var control in DefineControls())
+            {
+                m_controlMapper.Add(control.ControlName, control);
+            }
+        }
+
+        public void Update()
+        {
+            AnyKeyDown = false;
+
+            foreach (var control in m_controlMapper.Values)
+            {
+                control.Update();
+                if (control.Start)
+                {
+                    AnyKeyDown = true;
+                }
+            }
+        }
+
+        /// <summary> 用于列出这个输入设备的所有输入控件实例 </summary>
+        /// <returns></returns>
+        protected abstract List<InputControl> DefineControls();
+
+        /// <summary> 通过控件名称,找到对应的控件 </summary>
+        /// <param name="keyName"></param>
+        /// <returns></returns>
+        public InputControl FindControlByName(string controlName)
+        {
+            m_controlMapper.TryGetValue(controlName, out var key);
+            return key;
+        }
+
+    }
+}
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/Keyboard.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/Keyboard.cs
index 5daa7d32..a85464a2 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/Keyboard.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/Keyboard.cs
@@ -23,17 +23,15 @@ namespace AxibugEmuOnline.Client.InputDevices
             return keys;
         }
 
-        public class KeyboardKey : InputControl
+        public class KeyboardKey : Button
         {
             internal KeyCode m_keycode;
 
             internal KeyboardKey(KeyCode listenKey, KeyBoard keyboard)
-                : base(keyboard)
+                : base(keyboard, listenKey.ToString())
             {
                 m_keycode = listenKey;
             }
-
-            public override string ControlName => m_keycode.ToString();
         }
     }
 
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/PSVController.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/PSVController.cs
index 7b037956..9ebbbf72 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/PSVController.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/PSVController.cs
@@ -1,5 +1,4 @@
 using System.Collections.Generic;
-using UnityEngine;
 
 namespace AxibugEmuOnline.Client.InputDevices
 {
@@ -46,82 +45,10 @@ namespace AxibugEmuOnline.Client.InputDevices
             Down = new Button(this, "DOWN");
             Left = new Button(this, "LEFT");
 
+            LeftStick = new Stick(this, nameof(LeftStick));
+            RightStick = new Stick(this, nameof(RightStick));
+
             return result;
         }
-
-        public class Button : InputControl
-        {
-            internal string m_controlName;
-
-            public Button(InputDevice device, string controlName) : base(device)
-            {
-                m_controlName = controlName;
-            }
-
-            public override string ControlName => m_controlName;
-        }
-
-        public class Stick : InputControl
-        {
-            internal bool m_left;
-
-            public VirtualButton UP { get; private set; }
-            public VirtualButton Down { get; private set; }
-            public VirtualButton Left { get; private set; }
-            public VirtualButton Right { get; private set; }
-
-            public Stick(InputDevice device, bool left) : base(device)
-            {
-                m_left = left;
-
-                UP = new VirtualButton(device);
-                Down = new VirtualButton(device);
-                Left = new VirtualButton(device);
-                Right = new VirtualButton(device);
-            }
-
-            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 override string ControlName => $"{nameof(Stick)}_{(m_left ? "left" : "right")}";
-
-            public class VirtualButton : InputControl
-            {
-                internal bool m_performing;
-
-                public VirtualButton(InputDevice device) : base(device) { }
-
-                public override bool Performing
-                {
-                    get => m_performing;
-                }
-
-                public override Vector2 GetVector2()
-                {
-                    return default;
-                }
-
-                public override float GetFlaot()
-                {
-                    return Performing ? 1 : 0;
-                }
-
-                public override string ControlName => "VirtualStickButton";
-            }
-        }
     }
 }
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/DualWayDictionary.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/DualWayDictionary.cs
similarity index 100%
rename from AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/DualWayDictionary.cs
rename to AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/DualWayDictionary.cs
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/DualWayDictionary.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/DualWayDictionary.cs.meta
similarity index 100%
rename from AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/DualWayDictionary.cs.meta
rename to AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/DualWayDictionary.cs.meta
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs
index b4fff468..7dc4e2de 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs
@@ -62,111 +62,4 @@ namespace AxibugEmuOnline.Client.InputDevices
             foreach (var device in m_devices.Values) device.Update();
         }
     }
-
-    public abstract class InputDevice
-    {
-        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> m_controlMapper = new Dictionary<string, InputControl>();
-        protected InputResolver m_resolver;
-        public InputDevice(InputResolver resolver)
-        {
-            m_resolver = resolver;
-
-            foreach (var control in DefineControls())
-            {
-                m_controlMapper.Add(control.ControlName, control);
-            }
-        }
-
-        public void Update()
-        {
-            AnyKeyDown = false;
-
-            foreach (var control in m_controlMapper.Values)
-            {
-                control.Update();
-                if (control.Start)
-                {
-                    AnyKeyDown = true;
-                }
-            }
-        }
-
-        /// <summary> 用于列出这个输入设备的所有输入控件实例 </summary>
-        /// <returns></returns>
-        protected abstract List<InputControl> DefineControls();
-
-        /// <summary> 通过控件名称,找到对应的控件 </summary>
-        /// <param name="keyName"></param>
-        /// <returns></returns>
-        public InputControl FindControlByName(string controlName)
-        {
-            m_controlMapper.TryGetValue(controlName, out var key);
-            return key;
-        }
-
-        /// <summary>
-        /// 输入设备的抽象控件接口
-        /// </summary>
-        public abstract class InputControl
-        {
-            /// <summary> 控件所属设备 </summary>
-            public InputDevice 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() { }
-
-            /// <summary> 控件名,这个控件名称必须是唯一的 </summary>
-            public abstract string ControlName { get; }
-
-            internal InputControl(InputDevice device)
-            {
-                Device = device;
-            }
-        }
-
-    }
 }
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputResolver.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputResolver.cs
index 390eafbd..80692459 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputResolver.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputResolver.cs
@@ -56,9 +56,9 @@ namespace AxibugEmuOnline.Client.InputDevices
             OnDeviceConnected?.Invoke(connectDevice);
         }
 
-        public abstract bool CheckPerforming<CONTROLLER>(CONTROLLER control) where CONTROLLER : InputDevice.InputControl;
-        public abstract Vector2 GetVector2<CONTROLLER>(CONTROLLER control) where CONTROLLER : InputDevice.InputControl;
-        public abstract float GetFloat<CONTROLLER>(CONTROLLER control) where CONTROLLER : InputDevice.InputControl;
+        public abstract bool CheckPerforming<CONTROLLER>(CONTROLLER control) where CONTROLLER : InputControl;
+        public abstract Vector2 GetVector2<CONTROLLER>(CONTROLLER control) where CONTROLLER : InputControl;
+        public abstract float GetFloat<CONTROLLER>(CONTROLLER control) where CONTROLLER : InputControl;
         /// <summary>
         /// 获得输入设备的唯一名称
         /// </summary>
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs
index 49a03c53..9e121552 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs
@@ -1,7 +1,6 @@
 #if ENABLE_INPUT_SYSTEM
 using System.Collections.Generic;
 using UnityEngine;
-using UnityEngine.InputSystem;
 using UnityEngine.InputSystem.Controls;
 using IP = UnityEngine.InputSystem.InputSystem;
 using IPDevice = UnityEngine.InputSystem.InputDevice;
@@ -9,8 +8,8 @@ using IPKeyboard = UnityEngine.InputSystem.Keyboard;
 
 namespace AxibugEmuOnline.Client.InputDevices.ForInputSystem
 {
-    /// <summary> InputSystem对接类 </summary>
-    public partial class InputSystemResolver : InputResolver
+    /// <summary> 基于UnityInputSystem实现的输入解决器 </summary>
+    public class InputSystemResolver : InputResolver
     {
         DualWayDictionary<IPDevice, InputDevice> m_devices = new DualWayDictionary<IPDevice, InputDevice>();
 
@@ -101,10 +100,7 @@ namespace AxibugEmuOnline.Client.InputDevices.ForInputSystem
         {
             throw new System.NotImplementedException();
         }
-    }
 
-    public partial class InputSystemResolver : InputResolver
-    {
         static ButtonControl GetIPKeyboardKey(IPKeyboard keyboard, KeyCode key)
         {
             switch (key)
@@ -228,6 +224,7 @@ namespace AxibugEmuOnline.Client.InputDevices.ForInputSystem
                     throw new System.NotImplementedException($"Not Find KeyCode Mapper Code from {key}");
             }
         }
+
     }
 }
 #endif
\ 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
index 1c7ee738..6f95e0b2 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/PSVResolver.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/PSVResolver.cs
@@ -1,11 +1,9 @@
-using NUnit.Framework.Internal;
-using System.Collections.Generic;
+using System.Collections.Generic;
 using UnityEngine;
-using static Essgee.Emulation.Audio.DMGAudio;
-using static VirtualNes.Core.APU_INTERNAL;
 
 namespace AxibugEmuOnline.Client.InputDevices.ForPSV
 {
+    /// <summary> PSV特化输入解决器,只能用于PSV平台,并且只支持PSV控制器 </summary>
     public class PSVResolver : InputResolver
     {
         List<InputDevice> m_devices = new List<InputDevice>();
@@ -38,24 +36,21 @@ namespace AxibugEmuOnline.Client.InputDevices.ForPSV
         {
             if (control.Device is PSVController psvCon)
             {
-                if (control is PSVController.Button button)
+                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)
                 {
-                    if (button == psvCon.Cross) return Input.GetKey(KeyCode.Joystick1Button0);
-                    else if (button == psvCon.Circle) return Input.GetKey(KeyCode.Joystick1Button1);
-                    else if (button == psvCon.Square) return Input.GetKey(KeyCode.Joystick1Button2);
-                    else if (button == psvCon.Triangle) return Input.GetKey(KeyCode.Joystick1Button3);
-                    else if (button == psvCon.L) return Input.GetKey(KeyCode.Joystick1Button4);
-                    else if (button == psvCon.R) return Input.GetKey(KeyCode.Joystick1Button5);
-                    else if (button == psvCon.Select) return Input.GetKey(KeyCode.Joystick1Button6);
-                    else if (button == psvCon.Start) return Input.GetKey(KeyCode.Joystick1Button7);
-                    else if (button == psvCon.Up) return Input.GetKey(KeyCode.Joystick1Button8);
-                    else if (button == psvCon.Right) return Input.GetKey(KeyCode.Joystick1Button9);
-                    else if (button == psvCon.Down) return Input.GetKey(KeyCode.Joystick1Button10);
-                    else if (button == psvCon.Left) return Input.GetKey(KeyCode.Joystick1Button11);
-                }
-                else if (control is PSVController.Stick stick)
-                {
-                    var vec2 = stick.GetVector2();
+                    var vec2 = control.GetVector2();
                     return vec2.x != 0 || vec2.y != 0;
                 }
             }
@@ -65,24 +60,15 @@ namespace AxibugEmuOnline.Client.InputDevices.ForPSV
 
         public override Vector2 GetVector2<CONTROLLER>(CONTROLLER control)
         {
-            if (control.Device is PSVController)
+            if (control.Device is PSVController psvCon)
             {
-                if (control is PSVController.Stick stick)
+                if (control == psvCon.LeftStick)
                 {
-                    Vector2 result = Vector2.zero;
-
-                    if (stick.m_left)
-                    {
-                        result.x = Input.GetAxis("Joy1 Axis X");
-                        result.y = Input.GetAxis("Joy1 Axis Y");
-                    }
-                    else
-                    {
-                        result.x = Input.GetAxis("Joy1 Axis 4");
-                        result.y = Input.GetAxis("Joy1 Axis 5");
-                    }
-
-                    return result;
+                    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"));
                 }
             }
 

From 50e3a30f3178edbada54b1f4ec0ac4c573c5e8a2 Mon Sep 17 00:00:00 2001
From: "ALIENJACK\\alien" <alienjack@foxmail.com>
Date: Thu, 27 Mar 2025 15:02:41 +0800
Subject: [PATCH 13/20] =?UTF-8?q?=E5=B0=86=E6=89=80=E6=9C=89=E6=8A=BD?=
 =?UTF-8?q?=E8=B1=A1=E5=B1=82Input=E7=9A=84=E7=B1=BB=E5=8A=A0=E4=B8=8A?=
 =?UTF-8?q?=E5=90=8E=E7=BC=80,D=E4=BB=A3=E8=A1=A8=E8=AE=BE=E5=A4=87,C?=
 =?UTF-8?q?=E4=BB=A3=E8=A1=A8=E6=8E=A7=E4=BB=B6,=E9=81=BF=E5=85=8D?=
 =?UTF-8?q?=E5=92=8CInputSystem=E4=B8=AD=E7=9A=84=E8=AE=BE=E5=A4=87?=
 =?UTF-8?q?=E9=87=8D=E5=90=8D?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../KeyMapperSetting/EssgeeKeyBinding.cs      | 14 ++---
 .../KeyMapperSetting/KeyMapperSetting.cs      | 40 +++++++-------
 .../KeyMapperSetting/MAMEKeyBinding.cs        |  4 +-
 .../KeyMapperSetting/NesKeyBinding.cs         |  4 +-
 .../KeyMapperSetting/XMBKeyBinding.cs         |  4 +-
 .../InputDevicesManager/Devices/GamePad_D.cs  | 34 ++++++++++++
 .../Devices/GamePad_D.cs.meta                 |  2 +
 .../Devices/InputControls.meta                |  8 +++
 .../InputControls/{Button.cs => Button_C.cs}  |  4 +-
 .../Devices/InputControls/Button_C.cs.meta    |  2 +
 .../{InputControl.cs => InputControl_D.cs}    |  6 +--
 .../InputControls/InputControl_D.cs.meta      |  2 +
 .../InputControls/{Stick.cs => Stick_C.cs}    |  8 +--
 .../Devices/InputControls/Stick_C.cs.meta     |  2 +
 .../{InputDevice.cs => InputDevice_D.cs}      | 10 ++--
 .../Devices/InputDevice_D.cs.meta             |  2 +
 .../Devices/{Keyboard.cs => Keyboard_D.cs}    | 14 ++---
 .../{Keyboard.cs.meta => Keyboard_D.cs.meta}  |  0
 .../Devices/PSVController.cs                  | 54 -------------------
 .../Devices/PSVController_D.cs                | 54 +++++++++++++++++++
 ...roller.cs.meta => PSVController_D.cs.meta} |  0
 .../InputDevicesManager.cs                    | 16 +++---
 .../InputResolver/InputResolver.cs            | 20 +++----
 .../InputResolver/InputSystemResolver.cs      | 35 ++++++------
 .../InputResolver/PSVResolver.cs              | 18 +++----
 25 files changed, 203 insertions(+), 154 deletions(-)
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/GamePad_D.cs
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/GamePad_D.cs.meta
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls.meta
 rename AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/{Button.cs => Button_C.cs} (67%)
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/Button_C.cs.meta
 rename AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/{InputControl.cs => InputControl_D.cs} (89%)
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/InputControl_D.cs.meta
 rename AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/{Stick.cs => Stick_C.cs} (83%)
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/Stick_C.cs.meta
 rename AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/{InputDevice.cs => InputDevice_D.cs} (79%)
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputDevice_D.cs.meta
 rename AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/{Keyboard.cs => Keyboard_D.cs} (94%)
 rename AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/{Keyboard.cs.meta => Keyboard_D.cs.meta} (100%)
 delete mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/PSVController.cs
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/PSVController_D.cs
 rename AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/{PSVController.cs.meta => PSVController_D.cs.meta} (100%)

diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/EssgeeKeyBinding.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/EssgeeKeyBinding.cs
index 5423edc2..9b7d9bdf 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/EssgeeKeyBinding.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/EssgeeKeyBinding.cs
@@ -22,9 +22,9 @@ namespace AxibugEmuOnline.Client.Settings
 
     public abstract class EssgeeKeyBinding : EmuCoreControllerKeyBinding<EssgeeSingleKey>
     {
-        protected override void OnRegistDevices(InputDevice device, BindingPage binding)
+        protected override void OnRegistDevices(InputDevice_D device, BindingPage binding)
         {
-            if (device is KeyBoard keyboard)
+            if (device is Keyboard_D keyboard)
             {
                 switch (binding.ControllerIndex)
                 {
@@ -54,7 +54,7 @@ namespace AxibugEmuOnline.Client.Settings
                         break;
                 }
             }
-            else if (device is PSVController psvCon && binding.ControllerIndex == 0)
+            else if (device is PSVController_D psvCon && binding.ControllerIndex == 0)
             {
                 binding.SetBinding(EssgeeSingleKey.OPTION_1, psvCon.Start, 0);
                 binding.SetBinding(EssgeeSingleKey.OPTION_2, psvCon.Select, 0);
@@ -98,9 +98,9 @@ namespace AxibugEmuOnline.Client.Settings
         public override RomPlatformType Platform => RomPlatformType.GameBoyColor;
         public override int ControllerCount => 1;
 
-        protected override void OnRegistDevices(InputDevice device, BindingPage binding)
+        protected override void OnRegistDevices(InputDevice_D device, BindingPage binding)
         {
-            if (device is KeyBoard keyboard)
+            if (device is Keyboard_D keyboard)
             {
                 switch (binding.ControllerIndex)
                 {
@@ -125,9 +125,9 @@ namespace AxibugEmuOnline.Client.Settings
         public override RomPlatformType Platform => RomPlatformType.GameBoy;
         public override int ControllerCount => 1;
 
-        protected override void OnRegistDevices(InputDevice device, BindingPage binding)
+        protected override void OnRegistDevices(InputDevice_D device, BindingPage binding)
         {
-            if (device is KeyBoard keyboard)
+            if (device is Keyboard_D keyboard)
             {
                 switch (binding.ControllerIndex)
                 {
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs
index bfb5a1ba..112e0c1c 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs
@@ -70,7 +70,7 @@ namespace AxibugEmuOnline.Client.Settings
                 m_bindingPages.Add(new BindingPage(i, this));
             }
 
-            var keyboard = App.input.GetDevice<KeyBoard>();
+            var keyboard = App.input.GetDevice<Keyboard_D>();
             if (keyboard != null)
             {
                 foreach (var binding in m_bindingPages)
@@ -79,7 +79,7 @@ namespace AxibugEmuOnline.Client.Settings
                 }
             }
 
-            var psvController = App.input.GetDevice<PSVController>();
+            var psvController = App.input.GetDevice<PSVController_D>();
             if (psvController != null)
             {
                 foreach (var binding in m_bindingPages)
@@ -92,9 +92,9 @@ namespace AxibugEmuOnline.Client.Settings
             App.input.OnDeviceConnected += InputDevicesMgr_OnDeviceConnected;
         }
 
-        private void InputDevicesMgr_OnDeviceConnected(InputDevice connectDevice)
+        private void InputDevicesMgr_OnDeviceConnected(InputDevice_D connectDevice)
         {
-            if (connectDevice is KeyBoard)
+            if (connectDevice is Keyboard_D)
             {
                 foreach (var binding in m_bindingPages)
                 {
@@ -103,15 +103,15 @@ namespace AxibugEmuOnline.Client.Settings
             }
         }
 
-        private void InputDevicesMgr_OnDeviceLost(InputDevice lostDevice)
+        private void InputDevicesMgr_OnDeviceLost(InputDevice_D lostDevice)
         {
             foreach (var binding in m_bindingPages)
             {
                 binding.UnregistInputDevice(lostDevice);
             }
-            if (lostDevice is KeyBoard) //键盘丢失,立即查找还存在的键盘并建立连接
+            if (lostDevice is Keyboard_D) //键盘丢失,立即查找还存在的键盘并建立连接
             {
-                var anotherKeyboard = App.input.GetDevice<KeyBoard>();
+                var anotherKeyboard = App.input.GetDevice<Keyboard_D>();
                 if (anotherKeyboard != null)
                 {
                     foreach (var binding in m_bindingPages)
@@ -127,11 +127,11 @@ namespace AxibugEmuOnline.Client.Settings
             return Enum.GetValues(typeof(T)).Cast<T>();
         }
 
-        internal void RaiseDeviceRegist(InputDevice device, BindingPage binding)
+        internal void RaiseDeviceRegist(InputDevice_D device, BindingPage binding)
         {
             OnRegistDevices(device, binding);
         }
-        protected abstract void OnRegistDevices(InputDevice device, BindingPage binding);
+        protected abstract void OnRegistDevices(InputDevice_D device, BindingPage binding);
 
         public bool Start(T emuControl, int controllerIndex)
         {
@@ -232,12 +232,12 @@ namespace AxibugEmuOnline.Client.Settings
             else return totalFloat / totalControl;
         }
 
-        public class MapSetting : Dictionary<T, List<InputControl>> { }
+        public class MapSetting : Dictionary<T, List<InputControl_D>> { }
 
         public class BindingPage
         {
-            Dictionary<Type, InputDevice> m_registedDevices = new Dictionary<Type, InputDevice>();
-            Dictionary<InputDevice, MapSetting> m_mapSetting = new Dictionary<InputDevice, MapSetting>();
+            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 EmuCoreControllerKeyBinding<T> Host { get; }
@@ -248,7 +248,7 @@ namespace AxibugEmuOnline.Client.Settings
                 Host = host;
             }
 
-            internal bool IsRegisted<DEVICE>() where DEVICE : InputDevice
+            internal bool IsRegisted<DEVICE>() where DEVICE : InputDevice_D
             {
                 var type = typeof(T);
                 return IsRegisted(type);
@@ -258,7 +258,7 @@ namespace AxibugEmuOnline.Client.Settings
                 return m_registedDevices.ContainsKey(deviceType);
             }
 
-            internal void RegistInputDevice(InputDevice device)
+            internal void RegistInputDevice(InputDevice_D device)
             {
                 var type = device.GetType();
                 if (IsRegisted(type)) return;
@@ -268,7 +268,7 @@ namespace AxibugEmuOnline.Client.Settings
                 Host.RaiseDeviceRegist(device, this);
             }
 
-            internal void UnregistInputDevice(InputDevice device)
+            internal void UnregistInputDevice(InputDevice_D device)
             {
                 var type = device.GetType();
                 if (!IsRegisted(type)) return;
@@ -277,7 +277,7 @@ namespace AxibugEmuOnline.Client.Settings
                 m_mapSetting.Remove(device);
             }
 
-            public void SetBinding(T emuBtn, InputControl key, int settingSlot)
+            public void SetBinding(T emuBtn, InputControl_D key, int settingSlot)
             {
                 var device = key.Device;
                 m_registedDevices.TryGetValue(device.GetType(), out var inputDevice);
@@ -287,7 +287,7 @@ namespace AxibugEmuOnline.Client.Settings
                 var setting = m_mapSetting[inputDevice];
                 if (!setting.TryGetValue(emuBtn, out var settingList))
                 {
-                    settingList = new List<InputControl>();
+                    settingList = new List<InputControl_D>();
                     setting[emuBtn] = settingList;
                 }
 
@@ -297,7 +297,7 @@ namespace AxibugEmuOnline.Client.Settings
                 settingList[settingSlot] = key;
             }
 
-            public InputControl GetBinding(T emuBtn, InputDevice device, int settingSlot)
+            public InputControl_D GetBinding(T emuBtn, InputDevice_D device, int settingSlot)
             {
                 m_mapSetting.TryGetValue(device, out var mapSetting);
                 if (mapSetting == null) return null;
@@ -308,8 +308,8 @@ namespace AxibugEmuOnline.Client.Settings
                 return settingList[settingSlot];
             }
 
-            private List<InputControl> m_caches = new List<InputControl>();
-            public IEnumerable<InputControl> GetBinding(T emuBtn)
+            private List<InputControl_D> m_caches = new List<InputControl_D>();
+            public IEnumerable<InputControl_D> GetBinding(T emuBtn)
             {
                 m_caches.Clear();
 
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/MAMEKeyBinding.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/MAMEKeyBinding.cs
index 5fe780ab..8631ad58 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/MAMEKeyBinding.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/MAMEKeyBinding.cs
@@ -23,9 +23,9 @@ namespace AxibugEmuOnline.Client.Settings
     {
         public override int ControllerCount => 4;
 
-        protected override void OnRegistDevices(InputDevice device, BindingPage binding)
+        protected override void OnRegistDevices(InputDevice_D device, BindingPage binding)
         {
-            if (device is KeyBoard keyboard)
+            if (device is Keyboard_D keyboard)
             {
                 switch (binding.ControllerIndex)
                 {
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/NesKeyBinding.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/NesKeyBinding.cs
index 6c9d83ab..3ab0e60e 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/NesKeyBinding.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/NesKeyBinding.cs
@@ -9,9 +9,9 @@ namespace AxibugEmuOnline.Client.Settings
         public override RomPlatformType Platform => RomPlatformType.Nes;
         public override int ControllerCount => 4;
 
-        protected override void OnRegistDevices(InputDevice device, BindingPage binding)
+        protected override void OnRegistDevices(InputDevice_D device, BindingPage binding)
         {
-            if (device is KeyBoard keyboard)
+            if (device is Keyboard_D keyboard)
             {
                 switch (binding.ControllerIndex)
                 {
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/XMBKeyBinding.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/XMBKeyBinding.cs
index aa8e06fc..caec9054 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/XMBKeyBinding.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/XMBKeyBinding.cs
@@ -9,9 +9,9 @@ namespace AxibugEmuOnline.Client
         public override RomPlatformType Platform => RomPlatformType.Invalid;
         public override int ControllerCount => 2;
 
-        protected override void OnRegistDevices(InputDevice device, BindingPage binding)
+        protected override void OnRegistDevices(InputDevice_D device, BindingPage binding)
         {
-            if (device is KeyBoard keyboard)
+            if (device is Keyboard_D keyboard)
             {
                 switch (binding.ControllerIndex)
                 {
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..6bb15a6d
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/GamePad_D.cs
@@ -0,0 +1,34 @@
+using System.Collections.Generic;
+
+namespace AxibugEmuOnline.Client.InputDevices
+{
+    /// <summary>
+    /// 通用游戏控制器
+    /// </summary>
+    public class GamePad_D : InputDevice_D
+    {
+        public Button_C Up { get; private set; }
+        public Button_C Down { get; private set; }
+        public Button_C Left { get; private set; }
+        public Button_C Right { get; private set; }
+        public Button_C Option { get; private set; }
+        public Button_C Start { get; private set; }
+        public Button_C North { get; private set; }
+        public Button_C South { get; private set; }
+        public Button_C West { get; private set; }
+        public Button_C East { get; private set; }
+        public Button_C LeftShoulder { get; private set; }
+        public Button_C RightShoulder { get; private set; }
+        public Button_C LeftTrigger { get; private set; }
+        public Button_C RightTrigger { get; private set; }
+
+        public GamePad_D(InputResolver resolver) : base(resolver) { }
+
+        protected override List<InputControl_D> DefineControls()
+        {
+            throw new System.NotImplementedException();
+        }
+
+
+    }
+}
\ 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.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/Button_C.cs
similarity index 67%
rename from AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/Button.cs
rename to AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/Button_C.cs
index cc166856..521d34ec 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/Button.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/Button_C.cs
@@ -3,11 +3,11 @@
     /// <summary>
     /// 按键类型的输入控件
     /// </summary>
-    public class Button : InputControl
+    public class Button_C : InputControl_D
     {
         string m_controlName;
 
-        public Button(InputDevice device, string controlName) : base(device)
+        public Button_C(InputDevice_D device, string controlName) : base(device)
         {
             m_controlName = 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.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/InputControl_D.cs
similarity index 89%
rename from AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/InputControl.cs
rename to AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/InputControl_D.cs
index 9f8f811d..bcd70e18 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/InputControl.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/InputControl_D.cs
@@ -5,10 +5,10 @@ namespace AxibugEmuOnline.Client.InputDevices
     /// <summary>
     /// 输入设备的抽象控件接口
     /// </summary>
-    public abstract class InputControl
+    public abstract class InputControl_D
     {
         /// <summary> 控件所属设备 </summary>
-        public InputDevice Device { get; internal set; }
+        public InputDevice_D Device { get; internal set; }
 
         /// <summary> 获取该控件是否在当前调用帧被激发 </summary>
         public bool Start { get; private set; }
@@ -51,7 +51,7 @@ namespace AxibugEmuOnline.Client.InputDevices
         /// <summary> 控件名,这个控件名称必须是唯一的 </summary>
         public abstract string ControlName { get; }
 
-        internal InputControl(InputDevice device)
+        internal InputControl_D(InputDevice_D device)
         {
             Device = device;
         }
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/InputControl_D.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/InputControl_D.cs.meta
new file mode 100644
index 00000000..f5b08af4
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/InputControl_D.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.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/Stick_C.cs
similarity index 83%
rename from AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/Stick.cs
rename to AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/Stick_C.cs
index 227647c6..225da4c3 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/Stick.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/Stick_C.cs
@@ -5,7 +5,7 @@ namespace AxibugEmuOnline.Client.InputDevices
     /// <summary>
     /// 摇杆类型的输入控件,支持的返回值为Vector2
     /// </summary>
-    public class Stick : InputControl
+    public class Stick_C : InputControl_D
     {
         string m_controlName;
         public override string ControlName => m_controlName;
@@ -15,7 +15,7 @@ namespace AxibugEmuOnline.Client.InputDevices
         public VirtualButton Left { get; private set; }
         public VirtualButton Right { get; private set; }
 
-        public Stick(InputDevice device, string controlName) : base(device)
+        public Stick_C(InputDevice_D device, string controlName) : base(device)
         {
             m_controlName = controlName;
 
@@ -43,11 +43,11 @@ namespace AxibugEmuOnline.Client.InputDevices
         }
 
 
-        public class VirtualButton : InputControl
+        public class VirtualButton : InputControl_D
         {
             internal bool m_performing;
 
-            public VirtualButton(InputDevice device) : base(device) { }
+            public VirtualButton(InputDevice_D device) : base(device) { }
 
             public override bool Performing
             {
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.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputDevice_D.cs
similarity index 79%
rename from AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputDevice.cs
rename to AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputDevice_D.cs
index e8f17bc6..402df819 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputDevice.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputDevice_D.cs
@@ -2,7 +2,7 @@
 
 namespace AxibugEmuOnline.Client.InputDevices
 {
-    public abstract class InputDevice
+    public abstract class InputDevice_D
     {
         public string UniqueName => m_resolver.GetDeviceName(this);
 
@@ -13,9 +13,9 @@ namespace AxibugEmuOnline.Client.InputDevices
         /// <summary> 获得输入解决器 </summary>
         internal InputResolver Resolver => m_resolver;
 
-        protected Dictionary<string, InputControl> m_controlMapper = new Dictionary<string, InputControl>();
+        protected Dictionary<string, InputControl_D> m_controlMapper = new Dictionary<string, InputControl_D>();
         protected InputResolver m_resolver;
-        public InputDevice(InputResolver resolver)
+        public InputDevice_D(InputResolver resolver)
         {
             m_resolver = resolver;
 
@@ -41,12 +41,12 @@ namespace AxibugEmuOnline.Client.InputDevices
 
         /// <summary> 用于列出这个输入设备的所有输入控件实例 </summary>
         /// <returns></returns>
-        protected abstract List<InputControl> DefineControls();
+        protected abstract List<InputControl_D> DefineControls();
 
         /// <summary> 通过控件名称,找到对应的控件 </summary>
         /// <param name="keyName"></param>
         /// <returns></returns>
-        public InputControl FindControlByName(string controlName)
+        public InputControl_D FindControlByName(string controlName)
         {
             m_controlMapper.TryGetValue(controlName, out var key);
             return key;
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.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/Keyboard_D.cs
similarity index 94%
rename from AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/Keyboard.cs
rename to AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/Keyboard_D.cs
index a85464a2..34d41b59 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/Keyboard.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/Keyboard_D.cs
@@ -7,15 +7,15 @@ namespace AxibugEmuOnline.Client.InputDevices
     /// <summary>
     /// 通用键盘设备
     /// </summary>
-    public partial class KeyBoard : InputDevice
+    public partial class Keyboard_D : InputDevice_D
     {
         Dictionary<KeyCode, KeyboardKey> m_keyControllerMap = new Dictionary<KeyCode, KeyboardKey>();
 
-        public KeyBoard(InputResolver resolver) : base(resolver) { }
+        public Keyboard_D(InputResolver resolver) : base(resolver) { }
 
-        protected override List<InputControl> DefineControls()
+        protected override List<InputControl_D> DefineControls()
         {
-            var keys = s_keyboardKeys.Select(kc => new KeyboardKey(kc, this) as InputControl).ToList();
+            var keys = s_keyboardKeys.Select(kc => new KeyboardKey(kc, this) as InputControl_D).ToList();
             foreach (KeyboardKey key in keys)
             {
                 m_keyControllerMap.Add(key.m_keycode, key);
@@ -23,11 +23,11 @@ namespace AxibugEmuOnline.Client.InputDevices
             return keys;
         }
 
-        public class KeyboardKey : Button
+        public class KeyboardKey : Button_C
         {
             internal KeyCode m_keycode;
 
-            internal KeyboardKey(KeyCode listenKey, KeyBoard keyboard)
+            internal KeyboardKey(KeyCode listenKey, Keyboard_D keyboard)
                 : base(keyboard, listenKey.ToString())
             {
                 m_keycode = listenKey;
@@ -36,7 +36,7 @@ namespace AxibugEmuOnline.Client.InputDevices
     }
 
     #region HardCodeForKeyboard
-    public partial class KeyBoard : InputDevice
+    public partial class Keyboard_D : InputDevice_D
     {
         static readonly List<KeyCode> s_keyboardKeys = new List<KeyCode>
         {
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/Keyboard.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/Keyboard_D.cs.meta
similarity index 100%
rename from AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/Keyboard.cs.meta
rename to AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/Keyboard_D.cs.meta
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/PSVController.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/PSVController.cs
deleted file mode 100644
index 9ebbbf72..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/PSVController.cs
+++ /dev/null
@@ -1,54 +0,0 @@
-using System.Collections.Generic;
-
-namespace AxibugEmuOnline.Client.InputDevices
-{
-    public class PSVController : InputDevice
-    {
-        /// <summary> × </summary>
-        public Button Cross { get; private set; }
-        /// <summary> ○ </summary>
-        public Button Circle { get; private set; }
-        /// <summary> □ </summary>
-        public Button Square { get; private set; }
-        /// <summary> △ </summary>
-        public Button Triangle { get; private set; }
-        public Button L { get; private set; }
-        public Button R { get; private set; }
-        public Button Select { get; private set; }
-        public Button Start { get; private set; }
-        public Button Up { get; private set; }
-        public Button Right { get; private set; }
-        public Button Down { get; private set; }
-        public Button Left { get; private set; }
-        public Stick LeftStick { get; private set; }
-        public Stick RightStick { get; private set; }
-
-        public PSVController(InputResolver resolver) : base(resolver) { }
-
-        protected override List<InputControl> DefineControls()
-        {
-            List<InputControl> result = new List<InputControl>();
-
-            Cross = new Button(this, "X");
-            Circle = new Button(this, "⭕");
-            Square = new Button(this, "□");
-            Triangle = new Button(this, "△");
-
-            L = new Button(this, "L");
-            R = new Button(this, "R");
-
-            Select = new Button(this, "SELECT");
-            Start = new Button(this, "START");
-
-            Up = new Button(this, "UP");
-            Right = new Button(this, "RIGHT");
-            Down = new Button(this, "DOWN");
-            Left = new Button(this, "LEFT");
-
-            LeftStick = new Stick(this, nameof(LeftStick));
-            RightStick = new Stick(this, nameof(RightStick));
-
-            return result;
-        }
-    }
-}
\ 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..4d96be15
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/PSVController_D.cs
@@ -0,0 +1,54 @@
+using System.Collections.Generic;
+
+namespace AxibugEmuOnline.Client.InputDevices
+{
+    public class PSVController_D : InputDevice_D
+    {
+        /// <summary> × </summary>
+        public Button_C Cross { get; private set; }
+        /// <summary> ○ </summary>
+        public Button_C Circle { get; private set; }
+        /// <summary> □ </summary>
+        public Button_C Square { get; private set; }
+        /// <summary> △ </summary>
+        public Button_C Triangle { get; private set; }
+        public Button_C L { get; private set; }
+        public Button_C R { get; private set; }
+        public Button_C Select { get; private set; }
+        public Button_C Start { get; private set; }
+        public Button_C Up { get; private set; }
+        public Button_C Right { get; private set; }
+        public Button_C Down { get; private set; }
+        public Button_C Left { get; private set; }
+        public Stick_C LeftStick { get; private set; }
+        public Stick_C RightStick { get; private set; }
+
+        public PSVController_D(InputResolver resolver) : base(resolver) { }
+
+        protected override List<InputControl_D> DefineControls()
+        {
+            List<InputControl_D> result = new List<InputControl_D>();
+
+            Cross = new Button_C(this, "X");
+            Circle = new Button_C(this, "⭕");
+            Square = new Button_C(this, "□");
+            Triangle = new Button_C(this, "△");
+
+            L = new Button_C(this, "L");
+            R = new Button_C(this, "R");
+
+            Select = new Button_C(this, "SELECT");
+            Start = new Button_C(this, "START");
+
+            Up = new Button_C(this, "UP");
+            Right = new Button_C(this, "RIGHT");
+            Down = new Button_C(this, "DOWN");
+            Left = new Button_C(this, "LEFT");
+
+            LeftStick = new Stick_C(this, nameof(LeftStick));
+            RightStick = new Stick_C(this, nameof(RightStick));
+
+            return result;
+        }
+    }
+}
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/PSVController.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/PSVController_D.cs.meta
similarity index 100%
rename from AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/PSVController.cs.meta
rename to AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/PSVController_D.cs.meta
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs
index 7dc4e2de..0de419b2 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs
@@ -6,11 +6,11 @@ namespace AxibugEmuOnline.Client.InputDevices
     public class InputDevicesManager
     {
         InputResolver m_inputResolver = InputResolver.Create();
-        Dictionary<string, InputDevice> m_devices = new Dictionary<string, InputDevice>();
+        Dictionary<string, InputDevice_D> m_devices = new Dictionary<string, InputDevice_D>();
 
-        public delegate void OnDeviceConnectedHandle(InputDevice connectDevice);
+        public delegate void OnDeviceConnectedHandle(InputDevice_D connectDevice);
         public event OnDeviceConnectedHandle OnDeviceConnected;
-        public delegate void OnDeviceLostHandle(InputDevice lostDevice);
+        public delegate void OnDeviceLostHandle(InputDevice_D lostDevice);
         public event OnDeviceLostHandle OnDeviceLost;
 
         public InputDevicesManager()
@@ -21,23 +21,23 @@ namespace AxibugEmuOnline.Client.InputDevices
                 AddDevice(device);
         }
 
-        private void Resolver_OnDeviceLost(InputDevice lostDevice)
+        private void Resolver_OnDeviceLost(InputDevice_D lostDevice)
         {
             RemoveDevice(lostDevice);
         }
 
-        private void Resolver_OnDeviceConnected(InputDevice connectDevice)
+        private void Resolver_OnDeviceConnected(InputDevice_D connectDevice)
         {
             AddDevice(connectDevice);
         }
 
-        void AddDevice(InputDevice device)
+        void AddDevice(InputDevice_D device)
         {
             m_devices[device.UniqueName] = device;
             OnDeviceConnected?.Invoke(device);
         }
 
-        void RemoveDevice(InputDevice device)
+        void RemoveDevice(InputDevice_D device)
         {
             m_devices.Remove(device.UniqueName);
             OnDeviceLost?.Invoke(device);
@@ -46,7 +46,7 @@ namespace AxibugEmuOnline.Client.InputDevices
         /// <summary>
         /// 获得一个指定类型的设备
         /// </summary>
-        public T GetDevice<T>() where T : InputDevice
+        public T GetDevice<T>() where T : InputDevice_D
         {
             foreach (var d in m_devices.Values)
             {
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputResolver.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputResolver.cs
index 80692459..ee448e40 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputResolver.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputResolver.cs
@@ -30,40 +30,40 @@ namespace AxibugEmuOnline.Client.InputDevices
         /// 获得所有当前已连入的输入设备
         /// </summary>
         /// <returns></returns>
-        public abstract IEnumerable<InputDevice> GetDevices();
+        public abstract IEnumerable<InputDevice_D> GetDevices();
 
         /// <summary>
         /// 检查指定输入设备是否还保持着连接
         /// </summary>
         /// <returns></returns>
-        public abstract bool CheckOnline(InputDevice device);
+        public abstract bool CheckOnline(InputDevice_D device);
 
         /// <param name="lostDevice">丢失的设备</param>
-        public delegate void OnDeviceLostHandle(InputDevice lostDevice);
+        public delegate void OnDeviceLostHandle(InputDevice_D lostDevice);
         /// <summary> 当设备丢失时触发 </summary>
         public event OnDeviceLostHandle OnDeviceLost;
-        protected void RaiseDeviceLost(InputDevice lostDevice)
+        protected void RaiseDeviceLost(InputDevice_D lostDevice)
         {
             OnDeviceLost?.Invoke(lostDevice);
         }
 
         /// <param name="connectDevice">建立连接的设备</param>
-        public delegate void OnDeviceConnectedHandle(InputDevice connectDevice);
+        public delegate void OnDeviceConnectedHandle(InputDevice_D connectDevice);
         /// <summary> 当设备连接时触发 </summary>
         public event OnDeviceConnectedHandle OnDeviceConnected;
-        protected void RaiseDeviceConnected(InputDevice connectDevice)
+        protected void RaiseDeviceConnected(InputDevice_D connectDevice)
         {
             OnDeviceConnected?.Invoke(connectDevice);
         }
 
-        public abstract bool CheckPerforming<CONTROLLER>(CONTROLLER control) where CONTROLLER : InputControl;
-        public abstract Vector2 GetVector2<CONTROLLER>(CONTROLLER control) where CONTROLLER : InputControl;
-        public abstract float GetFloat<CONTROLLER>(CONTROLLER control) where CONTROLLER : InputControl;
+        public abstract bool CheckPerforming<CONTROLLER>(CONTROLLER control) where CONTROLLER : InputControl_D;
+        public abstract Vector2 GetVector2<CONTROLLER>(CONTROLLER control) where CONTROLLER : InputControl_D;
+        public abstract float GetFloat<CONTROLLER>(CONTROLLER control) where CONTROLLER : InputControl_D;
         /// <summary>
         /// 获得输入设备的唯一名称
         /// </summary>
         /// <param name="inputDevice">这个设备必须是由resolver提供,并且保持着连接</param>
         /// <returns></returns>
-        public abstract string GetDeviceName(InputDevice inputDevice);
+        public abstract string GetDeviceName(InputDevice_D inputDevice);
     }
 }
\ 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
index 9e121552..c8d96634 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs
@@ -1,30 +1,27 @@
 #if ENABLE_INPUT_SYSTEM
 using System.Collections.Generic;
 using UnityEngine;
+using UnityEngine.InputSystem;
 using UnityEngine.InputSystem.Controls;
-using IP = UnityEngine.InputSystem.InputSystem;
-using IPDevice = UnityEngine.InputSystem.InputDevice;
-using IPKeyboard = UnityEngine.InputSystem.Keyboard;
 
 namespace AxibugEmuOnline.Client.InputDevices.ForInputSystem
 {
     /// <summary> 基于UnityInputSystem实现的输入解决器 </summary>
     public class InputSystemResolver : InputResolver
     {
-        DualWayDictionary<IPDevice, InputDevice> m_devices = new DualWayDictionary<IPDevice, InputDevice>();
+        DualWayDictionary<InputDevice, InputDevice_D> m_devices = new DualWayDictionary<InputDevice, InputDevice_D>();
 
         protected override void OnInit()
         {
-            foreach (var device in IP.devices) AddDevice(device);
+            foreach (var device in InputSystem.devices) AddDevice(device);
 
-            IP.onDeviceChange += IP_onDeviceChange;
+            InputSystem.onDeviceChange += IP_onDeviceChange;
         }
 
-        private void AddDevice(IPDevice ipdev)
+        private void AddDevice(InputDevice ipdev)
         {
-            InputDevice newDevice = null;
-            if (ipdev is IPKeyboard) newDevice = new KeyBoard(this);
-
+            InputDevice_D newDevice = null;
+            if (ipdev is Keyboard) newDevice = new Keyboard_D(this);
             if (newDevice != null)
             {
                 m_devices.Add(ipdev, newDevice);
@@ -32,7 +29,7 @@ namespace AxibugEmuOnline.Client.InputDevices.ForInputSystem
             }
         }
 
-        private void RemoveDevice(IPDevice ipdev)
+        private void RemoveDevice(InputDevice ipdev)
         {
             if (m_devices.TryGetValue(ipdev, out var device))
             {
@@ -41,7 +38,7 @@ namespace AxibugEmuOnline.Client.InputDevices.ForInputSystem
             }
         }
 
-        public override string GetDeviceName(InputDevice inputDevice)
+        public override string GetDeviceName(InputDevice_D inputDevice)
         {
             m_devices.TryGetKey(inputDevice, out var ipdev);
             Debug.Assert(ipdev != null, "不能对已离线的设备获取名称");
@@ -49,12 +46,12 @@ namespace AxibugEmuOnline.Client.InputDevices.ForInputSystem
             return $"{ipdev.description.deviceClass}_{ipdev.description.interfaceName}_{ipdev.deviceId}";
         }
 
-        public override bool CheckOnline(InputDevice device)
+        public override bool CheckOnline(InputDevice_D device)
         {
             return m_devices.TryGetKey(device, out var _);
         }
 
-        private void IP_onDeviceChange(IPDevice device, UnityEngine.InputSystem.InputDeviceChange changeType)
+        private void IP_onDeviceChange(InputDevice device, UnityEngine.InputSystem.InputDeviceChange changeType)
         {
             switch (changeType)
             {
@@ -63,20 +60,20 @@ namespace AxibugEmuOnline.Client.InputDevices.ForInputSystem
             }
         }
 
-        public override IEnumerable<InputDevice> GetDevices()
+        public override IEnumerable<InputDevice_D> GetDevices()
         {
             return m_devices.Values;
         }
 
         public override bool CheckPerforming<CONTROLLER>(CONTROLLER control)
         {
-            if (control.Device is KeyBoard keyboard)
+            if (control.Device is Keyboard_D keyboard)
             {
-                if (control is KeyBoard.KeyboardKey key)
+                if (control is Keyboard_D.KeyboardKey key)
                 {
                     if (m_devices.TryGetKey(keyboard, out var ipdev))
                     {
-                        var ipKeyboard = ipdev as IPKeyboard;
+                        var ipKeyboard = ipdev as Keyboard;
                         if (ipKeyboard == null) return false;
 
                         var k = GetIPKeyboardKey(ipKeyboard, key.m_keycode);
@@ -101,7 +98,7 @@ namespace AxibugEmuOnline.Client.InputDevices.ForInputSystem
             throw new System.NotImplementedException();
         }
 
-        static ButtonControl GetIPKeyboardKey(IPKeyboard keyboard, KeyCode key)
+        static ButtonControl GetIPKeyboardKey(Keyboard keyboard, KeyCode key)
         {
             switch (key)
             {
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/PSVResolver.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/PSVResolver.cs
index 6f95e0b2..f97a973a 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/PSVResolver.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/PSVResolver.cs
@@ -6,35 +6,35 @@ namespace AxibugEmuOnline.Client.InputDevices.ForPSV
     /// <summary> PSV特化输入解决器,只能用于PSV平台,并且只支持PSV控制器 </summary>
     public class PSVResolver : InputResolver
     {
-        List<InputDevice> m_devices = new List<InputDevice>();
-        PSVController m_psvController;
+        List<InputDevice_D> m_devices = new List<InputDevice_D>();
+        PSVController_D m_psvController;
 
         protected override void OnInit()
         {
-            m_psvController = new PSVController(this);
+            m_psvController = new PSVController_D(this);
             m_devices.Add(m_psvController);
         }
 
-        public override IEnumerable<InputDevice> GetDevices()
+        public override IEnumerable<InputDevice_D> GetDevices()
         {
             return m_devices;
         }
 
-        public override bool CheckOnline(InputDevice device)
+        public override bool CheckOnline(InputDevice_D device)
         {
             return device == m_psvController;
         }
 
-        public override string GetDeviceName(InputDevice inputDevice)
+        public override string GetDeviceName(InputDevice_D inputDevice)
         {
             Debug.Assert(inputDevice == m_psvController, "只支持psv控制器");
 
-            return nameof(PSVController);
+            return nameof(PSVController_D);
         }
 
         public override bool CheckPerforming<CONTROLLER>(CONTROLLER control)
         {
-            if (control.Device is PSVController psvCon)
+            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);
@@ -60,7 +60,7 @@ namespace AxibugEmuOnline.Client.InputDevices.ForPSV
 
         public override Vector2 GetVector2<CONTROLLER>(CONTROLLER control)
         {
-            if (control.Device is PSVController psvCon)
+            if (control.Device is PSVController_D psvCon)
             {
                 if (control == psvCon.LeftStick)
                 {

From e463c23c4cbeb12934600289162106a4809e3fc2 Mon Sep 17 00:00:00 2001
From: "ALIENJACK\\alien" <alienjack@foxmail.com>
Date: Thu, 27 Mar 2025 19:19:05 +0800
Subject: [PATCH 14/20] =?UTF-8?q?Input=E9=80=BB=E8=BE=91=E7=BB=93=E6=9E=84?=
 =?UTF-8?q?=E8=B0=83=E6=95=B4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../KeyMapperSetting/KeyMapperSetting.cs      |  12 +-
 .../InputDevicesManager/Devices/GamePad_D.cs  |  43 ++-
 .../Devices/InputControls/Button_C.cs         |   9 +-
 .../{InputControl_D.cs => InputControl_C.cs}  |  44 ++-
 ...ntrol_D.cs.meta => InputControl_C.cs.meta} |   0
 .../Devices/InputControls/Stick_C.cs          |  27 +-
 .../Devices/InputDevice_D.cs                  |  32 +-
 .../InputDevicesManager/Devices/Keyboard_D.cs | 282 +++++++----------
 .../Devices/PSVController_D.cs                |  62 +---
 .../InputResolver/InputResolver.cs            |   6 +-
 .../InputResolver/InputSystemResolver.cs      | 284 +++++++++---------
 11 files changed, 358 insertions(+), 443 deletions(-)
 rename AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/{InputControl_D.cs => InputControl_C.cs} (56%)
 rename AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/{InputControl_D.cs.meta => InputControl_C.cs.meta} (100%)

diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs
index 112e0c1c..27d9e50a 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs
@@ -232,7 +232,7 @@ namespace AxibugEmuOnline.Client.Settings
             else return totalFloat / totalControl;
         }
 
-        public class MapSetting : Dictionary<T, List<InputControl_D>> { }
+        public class MapSetting : Dictionary<T, List<InputControl_C>> { }
 
         public class BindingPage
         {
@@ -277,7 +277,7 @@ namespace AxibugEmuOnline.Client.Settings
                 m_mapSetting.Remove(device);
             }
 
-            public void SetBinding(T emuBtn, InputControl_D key, int settingSlot)
+            public void SetBinding(T emuBtn, InputControl_C key, int settingSlot)
             {
                 var device = key.Device;
                 m_registedDevices.TryGetValue(device.GetType(), out var inputDevice);
@@ -287,7 +287,7 @@ namespace AxibugEmuOnline.Client.Settings
                 var setting = m_mapSetting[inputDevice];
                 if (!setting.TryGetValue(emuBtn, out var settingList))
                 {
-                    settingList = new List<InputControl_D>();
+                    settingList = new List<InputControl_C>();
                     setting[emuBtn] = settingList;
                 }
 
@@ -297,7 +297,7 @@ namespace AxibugEmuOnline.Client.Settings
                 settingList[settingSlot] = key;
             }
 
-            public InputControl_D GetBinding(T emuBtn, InputDevice_D device, int settingSlot)
+            public InputControl_C GetBinding(T emuBtn, InputDevice_D device, int settingSlot)
             {
                 m_mapSetting.TryGetValue(device, out var mapSetting);
                 if (mapSetting == null) return null;
@@ -308,8 +308,8 @@ namespace AxibugEmuOnline.Client.Settings
                 return settingList[settingSlot];
             }
 
-            private List<InputControl_D> m_caches = new List<InputControl_D>();
-            public IEnumerable<InputControl_D> GetBinding(T emuBtn)
+            private List<InputControl_C> m_caches = new List<InputControl_C>();
+            public IEnumerable<InputControl_C> GetBinding(T emuBtn)
             {
                 m_caches.Clear();
 
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
index 6bb15a6d..9792afa8 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/GamePad_D.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/GamePad_D.cs
@@ -1,34 +1,29 @@
-using System.Collections.Generic;
-
-namespace AxibugEmuOnline.Client.InputDevices
+namespace AxibugEmuOnline.Client.InputDevices
 {
     /// <summary>
     /// 通用游戏控制器
     /// </summary>
     public class GamePad_D : InputDevice_D
     {
-        public Button_C Up { get; private set; }
-        public Button_C Down { get; private set; }
-        public Button_C Left { get; private set; }
-        public Button_C Right { get; private set; }
-        public Button_C Option { get; private set; }
-        public Button_C Start { get; private set; }
-        public Button_C North { get; private set; }
-        public Button_C South { get; private set; }
-        public Button_C West { get; private set; }
-        public Button_C East { get; private set; }
-        public Button_C LeftShoulder { get; private set; }
-        public Button_C RightShoulder { get; private set; }
-        public Button_C LeftTrigger { get; private set; }
-        public Button_C RightTrigger { get; private set; }
+        public Button_C Up;
+        public Button_C Down;
+        public Button_C Left;
+        public Button_C Right;
+        public Button_C Option;
+        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) { }
-
-        protected override List<InputControl_D> DefineControls()
-        {
-            throw new System.NotImplementedException();
-        }
-
-
     }
 }
\ No newline at end of file
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
index 521d34ec..3eaaa7bd 100644
--- 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
@@ -3,15 +3,10 @@
     /// <summary>
     /// 按键类型的输入控件
     /// </summary>
-    public class Button_C : InputControl_D
+    public class Button_C : InputControl_C
     {
-        string m_controlName;
-
-        public Button_C(InputDevice_D device, string controlName) : base(device)
+        public Button_C(InputDevice_D device, string controlName) : base(device, controlName)
         {
-            m_controlName = controlName;
         }
-
-        public override string ControlName => m_controlName;
     }
 }
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/InputControl_D.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/InputControl_C.cs
similarity index 56%
rename from AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/InputControl_D.cs
rename to AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/InputControl_C.cs
index bcd70e18..ad1a5059 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/InputControl_D.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/InputControl_C.cs
@@ -1,11 +1,14 @@
-using UnityEngine;
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using UnityEngine;
 
 namespace AxibugEmuOnline.Client.InputDevices
 {
     /// <summary>
     /// 输入设备的抽象控件接口
     /// </summary>
-    public abstract class InputControl_D
+    public abstract class InputControl_C
     {
         /// <summary> 控件所属设备 </summary>
         public InputDevice_D Device { get; internal set; }
@@ -30,7 +33,6 @@ namespace AxibugEmuOnline.Client.InputDevices
             UpdateReleaseStartState();
             OnUpdate();
         }
-
         private void UpdateReleaseStartState()
         {
             var oldPerforming = m_performingLastFrame;
@@ -48,12 +50,42 @@ namespace AxibugEmuOnline.Client.InputDevices
 
         protected virtual void OnUpdate() { }
 
+        public InputControl_C Parent { get; private set; }
         /// <summary> 控件名,这个控件名称必须是唯一的 </summary>
-        public abstract string ControlName { get; }
-
-        internal InputControl_D(InputDevice_D device)
+        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, this, 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_D.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/InputControl_C.cs.meta
similarity index 100%
rename from AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/InputControl_D.cs.meta
rename to AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/InputControl_C.cs.meta
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
index 225da4c3..26cdf723 100644
--- 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
@@ -5,24 +5,15 @@ namespace AxibugEmuOnline.Client.InputDevices
     /// <summary>
     /// 摇杆类型的输入控件,支持的返回值为Vector2
     /// </summary>
-    public class Stick_C : InputControl_D
+    public class Stick_C : InputControl_C
     {
-        string m_controlName;
-        public override string ControlName => m_controlName;
+        public VirtualButton UP;
+        public VirtualButton Down;
+        public VirtualButton Left;
+        public VirtualButton Right;
 
-        public VirtualButton UP { get; private set; }
-        public VirtualButton Down { get; private set; }
-        public VirtualButton Left { get; private set; }
-        public VirtualButton Right { get; private set; }
-
-        public Stick_C(InputDevice_D device, string controlName) : base(device)
+        public Stick_C(InputDevice_D device, string controlName) : base(device, controlName)
         {
-            m_controlName = controlName;
-
-            UP = new VirtualButton(device);
-            Down = new VirtualButton(device);
-            Left = new VirtualButton(device);
-            Right = new VirtualButton(device);
         }
 
         protected override void OnUpdate()
@@ -43,11 +34,11 @@ namespace AxibugEmuOnline.Client.InputDevices
         }
 
 
-        public class VirtualButton : InputControl_D
+        public class VirtualButton : InputControl_C
         {
             internal bool m_performing;
 
-            public VirtualButton(InputDevice_D device) : base(device) { }
+            public VirtualButton(InputDevice_D device, string controlName) : base(device, controlName) { }
 
             public override bool Performing
             {
@@ -63,8 +54,6 @@ namespace AxibugEmuOnline.Client.InputDevices
             {
                 return Performing ? 1 : 0;
             }
-
-            public override string ControlName => "VirtualStickButton";
         }
     }
 }
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
index 402df819..b7d82bea 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputDevice_D.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputDevice_D.cs
@@ -1,4 +1,6 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
+using System.Reflection;
 
 namespace AxibugEmuOnline.Client.InputDevices
 {
@@ -13,15 +15,24 @@ namespace AxibugEmuOnline.Client.InputDevices
         /// <summary> 获得输入解决器 </summary>
         internal InputResolver Resolver => m_resolver;
 
-        protected Dictionary<string, InputControl_D> m_controlMapper = new Dictionary<string, InputControl_D>();
+        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();
+        }
 
-            foreach (var control in DefineControls())
+        private void DefineControls()
+        {
+            foreach (var field in GetType().GetFields(BindingFlags.Instance | BindingFlags.Public))
             {
-                m_controlMapper.Add(control.ControlName, control);
+                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;
             }
         }
 
@@ -39,18 +50,9 @@ namespace AxibugEmuOnline.Client.InputDevices
             }
         }
 
-        /// <summary> 用于列出这个输入设备的所有输入控件实例 </summary>
-        /// <returns></returns>
-        protected abstract List<InputControl_D> DefineControls();
-
-        /// <summary> 通过控件名称,找到对应的控件 </summary>
-        /// <param name="keyName"></param>
-        /// <returns></returns>
-        public InputControl_D FindControlByName(string controlName)
+        public override string ToString()
         {
-            m_controlMapper.TryGetValue(controlName, out var key);
-            return key;
+            return Resolver.GetDeviceName(this);
         }
-
     }
 }
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
index 34d41b59..35a28897 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/Keyboard_D.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/Keyboard_D.cs
@@ -1,190 +1,116 @@
 using System.Collections.Generic;
-using System.Linq;
-using UnityEngine;
 
 namespace AxibugEmuOnline.Client.InputDevices
 {
     /// <summary>
     /// 通用键盘设备
     /// </summary>
-    public partial class Keyboard_D : InputDevice_D
+    public class Keyboard_D : InputDevice_D
     {
-        Dictionary<KeyCode, KeyboardKey> m_keyControllerMap = new Dictionary<KeyCode, KeyboardKey>();
+        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) { }
-
-        protected override List<InputControl_D> DefineControls()
-        {
-            var keys = s_keyboardKeys.Select(kc => new KeyboardKey(kc, this) as InputControl_D).ToList();
-            foreach (KeyboardKey key in keys)
-            {
-                m_keyControllerMap.Add(key.m_keycode, key);
-            }
-            return keys;
-        }
-
-        public class KeyboardKey : Button_C
-        {
-            internal KeyCode m_keycode;
-
-            internal KeyboardKey(KeyCode listenKey, Keyboard_D keyboard)
-                : base(keyboard, listenKey.ToString())
-            {
-                m_keycode = listenKey;
-            }
-        }
     }
-
-    #region HardCodeForKeyboard
-    public partial class Keyboard_D : InputDevice_D
-    {
-        static readonly List<KeyCode> s_keyboardKeys = new List<KeyCode>
-        {
-            // 字母键 A-Z
-            KeyCode.A, KeyCode.B, KeyCode.C, KeyCode.D, KeyCode.E, KeyCode.F, KeyCode.G,
-            KeyCode.H, KeyCode.I, KeyCode.J, KeyCode.K, KeyCode.L, KeyCode.M, KeyCode.N,
-            KeyCode.O, KeyCode.P, KeyCode.Q, KeyCode.R, KeyCode.S, KeyCode.T, KeyCode.U,
-            KeyCode.V, KeyCode.W, KeyCode.X, KeyCode.Y, KeyCode.Z,
-
-            // 数字键 0-9
-            KeyCode.Alpha0, KeyCode.Alpha1, KeyCode.Alpha2, KeyCode.Alpha3, KeyCode.Alpha4,
-            KeyCode.Alpha5, KeyCode.Alpha6, KeyCode.Alpha7, KeyCode.Alpha8, KeyCode.Alpha9,
-
-            // 功能键 F1-F15
-            KeyCode.F1, KeyCode.F2, KeyCode.F3, KeyCode.F4, KeyCode.F5, KeyCode.F6,
-            KeyCode.F7, KeyCode.F8, KeyCode.F9, KeyCode.F10, KeyCode.F11, KeyCode.F12,
-
-            // 方向键
-            KeyCode.UpArrow, KeyCode.DownArrow, KeyCode.LeftArrow, KeyCode.RightArrow,
-
-            // 控制键
-            KeyCode.Space, KeyCode.Return, KeyCode.Escape, KeyCode.Tab, KeyCode.Backspace,
-            KeyCode.CapsLock, KeyCode.LeftShift, KeyCode.RightShift, KeyCode.LeftControl,
-            KeyCode.RightControl, KeyCode.LeftAlt, KeyCode.RightAlt, KeyCode.LeftCommand,
-            KeyCode.RightCommand,
-
-            // 符号键
-            KeyCode.Comma, KeyCode.Period, KeyCode.Slash, KeyCode.BackQuote, KeyCode.Quote,
-            KeyCode.Semicolon, KeyCode.LeftBracket, KeyCode.RightBracket, KeyCode.Backslash,
-            KeyCode.Minus, KeyCode.Equals, 
-
-            // 小键盘
-            KeyCode.Keypad0, KeyCode.Keypad1, KeyCode.Keypad2, KeyCode.Keypad3, KeyCode.Keypad4,
-            KeyCode.Keypad5, KeyCode.Keypad6, KeyCode.Keypad7, KeyCode.Keypad8, KeyCode.Keypad9,
-            KeyCode.KeypadPeriod, KeyCode.KeypadDivide, KeyCode.KeypadMultiply,
-            KeyCode.KeypadMinus, KeyCode.KeypadPlus, KeyCode.KeypadEnter, KeyCode.Numlock,
-
-            // 其他标准键
-            KeyCode.Print,  KeyCode.Insert, KeyCode.Delete, KeyCode.Home,
-            KeyCode.End, KeyCode.PageUp, KeyCode.PageDown, KeyCode.Pause, KeyCode.ScrollLock,
-        };
-
-        public KeyboardKey A => m_keyControllerMap[KeyCode.A];
-        public KeyboardKey B => m_keyControllerMap[KeyCode.B];
-        public KeyboardKey C => m_keyControllerMap[KeyCode.C];
-        public KeyboardKey D => m_keyControllerMap[KeyCode.D];
-        public KeyboardKey E => m_keyControllerMap[KeyCode.E];
-        public KeyboardKey F => m_keyControllerMap[KeyCode.F];
-        public KeyboardKey G => m_keyControllerMap[KeyCode.G];
-        public KeyboardKey H => m_keyControllerMap[KeyCode.H];
-        public KeyboardKey I => m_keyControllerMap[KeyCode.I];
-        public KeyboardKey J => m_keyControllerMap[KeyCode.J];
-        public KeyboardKey K => m_keyControllerMap[KeyCode.K];
-        public KeyboardKey L => m_keyControllerMap[KeyCode.L];
-        public KeyboardKey M => m_keyControllerMap[KeyCode.M];
-        public KeyboardKey N => m_keyControllerMap[KeyCode.N];
-        public KeyboardKey O => m_keyControllerMap[KeyCode.O];
-        public KeyboardKey P => m_keyControllerMap[KeyCode.P];
-        public KeyboardKey Q => m_keyControllerMap[KeyCode.Q];
-        public KeyboardKey R => m_keyControllerMap[KeyCode.R];
-        public KeyboardKey S => m_keyControllerMap[KeyCode.S];
-        public KeyboardKey T => m_keyControllerMap[KeyCode.T];
-        public KeyboardKey U => m_keyControllerMap[KeyCode.U];
-        public KeyboardKey V => m_keyControllerMap[KeyCode.V];
-        public KeyboardKey W => m_keyControllerMap[KeyCode.W];
-        public KeyboardKey X => m_keyControllerMap[KeyCode.X];
-        public KeyboardKey Y => m_keyControllerMap[KeyCode.Y];
-        public KeyboardKey Z => m_keyControllerMap[KeyCode.Z];
-        public KeyboardKey Alpha0 => m_keyControllerMap[KeyCode.Alpha0];
-        public KeyboardKey Alpha1 => m_keyControllerMap[KeyCode.Alpha1];
-        public KeyboardKey Alpha2 => m_keyControllerMap[KeyCode.Alpha2];
-        public KeyboardKey Alpha3 => m_keyControllerMap[KeyCode.Alpha3];
-        public KeyboardKey Alpha4 => m_keyControllerMap[KeyCode.Alpha4];
-        public KeyboardKey Alpha5 => m_keyControllerMap[KeyCode.Alpha5];
-        public KeyboardKey Alpha6 => m_keyControllerMap[KeyCode.Alpha6];
-        public KeyboardKey Alpha7 => m_keyControllerMap[KeyCode.Alpha7];
-        public KeyboardKey Alpha8 => m_keyControllerMap[KeyCode.Alpha8];
-        public KeyboardKey Alpha9 => m_keyControllerMap[KeyCode.Alpha9];
-        public KeyboardKey F1 => m_keyControllerMap[KeyCode.F1];
-        public KeyboardKey F2 => m_keyControllerMap[KeyCode.F2];
-        public KeyboardKey F3 => m_keyControllerMap[KeyCode.F3];
-        public KeyboardKey F4 => m_keyControllerMap[KeyCode.F4];
-        public KeyboardKey F5 => m_keyControllerMap[KeyCode.F5];
-        public KeyboardKey F6 => m_keyControllerMap[KeyCode.F6];
-        public KeyboardKey F7 => m_keyControllerMap[KeyCode.F7];
-        public KeyboardKey F8 => m_keyControllerMap[KeyCode.F8];
-        public KeyboardKey F9 => m_keyControllerMap[KeyCode.F9];
-        public KeyboardKey F10 => m_keyControllerMap[KeyCode.F10];
-        public KeyboardKey F11 => m_keyControllerMap[KeyCode.F11];
-        public KeyboardKey F12 => m_keyControllerMap[KeyCode.F12];
-        public KeyboardKey F13 => m_keyControllerMap[KeyCode.F13];
-        public KeyboardKey F14 => m_keyControllerMap[KeyCode.F14];
-        public KeyboardKey F15 => m_keyControllerMap[KeyCode.F15];
-        public KeyboardKey UpArrow => m_keyControllerMap[KeyCode.UpArrow];
-        public KeyboardKey DownArrow => m_keyControllerMap[KeyCode.DownArrow];
-        public KeyboardKey LeftArrow => m_keyControllerMap[KeyCode.LeftArrow];
-        public KeyboardKey RightArrow => m_keyControllerMap[KeyCode.RightArrow];
-        public KeyboardKey Space => m_keyControllerMap[KeyCode.Space];
-        public KeyboardKey Return => m_keyControllerMap[KeyCode.Return];
-        public KeyboardKey Escape => m_keyControllerMap[KeyCode.Escape];
-        public KeyboardKey Tab => m_keyControllerMap[KeyCode.Tab];
-        public KeyboardKey Backspace => m_keyControllerMap[KeyCode.Backspace];
-        public KeyboardKey CapsLock => m_keyControllerMap[KeyCode.CapsLock];
-        public KeyboardKey LeftShift => m_keyControllerMap[KeyCode.LeftShift];
-        public KeyboardKey RightShift => m_keyControllerMap[KeyCode.RightShift];
-        public KeyboardKey LeftControl => m_keyControllerMap[KeyCode.LeftControl];
-        public KeyboardKey RightControl => m_keyControllerMap[KeyCode.RightControl];
-        public KeyboardKey LeftAlt => m_keyControllerMap[KeyCode.LeftAlt];
-        public KeyboardKey RightAlt => m_keyControllerMap[KeyCode.RightAlt];
-        public KeyboardKey LeftCommand => m_keyControllerMap[KeyCode.LeftCommand];
-        public KeyboardKey RightCommand => m_keyControllerMap[KeyCode.RightCommand];
-        public KeyboardKey Comma => m_keyControllerMap[KeyCode.Comma];
-        public KeyboardKey Period => m_keyControllerMap[KeyCode.Period];
-        public KeyboardKey Slash => m_keyControllerMap[KeyCode.Slash];
-        public KeyboardKey BackQuote => m_keyControllerMap[KeyCode.BackQuote];
-        public KeyboardKey Quote => m_keyControllerMap[KeyCode.Quote];
-        public KeyboardKey Semicolon => m_keyControllerMap[KeyCode.Semicolon];
-        public KeyboardKey LeftBracket => m_keyControllerMap[KeyCode.LeftBracket];
-        public KeyboardKey RightBracket => m_keyControllerMap[KeyCode.RightBracket];
-        public KeyboardKey Backslash => m_keyControllerMap[KeyCode.Backslash];
-        public KeyboardKey Minus => m_keyControllerMap[KeyCode.Minus];
-        public KeyboardKey Equals_k => m_keyControllerMap[KeyCode.Equals];
-        public KeyboardKey Keypad0 => m_keyControllerMap[KeyCode.Keypad0];
-        public KeyboardKey Keypad1 => m_keyControllerMap[KeyCode.Keypad1];
-        public KeyboardKey Keypad2 => m_keyControllerMap[KeyCode.Keypad2];
-        public KeyboardKey Keypad3 => m_keyControllerMap[KeyCode.Keypad3];
-        public KeyboardKey Keypad4 => m_keyControllerMap[KeyCode.Keypad4];
-        public KeyboardKey Keypad5 => m_keyControllerMap[KeyCode.Keypad5];
-        public KeyboardKey Keypad6 => m_keyControllerMap[KeyCode.Keypad6];
-        public KeyboardKey Keypad7 => m_keyControllerMap[KeyCode.Keypad7];
-        public KeyboardKey Keypad8 => m_keyControllerMap[KeyCode.Keypad8];
-        public KeyboardKey Keypad9 => m_keyControllerMap[KeyCode.Keypad9];
-        public KeyboardKey KeypadPeriod => m_keyControllerMap[KeyCode.KeypadPeriod];
-        public KeyboardKey KeypadDivide => m_keyControllerMap[KeyCode.KeypadDivide];
-        public KeyboardKey KeypadMultiply => m_keyControllerMap[KeyCode.KeypadMultiply];
-        public KeyboardKey KeypadMinus => m_keyControllerMap[KeyCode.KeypadMinus];
-        public KeyboardKey KeypadPlus => m_keyControllerMap[KeyCode.KeypadPlus];
-        public KeyboardKey KeypadEnter => m_keyControllerMap[KeyCode.KeypadEnter];
-        public KeyboardKey Numlock => m_keyControllerMap[KeyCode.Numlock];
-        public KeyboardKey Print => m_keyControllerMap[KeyCode.Print];
-        public KeyboardKey Insert => m_keyControllerMap[KeyCode.Insert];
-        public KeyboardKey Delete => m_keyControllerMap[KeyCode.Delete];
-        public KeyboardKey Home => m_keyControllerMap[KeyCode.Home];
-        public KeyboardKey End => m_keyControllerMap[KeyCode.End];
-        public KeyboardKey PageUp => m_keyControllerMap[KeyCode.PageUp];
-        public KeyboardKey PageDown => m_keyControllerMap[KeyCode.PageDown];
-        public KeyboardKey Pause => m_keyControllerMap[KeyCode.Pause];
-        public KeyboardKey ScrollLock => m_keyControllerMap[KeyCode.ScrollLock];
-    }
-    #endregion
 }
\ 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
index 4d96be15..85a6e3c3 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/PSVController_D.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/PSVController_D.cs
@@ -1,54 +1,22 @@
-using System.Collections.Generic;
-
-namespace AxibugEmuOnline.Client.InputDevices
+namespace AxibugEmuOnline.Client.InputDevices
 {
     public class PSVController_D : InputDevice_D
     {
-        /// <summary> × </summary>
-        public Button_C Cross { get; private set; }
-        /// <summary> ○ </summary>
-        public Button_C Circle { get; private set; }
-        /// <summary> □ </summary>
-        public Button_C Square { get; private set; }
-        /// <summary> △ </summary>
-        public Button_C Triangle { get; private set; }
-        public Button_C L { get; private set; }
-        public Button_C R { get; private set; }
-        public Button_C Select { get; private set; }
-        public Button_C Start { get; private set; }
-        public Button_C Up { get; private set; }
-        public Button_C Right { get; private set; }
-        public Button_C Down { get; private set; }
-        public Button_C Left { get; private set; }
-        public Stick_C LeftStick { get; private set; }
-        public Stick_C RightStick { get; private set; }
+        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) { }
-
-        protected override List<InputControl_D> DefineControls()
-        {
-            List<InputControl_D> result = new List<InputControl_D>();
-
-            Cross = new Button_C(this, "X");
-            Circle = new Button_C(this, "⭕");
-            Square = new Button_C(this, "□");
-            Triangle = new Button_C(this, "△");
-
-            L = new Button_C(this, "L");
-            R = new Button_C(this, "R");
-
-            Select = new Button_C(this, "SELECT");
-            Start = new Button_C(this, "START");
-
-            Up = new Button_C(this, "UP");
-            Right = new Button_C(this, "RIGHT");
-            Down = new Button_C(this, "DOWN");
-            Left = new Button_C(this, "LEFT");
-
-            LeftStick = new Stick_C(this, nameof(LeftStick));
-            RightStick = new Stick_C(this, nameof(RightStick));
-
-            return result;
-        }
     }
 }
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputResolver.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputResolver.cs
index ee448e40..4efbdeb9 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputResolver.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputResolver.cs
@@ -56,9 +56,9 @@ namespace AxibugEmuOnline.Client.InputDevices
             OnDeviceConnected?.Invoke(connectDevice);
         }
 
-        public abstract bool CheckPerforming<CONTROLLER>(CONTROLLER control) where CONTROLLER : InputControl_D;
-        public abstract Vector2 GetVector2<CONTROLLER>(CONTROLLER control) where CONTROLLER : InputControl_D;
-        public abstract float GetFloat<CONTROLLER>(CONTROLLER control) where CONTROLLER : InputControl_D;
+        public abstract bool CheckPerforming<CONTROLLER>(CONTROLLER control) where CONTROLLER : InputControl_C;
+        public abstract Vector2 GetVector2<CONTROLLER>(CONTROLLER control) where CONTROLLER : InputControl_C;
+        public abstract float GetFloat<CONTROLLER>(CONTROLLER control) where CONTROLLER : InputControl_C;
         /// <summary>
         /// 获得输入设备的唯一名称
         /// </summary>
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs
index c8d96634..8144eef9 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs
@@ -21,7 +21,13 @@ namespace AxibugEmuOnline.Client.InputDevices.ForInputSystem
         private void AddDevice(InputDevice ipdev)
         {
             InputDevice_D newDevice = null;
-            if (ipdev is Keyboard) newDevice = new Keyboard_D(this);
+            if (ipdev is Keyboard)
+            {
+                newDevice = new Keyboard_D(this);
+                AddKeyboardMapper((Keyboard_D)newDevice, (Keyboard)ipdev);
+            }
+            else if (ipdev is Gamepad) newDevice = new GamePad_D(this);
+
             if (newDevice != null)
             {
                 m_devices.Add(ipdev, newDevice);
@@ -35,12 +41,23 @@ namespace AxibugEmuOnline.Client.InputDevices.ForInputSystem
             {
                 m_devices.Remove(ipdev);
                 RaiseDeviceLost(device);
+
+                if (device is Keyboard_D)
+                {
+                    RemoveKeyboardMapper((Keyboard_D)device);
+                }
             }
         }
 
+        private T GetInputSystemDevice<T>(InputDevice_D device) where T : InputDevice
+        {
+            m_devices.TryGetKey(device, out var ipDev);
+            return ipDev as T;
+        }
+
         public override string GetDeviceName(InputDevice_D inputDevice)
         {
-            m_devices.TryGetKey(inputDevice, out var ipdev);
+            var ipdev = GetInputSystemDevice<InputDevice>(inputDevice);
             Debug.Assert(ipdev != null, "不能对已离线的设备获取名称");
 
             return $"{ipdev.description.deviceClass}_{ipdev.description.interfaceName}_{ipdev.deviceId}";
@@ -51,12 +68,12 @@ namespace AxibugEmuOnline.Client.InputDevices.ForInputSystem
             return m_devices.TryGetKey(device, out var _);
         }
 
-        private void IP_onDeviceChange(InputDevice device, UnityEngine.InputSystem.InputDeviceChange changeType)
+        private void IP_onDeviceChange(InputDevice device, InputDeviceChange changeType)
         {
             switch (changeType)
             {
-                case UnityEngine.InputSystem.InputDeviceChange.Added: AddDevice(device); break;
-                case UnityEngine.InputSystem.InputDeviceChange.Removed: RemoveDevice(device); break;
+                case InputDeviceChange.Added: AddDevice(device); break;
+                case InputDeviceChange.Removed: RemoveDevice(device); break;
             }
         }
 
@@ -69,22 +86,11 @@ namespace AxibugEmuOnline.Client.InputDevices.ForInputSystem
         {
             if (control.Device is Keyboard_D keyboard)
             {
-                if (control is Keyboard_D.KeyboardKey key)
-                {
-                    if (m_devices.TryGetKey(keyboard, out var ipdev))
-                    {
-                        var ipKeyboard = ipdev as Keyboard;
-                        if (ipKeyboard == null) return false;
-
-                        var k = GetIPKeyboardKey(ipKeyboard, key.m_keycode);
-                        return k.isPressed;
-                    }
-
-                    return false;
-                }
+                var ipKeyboard = GetInputSystemDevice<Keyboard>(keyboard);
+                var k = GetIPKeyboardKey(ipKeyboard, keyboard, control);
+                return k.isPressed;
             }
 
-
             throw new System.NotImplementedException();
         }
 
@@ -98,130 +104,132 @@ namespace AxibugEmuOnline.Client.InputDevices.ForInputSystem
             throw new System.NotImplementedException();
         }
 
-        static ButtonControl GetIPKeyboardKey(Keyboard keyboard, KeyCode key)
+        ButtonControl GetIPKeyboardKey(Keyboard ipKeyboard, Keyboard_D keyboard, InputControl_C key)
         {
-            switch (key)
+            var mapper = m_keyboardMapper[keyboard];
+            mapper.TryGetValue(key, out ButtonControl inputBtn);
+            if (inputBtn != null)
+                return inputBtn;
+            else
             {
-                // 字母键(A-Z)
-                case KeyCode.A: return keyboard.aKey;
-                case KeyCode.B: return keyboard.bKey;
-                case KeyCode.C: return keyboard.cKey;
-                case KeyCode.D: return keyboard.dKey;
-                case KeyCode.E: return keyboard.eKey;
-                case KeyCode.F: return keyboard.fKey;
-                case KeyCode.G: return keyboard.gKey;
-                case KeyCode.H: return keyboard.hKey;
-                case KeyCode.I: return keyboard.iKey;
-                case KeyCode.J: return keyboard.jKey;
-                case KeyCode.K: return keyboard.kKey;
-                case KeyCode.L: return keyboard.lKey;
-                case KeyCode.M: return keyboard.mKey;
-                case KeyCode.N: return keyboard.nKey;
-                case KeyCode.O: return keyboard.oKey;
-                case KeyCode.P: return keyboard.pKey;
-                case KeyCode.Q: return keyboard.qKey;
-                case KeyCode.R: return keyboard.rKey;
-                case KeyCode.S: return keyboard.sKey;
-                case KeyCode.T: return keyboard.tKey;
-                case KeyCode.U: return keyboard.uKey;
-                case KeyCode.V: return keyboard.vKey;
-                case KeyCode.W: return keyboard.wKey;
-                case KeyCode.X: return keyboard.xKey;
-                case KeyCode.Y: return keyboard.yKey;
-                case KeyCode.Z: return keyboard.zKey;
-
-                // 数字键(0-9)
-                case KeyCode.Alpha0: return keyboard.digit0Key;
-                case KeyCode.Alpha1: return keyboard.digit1Key;
-                case KeyCode.Alpha2: return keyboard.digit2Key;
-                case KeyCode.Alpha3: return keyboard.digit3Key;
-                case KeyCode.Alpha4: return keyboard.digit4Key;
-                case KeyCode.Alpha5: return keyboard.digit5Key;
-                case KeyCode.Alpha6: return keyboard.digit6Key;
-                case KeyCode.Alpha7: return keyboard.digit7Key;
-                case KeyCode.Alpha8: return keyboard.digit8Key;
-                case KeyCode.Alpha9: return keyboard.digit9Key;
-
-                // 小键盘
-                case KeyCode.Keypad0: return keyboard.numpad0Key;
-                case KeyCode.Keypad1: return keyboard.numpad1Key;
-                case KeyCode.Keypad2: return keyboard.numpad2Key;
-                case KeyCode.Keypad3: return keyboard.numpad3Key;
-                case KeyCode.Keypad4: return keyboard.numpad4Key;
-                case KeyCode.Keypad5: return keyboard.numpad5Key;
-                case KeyCode.Keypad6: return keyboard.numpad6Key;
-                case KeyCode.Keypad7: return keyboard.numpad7Key;
-                case KeyCode.Keypad8: return keyboard.numpad8Key;
-                case KeyCode.Keypad9: return keyboard.numpad9Key;
-                case KeyCode.KeypadPeriod: return keyboard.numpadPeriodKey;
-                case KeyCode.KeypadDivide: return keyboard.numpadDivideKey;
-                case KeyCode.KeypadMultiply: return keyboard.numpadMultiplyKey;
-                case KeyCode.KeypadMinus: return keyboard.numpadMinusKey;
-                case KeyCode.KeypadPlus: return keyboard.numpadPlusKey;
-                case KeyCode.KeypadEnter: return keyboard.numpadEnterKey;
-                case KeyCode.KeypadEquals: return keyboard.numpadEqualsKey;
-
-                // 功能键(F1-F15)
-                case KeyCode.F1: return keyboard.f1Key;
-                case KeyCode.F2: return keyboard.f2Key;
-                case KeyCode.F3: return keyboard.f3Key;
-                case KeyCode.F4: return keyboard.f4Key;
-                case KeyCode.F5: return keyboard.f5Key;
-                case KeyCode.F6: return keyboard.f6Key;
-                case KeyCode.F7: return keyboard.f7Key;
-                case KeyCode.F8: return keyboard.f8Key;
-                case KeyCode.F9: return keyboard.f9Key;
-                case KeyCode.F10: return keyboard.f10Key;
-                case KeyCode.F11: return keyboard.f11Key;
-                case KeyCode.F12: return keyboard.f12Key;
-
-                // 方向键
-                case KeyCode.UpArrow: return keyboard.upArrowKey;
-                case KeyCode.DownArrow: return keyboard.downArrowKey;
-                case KeyCode.LeftArrow: return keyboard.leftArrowKey;
-                case KeyCode.RightArrow: return keyboard.rightArrowKey;
-
-                // 符号键
-                case KeyCode.Space: return keyboard.spaceKey;
-                case KeyCode.Backspace: return keyboard.backspaceKey;
-                case KeyCode.Tab: return keyboard.tabKey;
-                case KeyCode.Return: return keyboard.enterKey;
-                case KeyCode.Escape: return keyboard.escapeKey;
-                case KeyCode.LeftShift: return keyboard.leftShiftKey;
-                case KeyCode.RightShift: return keyboard.rightShiftKey;
-                case KeyCode.LeftControl: return keyboard.leftCtrlKey;
-                case KeyCode.RightControl: return keyboard.rightCtrlKey;
-                case KeyCode.LeftAlt: return keyboard.leftAltKey;
-                case KeyCode.RightAlt: return keyboard.rightAltKey;
-                case KeyCode.LeftCommand: return keyboard.leftCommandKey; // macOS Command键
-                case KeyCode.RightCommand: return keyboard.rightCommandKey;
-                case KeyCode.CapsLock: return keyboard.capsLockKey;
-                case KeyCode.Numlock: return keyboard.numLockKey;
-                case KeyCode.ScrollLock: return keyboard.scrollLockKey;
-                case KeyCode.Print: return keyboard.printScreenKey;
-                case KeyCode.Pause: return keyboard.pauseKey;
-                case KeyCode.Insert: return keyboard.insertKey;
-                case KeyCode.Home: return keyboard.homeKey;
-                case KeyCode.End: return keyboard.endKey;
-                case KeyCode.PageUp: return keyboard.pageUpKey;
-                case KeyCode.PageDown: return keyboard.pageDownKey;
-                case KeyCode.Delete: return keyboard.deleteKey;
-                case KeyCode.Comma: return keyboard.commaKey;
-                case KeyCode.Period: return keyboard.periodKey;
-                case KeyCode.Slash: return keyboard.slashKey;
-                case KeyCode.BackQuote: return keyboard.backquoteKey;
-                case KeyCode.Minus: return keyboard.minusKey;
-                case KeyCode.Equals: return keyboard.equalsKey;
-                case KeyCode.LeftBracket: return keyboard.leftBracketKey;
-                case KeyCode.RightBracket: return keyboard.rightBracketKey;
-                case KeyCode.Backslash: return keyboard.backslashKey;
-                case KeyCode.Semicolon: return keyboard.semicolonKey;
-                case KeyCode.Quote: return keyboard.quoteKey;
-                default:
-                    throw new System.NotImplementedException($"Not Find KeyCode Mapper Code from {key}");
+                throw new System.Exception($"not found keyboard mapper setting : {key}");
             }
         }
+        Dictionary<Keyboard_D, Dictionary<InputControl_C, ButtonControl>> m_keyboardMapper = new Dictionary<Keyboard_D, Dictionary<InputControl_C, ButtonControl>>();
+        void AddKeyboardMapper(Keyboard_D keyboard_d, Keyboard ipkeyboard)
+        {
+            m_keyboardMapper.Add(keyboard_d, new Dictionary<InputControl_C, ButtonControl>());
+            var mapper = m_keyboardMapper[keyboard_d];
 
+            mapper.Add(keyboard_d.A, ipkeyboard.aKey);
+            mapper.Add(keyboard_d.B, ipkeyboard.bKey);
+            mapper.Add(keyboard_d.C, ipkeyboard.cKey);
+            mapper.Add(keyboard_d.D, ipkeyboard.dKey);
+            mapper.Add(keyboard_d.E, ipkeyboard.eKey);
+            mapper.Add(keyboard_d.F, ipkeyboard.fKey);
+            mapper.Add(keyboard_d.G, ipkeyboard.gKey);
+            mapper.Add(keyboard_d.H, ipkeyboard.hKey);
+            mapper.Add(keyboard_d.I, ipkeyboard.iKey);
+            mapper.Add(keyboard_d.J, ipkeyboard.jKey);
+            mapper.Add(keyboard_d.K, ipkeyboard.kKey);
+            mapper.Add(keyboard_d.L, ipkeyboard.lKey);
+            mapper.Add(keyboard_d.M, ipkeyboard.mKey);
+            mapper.Add(keyboard_d.N, ipkeyboard.nKey);
+            mapper.Add(keyboard_d.O, ipkeyboard.oKey);
+            mapper.Add(keyboard_d.P, ipkeyboard.pKey);
+            mapper.Add(keyboard_d.Q, ipkeyboard.qKey);
+            mapper.Add(keyboard_d.R, ipkeyboard.rKey);
+            mapper.Add(keyboard_d.S, ipkeyboard.sKey);
+            mapper.Add(keyboard_d.T, ipkeyboard.tKey);
+            mapper.Add(keyboard_d.U, ipkeyboard.uKey);
+            mapper.Add(keyboard_d.V, ipkeyboard.vKey);
+            mapper.Add(keyboard_d.W, ipkeyboard.wKey);
+            mapper.Add(keyboard_d.X, ipkeyboard.xKey);
+            mapper.Add(keyboard_d.Y, ipkeyboard.yKey);
+            mapper.Add(keyboard_d.Z, ipkeyboard.zKey);
+            mapper.Add(keyboard_d.Alpha0, ipkeyboard.digit0Key);
+            mapper.Add(keyboard_d.Alpha1, ipkeyboard.digit1Key);
+            mapper.Add(keyboard_d.Alpha2, ipkeyboard.digit2Key);
+            mapper.Add(keyboard_d.Alpha3, ipkeyboard.digit3Key);
+            mapper.Add(keyboard_d.Alpha4, ipkeyboard.digit4Key);
+            mapper.Add(keyboard_d.Alpha5, ipkeyboard.digit5Key);
+            mapper.Add(keyboard_d.Alpha6, ipkeyboard.digit6Key);
+            mapper.Add(keyboard_d.Alpha7, ipkeyboard.digit7Key);
+            mapper.Add(keyboard_d.Alpha8, ipkeyboard.digit8Key);
+            mapper.Add(keyboard_d.Alpha9, ipkeyboard.digit9Key);
+            mapper.Add(keyboard_d.Keypad0, ipkeyboard.numpad0Key);
+            mapper.Add(keyboard_d.Keypad1, ipkeyboard.numpad1Key);
+            mapper.Add(keyboard_d.Keypad2, ipkeyboard.numpad2Key);
+            mapper.Add(keyboard_d.Keypad3, ipkeyboard.numpad3Key);
+            mapper.Add(keyboard_d.Keypad4, ipkeyboard.numpad4Key);
+            mapper.Add(keyboard_d.Keypad5, ipkeyboard.numpad5Key);
+            mapper.Add(keyboard_d.Keypad6, ipkeyboard.numpad6Key);
+            mapper.Add(keyboard_d.Keypad7, ipkeyboard.numpad7Key);
+            mapper.Add(keyboard_d.Keypad8, ipkeyboard.numpad8Key);
+            mapper.Add(keyboard_d.Keypad9, ipkeyboard.numpad9Key);
+            mapper.Add(keyboard_d.KeypadPeriod, ipkeyboard.numpadPeriodKey);
+            mapper.Add(keyboard_d.KeypadDivide, ipkeyboard.numpadDivideKey);
+            mapper.Add(keyboard_d.KeypadMultiply, ipkeyboard.numpadMultiplyKey);
+            mapper.Add(keyboard_d.KeypadMinus, ipkeyboard.numpadMinusKey);
+            mapper.Add(keyboard_d.KeypadPlus, ipkeyboard.numpadPlusKey);
+            mapper.Add(keyboard_d.KeypadEnter, ipkeyboard.numpadEnterKey);
+            mapper.Add(keyboard_d.F1, ipkeyboard.f1Key);
+            mapper.Add(keyboard_d.F2, ipkeyboard.f2Key);
+            mapper.Add(keyboard_d.F3, ipkeyboard.f3Key);
+            mapper.Add(keyboard_d.F4, ipkeyboard.f4Key);
+            mapper.Add(keyboard_d.F5, ipkeyboard.f5Key);
+            mapper.Add(keyboard_d.F6, ipkeyboard.f6Key);
+            mapper.Add(keyboard_d.F7, ipkeyboard.f7Key);
+            mapper.Add(keyboard_d.F8, ipkeyboard.f8Key);
+            mapper.Add(keyboard_d.F9, ipkeyboard.f9Key);
+            mapper.Add(keyboard_d.F10, ipkeyboard.f10Key);
+            mapper.Add(keyboard_d.F11, ipkeyboard.f11Key);
+            mapper.Add(keyboard_d.F12, ipkeyboard.f12Key);
+            mapper.Add(keyboard_d.UpArrow, ipkeyboard.upArrowKey);
+            mapper.Add(keyboard_d.DownArrow, ipkeyboard.downArrowKey);
+            mapper.Add(keyboard_d.LeftArrow, ipkeyboard.leftArrowKey);
+            mapper.Add(keyboard_d.RightArrow, ipkeyboard.rightArrowKey);
+            mapper.Add(keyboard_d.Space, ipkeyboard.spaceKey);
+            mapper.Add(keyboard_d.Backspace, ipkeyboard.backspaceKey);
+            mapper.Add(keyboard_d.Tab, ipkeyboard.tabKey);
+            mapper.Add(keyboard_d.Return, ipkeyboard.enterKey);
+            mapper.Add(keyboard_d.Escape, ipkeyboard.escapeKey);
+            mapper.Add(keyboard_d.LeftShift, ipkeyboard.leftShiftKey);
+            mapper.Add(keyboard_d.RightShift, ipkeyboard.rightShiftKey);
+            mapper.Add(keyboard_d.LeftControl, ipkeyboard.leftCtrlKey);
+            mapper.Add(keyboard_d.RightControl, ipkeyboard.rightCtrlKey);
+            mapper.Add(keyboard_d.LeftAlt, ipkeyboard.leftAltKey);
+            mapper.Add(keyboard_d.RightAlt, ipkeyboard.rightAltKey);
+            mapper.Add(keyboard_d.LeftCommand, ipkeyboard.leftCommandKey);
+            mapper.Add(keyboard_d.RightCommand, ipkeyboard.rightCommandKey);
+            mapper.Add(keyboard_d.CapsLock, ipkeyboard.capsLockKey);
+            mapper.Add(keyboard_d.Numlock, ipkeyboard.numLockKey);
+            mapper.Add(keyboard_d.ScrollLock, ipkeyboard.scrollLockKey);
+            mapper.Add(keyboard_d.Print, ipkeyboard.printScreenKey);
+            mapper.Add(keyboard_d.Pause, ipkeyboard.pauseKey);
+            mapper.Add(keyboard_d.Insert, ipkeyboard.insertKey);
+            mapper.Add(keyboard_d.Home, ipkeyboard.homeKey);
+            mapper.Add(keyboard_d.End, ipkeyboard.endKey);
+            mapper.Add(keyboard_d.PageUp, ipkeyboard.pageUpKey);
+            mapper.Add(keyboard_d.PageDown, ipkeyboard.pageDownKey);
+            mapper.Add(keyboard_d.Delete, ipkeyboard.deleteKey);
+            mapper.Add(keyboard_d.Comma, ipkeyboard.commaKey);
+            mapper.Add(keyboard_d.Period, ipkeyboard.periodKey);
+            mapper.Add(keyboard_d.Slash, ipkeyboard.slashKey);
+            mapper.Add(keyboard_d.BackQuote, ipkeyboard.backquoteKey);
+            mapper.Add(keyboard_d.Minus, ipkeyboard.minusKey);
+            mapper.Add(keyboard_d.Equals_k, ipkeyboard.equalsKey);
+            mapper.Add(keyboard_d.LeftBracket, ipkeyboard.leftBracketKey);
+            mapper.Add(keyboard_d.RightBracket, ipkeyboard.rightBracketKey);
+            mapper.Add(keyboard_d.Backslash, ipkeyboard.backslashKey);
+            mapper.Add(keyboard_d.Semicolon, ipkeyboard.semicolonKey);
+            mapper.Add(keyboard_d.Quote, ipkeyboard.quoteKey);
+        }
+        void RemoveKeyboardMapper(Keyboard_D keyboard_d)
+        {
+            m_keyboardMapper.Remove(keyboard_d);
+        }
     }
+
 }
 #endif
\ No newline at end of file

From 4e87cfe9ee01871812e13ba404ee91ea63478d77 Mon Sep 17 00:00:00 2001
From: "ALIENJACK\\alien" <alienjack@foxmail.com>
Date: Thu, 27 Mar 2025 20:08:31 +0800
Subject: [PATCH 15/20] =?UTF-8?q?Input=E4=BB=A3=E7=A0=81=E8=BF=AD=E4=BB=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../InputResolver/InputSystemResolver.cs      | 268 +++++++++---------
 1 file changed, 134 insertions(+), 134 deletions(-)

diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs
index 8144eef9..f89f87ca 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs
@@ -2,7 +2,6 @@
 using System.Collections.Generic;
 using UnityEngine;
 using UnityEngine.InputSystem;
-using UnityEngine.InputSystem.Controls;
 
 namespace AxibugEmuOnline.Client.InputDevices.ForInputSystem
 {
@@ -21,16 +20,13 @@ namespace AxibugEmuOnline.Client.InputDevices.ForInputSystem
         private void AddDevice(InputDevice ipdev)
         {
             InputDevice_D newDevice = null;
-            if (ipdev is Keyboard)
-            {
-                newDevice = new Keyboard_D(this);
-                AddKeyboardMapper((Keyboard_D)newDevice, (Keyboard)ipdev);
-            }
+            if (ipdev is Keyboard) newDevice = new Keyboard_D(this);
             else if (ipdev is Gamepad) newDevice = new GamePad_D(this);
 
             if (newDevice != null)
             {
                 m_devices.Add(ipdev, newDevice);
+                AddDeviceMapper(newDevice, ipdev);
                 RaiseDeviceConnected(newDevice);
             }
         }
@@ -40,12 +36,8 @@ namespace AxibugEmuOnline.Client.InputDevices.ForInputSystem
             if (m_devices.TryGetValue(ipdev, out var device))
             {
                 m_devices.Remove(ipdev);
+                RemoveDeviceMapper(device);
                 RaiseDeviceLost(device);
-
-                if (device is Keyboard_D)
-                {
-                    RemoveKeyboardMapper((Keyboard_D)device);
-                }
             }
         }
 
@@ -84,150 +76,158 @@ namespace AxibugEmuOnline.Client.InputDevices.ForInputSystem
 
         public override bool CheckPerforming<CONTROLLER>(CONTROLLER control)
         {
-            if (control.Device is Keyboard_D keyboard)
-            {
-                var ipKeyboard = GetInputSystemDevice<Keyboard>(keyboard);
-                var k = GetIPKeyboardKey(ipKeyboard, keyboard, control);
-                return k.isPressed;
-            }
-
-            throw new System.NotImplementedException();
+            var ipControl = GetInputSystemControl(control);
+            return ipControl.IsPressed();
         }
 
         public override Vector2 GetVector2<CONTROLLER>(CONTROLLER control)
         {
-            throw new System.NotImplementedException();
+            var ipControl = GetInputSystemControl(control);
+            return (ipControl as InputControl<Vector2>).value;
         }
 
         public override float GetFloat<CONTROLLER>(CONTROLLER control)
         {
-            throw new System.NotImplementedException();
+            var ipControl = GetInputSystemControl(control);
+            return (ipControl as InputControl<float>).value;
         }
 
-        ButtonControl GetIPKeyboardKey(Keyboard ipKeyboard, Keyboard_D keyboard, InputControl_C key)
+        InputControl GetInputSystemControl(InputControl_C key)
         {
-            var mapper = m_keyboardMapper[keyboard];
-            mapper.TryGetValue(key, out ButtonControl inputBtn);
+            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 keyboard mapper setting : {key}");
+                throw new System.Exception($"not found mapper setting : {key}");
             }
         }
-        Dictionary<Keyboard_D, Dictionary<InputControl_C, ButtonControl>> m_keyboardMapper = new Dictionary<Keyboard_D, Dictionary<InputControl_C, ButtonControl>>();
-        void AddKeyboardMapper(Keyboard_D keyboard_d, Keyboard ipkeyboard)
+        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_keyboardMapper.Add(keyboard_d, new Dictionary<InputControl_C, ButtonControl>());
-            var mapper = m_keyboardMapper[keyboard_d];
+            m_deviceMapper.Add(device_d, new Dictionary<InputControl_C, InputControl>());
+            var mapper = m_deviceMapper[device_d];
 
-            mapper.Add(keyboard_d.A, ipkeyboard.aKey);
-            mapper.Add(keyboard_d.B, ipkeyboard.bKey);
-            mapper.Add(keyboard_d.C, ipkeyboard.cKey);
-            mapper.Add(keyboard_d.D, ipkeyboard.dKey);
-            mapper.Add(keyboard_d.E, ipkeyboard.eKey);
-            mapper.Add(keyboard_d.F, ipkeyboard.fKey);
-            mapper.Add(keyboard_d.G, ipkeyboard.gKey);
-            mapper.Add(keyboard_d.H, ipkeyboard.hKey);
-            mapper.Add(keyboard_d.I, ipkeyboard.iKey);
-            mapper.Add(keyboard_d.J, ipkeyboard.jKey);
-            mapper.Add(keyboard_d.K, ipkeyboard.kKey);
-            mapper.Add(keyboard_d.L, ipkeyboard.lKey);
-            mapper.Add(keyboard_d.M, ipkeyboard.mKey);
-            mapper.Add(keyboard_d.N, ipkeyboard.nKey);
-            mapper.Add(keyboard_d.O, ipkeyboard.oKey);
-            mapper.Add(keyboard_d.P, ipkeyboard.pKey);
-            mapper.Add(keyboard_d.Q, ipkeyboard.qKey);
-            mapper.Add(keyboard_d.R, ipkeyboard.rKey);
-            mapper.Add(keyboard_d.S, ipkeyboard.sKey);
-            mapper.Add(keyboard_d.T, ipkeyboard.tKey);
-            mapper.Add(keyboard_d.U, ipkeyboard.uKey);
-            mapper.Add(keyboard_d.V, ipkeyboard.vKey);
-            mapper.Add(keyboard_d.W, ipkeyboard.wKey);
-            mapper.Add(keyboard_d.X, ipkeyboard.xKey);
-            mapper.Add(keyboard_d.Y, ipkeyboard.yKey);
-            mapper.Add(keyboard_d.Z, ipkeyboard.zKey);
-            mapper.Add(keyboard_d.Alpha0, ipkeyboard.digit0Key);
-            mapper.Add(keyboard_d.Alpha1, ipkeyboard.digit1Key);
-            mapper.Add(keyboard_d.Alpha2, ipkeyboard.digit2Key);
-            mapper.Add(keyboard_d.Alpha3, ipkeyboard.digit3Key);
-            mapper.Add(keyboard_d.Alpha4, ipkeyboard.digit4Key);
-            mapper.Add(keyboard_d.Alpha5, ipkeyboard.digit5Key);
-            mapper.Add(keyboard_d.Alpha6, ipkeyboard.digit6Key);
-            mapper.Add(keyboard_d.Alpha7, ipkeyboard.digit7Key);
-            mapper.Add(keyboard_d.Alpha8, ipkeyboard.digit8Key);
-            mapper.Add(keyboard_d.Alpha9, ipkeyboard.digit9Key);
-            mapper.Add(keyboard_d.Keypad0, ipkeyboard.numpad0Key);
-            mapper.Add(keyboard_d.Keypad1, ipkeyboard.numpad1Key);
-            mapper.Add(keyboard_d.Keypad2, ipkeyboard.numpad2Key);
-            mapper.Add(keyboard_d.Keypad3, ipkeyboard.numpad3Key);
-            mapper.Add(keyboard_d.Keypad4, ipkeyboard.numpad4Key);
-            mapper.Add(keyboard_d.Keypad5, ipkeyboard.numpad5Key);
-            mapper.Add(keyboard_d.Keypad6, ipkeyboard.numpad6Key);
-            mapper.Add(keyboard_d.Keypad7, ipkeyboard.numpad7Key);
-            mapper.Add(keyboard_d.Keypad8, ipkeyboard.numpad8Key);
-            mapper.Add(keyboard_d.Keypad9, ipkeyboard.numpad9Key);
-            mapper.Add(keyboard_d.KeypadPeriod, ipkeyboard.numpadPeriodKey);
-            mapper.Add(keyboard_d.KeypadDivide, ipkeyboard.numpadDivideKey);
-            mapper.Add(keyboard_d.KeypadMultiply, ipkeyboard.numpadMultiplyKey);
-            mapper.Add(keyboard_d.KeypadMinus, ipkeyboard.numpadMinusKey);
-            mapper.Add(keyboard_d.KeypadPlus, ipkeyboard.numpadPlusKey);
-            mapper.Add(keyboard_d.KeypadEnter, ipkeyboard.numpadEnterKey);
-            mapper.Add(keyboard_d.F1, ipkeyboard.f1Key);
-            mapper.Add(keyboard_d.F2, ipkeyboard.f2Key);
-            mapper.Add(keyboard_d.F3, ipkeyboard.f3Key);
-            mapper.Add(keyboard_d.F4, ipkeyboard.f4Key);
-            mapper.Add(keyboard_d.F5, ipkeyboard.f5Key);
-            mapper.Add(keyboard_d.F6, ipkeyboard.f6Key);
-            mapper.Add(keyboard_d.F7, ipkeyboard.f7Key);
-            mapper.Add(keyboard_d.F8, ipkeyboard.f8Key);
-            mapper.Add(keyboard_d.F9, ipkeyboard.f9Key);
-            mapper.Add(keyboard_d.F10, ipkeyboard.f10Key);
-            mapper.Add(keyboard_d.F11, ipkeyboard.f11Key);
-            mapper.Add(keyboard_d.F12, ipkeyboard.f12Key);
-            mapper.Add(keyboard_d.UpArrow, ipkeyboard.upArrowKey);
-            mapper.Add(keyboard_d.DownArrow, ipkeyboard.downArrowKey);
-            mapper.Add(keyboard_d.LeftArrow, ipkeyboard.leftArrowKey);
-            mapper.Add(keyboard_d.RightArrow, ipkeyboard.rightArrowKey);
-            mapper.Add(keyboard_d.Space, ipkeyboard.spaceKey);
-            mapper.Add(keyboard_d.Backspace, ipkeyboard.backspaceKey);
-            mapper.Add(keyboard_d.Tab, ipkeyboard.tabKey);
-            mapper.Add(keyboard_d.Return, ipkeyboard.enterKey);
-            mapper.Add(keyboard_d.Escape, ipkeyboard.escapeKey);
-            mapper.Add(keyboard_d.LeftShift, ipkeyboard.leftShiftKey);
-            mapper.Add(keyboard_d.RightShift, ipkeyboard.rightShiftKey);
-            mapper.Add(keyboard_d.LeftControl, ipkeyboard.leftCtrlKey);
-            mapper.Add(keyboard_d.RightControl, ipkeyboard.rightCtrlKey);
-            mapper.Add(keyboard_d.LeftAlt, ipkeyboard.leftAltKey);
-            mapper.Add(keyboard_d.RightAlt, ipkeyboard.rightAltKey);
-            mapper.Add(keyboard_d.LeftCommand, ipkeyboard.leftCommandKey);
-            mapper.Add(keyboard_d.RightCommand, ipkeyboard.rightCommandKey);
-            mapper.Add(keyboard_d.CapsLock, ipkeyboard.capsLockKey);
-            mapper.Add(keyboard_d.Numlock, ipkeyboard.numLockKey);
-            mapper.Add(keyboard_d.ScrollLock, ipkeyboard.scrollLockKey);
-            mapper.Add(keyboard_d.Print, ipkeyboard.printScreenKey);
-            mapper.Add(keyboard_d.Pause, ipkeyboard.pauseKey);
-            mapper.Add(keyboard_d.Insert, ipkeyboard.insertKey);
-            mapper.Add(keyboard_d.Home, ipkeyboard.homeKey);
-            mapper.Add(keyboard_d.End, ipkeyboard.endKey);
-            mapper.Add(keyboard_d.PageUp, ipkeyboard.pageUpKey);
-            mapper.Add(keyboard_d.PageDown, ipkeyboard.pageDownKey);
-            mapper.Add(keyboard_d.Delete, ipkeyboard.deleteKey);
-            mapper.Add(keyboard_d.Comma, ipkeyboard.commaKey);
-            mapper.Add(keyboard_d.Period, ipkeyboard.periodKey);
-            mapper.Add(keyboard_d.Slash, ipkeyboard.slashKey);
-            mapper.Add(keyboard_d.BackQuote, ipkeyboard.backquoteKey);
-            mapper.Add(keyboard_d.Minus, ipkeyboard.minusKey);
-            mapper.Add(keyboard_d.Equals_k, ipkeyboard.equalsKey);
-            mapper.Add(keyboard_d.LeftBracket, ipkeyboard.leftBracketKey);
-            mapper.Add(keyboard_d.RightBracket, ipkeyboard.rightBracketKey);
-            mapper.Add(keyboard_d.Backslash, ipkeyboard.backslashKey);
-            mapper.Add(keyboard_d.Semicolon, ipkeyboard.semicolonKey);
-            mapper.Add(keyboard_d.Quote, ipkeyboard.quoteKey);
+            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 GamePad_D gamepad_d)
+            {
+                var ipGamepad = ipdevice as Gamepad;
+                mapper[gamepad_d.Up] = ipGamepad.dpad.up;
+            }
+            else throw new System.NotImplementedException($"初始化设备失败,未实现的物理按键映射 for {device_d.GetType()}");
         }
-        void RemoveKeyboardMapper(Keyboard_D keyboard_d)
+        void RemoveDeviceMapper(InputDevice_D keyboard_d)
         {
-            m_keyboardMapper.Remove(keyboard_d);
+            m_deviceMapper.Remove(keyboard_d);
         }
     }
 

From 3797bba442e4b456d9104a2e7292055afea567c0 Mon Sep 17 00:00:00 2001
From: "ALIENJACK\\alien" <alienjack@foxmail.com>
Date: Thu, 27 Mar 2025 20:13:00 +0800
Subject: [PATCH 16/20] =?UTF-8?q?=E5=AE=8C=E5=96=84GamePad=E6=94=AF?=
 =?UTF-8?q?=E6=8C=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../InputDevicesManager/Devices/GamePad_D.cs  |  2 +-
 .../InputResolver/InputSystemResolver.cs      | 20 +++++++++++++++++++
 2 files changed, 21 insertions(+), 1 deletion(-)

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
index 9792afa8..1834a25c 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/GamePad_D.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/GamePad_D.cs
@@ -9,7 +9,7 @@
         public Button_C Down;
         public Button_C Left;
         public Button_C Right;
-        public Button_C Option;
+        public Button_C Select;
         public Button_C Start;
         public Button_C North;
         public Button_C South;
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs
index f89f87ca..9ac5ddeb 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs
@@ -1,5 +1,8 @@
 #if ENABLE_INPUT_SYSTEM
+using Google.Protobuf.WellKnownTypes;
+using NUnit.Framework.Internal;
 using System.Collections.Generic;
+using UnityEditor.Experimental.GraphView;
 using UnityEngine;
 using UnityEngine.InputSystem;
 
@@ -222,6 +225,23 @@ namespace AxibugEmuOnline.Client.InputDevices.ForInputSystem
             {
                 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()}");
         }

From fbe47bce1b348f24acecb66551f0e49fcedae9c8 Mon Sep 17 00:00:00 2001
From: "ALIENJACK\\alien" <alienjack@foxmail.com>
Date: Mon, 31 Mar 2025 16:20:39 +0800
Subject: [PATCH 17/20] =?UTF-8?q?=E6=B7=BB=E5=8A=A0DS=E5=92=8CXbox?=
 =?UTF-8?q?=E6=89=8B=E6=9F=84=E6=94=AF=E6=8C=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../Devices/DualShockController_D.cs          | 28 ++++++++++
 .../Devices/DualShockController_D.cs.meta     |  2 +
 .../Devices/XboxController_D.cs               | 27 ++++++++++
 .../Devices/XboxController_D.cs.meta          |  2 +
 .../InputResolver/InputSystemResolver.cs      | 53 ++++++++++++++++++-
 5 files changed, 111 insertions(+), 1 deletion(-)
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/DualShockController_D.cs
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/DualShockController_D.cs.meta
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/XboxController_D.cs
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/XboxController_D.cs.meta

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/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/InputResolver/InputSystemResolver.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs
index 9ac5ddeb..82f226ce 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs
@@ -5,6 +5,9 @@ using System.Collections.Generic;
 using UnityEditor.Experimental.GraphView;
 using UnityEngine;
 using UnityEngine.InputSystem;
+using UnityEngine.InputSystem.DualShock;
+using UnityEngine.InputSystem.Haptics;
+using UnityEngine.InputSystem.XInput;
 
 namespace AxibugEmuOnline.Client.InputDevices.ForInputSystem
 {
@@ -24,7 +27,9 @@ namespace AxibugEmuOnline.Client.InputDevices.ForInputSystem
         {
             InputDevice_D newDevice = null;
             if (ipdev is Keyboard) newDevice = new Keyboard_D(this);
-            else if (ipdev is Gamepad) newDevice = new GamePad_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)
             {
@@ -221,6 +226,52 @@ namespace AxibugEmuOnline.Client.InputDevices.ForInputSystem
                 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;

From 6cc7b2fb4bd5573f9df314ab213e2bb40c5f7b29 Mon Sep 17 00:00:00 2001
From: "ALIENJACK\\alien" <alienjack@foxmail.com>
Date: Mon, 31 Mar 2025 18:25:07 +0800
Subject: [PATCH 18/20] =?UTF-8?q?=E5=BC=95=E5=85=A5IDeviceBinder=E6=8E=A5?=
 =?UTF-8?q?=E5=8F=A3,=E4=BB=A5=E5=88=A9=E7=94=A8=E7=BC=96=E8=AF=91?=
 =?UTF-8?q?=E6=8A=A5=E9=94=99=E8=A1=A5=E5=85=85=E5=BA=94=E8=AF=A5=E7=BC=96?=
 =?UTF-8?q?=E5=86=99=E7=9A=84=E4=BB=A3=E7=A0=81,=E9=81=BF=E5=85=8D?=
 =?UTF-8?q?=E6=BC=8F=E6=8E=89?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../KeyMapperSetting/EssgeeKeyBinding.cs      | 190 ++++++++++--------
 .../KeyMapperSetting/IDeviceBinder.cs         |  17 ++
 .../KeyMapperSetting/IDeviceBinder.cs.meta    |   2 +
 .../KeyMapperSetting/KeyMapperSetting.cs      |  71 +++----
 .../KeyMapperSetting/MAMEKeyBinding.cs        | 144 ++++++++++---
 .../KeyMapperSetting/NesKeyBinding.cs         | 117 ++++++++---
 .../KeyMapperSetting/XMBKeyBinding.cs         | 112 ++++++++---
 .../Devices/InputControls/Stick_C.cs          |   6 +-
 .../InputDevicesManager.cs                    |   8 +
 .../InputResolver/InputSystemResolver.cs      |   6 +-
 10 files changed, 447 insertions(+), 226 deletions(-)
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/IDeviceBinder.cs
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/IDeviceBinder.cs.meta

diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/EssgeeKeyBinding.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/EssgeeKeyBinding.cs
index 9b7d9bdf..df56af03 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/EssgeeKeyBinding.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/EssgeeKeyBinding.cs
@@ -22,57 +22,113 @@ namespace AxibugEmuOnline.Client.Settings
 
     public abstract class EssgeeKeyBinding : EmuCoreControllerKeyBinding<EssgeeSingleKey>
     {
-        protected override void OnRegistDevices(InputDevice_D device, BindingPage binding)
+        public override void Bind(Keyboard_D device, ControllerBinder controller)
         {
-            if (device is Keyboard_D keyboard)
+            switch (controller.ControllerIndex)
             {
-                switch (binding.ControllerIndex)
-                {
-                    case 0:
-                        binding.SetBinding(EssgeeSingleKey.OPTION_1, keyboard.Return, 0);
-                        binding.SetBinding(EssgeeSingleKey.OPTION_2, keyboard.RightShift, 0);
-                        binding.SetBinding(EssgeeSingleKey.UP, keyboard.W, 0);
-                        binding.SetBinding(EssgeeSingleKey.DOWN, keyboard.S, 0);
-                        binding.SetBinding(EssgeeSingleKey.LEFT, keyboard.A, 0);
-                        binding.SetBinding(EssgeeSingleKey.RIGHT, keyboard.D, 0);
-                        binding.SetBinding(EssgeeSingleKey.BTN_1, keyboard.J, 0);
-                        binding.SetBinding(EssgeeSingleKey.BTN_2, keyboard.K, 0);
-                        binding.SetBinding(EssgeeSingleKey.BTN_3, keyboard.U, 0);
-                        binding.SetBinding(EssgeeSingleKey.BTN_4, keyboard.I, 0);
-                        break;
-                    case 1:
-                        binding.SetBinding(EssgeeSingleKey.OPTION_1, keyboard.Keypad0, 0);
-                        binding.SetBinding(EssgeeSingleKey.OPTION_2, keyboard.Delete, 0);
-                        binding.SetBinding(EssgeeSingleKey.UP, keyboard.UpArrow, 0);
-                        binding.SetBinding(EssgeeSingleKey.DOWN, keyboard.DownArrow, 0);
-                        binding.SetBinding(EssgeeSingleKey.LEFT, keyboard.LeftArrow, 0);
-                        binding.SetBinding(EssgeeSingleKey.RIGHT, keyboard.RightArrow, 0);
-                        binding.SetBinding(EssgeeSingleKey.BTN_1, keyboard.Keypad1, 0);
-                        binding.SetBinding(EssgeeSingleKey.BTN_2, keyboard.Keypad2, 0);
-                        binding.SetBinding(EssgeeSingleKey.BTN_3, keyboard.Keypad3, 0);
-                        binding.SetBinding(EssgeeSingleKey.BTN_4, keyboard.Keypad4, 0);
-                        break;
-                }
+                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;
             }
-            else if (device is PSVController_D psvCon && binding.ControllerIndex == 0)
+        }
+        public override void Bind(PSVController_D device, ControllerBinder controller)
+        {
+            switch (controller.ControllerIndex)
             {
-                binding.SetBinding(EssgeeSingleKey.OPTION_1, psvCon.Start, 0);
-                binding.SetBinding(EssgeeSingleKey.OPTION_2, psvCon.Select, 0);
-                binding.SetBinding(EssgeeSingleKey.UP, psvCon.Up, 0);
-                binding.SetBinding(EssgeeSingleKey.DOWN, psvCon.Down, 0);
-                binding.SetBinding(EssgeeSingleKey.LEFT, psvCon.Left, 0);
-                binding.SetBinding(EssgeeSingleKey.RIGHT, psvCon.Right, 0);
-                binding.SetBinding(EssgeeSingleKey.BTN_1, psvCon.Cross, 0);
-                binding.SetBinding(EssgeeSingleKey.BTN_2, psvCon.Circle, 0);
-                binding.SetBinding(EssgeeSingleKey.BTN_3, psvCon.Square, 0);
-                binding.SetBinding(EssgeeSingleKey.BTN_4, psvCon.Triangle, 0);
-                //PSV 摇杆
-                binding.SetBinding(EssgeeSingleKey.UP, psvCon.LeftStick.UP, 1);
-                binding.SetBinding(EssgeeSingleKey.DOWN, psvCon.LeftStick.Down, 1);
-                binding.SetBinding(EssgeeSingleKey.LEFT, psvCon.LeftStick.Left, 1);
-                binding.SetBinding(EssgeeSingleKey.RIGHT, psvCon.LeftStick.Right, 1);
+                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 class MasterSystemKeyBinding : EssgeeKeyBinding
@@ -97,55 +153,11 @@ namespace AxibugEmuOnline.Client.Settings
     {
         public override RomPlatformType Platform => RomPlatformType.GameBoyColor;
         public override int ControllerCount => 1;
-
-        protected override void OnRegistDevices(InputDevice_D device, BindingPage binding)
-        {
-            if (device is Keyboard_D keyboard)
-            {
-                switch (binding.ControllerIndex)
-                {
-                    case 0:
-                        binding.SetBinding(EssgeeSingleKey.OPTION_1, keyboard.Return, 0);
-                        binding.SetBinding(EssgeeSingleKey.OPTION_2, keyboard.RightShift, 0);
-                        binding.SetBinding(EssgeeSingleKey.UP, keyboard.W, 0);
-                        binding.SetBinding(EssgeeSingleKey.DOWN, keyboard.S, 0);
-                        binding.SetBinding(EssgeeSingleKey.LEFT, keyboard.A, 0);
-                        binding.SetBinding(EssgeeSingleKey.RIGHT, keyboard.D, 0);
-                        binding.SetBinding(EssgeeSingleKey.BTN_1, keyboard.J, 0);
-                        binding.SetBinding(EssgeeSingleKey.BTN_2, keyboard.K, 0);
-                        binding.SetBinding(EssgeeSingleKey.BTN_3, keyboard.U, 0);
-                        binding.SetBinding(EssgeeSingleKey.BTN_4, keyboard.I, 0);
-                        break;
-                }
-            }
-        }
     }
     public class GameBoyKeyBinding : EssgeeKeyBinding
     {
         public override RomPlatformType Platform => RomPlatformType.GameBoy;
         public override int ControllerCount => 1;
-
-        protected override void OnRegistDevices(InputDevice_D device, BindingPage binding)
-        {
-            if (device is Keyboard_D keyboard)
-            {
-                switch (binding.ControllerIndex)
-                {
-                    case 0:
-                        binding.SetBinding(EssgeeSingleKey.OPTION_1, keyboard.Return, 0);
-                        binding.SetBinding(EssgeeSingleKey.OPTION_2, keyboard.RightShift, 0);
-                        binding.SetBinding(EssgeeSingleKey.UP, keyboard.W, 0);
-                        binding.SetBinding(EssgeeSingleKey.DOWN, keyboard.S, 0);
-                        binding.SetBinding(EssgeeSingleKey.LEFT, keyboard.A, 0);
-                        binding.SetBinding(EssgeeSingleKey.RIGHT, keyboard.D, 0);
-                        binding.SetBinding(EssgeeSingleKey.BTN_1, keyboard.J, 0);
-                        binding.SetBinding(EssgeeSingleKey.BTN_2, keyboard.K, 0);
-                        binding.SetBinding(EssgeeSingleKey.BTN_3, keyboard.U, 0);
-                        binding.SetBinding(EssgeeSingleKey.BTN_4, keyboard.I, 0);
-                        break;
-                }
-            }
-        }
     }
 
     public class GameGearKeyBinding : EssgeeKeyBinding
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/IDeviceBinder.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/IDeviceBinder.cs
new file mode 100644
index 00000000..3001ea39
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/IDeviceBinder.cs
@@ -0,0 +1,17 @@
+using AxibugEmuOnline.Client.InputDevices;
+using System;
+
+namespace AxibugEmuOnline.Client.Settings
+{
+    /// <summary>
+    /// 在所有<see cref="EmuCoreControllerKeyBinding{T}"/>的派生类中实现此接口以支持一种设备的绑定
+    /// <para>一种<see cref="EmuCoreControllerKeyBinding{T}"/>
+    /// 一个<see cref="EmuCoreControllerKeyBinding{T}.ControllerBinder"/>可以与多种设备建立绑定,但设备类型不可重复</para>
+    /// </summary>
+    public interface IDeviceBinder<ENUM, DEVICE>
+        where ENUM : Enum
+        where DEVICE : InputDevice_D
+    {
+        void Bind(DEVICE device, EmuCoreControllerKeyBinding<ENUM>.ControllerBinder controller);
+    }
+}
\ No newline at end of file
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/IDeviceBinder.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/IDeviceBinder.cs.meta
new file mode 100644
index 00000000..0533689b
--- /dev/null
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/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/KeyMapperSetting.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs
index 27d9e50a..4d63326b 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs
@@ -2,7 +2,6 @@
 using AxibugEmuOnline.Client.InputDevices;
 using AxibugProtobuf;
 using System;
-using System.Collections;
 using System.Collections.Generic;
 using System.Linq;
 using UnityEngine;
@@ -58,33 +57,31 @@ namespace AxibugEmuOnline.Client.Settings
     /// 模拟器核心控制器键位绑定器
     /// </summary>
     /// <typeparam name="T"></typeparam>
-    public abstract class EmuCoreControllerKeyBinding<T> : EmuCoreControllerKeyBinding
+    public abstract class EmuCoreControllerKeyBinding<T> : EmuCoreControllerKeyBinding,
+        IDeviceBinder<T, Keyboard_D>,
+        IDeviceBinder<T, GamePad_D>,
+        IDeviceBinder<T, DualShockController_D>,
+        IDeviceBinder<T, XboxController_D>,
+        IDeviceBinder<T, PSVController_D>
         where T : Enum
     {
-        List<BindingPage> m_bindingPages = new List<BindingPage>();
+        //每一个实例代表一个对应模拟器平台的控制器索引
+        List<ControllerBinder> m_bindingPages = new List<ControllerBinder>();
 
         public EmuCoreControllerKeyBinding()
         {
+            var types = GetType().GetInterfaces();
+
             for (int i = 0; i < ControllerCount; i++)
             {
-                m_bindingPages.Add(new BindingPage(i, this));
+                m_bindingPages.Add(new ControllerBinder(i, this));
             }
 
-            var keyboard = App.input.GetDevice<Keyboard_D>();
-            if (keyboard != null)
+            foreach (var device in App.input.GetDevices())
             {
                 foreach (var binding in m_bindingPages)
                 {
-                    binding.RegistInputDevice(keyboard);
-                }
-            }
-
-            var psvController = App.input.GetDevice<PSVController_D>();
-            if (psvController != null)
-            {
-                foreach (var binding in m_bindingPages)
-                {
-                    binding.RegistInputDevice(psvController);
+                    binding.RegistInputDevice(device);
                 }
             }
 
@@ -94,12 +91,9 @@ namespace AxibugEmuOnline.Client.Settings
 
         private void InputDevicesMgr_OnDeviceConnected(InputDevice_D connectDevice)
         {
-            if (connectDevice is Keyboard_D)
+            foreach (var binding in m_bindingPages)
             {
-                foreach (var binding in m_bindingPages)
-                {
-                    binding.RegistInputDevice(connectDevice);
-                }
+                binding.RegistInputDevice(connectDevice);
             }
         }
 
@@ -109,30 +103,18 @@ namespace AxibugEmuOnline.Client.Settings
             {
                 binding.UnregistInputDevice(lostDevice);
             }
-            if (lostDevice is Keyboard_D) //键盘丢失,立即查找还存在的键盘并建立连接
-            {
-                var anotherKeyboard = App.input.GetDevice<Keyboard_D>();
-                if (anotherKeyboard != null)
-                {
-                    foreach (var binding in m_bindingPages)
-                    {
-                        binding.UnregistInputDevice(lostDevice);
-                    }
-                }
-            }
         }
 
-        IEnumerable<T> DefineKeys()
+        internal void RaiseDeviceRegist(InputDevice_D device, ControllerBinder binding)
         {
-            return Enum.GetValues(typeof(T)).Cast<T>();
+            if (device is Keyboard_D keyboard && this is IDeviceBinder<T, Keyboard_D> keyboardIn) keyboardIn.Bind(keyboard, binding);
+            if (device is GamePad_D gamePad && this is IDeviceBinder<T, GamePad_D> gamepadIn) gamepadIn.Bind(gamePad, binding);
+            if (device is DualShockController_D dsC && this is IDeviceBinder<T, DualShockController_D> dsIn) dsIn.Bind(dsC, binding);
+            if (device is XboxController_D xbC && this is IDeviceBinder<T, XboxController_D> xbIn) xbIn.Bind(xbC, binding);
+            if (device is PSVController_D psvC && this is IDeviceBinder<T, PSVController_D> psvIn) psvIn.Bind(psvC, binding);
+            else throw new NotImplementedException($"{device.GetType()}");
         }
 
-        internal void RaiseDeviceRegist(InputDevice_D device, BindingPage binding)
-        {
-            OnRegistDevices(device, binding);
-        }
-        protected abstract void OnRegistDevices(InputDevice_D device, BindingPage binding);
-
         public bool Start(T emuControl, int controllerIndex)
         {
             var binding = m_bindingPages[controllerIndex];
@@ -234,7 +216,7 @@ namespace AxibugEmuOnline.Client.Settings
 
         public class MapSetting : Dictionary<T, List<InputControl_C>> { }
 
-        public class BindingPage
+        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>();
@@ -242,7 +224,7 @@ namespace AxibugEmuOnline.Client.Settings
             public int ControllerIndex { get; }
             public EmuCoreControllerKeyBinding<T> Host { get; }
 
-            internal BindingPage(int controllerIndex, EmuCoreControllerKeyBinding<T> host)
+            internal ControllerBinder(int controllerIndex, EmuCoreControllerKeyBinding<T> host)
             {
                 ControllerIndex = controllerIndex;
                 Host = host;
@@ -342,5 +324,10 @@ namespace AxibugEmuOnline.Client.Settings
             }
         }
 
+        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);
     }
 }
\ 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
index 8631ad58..39a2fe40 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/MAMEKeyBinding.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/MAMEKeyBinding.cs
@@ -1,5 +1,6 @@
 using AxibugEmuOnline.Client.InputDevices;
 using AxibugProtobuf;
+using UnityEngine.UIElements;
 
 namespace AxibugEmuOnline.Client.Settings
 {
@@ -23,43 +24,120 @@ namespace AxibugEmuOnline.Client.Settings
     {
         public override int ControllerCount => 4;
 
-        protected override void OnRegistDevices(InputDevice_D device, BindingPage binding)
+        public override void Bind(Keyboard_D device, ControllerBinder controller)
         {
-            if (device is Keyboard_D keyboard)
+            switch (controller.ControllerIndex)
             {
-                switch (binding.ControllerIndex)
-                {
-                    case 0:
-                        binding.SetBinding(UMAMEKSingleKey.INSERT_COIN, keyboard.Q, 0);
-                        binding.SetBinding(UMAMEKSingleKey.GAMESTART, keyboard.E, 0);
-                        binding.SetBinding(UMAMEKSingleKey.UP, keyboard.W, 0);
-                        binding.SetBinding(UMAMEKSingleKey.DOWN, keyboard.S, 0);
-                        binding.SetBinding(UMAMEKSingleKey.LEFT, keyboard.A, 0);
-                        binding.SetBinding(UMAMEKSingleKey.RIGHT, keyboard.D, 0);
-                        binding.SetBinding(UMAMEKSingleKey.BTN_A, keyboard.J, 0);
-                        binding.SetBinding(UMAMEKSingleKey.BTN_B, keyboard.K, 0);
-                        binding.SetBinding(UMAMEKSingleKey.BTN_C, keyboard.L, 0);
-                        binding.SetBinding(UMAMEKSingleKey.BTN_D, keyboard.U, 0);
-                        binding.SetBinding(UMAMEKSingleKey.BTN_E, keyboard.I, 0);
-                        binding.SetBinding(UMAMEKSingleKey.BTN_F, keyboard.O, 0);
-                        break;
-                    case 1:
-                        binding.SetBinding(UMAMEKSingleKey.INSERT_COIN, keyboard.Delete, 0);
-                        binding.SetBinding(UMAMEKSingleKey.GAMESTART, keyboard.PageDown, 0);
-                        binding.SetBinding(UMAMEKSingleKey.UP, keyboard.UpArrow, 0);
-                        binding.SetBinding(UMAMEKSingleKey.DOWN, keyboard.DownArrow, 0);
-                        binding.SetBinding(UMAMEKSingleKey.LEFT, keyboard.LeftArrow, 0);
-                        binding.SetBinding(UMAMEKSingleKey.RIGHT, keyboard.RightArrow, 0);
-                        binding.SetBinding(UMAMEKSingleKey.BTN_A, keyboard.Keypad1, 0);
-                        binding.SetBinding(UMAMEKSingleKey.BTN_B, keyboard.Keypad2, 0);
-                        binding.SetBinding(UMAMEKSingleKey.BTN_C, keyboard.Keypad3, 0);
-                        binding.SetBinding(UMAMEKSingleKey.BTN_D, keyboard.Keypad4, 0);
-                        binding.SetBinding(UMAMEKSingleKey.BTN_E, keyboard.Keypad5, 0);
-                        binding.SetBinding(UMAMEKSingleKey.BTN_F, keyboard.Keypad6, 0);
-                        break;
-                }
+                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 class NEOGEOKeyBinding : MAMEKeyBinding
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/NesKeyBinding.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/NesKeyBinding.cs
index 3ab0e60e..39ddbade 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/NesKeyBinding.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/NesKeyBinding.cs
@@ -9,35 +9,100 @@ namespace AxibugEmuOnline.Client.Settings
         public override RomPlatformType Platform => RomPlatformType.Nes;
         public override int ControllerCount => 4;
 
-        protected override void OnRegistDevices(InputDevice_D device, BindingPage binding)
+        public override void Bind(Keyboard_D device, ControllerBinder controller)
         {
-            if (device is Keyboard_D keyboard)
+            switch (controller.ControllerIndex)
             {
-                switch (binding.ControllerIndex)
-                {
-                    case 0:
-                        binding.SetBinding(EnumButtonType.LEFT, keyboard.A, 0);
-                        binding.SetBinding(EnumButtonType.RIGHT, keyboard.D, 0);
-                        binding.SetBinding(EnumButtonType.UP, keyboard.W, 0);
-                        binding.SetBinding(EnumButtonType.DOWN, keyboard.S, 0);
-                        binding.SetBinding(EnumButtonType.A, keyboard.K, 0);
-                        binding.SetBinding(EnumButtonType.B, keyboard.J, 0);
-                        binding.SetBinding(EnumButtonType.SELECT, keyboard.V, 0);
-                        binding.SetBinding(EnumButtonType.START, keyboard.B, 0);
-                        binding.SetBinding(EnumButtonType.MIC, keyboard.M, 0);
-                        break;
-                    case 1:
-                        binding.SetBinding(EnumButtonType.UP, keyboard.UpArrow, 0);
-                        binding.SetBinding(EnumButtonType.DOWN, keyboard.DownArrow, 0);
-                        binding.SetBinding(EnumButtonType.LEFT, keyboard.LeftArrow, 0);
-                        binding.SetBinding(EnumButtonType.RIGHT, keyboard.RightArrow, 0);
-                        binding.SetBinding(EnumButtonType.A, keyboard.Keypad2, 0);
-                        binding.SetBinding(EnumButtonType.B, keyboard.Keypad1, 0);
-                        binding.SetBinding(EnumButtonType.SELECT, keyboard.Keypad0, 0);
-                        binding.SetBinding(EnumButtonType.START, keyboard.KeypadPeriod, 0);
-                        break;
-                }
+                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, 0);
+            controller.SetBinding(EnumButtonType.RIGHT, device.LeftStick.Right, 0);
+            controller.SetBinding(EnumButtonType.UP, device.LeftStick.Up, 0);
+            controller.SetBinding(EnumButtonType.DOWN, device.LeftStick.Down, 0);
+        }
+        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, 0);
+            controller.SetBinding(EnumButtonType.RIGHT, device.LeftStick.Right, 0);
+            controller.SetBinding(EnumButtonType.UP, device.LeftStick.Up, 0);
+            controller.SetBinding(EnumButtonType.DOWN, device.LeftStick.Down, 0);
+        }
     }
 }
\ 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
index caec9054..f749e14b 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/XMBKeyBinding.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/XMBKeyBinding.cs
@@ -9,38 +9,94 @@ namespace AxibugEmuOnline.Client
         public override RomPlatformType Platform => RomPlatformType.Invalid;
         public override int ControllerCount => 2;
 
-        protected override void OnRegistDevices(InputDevice_D device, BindingPage binding)
+        public override void Bind(Keyboard_D device, ControllerBinder controller)
         {
-            if (device is Keyboard_D keyboard)
+            switch (controller.ControllerIndex)
             {
-                switch (binding.ControllerIndex)
-                {
-                    case 0://设置标准UI控制
-                           //第一套控制布局 WSAD+JKLI
-                        binding.SetBinding(EnumCommand.Back, keyboard.L, 0);
-                        binding.SetBinding(EnumCommand.Enter, keyboard.K, 0);
-                        binding.SetBinding(EnumCommand.OptionMenu, keyboard.I, 0);
-                        binding.SetBinding(EnumCommand.SelectItemDown, keyboard.S, 0);
-                        binding.SetBinding(EnumCommand.SelectItemLeft, keyboard.A, 0);
-                        binding.SetBinding(EnumCommand.SelectItemRight, keyboard.D, 0);
-                        binding.SetBinding(EnumCommand.SelectItemUp, keyboard.W, 0);
+                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用
-                        binding.SetBinding(EnumCommand.Back, keyboard.Escape, 1);
-                        binding.SetBinding(EnumCommand.Back, keyboard.Backspace, 2);
-                        binding.SetBinding(EnumCommand.Enter, keyboard.Return, 1);
-                        binding.SetBinding(EnumCommand.OptionMenu, keyboard.LeftShift, 1);
-                        binding.SetBinding(EnumCommand.OptionMenu, keyboard.RightShift, 2);
-                        binding.SetBinding(EnumCommand.SelectItemDown, keyboard.DownArrow, 1);
-                        binding.SetBinding(EnumCommand.SelectItemLeft, keyboard.LeftArrow, 1);
-                        binding.SetBinding(EnumCommand.SelectItemRight, keyboard.RightArrow, 1);
-                        binding.SetBinding(EnumCommand.SelectItemUp, keyboard.UpArrow, 1);
-                        break;
-                    case 1://游戏中UI控制
-                        binding.SetBinding(EnumCommand.OptionMenu, keyboard.Escape, 0);
-                        break;
-                }
+                    //第二套控制布局 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);
+        }
     }
 }
\ 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
index 26cdf723..2243ef8a 100644
--- 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
@@ -7,7 +7,7 @@ namespace AxibugEmuOnline.Client.InputDevices
     /// </summary>
     public class Stick_C : InputControl_C
     {
-        public VirtualButton UP;
+        public VirtualButton Up;
         public VirtualButton Down;
         public VirtualButton Left;
         public VirtualButton Right;
@@ -20,8 +20,8 @@ namespace AxibugEmuOnline.Client.InputDevices
         {
             var axis = GetVector2();
 
-            UP.m_performing = axis.y > 0f;
-            UP.Update();
+            Up.m_performing = axis.y > 0f;
+            Up.Update();
 
             Down.m_performing = axis.y < 0f;
             Down.Update();
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs
index 0de419b2..b41cc3cb 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs
@@ -55,6 +55,14 @@ namespace AxibugEmuOnline.Client.InputDevices
 
             return null;
         }
+        /// <summary>
+        /// 获得所有存在的输入设备
+        /// </summary>
+        /// <returns></returns>
+        public IEnumerable<InputDevice_D> GetDevices()
+        {
+            return m_devices.Values;
+        }
 
         /// <summary> 由外部驱动的逻辑更新入口 </summary>
         public void Update()
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs
index 82f226ce..6f2c76ab 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs
@@ -1,12 +1,8 @@
 #if ENABLE_INPUT_SYSTEM
-using Google.Protobuf.WellKnownTypes;
-using NUnit.Framework.Internal;
 using System.Collections.Generic;
-using UnityEditor.Experimental.GraphView;
 using UnityEngine;
 using UnityEngine.InputSystem;
 using UnityEngine.InputSystem.DualShock;
-using UnityEngine.InputSystem.Haptics;
 using UnityEngine.InputSystem.XInput;
 
 namespace AxibugEmuOnline.Client.InputDevices.ForInputSystem
@@ -249,7 +245,7 @@ namespace AxibugEmuOnline.Client.InputDevices.ForInputSystem
                 mapper[ds_d.LeftStick] = ipDsGamePad.leftStick;
                 mapper[ds_d.RightStick] = ipDsGamePad.rightStick;
             }
-            else if(device_d is XboxController_D xbox_d)
+            else if (device_d is XboxController_D xbox_d)
             {
                 var ipXInputGamePad = ipdevice as XInputController;
                 mapper[xbox_d.X] = ipXInputGamePad.xButton;

From 34cf5487e8d7242e321f9e0a160fc9dab2cf4cc5 Mon Sep 17 00:00:00 2001
From: "ALIENJACK\\alien" <alienjack@foxmail.com>
Date: Mon, 31 Mar 2025 18:35:38 +0800
Subject: [PATCH 19/20] fix bug

---
 .../AppSettings/KeyMapperSetting/KeyMapperSetting.cs   | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs
index 4d63326b..81a80857 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs
@@ -107,11 +107,11 @@ namespace AxibugEmuOnline.Client.Settings
 
         internal void RaiseDeviceRegist(InputDevice_D device, ControllerBinder binding)
         {
-            if (device is Keyboard_D keyboard && this is IDeviceBinder<T, Keyboard_D> keyboardIn) keyboardIn.Bind(keyboard, binding);
-            if (device is GamePad_D gamePad && this is IDeviceBinder<T, GamePad_D> gamepadIn) gamepadIn.Bind(gamePad, binding);
-            if (device is DualShockController_D dsC && this is IDeviceBinder<T, DualShockController_D> dsIn) dsIn.Bind(dsC, binding);
-            if (device is XboxController_D xbC && this is IDeviceBinder<T, XboxController_D> xbIn) xbIn.Bind(xbC, binding);
-            if (device is PSVController_D psvC && this is IDeviceBinder<T, PSVController_D> psvIn) psvIn.Bind(psvC, 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 throw new NotImplementedException($"{device.GetType()}");
         }
 

From cfb3bc8b6a6323841ecaa30a15338324a89217ad Mon Sep 17 00:00:00 2001
From: "ALIENJACK\\alien" <alienjack@foxmail.com>
Date: Tue, 1 Apr 2025 15:35:17 +0800
Subject: [PATCH 20/20] =?UTF-8?q?Input=E6=9C=BA=E5=88=B6=E4=BF=AE=E6=94=B9?=
 =?UTF-8?q?=E5=B7=B2=E5=AE=8C=E6=88=90?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../UIPrefabs/OverlayUI/Overlay.prefab        |  13 +-
 .../Resources/UIPrefabs/ScreenKeyPad.prefab   |  13 +
 .../Assets/Scene/AxibugEmuOnline.Client.unity |   2 +-
 .../ColecoVisionMultiKeysSetting.cs           |  86 -----
 .../ColecoVisionMultiKeysSetting.cs.meta      |   2 -
 .../GameBoyColorMultiKeysSetting.cs           |  69 ----
 .../GameBoyColorMultiKeysSetting.cs.meta      |   2 -
 .../GameBoyMultiKeysSetting.cs                |  69 ----
 .../GameBoyMultiKeysSetting.cs.meta           |   2 -
 .../GameGearMultiKeysSetting.cs               |  86 -----
 .../GameGearMultiKeysSetting.cs.meta          |   2 -
 .../GamingMultiKeysSetting.cs                 |  43 ---
 .../GamingMultiKeysSetting.cs.meta            |   2 -
 .../MasterSystemMultiKeysSetting.cs           |  88 -----
 .../MasterSystemMultiKeysSetting.cs.meta      |   2 -
 .../NESMultiKeysSetting.cs                    |  80 -----
 .../NESMultiKeysSetting.cs.meta               |   2 -
 .../SC3000MultiKeysSetting.cs                 |  86 -----
 .../SC3000MultiKeysSetting.cs.meta            |   2 -
 .../SG1000MultiKeysSetting.cs                 |  86 -----
 .../SG1000MultiKeysSetting.cs.meta            |   2 -
 .../UMAMEMultiKeysSetting.cs                  |  83 -----
 .../UMAMEMultiKeysSetting.cs.meta             |   2 -
 .../XMBMultiKeysSetting.cs                    |  72 ----
 .../XMBMultiKeysSetting.cs.meta               |   2 -
 .../AppMain/AxiInputSP/AxiInput.Struct.cs     |   8 +-
 .../Script/AppMain/AxiInputSP/AxiInputEx.cs   |  79 -----
 .../AppMain/AxiInputSP/AxiInputEx.cs.meta     |   2 -
 .../AxiInputSP/UGUI/AxiInputUGUICenter.cs     |  78 -----
 .../UGUI/AxiInputUGUICenter.cs.meta           |   2 -
 .../AxiInputSP/UGUI/AxiInputUGUIHandle.cs     |  40 ---
 .../UGUI/AxiInputUGUIHandle.cs.meta           |   2 -
 .../AppMain/AxiInputSP/UGUI/AxiIptButton.cs   |  43 +--
 .../AppMain/AxiInputSP/UGUI/AxiIptJoystick.cs | 121 -------
 .../AxiInputSP/UGUI/AxiIptJoystick.cs.meta    |   2 -
 .../AxiInputSP/UGUI/AxiScreenGamepad.cs       |  62 ++++
 .../AxiInputSP/UGUI/AxiScreenGamepad.cs.meta  |   2 +
 .../UEssgeeInterface/UEGKeyboard.cs           |   2 -
 .../MameEmulator/UniInterface/UniKeyboard.cs  |   1 -
 .../Assets/Script/AppMain/Manager/AppInput.cs | 179 ----------
 .../Script/AppMain/Manager/AppInput.cs.meta   |   2 -
 .../KeyMapperSetting/EssgeeKeyBinding.cs      |  20 +-
 .../KeyMapperSetting/IDeviceBinder.cs         |  17 -
 .../KeyMapperSetting/KeyMapperSetting.cs      | 307 +-----------------
 .../KeyMapperSetting/MAMEKeyBinding.cs        |  22 +-
 .../AppSettings/KeyMapperSetting/Model.meta}  |   2 +-
 .../KeyMapperSetting/Model/EmuCoreBinder.cs   | 287 ++++++++++++++++
 .../Model/EmuCoreBinder.cs.meta               |   2 +
 .../KeyMapperSetting/Model/IDeviceBinder.cs   |  17 +
 .../{ => Model}/IDeviceBinder.cs.meta         |   0
 .../Model/InternalEmuCoreBinder.cs            |  12 +
 .../Model/InternalEmuCoreBinder.cs.meta       |   2 +
 .../KeyMapperSetting/NesKeyBinding.cs         |  35 +-
 .../KeyMapperSetting/XMBKeyBinding.cs         |  18 +-
 .../Devices/InputControls/InputControl_C.cs   |   2 +-
 .../Devices/InputControls/Stick_C.cs          |   4 +-
 .../Devices/ScreenGamepad_D.cs                |  74 +++++
 .../Devices/ScreenGamepad_D.cs.meta           |   2 +
 .../InputDevicesManager.cs                    |   9 +
 .../InputResolver/InputResolver.cs            | 100 +++++-
 .../InputResolver/InputSystemResolver.cs      |  12 +-
 .../InputResolver/PSVResolver.cs              |  12 +-
 .../AppMain/UI/Joystick/FloatingJoystick.cs   |  23 +-
 .../AppMain/UI/OverlayUI/OverlayManager.cs    |   5 +-
 64 files changed, 699 insertions(+), 1808 deletions(-)
 delete mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/ColecoVisionMultiKeysSetting.cs
 delete mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/ColecoVisionMultiKeysSetting.cs.meta
 delete mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GameBoyColorMultiKeysSetting.cs
 delete mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GameBoyColorMultiKeysSetting.cs.meta
 delete mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GameBoyMultiKeysSetting.cs
 delete mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GameBoyMultiKeysSetting.cs.meta
 delete mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GameGearMultiKeysSetting.cs
 delete mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GameGearMultiKeysSetting.cs.meta
 delete mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GamingMultiKeysSetting.cs
 delete mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GamingMultiKeysSetting.cs.meta
 delete mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/MasterSystemMultiKeysSetting.cs
 delete mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/MasterSystemMultiKeysSetting.cs.meta
 delete mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/NESMultiKeysSetting.cs
 delete mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/NESMultiKeysSetting.cs.meta
 delete mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/SC3000MultiKeysSetting.cs
 delete mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/SC3000MultiKeysSetting.cs.meta
 delete mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/SG1000MultiKeysSetting.cs
 delete mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/SG1000MultiKeysSetting.cs.meta
 delete mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/UMAMEMultiKeysSetting.cs
 delete mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/UMAMEMultiKeysSetting.cs.meta
 delete mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/XMBMultiKeysSetting.cs
 delete mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/XMBMultiKeysSetting.cs.meta
 delete mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/AxiInputEx.cs
 delete mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/AxiInputEx.cs.meta
 delete mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/UGUI/AxiInputUGUICenter.cs
 delete mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/UGUI/AxiInputUGUICenter.cs.meta
 delete mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/UGUI/AxiInputUGUIHandle.cs
 delete mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/UGUI/AxiInputUGUIHandle.cs.meta
 delete mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/UGUI/AxiIptJoystick.cs
 delete mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/UGUI/AxiIptJoystick.cs.meta
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/UGUI/AxiScreenGamepad.cs
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP/UGUI/AxiScreenGamepad.cs.meta
 delete mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppInput.cs
 delete mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppInput.cs.meta
 delete mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/IDeviceBinder.cs
 rename AxibugEmuOnline.Client/Assets/Script/AppMain/{AxiInputSP.Settings.meta => Manager/AppSettings/KeyMapperSetting/Model.meta} (77%)
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/Model/EmuCoreBinder.cs
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/Model/EmuCoreBinder.cs.meta
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/Model/IDeviceBinder.cs
 rename AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/{ => Model}/IDeviceBinder.cs.meta (100%)
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/Model/InternalEmuCoreBinder.cs
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/Model/InternalEmuCoreBinder.cs.meta
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/ScreenGamepad_D.cs
 create mode 100644 AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/ScreenGamepad_D.cs.meta

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/AxiInputSP.Settings/ColecoVisionMultiKeysSetting.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/ColecoVisionMultiKeysSetting.cs
deleted file mode 100644
index 29ad615b..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/ColecoVisionMultiKeysSetting.cs
+++ /dev/null
@@ -1,86 +0,0 @@
-using AxibugEmuOnline.Client.Manager;
-using AxibugEmuOnline.Client.Settings;
-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 71c4b648..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GameBoyColorMultiKeysSetting.cs
+++ /dev/null
@@ -1,69 +0,0 @@
-using AxibugEmuOnline.Client.Manager;
-using AxibugEmuOnline.Client.Settings;
-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 74c553f8..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GameBoyMultiKeysSetting.cs
+++ /dev/null
@@ -1,69 +0,0 @@
-using AxibugEmuOnline.Client.Manager;
-using AxibugEmuOnline.Client.Settings;
-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 52a7c89f..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/GameGearMultiKeysSetting.cs
+++ /dev/null
@@ -1,86 +0,0 @@
-using AxibugEmuOnline.Client.Manager;
-using AxibugEmuOnline.Client.Settings;
-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 2c54db97..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/MasterSystemMultiKeysSetting.cs
+++ /dev/null
@@ -1,88 +0,0 @@
-using AxibugEmuOnline.Client.Manager;
-using AxibugEmuOnline.Client.Settings;
-using System;
-using UnityEngine;
-
-namespace AxiInputSP.Setting
-{
-    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 5db67991..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
-            //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 d305c562..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/SC3000MultiKeysSetting.cs
+++ /dev/null
@@ -1,86 +0,0 @@
-using AxibugEmuOnline.Client.Manager;
-using AxibugEmuOnline.Client.Settings;
-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 316248d0..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/SG1000MultiKeysSetting.cs
+++ /dev/null
@@ -1,86 +0,0 @@
-using AxibugEmuOnline.Client.Manager;
-using AxibugEmuOnline.Client.Settings;
-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 4f35c774..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings/UMAMEMultiKeysSetting.cs
+++ /dev/null
@@ -1,83 +0,0 @@
-using AxibugEmuOnline.Client.Manager;
-using AxibugEmuOnline.Client.Settings;
-using UnityEngine;
-
-namespace AxiInputSP.Setting
-{
-    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/Emulator/EssgeeEmulator/UEssgeeInterface/UEGKeyboard.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/EssgeeEmulator/UEssgeeInterface/UEGKeyboard.cs
index a8102448..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,9 +1,7 @@
 using AxibugEmuOnline.Client;
 using AxibugEmuOnline.Client.ClientCore;
 using AxibugEmuOnline.Client.Event;
-using AxibugEmuOnline.Client.Manager;
 using AxibugEmuOnline.Client.Settings;
-using AxiInputSP.Setting;
 using AxiReplay;
 using System;
 using System.Collections.Generic;
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 c16a915a..20521e68 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/MameEmulator/UniInterface/UniKeyboard.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Emulator/MameEmulator/UniInterface/UniKeyboard.cs
@@ -2,7 +2,6 @@
 using AxibugEmuOnline.Client.ClientCore;
 using AxibugEmuOnline.Client.Event;
 using AxibugEmuOnline.Client.Settings;
-using AxiInputSP.Setting;
 using AxiReplay;
 using MAME.Core;
 using System;
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/KeyMapperSetting/EssgeeKeyBinding.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/EssgeeKeyBinding.cs
index df56af03..8e859bd7 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/EssgeeKeyBinding.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/EssgeeKeyBinding.cs
@@ -20,7 +20,7 @@ namespace AxibugEmuOnline.Client.Settings
         OPTION_2 = 1 << 9,
     }
 
-    public abstract class EssgeeKeyBinding : EmuCoreControllerKeyBinding<EssgeeSingleKey>
+    public abstract class EssgeeKeyBinding : EmuCoreBinder<EssgeeSingleKey>
     {
         public override void Bind(Keyboard_D device, ControllerBinder controller)
         {
@@ -129,6 +129,24 @@ namespace AxibugEmuOnline.Client.Settings
             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
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/IDeviceBinder.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/IDeviceBinder.cs
deleted file mode 100644
index 3001ea39..00000000
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/IDeviceBinder.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using AxibugEmuOnline.Client.InputDevices;
-using System;
-
-namespace AxibugEmuOnline.Client.Settings
-{
-    /// <summary>
-    /// 在所有<see cref="EmuCoreControllerKeyBinding{T}"/>的派生类中实现此接口以支持一种设备的绑定
-    /// <para>一种<see cref="EmuCoreControllerKeyBinding{T}"/>
-    /// 一个<see cref="EmuCoreControllerKeyBinding{T}.ControllerBinder"/>可以与多种设备建立绑定,但设备类型不可重复</para>
-    /// </summary>
-    public interface IDeviceBinder<ENUM, DEVICE>
-        where ENUM : Enum
-        where DEVICE : InputDevice_D
-    {
-        void Bind(DEVICE device, EmuCoreControllerKeyBinding<ENUM>.ControllerBinder controller);
-    }
-}
\ 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
index 81a80857..1447b390 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/KeyMapperSetting.cs
@@ -1,10 +1,6 @@
-using AxibugEmuOnline.Client.ClientCore;
-using AxibugEmuOnline.Client.InputDevices;
-using AxibugProtobuf;
+using AxibugProtobuf;
 using System;
 using System.Collections.Generic;
-using System.Linq;
-using UnityEngine;
 
 namespace AxibugEmuOnline.Client.Settings
 {
@@ -13,321 +9,32 @@ namespace AxibugEmuOnline.Client.Settings
     /// </summary>
     public class KeyMapperSetting
     {
-        Dictionary<RomPlatformType, EmuCoreControllerKeyBinding> m_binders = new Dictionary<RomPlatformType, EmuCoreControllerKeyBinding>();
-        Dictionary<Type, EmuCoreControllerKeyBinding> m_bindersByType = new Dictionary<Type, EmuCoreControllerKeyBinding>();
+        Dictionary<RomPlatformType, InternalEmuCoreBinder> m_binders = new Dictionary<RomPlatformType, InternalEmuCoreBinder>();
+        Dictionary<Type, InternalEmuCoreBinder> m_bindersByType = new Dictionary<Type, InternalEmuCoreBinder>();
         public KeyMapperSetting()
         {
-            var baseType = typeof(EmuCoreControllerKeyBinding);
+            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 EmuCoreControllerKeyBinding;
+                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 : EmuCoreControllerKeyBinding
+        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 : EmuCoreControllerKeyBinding
+        public T GetBinder<T>(RomPlatformType romType) where T : InternalEmuCoreBinder
         {
             m_binders.TryGetValue(romType, out var binder);
             return binder as T;
         }
     }
-
-    /// <summary>
-    /// 此类为内部继承, 请勿继承此类
-    /// </summary>
-    public abstract class EmuCoreControllerKeyBinding
-    {
-        /// <summary> 所属核心 </summary>
-        public abstract RomPlatformType Platform { get; }
-        /// <summary> 控制器数量 </summary>
-        public abstract int ControllerCount { get; }
-    }
-
-    /// <summary>
-    /// 模拟器核心控制器键位绑定器
-    /// </summary>
-    /// <typeparam name="T"></typeparam>
-    public abstract class EmuCoreControllerKeyBinding<T> : EmuCoreControllerKeyBinding,
-        IDeviceBinder<T, Keyboard_D>,
-        IDeviceBinder<T, GamePad_D>,
-        IDeviceBinder<T, DualShockController_D>,
-        IDeviceBinder<T, XboxController_D>,
-        IDeviceBinder<T, PSVController_D>
-        where T : Enum
-    {
-        //每一个实例代表一个对应模拟器平台的控制器索引
-        List<ControllerBinder> m_bindingPages = new List<ControllerBinder>();
-
-        public EmuCoreControllerKeyBinding()
-        {
-            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 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 EmuCoreControllerKeyBinding<T> Host { get; }
-
-            internal ControllerBinder(int controllerIndex, EmuCoreControllerKeyBinding<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);
-    }
 }
\ 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
index 39a2fe40..7c6d6175 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/MAMEKeyBinding.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/MAMEKeyBinding.cs
@@ -20,7 +20,7 @@ namespace AxibugEmuOnline.Client.Settings
         BTN_F
     }
 
-    public abstract class MAMEKeyBinding : EmuCoreControllerKeyBinding<UMAMEKSingleKey>
+    public abstract class MAMEKeyBinding : EmuCoreBinder<UMAMEKSingleKey>
     {
         public override int ControllerCount => 4;
 
@@ -138,6 +138,26 @@ namespace AxibugEmuOnline.Client.Settings
             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
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/Model.meta
similarity index 77%
rename from AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings.meta
rename to AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/Model.meta
index a924eaef..b7a6eef8 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/AxiInputSP.Settings.meta
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/Model.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: 91746af636f351140a4796dc4e98be6d
+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/IDeviceBinder.cs.meta b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/Model/IDeviceBinder.cs.meta
similarity index 100%
rename from AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/IDeviceBinder.cs.meta
rename to AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/Model/IDeviceBinder.cs.meta
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
index 39ddbade..8a743318 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/NesKeyBinding.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/NesKeyBinding.cs
@@ -4,7 +4,7 @@ using VirtualNes.Core;
 
 namespace AxibugEmuOnline.Client.Settings
 {
-    public class NesKeyBinding : EmuCoreControllerKeyBinding<EnumButtonType>
+    public class NesKeyBinding : EmuCoreBinder<EnumButtonType>
     {
         public override RomPlatformType Platform => RomPlatformType.Nes;
         public override int ControllerCount => 4;
@@ -82,10 +82,10 @@ namespace AxibugEmuOnline.Client.Settings
             controller.SetBinding(EnumButtonType.START, device.Start, 0);
             controller.SetBinding(EnumButtonType.MIC, device.L, 0);
 
-            controller.SetBinding(EnumButtonType.LEFT, device.LeftStick.Left, 0);
-            controller.SetBinding(EnumButtonType.RIGHT, device.LeftStick.Right, 0);
-            controller.SetBinding(EnumButtonType.UP, device.LeftStick.Up, 0);
-            controller.SetBinding(EnumButtonType.DOWN, device.LeftStick.Down, 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)
         {
@@ -99,10 +99,27 @@ namespace AxibugEmuOnline.Client.Settings
             controller.SetBinding(EnumButtonType.START, device.Menu, 0);
             controller.SetBinding(EnumButtonType.MIC, device.LeftBumper, 0);
 
-            controller.SetBinding(EnumButtonType.LEFT, device.LeftStick.Left, 0);
-            controller.SetBinding(EnumButtonType.RIGHT, device.LeftStick.Right, 0);
-            controller.SetBinding(EnumButtonType.UP, device.LeftStick.Up, 0);
-            controller.SetBinding(EnumButtonType.DOWN, device.LeftStick.Down, 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/XMBKeyBinding.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/XMBKeyBinding.cs
index f749e14b..a7bce802 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/XMBKeyBinding.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/AppSettings/KeyMapperSetting/XMBKeyBinding.cs
@@ -1,10 +1,9 @@
 using AxibugEmuOnline.Client.InputDevices;
-using AxibugEmuOnline.Client.Settings;
 using AxibugProtobuf;
 
 namespace AxibugEmuOnline.Client
 {
-    public class XMBKeyBinding : EmuCoreControllerKeyBinding<EnumCommand>
+    public class XMBKeyBinding : EmuCoreBinder<EnumCommand>
     {
         public override RomPlatformType Platform => RomPlatformType.Invalid;
         public override int ControllerCount => 2;
@@ -98,5 +97,20 @@ namespace AxibugEmuOnline.Client
             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/InputDevicesManager/Devices/InputControls/InputControl_C.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/Devices/InputControls/InputControl_C.cs
index ad1a5059..772d697e 100644
--- 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
@@ -68,7 +68,7 @@ namespace AxibugEmuOnline.Client.InputDevices
             {
                 if (!typeof(InputControl_C).IsAssignableFrom(field.FieldType)) continue;
 
-                var controlIns = Activator.CreateInstance(field.FieldType, this, field.Name) as InputControl_C;
+                var controlIns = Activator.CreateInstance(field.FieldType, Device, field.Name) as InputControl_C;
                 controlIns.Parent = this;
                 field.SetValue(this, controlIns);
 
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
index 2243ef8a..023b1146 100644
--- 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
@@ -12,9 +12,7 @@ namespace AxibugEmuOnline.Client.InputDevices
         public VirtualButton Left;
         public VirtualButton Right;
 
-        public Stick_C(InputDevice_D device, string controlName) : base(device, controlName)
-        {
-        }
+        public Stick_C(InputDevice_D device, string controlName) : base(device, controlName) { }
 
         protected override void OnUpdate()
         {
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/InputDevicesManager.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs
index b41cc3cb..eb323aa1 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputDevicesManager.cs
@@ -13,14 +13,21 @@ namespace AxibugEmuOnline.Client.InputDevices
         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);
@@ -39,6 +46,8 @@ namespace AxibugEmuOnline.Client.InputDevices
 
         void RemoveDevice(InputDevice_D device)
         {
+            if (m_quiting) return;
+
             m_devices.Remove(device.UniqueName);
             OnDeviceLost?.Invoke(device);
         }
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputResolver.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputResolver.cs
index 4efbdeb9..c681bb0a 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputResolver.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputResolver.cs
@@ -1,6 +1,6 @@
-using System.Collections.Generic;
+using AxiInputSP.UGUI;
+using System.Collections.Generic;
 using UnityEngine;
-using UnityEngine.InputSystem;
 
 namespace AxibugEmuOnline.Client.InputDevices
 {
@@ -18,25 +18,64 @@ namespace AxibugEmuOnline.Client.InputDevices
             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 abstract IEnumerable<InputDevice_D> GetDevices();
+        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>
-        /// <returns></returns>
-        public abstract bool CheckOnline(InputDevice_D device);
+        /// <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);
@@ -56,14 +95,51 @@ namespace AxibugEmuOnline.Client.InputDevices
             OnDeviceConnected?.Invoke(connectDevice);
         }
 
-        public abstract bool CheckPerforming<CONTROLLER>(CONTROLLER control) where CONTROLLER : InputControl_C;
-        public abstract Vector2 GetVector2<CONTROLLER>(CONTROLLER control) where CONTROLLER : InputControl_C;
-        public abstract float GetFloat<CONTROLLER>(CONTROLLER control) where CONTROLLER : InputControl_C;
+        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 abstract string GetDeviceName(InputDevice_D inputDevice);
+        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/InputSystemResolver.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs
index 6f2c76ab..02eec3fd 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/InputSystemResolver.cs
@@ -51,7 +51,7 @@ namespace AxibugEmuOnline.Client.InputDevices.ForInputSystem
             return ipDev as T;
         }
 
-        public override string GetDeviceName(InputDevice_D inputDevice)
+        protected override string OnGetDeviceName(InputDevice_D inputDevice)
         {
             var ipdev = GetInputSystemDevice<InputDevice>(inputDevice);
             Debug.Assert(ipdev != null, "不能对已离线的设备获取名称");
@@ -59,7 +59,7 @@ namespace AxibugEmuOnline.Client.InputDevices.ForInputSystem
             return $"{ipdev.description.deviceClass}_{ipdev.description.interfaceName}_{ipdev.deviceId}";
         }
 
-        public override bool CheckOnline(InputDevice_D device)
+        protected override bool OnCheckOnline(InputDevice_D device)
         {
             return m_devices.TryGetKey(device, out var _);
         }
@@ -73,24 +73,24 @@ namespace AxibugEmuOnline.Client.InputDevices.ForInputSystem
             }
         }
 
-        public override IEnumerable<InputDevice_D> GetDevices()
+        protected override IEnumerable<InputDevice_D> OnGetDevices()
         {
             return m_devices.Values;
         }
 
-        public override bool CheckPerforming<CONTROLLER>(CONTROLLER control)
+        protected override bool OnCheckPerforming<CONTROLLER>(CONTROLLER control)
         {
             var ipControl = GetInputSystemControl(control);
             return ipControl.IsPressed();
         }
 
-        public override Vector2 GetVector2<CONTROLLER>(CONTROLLER control)
+        protected override Vector2 OnGetVector2<CONTROLLER>(CONTROLLER control)
         {
             var ipControl = GetInputSystemControl(control);
             return (ipControl as InputControl<Vector2>).value;
         }
 
-        public override float GetFloat<CONTROLLER>(CONTROLLER control)
+        protected override float OnGetFloat<CONTROLLER>(CONTROLLER control)
         {
             var ipControl = GetInputSystemControl(control);
             return (ipControl as InputControl<float>).value;
diff --git a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/PSVResolver.cs b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/PSVResolver.cs
index f97a973a..b13ac075 100644
--- a/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/PSVResolver.cs
+++ b/AxibugEmuOnline.Client/Assets/Script/AppMain/Manager/InputDevicesManager/InputResolver/PSVResolver.cs
@@ -15,24 +15,24 @@ namespace AxibugEmuOnline.Client.InputDevices.ForPSV
             m_devices.Add(m_psvController);
         }
 
-        public override IEnumerable<InputDevice_D> GetDevices()
+        protected override IEnumerable<InputDevice_D> OnGetDevices()
         {
             return m_devices;
         }
 
-        public override bool CheckOnline(InputDevice_D device)
+        protected override bool OnCheckOnline(InputDevice_D device)
         {
             return device == m_psvController;
         }
 
-        public override string GetDeviceName(InputDevice_D inputDevice)
+        protected override string OnGetDeviceName(InputDevice_D inputDevice)
         {
             Debug.Assert(inputDevice == m_psvController, "只支持psv控制器");
 
             return nameof(PSVController_D);
         }
 
-        public override bool CheckPerforming<CONTROLLER>(CONTROLLER control)
+        protected override bool OnCheckPerforming<CONTROLLER>(CONTROLLER control)
         {
             if (control.Device is PSVController_D psvCon)
             {
@@ -58,7 +58,7 @@ namespace AxibugEmuOnline.Client.InputDevices.ForPSV
             throw new System.NotImplementedException();
         }
 
-        public override Vector2 GetVector2<CONTROLLER>(CONTROLLER control)
+        protected override Vector2 OnGetVector2<CONTROLLER>(CONTROLLER control)
         {
             if (control.Device is PSVController_D psvCon)
             {
@@ -75,7 +75,7 @@ namespace AxibugEmuOnline.Client.InputDevices.ForPSV
             throw new System.NotImplementedException();
         }
 
-        public override float GetFloat<CONTROLLER>(CONTROLLER control)
+        protected override float OnGetFloat<CONTROLLER>(CONTROLLER control)
         {
             throw new System.NotImplementedException();
         }
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/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)