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;