using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.InputSystem; /// /// Runtime key rebinding UI. Toggle with F2. /// Manages rebinding for InputSystem actions (movement, jump) /// and custom camera orbit keys (ZQSD). /// All overrides persist in PlayerPrefs. /// public class KeyBindingUI : MonoBehaviour { private bool _visible = false; private string _rebindingAction = null; /// True when the keybind config menu is open. Used to freeze camera + unlock cursor. public static bool IsVisible { get; private set; } private InputActionRebindingExtensions.RebindingOperation _rebindOp; // Default camera keys (physical WASD positions = ZQSD on AZERTY) private static readonly Dictionary _defaultCameraKeys = new() { { "CamUp", Key.W }, { "CamDown", Key.S }, { "CamLeft", Key.A }, { "CamRight", Key.D }, }; private static readonly string[] _cameraKeyNames = { "CamUp", "CamDown", "CamLeft", "CamRight" }; private static readonly string[] _cameraKeyLabels = { "Caméra haut", "Caméra bas", "Caméra gauche", "Caméra droite" }; private static Dictionary _currentCameraKeys; private PlayerInput _playerInput; void Awake() { LoadCameraKeys(); } void Start() { _playerInput = FindFirstObjectByType(); LoadBindingOverrides(); } void Update() { if (Keyboard.current != null && Keyboard.current[Key.F2].wasPressedThisFrame) { _visible = !_visible; IsVisible = _visible; if (_visible) { Cursor.lockState = CursorLockMode.None; Cursor.visible = true; } else { CancelRebind(); Cursor.lockState = CursorLockMode.Locked; Cursor.visible = false; } } } void LateUpdate() { // Process camera key rebinding if (_rebindingAction == null) return; if (!_defaultCameraKeys.ContainsKey(_rebindingAction)) return; var kb = Keyboard.current; if (kb == null) return; foreach (Key k in Enum.GetValues(typeof(Key))) { if (k == Key.None) continue; try { if (kb[k].wasPressedThisFrame) { if (k == Key.Escape) { _rebindingAction = null; return; } _currentCameraKeys[_rebindingAction] = k; SaveCameraKeys(); _rebindingAction = null; return; } } catch { } } } void OnGUI() { if (!_visible) return; ImGuiSkin.EnsureReady(); // Overlay ImGuiSkin.DrawOverlay(); float w = 480, h = 540; ImGuiSkin.BeginWindow(w, h, "Configuration des touches"); // --- Movement --- ImGuiSkin.DrawSectionHeader("DÉPLACEMENT"); GUILayout.Space(4); DrawActionBinding("forward", "Avancer"); DrawActionBinding("backwards", "Reculer"); DrawActionBinding("left", "Gauche"); DrawActionBinding("right", "Droite"); DrawActionBinding("jump", "Sauter"); GUILayout.Space(10); // --- Camera --- ImGuiSkin.DrawSectionHeader("CAMÉRA (+ SOURIS)"); GUILayout.Space(4); for (int i = 0; i < _cameraKeyNames.Length; i++) DrawCameraKeyBinding(_cameraKeyNames[i], _cameraKeyLabels[i]); GUILayout.Space(16); // Buttons GUILayout.BeginHorizontal(); if (GUILayout.Button("Réinitialiser tout", ImGuiSkin.Button, GUILayout.Height(32))) ResetAllBindings(); if (GUILayout.Button("Fermer (F2)", ImGuiSkin.Button, GUILayout.Height(32))) { _visible = false; CancelRebind(); } GUILayout.EndHorizontal(); GUILayout.Space(6); if (_rebindingAction != null) { GUILayout.Label("Appuyez sur une touche pour assigner...", ImGuiSkin.Hint); } // F2 hint GUILayout.Label("F2 — Ouvrir / Fermer ce menu", ImGuiSkin.Footer); ImGuiSkin.EndWindow(); } // --- Drawing helpers --- private void DrawActionBinding(string actionName, string label) { if (_playerInput == null) return; var action = _playerInput.actions.FindAction(actionName); if (action == null) return; GUILayout.BeginHorizontal(); GUILayout.Label(label, ImGuiSkin.Label, GUILayout.Width(150)); string currentBinding = "---"; if (action.bindings.Count > 0) currentBinding = InputControlPath.ToHumanReadableString( action.bindings[0].effectivePath, InputControlPath.HumanReadableStringOptions.OmitDevice); bool isRebinding = _rebindingAction == actionName; string btnText = isRebinding ? "[ ... ]" : currentBinding; GUIStyle btnStyle = isRebinding ? ImGuiSkin.ButtonAccent : ImGuiSkin.ButtonSmall; if (GUILayout.Button(btnText, btnStyle, GUILayout.Width(170), GUILayout.Height(26))) { if (!isRebinding) StartActionRebind(actionName); else CancelRebind(); } GUILayout.EndHorizontal(); } private void DrawCameraKeyBinding(string keyName, string label) { GUILayout.BeginHorizontal(); GUILayout.Label(label, ImGuiSkin.Label, GUILayout.Width(150)); Key current = GetKey(keyName, _defaultCameraKeys[keyName]); bool isRebinding = _rebindingAction == keyName; string btnText = isRebinding ? "[ ... ]" : current.ToString(); GUIStyle btnStyle = isRebinding ? ImGuiSkin.ButtonAccent : ImGuiSkin.ButtonSmall; if (GUILayout.Button(btnText, btnStyle, GUILayout.Width(170), GUILayout.Height(26))) { if (!isRebinding) StartCameraKeyRebind(keyName); else CancelRebind(); } GUILayout.EndHorizontal(); } // --- Rebinding logic --- private void StartActionRebind(string actionName) { CancelRebind(); var action = _playerInput?.actions.FindAction(actionName); if (action == null) return; _rebindingAction = actionName; action.Disable(); _rebindOp = action.PerformInteractiveRebinding(0) .WithControlsExcluding("Mouse") .OnMatchWaitForAnother(0.1f) .OnComplete(op => { action.Enable(); SaveBindingOverrides(); _rebindingAction = null; op.Dispose(); _rebindOp = null; }) .OnCancel(op => { action.Enable(); _rebindingAction = null; op.Dispose(); _rebindOp = null; }) .Start(); } private void StartCameraKeyRebind(string keyName) { CancelRebind(); _rebindingAction = keyName; } private void CancelRebind() { if (_rebindOp != null) { _rebindOp.Cancel(); _rebindOp.Dispose(); _rebindOp = null; } _rebindingAction = null; } // --- Persistence --- private void SaveBindingOverrides() { if (_playerInput == null) return; string json = _playerInput.actions.SaveBindingOverridesAsJson(); PlayerPrefs.SetString("InputOverrides", json); PlayerPrefs.Save(); } private void LoadBindingOverrides() { if (_playerInput == null) return; string json = PlayerPrefs.GetString("InputOverrides", ""); if (!string.IsNullOrEmpty(json)) _playerInput.actions.LoadBindingOverridesFromJson(json); } private static void LoadCameraKeys() { _currentCameraKeys = new Dictionary(); foreach (var kv in _defaultCameraKeys) { string saved = PlayerPrefs.GetString($"CamKey_{kv.Key}", ""); if (!string.IsNullOrEmpty(saved) && Enum.TryParse(saved, out Key parsed)) _currentCameraKeys[kv.Key] = parsed; else _currentCameraKeys[kv.Key] = kv.Value; } } private static void SaveCameraKeys() { if (_currentCameraKeys == null) return; foreach (var kv in _currentCameraKeys) PlayerPrefs.SetString($"CamKey_{kv.Key}", kv.Value.ToString()); PlayerPrefs.Save(); } /// /// Get a camera key binding. Usable globally (static). /// public static Key GetKey(string name, Key fallback) { if (_currentCameraKeys == null) LoadCameraKeys(); return _currentCameraKeys != null && _currentCameraKeys.TryGetValue(name, out Key k) ? k : fallback; } private void ResetAllBindings() { // Reset InputSystem actions if (_playerInput != null) { foreach (var action in _playerInput.actions) action.RemoveAllBindingOverrides(); PlayerPrefs.DeleteKey("InputOverrides"); } // Reset camera keys _currentCameraKeys = new Dictionary(_defaultCameraKeys); foreach (var kv in _defaultCameraKeys) PlayerPrefs.DeleteKey($"CamKey_{kv.Key}"); PlayerPrefs.Save(); } }