projectEli/Assets/NeoFPS/Core/Settings/Contexts/FpsKeyBindings.cs

613 lines
22 KiB
C#
Raw Normal View History

2022-11-07 01:28:33 +00:00
#if UNITY_STANDALONE
// Should other platforms use Json text files saved to disk?
#define SETTINGS_USES_JSON
using System.IO;
#endif
using System;
using System.Collections;
using UnityEngine;
using NeoFPS.Constants;
namespace NeoFPS
{
[HelpURL("https://docs.neofps.com/manual/neofpsref-mb-fpskeybindings.html")]
[CreateAssetMenu(fileName = "FpsSettings_KeyBindings", menuName = "NeoFPS/Settings/KeyBindings", order = NeoFpsMenuPriorities.settings_keybindings)]
public class FpsKeyBindings : SettingsContext<FpsKeyBindings>
{
protected override string contextName { get { return "KeyBindings"; } }
public override string displayTitle { get { return "NeoFPS Key Bindings"; } }
public override string tocName { get { return "Key Bindings"; } }
public override string tocID { get { return "settings_keybindings"; } }
[SerializeField, Tooltip("The keyboard keycodes assigned based on the FpsInputButton generated constant.")]
private KeyCodePair[] m_KeyCodes = null;
[Serializable]
private struct KeyCodePair
{
[Tooltip("The primary key or button.")]
public KeyCode primary;
[Tooltip("The secondary (alternative) key or button.")]
public KeyCode secondary;
public KeyCodePair(KeyCode k1, KeyCode k2)
{
primary = k1;
secondary = k2;
}
}
public void ResetToDefault(KeyboardLayout layout = KeyboardLayout.Qwerty)
{
m_KeyCodes = new KeyCodePair[FpsInputButton.count];
for (int i = 0; i < m_KeyCodes.Length; ++i)
{
m_KeyCodes[i] = new KeyCodePair(
NeoFpsInputManager.GetDefaultPrimaryKey(i, layout),
NeoFpsInputManager.GetDefaultSecondaryKey(i, layout)
);
}
}
public override void OnLoad()
{
// This needs improving to keep existing bindings
if (m_KeyCodes.Length != FpsInputButton.count)
ResetToDefault();
//settingsObject.AddComponent<ProceduralInputBehaviour>();
}
protected override bool CheckIfCurrent()
{
return FpsSettings.keyBindings == this;
}
public KeyCode GetPrimaryKey(FpsInputButton button)
{
return m_KeyCodes[button].primary;
}
public KeyCode GetSecondaryKey(FpsInputButton button)
{
return m_KeyCodes[button].secondary;
}
public bool GetButton(FpsInputButton button)
{
#if UNITY_EDITOR
if (ProceduralInputBehaviour.GetButton(button))
return true;
#endif
KeyCode p = m_KeyCodes[button].primary;
KeyCode s = m_KeyCodes[button].secondary;
// Not bound
if (p == KeyCode.None && s == KeyCode.None)
return false;
// One binding
if (s == KeyCode.None)
return Input.GetKey(p);
if (p == KeyCode.None)
return Input.GetKey(s);
// Two bindings
return Input.GetKey(p) || Input.GetKey(s);
}
public bool GetButtonDown(FpsInputButton button)
{
#if UNITY_EDITOR
if (ProceduralInputBehaviour.GetButtonDown(button))
return true;
#endif
KeyCode p = m_KeyCodes[button].primary;
KeyCode s = m_KeyCodes[button].secondary;
// Not bound
if (p == KeyCode.None && s == KeyCode.None)
return false;
// One binding
if (s == KeyCode.None)
return Input.GetKeyDown(p);
if (p == KeyCode.None)
return Input.GetKeyDown(s);
// Two bindings
int down = 0;
if (Input.GetKeyDown(p))
++down;
if (Input.GetKeyDown(s))
++down;
switch (down)
{
case 0:
return false;
case 2:
return true;
default:
{
int held = 0;
if (Input.GetKey(p))
++held;
if (Input.GetKey(s))
++held;
return held == 1;
}
}
}
public bool GetButtonUp(FpsInputButton button)
{
#if UNITY_EDITOR
if (ProceduralInputBehaviour.GetButtonReleased(button))
return true;
#endif
KeyCode p = m_KeyCodes[button].primary;
KeyCode s = m_KeyCodes[button].secondary;
// Not bound
if (p == KeyCode.None && s == KeyCode.None)
return false;
// One binding
if (s == KeyCode.None)
return Input.GetKeyUp(p);
if (p == KeyCode.None)
return Input.GetKeyUp(s);
// Two bindings
int up = 0;
if (Input.GetKeyUp(p))
++up;
if (Input.GetKeyUp(s))
++up;
switch (up)
{
case 0:
return false;
case 2:
return true;
default:
{
int held = 0;
if (Input.GetKey(p))
++held;
if (Input.GetKey(s))
++held;
return held == 0;
}
}
}
#region BINDING
// Rebinding callback
public delegate void OnRebindDelegate(FpsInputButton button, bool primary, KeyCode to);
public event OnRebindDelegate onRebind;
private KeyRebinderBehaviour m_Rebinder = null;
private KeyRebinderBehaviour rebinder
{
get
{
if (m_Rebinder == null)
{
var settingsObject = FpsSettings.runtimeSettingsObject;
m_Rebinder = settingsObject.AddComponent<KeyRebinderBehaviour>();
}
return m_Rebinder;
}
}
public void RebindInput(FpsInputButton button, bool primary)
{
rebinder.RebindInput(button, primary);
}
private class KeyRebinderBehaviour : MonoBehaviour
{
private Coroutine m_CheckRebindCoroutine;
private FpsInputButton m_Rebinding = FpsInputButton.None;
private bool m_RebindingPrimary = false;
enum SpecialKey
{
None,
Cancel,
Clear
}
private SpecialKey CheckSpecials()
{
#if UNITY_WEBGL
if (Input.GetKeyDown(KeyCode.Tab))
return SpecialKey.Cancel;
#endif
if (Input.GetKeyDown(KeyCode.Escape) ||
Input.GetKeyDown(KeyCode.LeftWindows) ||
Input.GetKeyDown(KeyCode.RightWindows) ||
Input.GetKeyDown(KeyCode.LeftApple) ||
Input.GetKeyDown(KeyCode.RightApple))
return SpecialKey.Cancel;
if (Input.GetKeyDown(KeyCode.Backspace) ||
Input.GetKeyDown(KeyCode.Delete))
return SpecialKey.Clear;
return SpecialKey.None;
}
private bool CheckValid(KeyCode code)
{
if (code == KeyCode.None)
return false;
if (code >= KeyCode.JoystickButton0 && code <= KeyCode.Joystick8Button19)
return false;
return true;
}
private KeyCode GetKeyDown()
{
// Check if any key pressed
if (!Input.anyKeyDown)
return KeyCode.None;
// Loop through possible keycodes
foreach (var uncast in Enum.GetValues(typeof(KeyCode)))
{
KeyCode current = (KeyCode)uncast;
if (Input.GetKeyDown(current) && CheckValid(current))
return current;
}
return KeyCode.None;
}
private IEnumerator CheckForRebind()
{
NeoFpsInputManagerBase.PushEscapeHandler(StubEscapeHandler);
while (m_Rebinding != FpsInputButton.None)
{
yield return null;
// In rebinding mode here. First valid key pressed
// will be bound to pending action and saved in settings
if (Input.anyKeyDown)
{
switch (CheckSpecials())
{
case SpecialKey.Cancel:
CancelRebinding();
break;
case SpecialKey.Clear:
ApplyRebind(KeyCode.None);
break;
default:
{
KeyCode down = GetKeyDown();
if (CheckValid(down))
ApplyRebind(down);
}
break;
}
Input.ResetInputAxes();
}
}
NeoFpsInputManagerBase.PopEscapeHandler(StubEscapeHandler);
m_CheckRebindCoroutine = null;
}
void StubEscapeHandler()
{
}
public void RebindInput(FpsInputButton button, bool primary)
{
if (button != FpsInputButton.None)
{
m_Rebinding = button;
if (m_CheckRebindCoroutine != null)
{
StopCoroutine(m_CheckRebindCoroutine);
NeoFpsInputManagerBase.PopEscapeHandler(StubEscapeHandler);
}
m_RebindingPrimary = primary;
instance.dirty = true;
m_CheckRebindCoroutine = StartCoroutine(CheckForRebind());
}
else
CancelRebinding();
}
private void ApplyRebind(KeyCode keyCode)
{
// If setting a key, check for clashes with other bindings
if (keyCode != KeyCode.None)
{
for (int i = 0; i < FpsInputButton.count; ++i)
{
if (instance.m_KeyCodes[i].primary == keyCode)
{
// Cancel if rebinding to same key. Swap if not
FpsInputButton b = i;
if (b == m_Rebinding && m_RebindingPrimary)
{
CancelRebinding();
return;
}
else
{
// Clear the other binding if required
bool clash = !KeyBindingContextMatrix.CanOverlap(NeoFpsInputManager.GetKeyBindingContext(m_Rebinding), NeoFpsInputManager.GetKeyBindingContext(b));
//(
// NeoFpsInputManager.GetKeyBindingContext(m_Rebinding) == KeyBindingContext.Default ||
// NeoFpsInputManager.GetKeyBindingContext(b) == KeyBindingContext.Default ||
// NeoFpsInputManager.GetKeyBindingContext(b) == NeoFpsInputManager.GetKeyBindingContext(m_Rebinding)
// );
if (clash)
{
instance.m_KeyCodes[i].primary = FpsInputButton.None;
if (instance.onRebind != null)
instance.onRebind(i, true, FpsInputButton.None);
}
}
}
if (instance.m_KeyCodes[i].secondary == keyCode)
{
// Cancel if rebinding to same key. Swap if not
FpsInputButton b = i;
if (b == m_Rebinding && !m_RebindingPrimary)
{
CancelRebinding();
return;
}
else
{
// Clear the other binding if required
bool clash = !KeyBindingContextMatrix.CanOverlap(NeoFpsInputManager.GetKeyBindingContext(m_Rebinding), NeoFpsInputManager.GetKeyBindingContext(b));
//bool clash = (
// NeoFpsInputManager.GetKeyBindingContext(m_Rebinding) == KeyBindingContext.Default ||
// NeoFpsInputManager.GetKeyBindingContext(b) == KeyBindingContext.Default ||
// NeoFpsInputManager.GetKeyBindingContext(b) == NeoFpsInputManager.GetKeyBindingContext(m_Rebinding)
// );
if (clash)
{
instance.m_KeyCodes[i].secondary = FpsInputButton.None;
if (instance.onRebind != null)
instance.onRebind(i, false, FpsInputButton.None);
}
}
}
}
}
// Rebind
if (m_RebindingPrimary)
instance.m_KeyCodes[m_Rebinding].primary = keyCode;
else
instance.m_KeyCodes[m_Rebinding].secondary = keyCode;
// Notify
if (instance.onRebind != null)
instance.onRebind(m_Rebinding, m_RebindingPrimary, keyCode);
m_Rebinding = FpsInputButton.None;
}
private void CancelRebinding()
{
if (instance.onRebind != null && m_Rebinding != FpsInputButton.None)
{
if (m_RebindingPrimary)
instance.onRebind(m_Rebinding, true, instance.m_KeyCodes[m_Rebinding].primary);
else
instance.onRebind(m_Rebinding, false, instance.m_KeyCodes[m_Rebinding].secondary);
}
m_Rebinding = FpsInputButton.None;
}
private KeyCode GetOldBinding()
{
if (m_Rebinding == FpsInputButton.None)
return KeyCode.None;
if (m_RebindingPrimary)
return instance.m_KeyCodes[m_Rebinding].primary;
else
return instance.m_KeyCodes[m_Rebinding].secondary;
}
}
#endregion
#region PROCEDURAL INPUT (FOR TESTING AND RECORDING)
#if UNITY_EDITOR
private class ProceduralInputBehaviour : MonoBehaviour
{
Coroutine m_ProceduralInputCoroutine = null;
ButtonState[] m_ProceduralButtonStates = new ButtonState[FpsInputButton.count];
private static ProceduralInputBehaviour s_Instance = null;
public enum ButtonState
{
Up,
Pressed,
Down,
Released
}
public static bool GetButtonDown(FpsInputButton button)
{
if (s_Instance != null)
return s_Instance.m_ProceduralButtonStates[button] == ButtonState.Pressed;
else
return false;
}
public static bool GetButton(FpsInputButton button)
{
if (s_Instance != null)
{
return s_Instance.m_ProceduralButtonStates[button] == ButtonState.Down ||
s_Instance.m_ProceduralButtonStates[button] == ButtonState.Pressed;
}
else
return false;
}
public static bool GetButtonReleased(FpsInputButton button)
{
if (s_Instance != null)
return s_Instance.m_ProceduralButtonStates[button] == ButtonState.Released;
else
return false;
}
void Awake()
{
s_Instance = this;
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Insert))
{
if (m_ProceduralInputCoroutine != null)
StopCoroutine(m_ProceduralInputCoroutine);
ResetProceduralInput();
m_ProceduralInputCoroutine = StartCoroutine(ProceduralInputCoroutine());
}
}
void ResetProceduralInput()
{
for (int i = 0; i < m_ProceduralButtonStates.Length; ++i)
m_ProceduralButtonStates[i] = ButtonState.Up;
m_ProceduralInputCoroutine = null;
}
private float m_ProceduralInputStartTime;
IEnumerator ProceduralInputCoroutine()
{
m_ProceduralInputStartTime = Time.realtimeSinceStartup;
yield return WaitForTime(1f);
yield return TapButton(FpsInputButton.Quickslot1);
yield return WaitForTime(2f);
yield return TapButton(FpsInputButton.PrimaryFire);
yield return WaitForTime(4f);
yield return PressButton(FpsInputButton.SecondaryFire);
yield return WaitForTime(6f);
yield return ReleaseButton(FpsInputButton.SecondaryFire);
yield return WaitForTime(8f);
yield return TapButton(FpsInputButton.Quickslot8);
yield return WaitForTime(9f);
yield return TapButton(FpsInputButton.PrimaryFire);
yield return WaitForTime(14f);
yield return TapButton(FpsInputButton.SecondaryFire);
// Cleanup
ResetProceduralInput();
}
IEnumerator TapButton(FpsInputButton button)
{
m_ProceduralButtonStates[button] = ButtonState.Pressed;
yield return null;
m_ProceduralButtonStates[button] = ButtonState.Down;
yield return null;
m_ProceduralButtonStates[button] = ButtonState.Released;
yield return null;
m_ProceduralButtonStates[button] = ButtonState.Up;
}
IEnumerator PressButton(FpsInputButton button)
{
m_ProceduralButtonStates[button] = ButtonState.Pressed;
yield return null;
m_ProceduralButtonStates[button] = ButtonState.Down;
}
IEnumerator ReleaseButton(FpsInputButton button)
{
m_ProceduralButtonStates[button] = ButtonState.Released;
yield return null;
m_ProceduralButtonStates[button] = ButtonState.Up;
}
IEnumerator HoldButton(FpsInputButton button, float duration)
{
m_ProceduralButtonStates[button] = ButtonState.Pressed;
yield return null;
m_ProceduralButtonStates[button] = ButtonState.Down;
yield return new WaitForSecondsRealtime(duration - (Time.deltaTime * 2f));
m_ProceduralButtonStates[button] = ButtonState.Released;
yield return null;
m_ProceduralButtonStates[button] = ButtonState.Up;
}
IEnumerator WaitForTime(float targetTime)
{
targetTime += m_ProceduralInputStartTime;
while (Time.realtimeSinceStartup < targetTime)
yield return null;
}
IEnumerator TapButtonCoroutine(FpsInputButton button)
{
m_ProceduralButtonStates[button] = ButtonState.Pressed;
yield return null;
m_ProceduralButtonStates[button] = ButtonState.Down;
yield return null;
m_ProceduralButtonStates[button] = ButtonState.Released;
yield return null;
m_ProceduralButtonStates[button] = ButtonState.Up;
}
IEnumerator PressButtonCoroutine(FpsInputButton button)
{
m_ProceduralButtonStates[button] = ButtonState.Pressed;
yield return null;
m_ProceduralButtonStates[button] = ButtonState.Down;
}
IEnumerator ReleaseButtonCoroutine(FpsInputButton button)
{
m_ProceduralButtonStates[button] = ButtonState.Released;
yield return null;
m_ProceduralButtonStates[button] = ButtonState.Up;
}
IEnumerator HoldButtonCoroutine(FpsInputButton button, float duration)
{
m_ProceduralButtonStates[button] = ButtonState.Pressed;
yield return null;
m_ProceduralButtonStates[button] = ButtonState.Down;
yield return new WaitForSecondsRealtime(duration - (Time.deltaTime * 2f));
m_ProceduralButtonStates[button] = ButtonState.Released;
yield return null;
m_ProceduralButtonStates[button] = ButtonState.Up;
}
}
#endif
#endregion
}
}