using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BoneLib;
using BoneLib.BoneMenu;
using BoneLib.BoneMenu.UI;
using Il2CppSLZ.Bonelab;
using Il2CppSLZ.Marrow;
using Il2CppTMPro;
using MelonLoader;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
using VoicemodKeybinds;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("VoicemodKeybinds")]
[assembly: AssemblyDescription("Bind VR controller inputs to keyboard letters for Voicemod hotkeys")]
[assembly: AssemblyFileVersion("1.0.0")]
[assembly: MelonInfo(typeof(Main), "VoicemodKeybinds", "1.0.0", "MrYetiSpaghetti", null)]
[assembly: MelonGame("Stress Level Zero", "BONELAB")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace VoicemodKeybinds
{
public class KeybindSlot
{
private VRKeybind _keybind;
private bool _prevState;
private bool _suppressLetterCallback;
public int Index { get; }
public string Letter { get; private set; } = "";
public StringElement LetterElement { get; set; }
public EnumElement BindElement { get; set; }
public VRKeybind Keybind
{
get
{
return _keybind;
}
set
{
_keybind = value;
_prevState = false;
}
}
public KeybindSlot(int index)
{
Index = index;
MelonPreferences_Entry<string> val = Main.PrefCategory.CreateEntry<string>($"Slot{index}_Letter", "", (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
Letter = NormalizeLetter(val.Value);
MelonPreferences_Entry<VRKeybind> val2 = Main.PrefCategory.CreateEntry<VRKeybind>($"Slot{index}_Bind", VRKeybind.None, (string)null, (string)null, false, false, (ValueValidator)null, (string)null);
_keybind = val2.Value;
}
public void Update()
{
if (_keybind != 0 && !string.IsNullOrEmpty(Letter) && VRInput.IsKeybindJustPressed(_keybind, ref _prevState))
{
KeyboardInjector.TapLetter(Letter[0]);
}
}
public void OnLetterTyped(string newValue)
{
if (_suppressLetterCallback)
{
return;
}
string text2 = (Letter = NormalizeLetter(newValue));
SaveLetter();
if (LetterElement == null || !(newValue != text2))
{
return;
}
_suppressLetterCallback = true;
try
{
LetterElement.Value = text2;
}
finally
{
_suppressLetterCallback = false;
}
}
public void OnKeybindCycled(VRKeybind value)
{
Keybind = value;
SaveBind();
}
public void ResetToDefault()
{
_suppressLetterCallback = true;
try
{
Letter = "";
Keybind = VRKeybind.None;
SaveLetter();
SaveBind();
}
finally
{
_suppressLetterCallback = false;
}
}
public void SaveLetter()
{
MelonPreferences_Entry<string> entry = Main.PrefCategory.GetEntry<string>($"Slot{Index}_Letter");
if (entry != null)
{
entry.Value = Letter;
}
Main.PrefCategory.SaveToFile(false);
}
public void SaveBind()
{
MelonPreferences_Entry<VRKeybind> entry = Main.PrefCategory.GetEntry<VRKeybind>($"Slot{Index}_Bind");
if (entry != null)
{
entry.Value = _keybind;
}
Main.PrefCategory.SaveToFile(false);
}
private static string NormalizeLetter(string raw)
{
if (string.IsNullOrEmpty(raw))
{
return "";
}
string text = raw.Trim();
if (text.Length != 1)
{
return "";
}
char c = text[0];
if (c >= 'a' && c <= 'z')
{
return char.ToUpperInvariant(c).ToString();
}
if (c >= 'A' && c <= 'Z')
{
return c.ToString();
}
return "";
}
}
public static class KeyboardInjector
{
private struct INPUT
{
public uint type;
public InputUnion U;
}
[StructLayout(LayoutKind.Explicit)]
private struct InputUnion
{
[FieldOffset(0)]
public KEYBDINPUT ki;
[FieldOffset(0)]
public MOUSEINPUT mi;
[FieldOffset(0)]
public HARDWAREINPUT hi;
}
private struct KEYBDINPUT
{
public ushort wVk;
public ushort wScan;
public uint dwFlags;
public uint time;
public IntPtr dwExtraInfo;
}
private struct MOUSEINPUT
{
public int dx;
public int dy;
public uint mouseData;
public uint dwFlags;
public uint time;
public IntPtr dwExtraInfo;
}
private struct HARDWAREINPUT
{
public uint uMsg;
public ushort wParamL;
public ushort wParamH;
}
private const uint INPUT_KEYBOARD = 1u;
private const uint KEYEVENTF_KEYUP = 2u;
[DllImport("user32.dll", SetLastError = true)]
private static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize);
public static void TapLetter(char letter)
{
char c = char.ToUpperInvariant(letter);
if (c >= 'A' && c <= 'Z')
{
ushort wVk = c;
INPUT[] array = new INPUT[2];
array[0].type = 1u;
array[0].U.ki.wVk = wVk;
array[1].type = 1u;
array[1].U.ki.wVk = wVk;
array[1].U.ki.dwFlags = 2u;
SendInput((uint)array.Length, array, Marshal.SizeOf<INPUT>());
}
}
}
public class Main : MelonMod
{
public const int SlotCount = 10;
private static readonly KeybindSlot[] _slots = new KeybindSlot[10];
public static MelonPreferences_Category PrefCategory { get; private set; }
public override void OnInitializeMelon()
{
PrefCategory = MelonPreferences.CreateCategory("VoicemodKeybinds");
for (int i = 0; i < 10; i++)
{
_slots[i] = new KeybindSlot(i + 1);
}
MenuSetup.Build(_slots);
}
public override void OnUpdate()
{
if ((Object)(object)Player.RigManager == (Object)null || HelperMethods.IsLoading())
{
return;
}
UIRig instance = UIRig.Instance;
if ((Object)(object)instance != (Object)null && (Object)(object)instance.popUpMenu != (Object)null && instance.popUpMenu.m_IsCursorShown)
{
return;
}
for (int i = 0; i < _slots.Length; i++)
{
try
{
_slots[i].Update();
}
catch (Exception)
{
}
}
MenuSetup.ClampScrollVelocity();
}
}
public static class MenuSetup
{
private static readonly FieldInfo _enumIndexField = typeof(EnumElement).GetField("_index", BindingFlags.Instance | BindingFlags.NonPublic);
private static Page _page;
private static GameObject _navContainer;
private static Sprite _fillSprite;
private static Sprite _borderSprite;
private static ScrollRect _cachedScrollRect;
private static bool _scrollOverrideActive;
public static void Build(KeybindSlot[] slots)
{
//IL_000a: Unknown result type (might be due to invalid IL or missing references)
//IL_0090: Unknown result type (might be due to invalid IL or missing references)
//IL_00e7: Unknown result type (might be due to invalid IL or missing references)
//IL_0117: Unknown result type (might be due to invalid IL or missing references)
//IL_016e: Unknown result type (might be due to invalid IL or missing references)
Page val2 = (_page = Page.Root.CreatePage("VoicemodKeybinds", Color.cyan, 0, true));
Menu.OnPageOpened += OnPageOpened;
foreach (KeybindSlot keybindSlot in slots)
{
KeybindSlot capturedSlot = keybindSlot;
val2.CreateFunction($"--- Keybind {keybindSlot.Index} ---", Color.cyan, (Action)delegate
{
});
StringElement val3 = null;
val3 = val2.CreateString($"Letter {keybindSlot.Index}", Color.white, keybindSlot.Letter, (Action<string>)delegate(string val)
{
capturedSlot.OnLetterTyped(val);
});
keybindSlot.LetterElement = val3;
EnumElement val4 = null;
val4 = val2.CreateEnum("Controller Keybind", Color.magenta, (Enum)keybindSlot.Keybind, (Action<Enum>)delegate(Enum val)
{
capturedSlot.OnKeybindCycled((VRKeybind)(object)val);
});
keybindSlot.BindElement = val4;
val2.CreateFunction($"Reset Keybind {keybindSlot.Index}", Color.red, (Action)delegate
{
ResetSlot(capturedSlot);
});
}
}
private static void ResetSlot(KeybindSlot slot)
{
slot.ResetToDefault();
if (slot.LetterElement != null)
{
slot.LetterElement.Value = "";
}
if (slot.BindElement != null)
{
slot.BindElement.Value = VRKeybind.None;
if (_enumIndexField != null)
{
_enumIndexField.SetValue(slot.BindElement, 0);
}
}
}
private static void OnPageOpened(Page page)
{
if (page == _page)
{
if ((Object)(object)_navContainer == (Object)null)
{
CreateNavButtons();
}
if ((Object)(object)_navContainer != (Object)null)
{
_navContainer.SetActive(true);
}
ApplyScrollOverride();
}
else
{
if ((Object)(object)_navContainer != (Object)null)
{
_navContainer.SetActive(false);
}
RestoreScrollOverride();
}
}
private static void ApplyScrollOverride()
{
_scrollOverrideActive = true;
CacheScrollRect();
}
private static void RestoreScrollOverride()
{
_scrollOverrideActive = false;
}
private static void CacheScrollRect()
{
if ((Object)(object)_cachedScrollRect != (Object)null)
{
return;
}
try
{
GUIMenu instance = GUIMenu.Instance;
if (!((Object)(object)instance == (Object)null))
{
Transform val = ((Component)instance).transform.Find("Page/Content/Viewport");
if ((Object)(object)val != (Object)null)
{
_cachedScrollRect = ((Component)val).GetComponent<ScrollRect>();
}
}
}
catch
{
}
}
public static void ClampScrollVelocity()
{
//IL_001b: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
//IL_0038: Unknown result type (might be due to invalid IL or missing references)
//IL_003e: Unknown result type (might be due to invalid IL or missing references)
//IL_004f: Unknown result type (might be due to invalid IL or missing references)
if (!_scrollOverrideActive || (Object)(object)_cachedScrollRect == (Object)null)
{
return;
}
try
{
Vector2 velocity = _cachedScrollRect.velocity;
if (Mathf.Abs(velocity.y) > 1250f)
{
_cachedScrollRect.velocity = new Vector2(velocity.x, Mathf.Sign(velocity.y) * 1250f);
}
}
catch
{
}
}
private static void CreateNavButtons()
{
//IL_00de: Unknown result type (might be due to invalid IL or missing references)
//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
//IL_0106: Unknown result type (might be due to invalid IL or missing references)
//IL_0147: Unknown result type (might be due to invalid IL or missing references)
//IL_015e: Unknown result type (might be due to invalid IL or missing references)
//IL_018d: Unknown result type (might be due to invalid IL or missing references)
//IL_0197: Expected O, but got Unknown
//IL_01b5: Unknown result type (might be due to invalid IL or missing references)
//IL_01c2: Unknown result type (might be due to invalid IL or missing references)
//IL_01d7: Unknown result type (might be due to invalid IL or missing references)
//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
//IL_01f0: Unknown result type (might be due to invalid IL or missing references)
//IL_01fe: Unknown result type (might be due to invalid IL or missing references)
//IL_02d5: Unknown result type (might be due to invalid IL or missing references)
//IL_0327: Unknown result type (might be due to invalid IL or missing references)
//IL_0331: Unknown result type (might be due to invalid IL or missing references)
//IL_033d: Unknown result type (might be due to invalid IL or missing references)
//IL_0389: Unknown result type (might be due to invalid IL or missing references)
//IL_038e: Unknown result type (might be due to invalid IL or missing references)
//IL_03a6: Unknown result type (might be due to invalid IL or missing references)
//IL_03c6: Unknown result type (might be due to invalid IL or missing references)
//IL_03e6: Unknown result type (might be due to invalid IL or missing references)
//IL_0406: Unknown result type (might be due to invalid IL or missing references)
//IL_042a: Unknown result type (might be due to invalid IL or missing references)
//IL_04b3: Unknown result type (might be due to invalid IL or missing references)
//IL_04b8: Unknown result type (might be due to invalid IL or missing references)
//IL_04cb: Unknown result type (might be due to invalid IL or missing references)
//IL_04d2: Unknown result type (might be due to invalid IL or missing references)
//IL_04dd: Unknown result type (might be due to invalid IL or missing references)
//IL_04e8: Unknown result type (might be due to invalid IL or missing references)
//IL_04f2: Unknown result type (might be due to invalid IL or missing references)
//IL_0526: Unknown result type (might be due to invalid IL or missing references)
//IL_053d: Unknown result type (might be due to invalid IL or missing references)
//IL_0542: Unknown result type (might be due to invalid IL or missing references)
//IL_0555: Unknown result type (might be due to invalid IL or missing references)
//IL_055c: Unknown result type (might be due to invalid IL or missing references)
//IL_0567: Unknown result type (might be due to invalid IL or missing references)
//IL_0572: Unknown result type (might be due to invalid IL or missing references)
//IL_057c: Unknown result type (might be due to invalid IL or missing references)
//IL_05a4: Unknown result type (might be due to invalid IL or missing references)
//IL_049c: Unknown result type (might be due to invalid IL or missing references)
GUIMenu instance = GUIMenu.Instance;
if ((Object)(object)instance == (Object)null)
{
return;
}
Transform val = ((Component)instance).transform.Find("Page/Content");
if ((Object)(object)val == (Object)null)
{
return;
}
Transform val2 = val.Find("Interaction");
if ((Object)(object)val2 == (Object)null)
{
return;
}
Transform val3 = val2.Find("ScrollUp");
Transform val4 = val2.Find("ScrollDown");
if ((Object)(object)val3 == (Object)null || (Object)(object)val4 == (Object)null)
{
return;
}
Transform val5 = val.Find("Viewport");
ScrollRect scrollRect = (((Object)(object)val5 != (Object)null) ? ((Component)val5).GetComponent<ScrollRect>() : null);
if ((Object)(object)scrollRect == (Object)null)
{
return;
}
TMP_FontAsset val6 = null;
TextMeshProUGUI componentInChildren = ((Component)val).GetComponentInChildren<TextMeshProUGUI>();
if ((Object)(object)componentInChildren != (Object)null)
{
val6 = ((TMP_Text)componentInChildren).font;
}
RectTransform component = ((Component)val3).GetComponent<RectTransform>();
RectTransform component2 = ((Component)val4).GetComponent<RectTransform>();
float y = component.anchoredPosition.y;
float y2 = component2.anchoredPosition.y;
float num = component.sizeDelta.y;
float num2 = component.sizeDelta.x;
if (num2 < 1f)
{
num2 = 40f;
}
if (num < 1f)
{
num = 40f;
}
EnsureSprites();
float num3 = (y + y2) / 2f;
float num4 = y - num * component.pivot.y;
float num5 = y2 + num * (1f - component2.pivot.y);
float num6 = Mathf.Abs(num4 - num5);
float num7 = 2f;
float num8 = num2 * 6f;
_navContainer = new GameObject("VoicemodKeybinds_NavButtons");
_navContainer.transform.SetParent(val2, false);
RectTransform obj = _navContainer.AddComponent<RectTransform>();
obj.anchorMin = component.anchorMin;
obj.anchorMax = component.anchorMax;
obj.pivot = new Vector2(0.5f, 0.5f);
obj.anchoredPosition = new Vector2(component.anchoredPosition.x, num3);
obj.sizeDelta = new Vector2(num8, num6);
VerticalLayoutGroup obj2 = _navContainer.AddComponent<VerticalLayoutGroup>();
((LayoutGroup)obj2).childAlignment = (TextAnchor)4;
((HorizontalOrVerticalLayoutGroup)obj2).childControlWidth = true;
((HorizontalOrVerticalLayoutGroup)obj2).childControlHeight = true;
((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandWidth = true;
((HorizontalOrVerticalLayoutGroup)obj2).childForceExpandHeight = true;
((HorizontalOrVerticalLayoutGroup)obj2).spacing = num7;
string[] array = new string[5] { "Top", "Upper", "Middle", "Lower", "Bottom" };
float[] array2 = new float[5] { 0f, 0.25f, 0.5f, 0.75f, 1f };
GameObject gameObject = ((Component)val3).gameObject;
for (int i = 0; i < 5; i++)
{
float frac = array2[i];
string text = array[i];
GameObject val7 = Object.Instantiate<GameObject>(gameObject, _navContainer.transform);
((Object)val7).name = text;
val7.transform.localRotation = Quaternion.identity;
LayoutElement component3 = val7.GetComponent<LayoutElement>();
if ((Object)(object)component3 != (Object)null)
{
Object.Destroy((Object)(object)component3);
}
BoxCollider component4 = val7.GetComponent<BoxCollider>();
if ((Object)(object)component4 != (Object)null)
{
float num9 = (num6 - num7 * 4f) / 5f;
component4.size = new Vector3(num8, num9, component4.size.z);
component4.center = Vector3.zero;
}
Button component5 = val7.GetComponent<Button>();
if ((Object)(object)component5 != (Object)null)
{
((UnityEventBase)component5.onClick).RemoveAllListeners();
((UnityEvent)component5.onClick).AddListener(UnityAction.op_Implicit((Action)delegate
{
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
scrollRect.normalizedPosition = new Vector2(0f, 1f - frac);
scrollRect.velocity = Vector2.zero;
}));
ColorBlock colors = ((Selectable)component5).colors;
((ColorBlock)(ref colors)).normalColor = new Color(1f, 1f, 1f, 0.06f);
((ColorBlock)(ref colors)).highlightedColor = new Color(1f, 1f, 1f, 0.25f);
((ColorBlock)(ref colors)).pressedColor = new Color(1f, 1f, 1f, 1f);
((ColorBlock)(ref colors)).selectedColor = new Color(1f, 1f, 1f, 0.06f);
((ColorBlock)(ref colors)).colorMultiplier = 1f;
((ColorBlock)(ref colors)).fadeDuration = 0.08f;
((Selectable)component5).colors = colors;
}
for (int num10 = val7.transform.childCount - 1; num10 >= 0; num10--)
{
Object.Destroy((Object)(object)((Component)val7.transform.GetChild(num10)).gameObject);
}
Image component6 = val7.GetComponent<Image>();
if ((Object)(object)component6 != (Object)null)
{
if ((Object)(object)_fillSprite != (Object)null)
{
component6.sprite = _fillSprite;
component6.type = (Type)1;
}
((Graphic)component6).color = Color.white;
((Graphic)component6).raycastTarget = true;
}
GameObject val8 = new GameObject("Border");
val8.transform.SetParent(val7.transform, false);
RectTransform obj3 = val8.AddComponent<RectTransform>();
obj3.anchorMin = Vector2.zero;
obj3.anchorMax = Vector2.one;
obj3.sizeDelta = Vector2.zero;
obj3.anchoredPosition = Vector2.zero;
Image val9 = val8.AddComponent<Image>();
if ((Object)(object)_borderSprite != (Object)null)
{
val9.sprite = _borderSprite;
val9.type = (Type)1;
}
((Graphic)val9).color = Color.white;
((Graphic)val9).raycastTarget = false;
GameObject val10 = new GameObject("Text");
val10.transform.SetParent(val7.transform, false);
RectTransform obj4 = val10.AddComponent<RectTransform>();
obj4.anchorMin = Vector2.zero;
obj4.anchorMax = Vector2.one;
obj4.sizeDelta = Vector2.zero;
obj4.anchoredPosition = Vector2.zero;
TextMeshProUGUI val11 = val10.AddComponent<TextMeshProUGUI>();
((TMP_Text)val11).text = text;
((TMP_Text)val11).alignment = (TextAlignmentOptions)514;
((Graphic)val11).color = Color.white;
((TMP_Text)val11).enableAutoSizing = true;
((TMP_Text)val11).fontSizeMin = 6f;
((TMP_Text)val11).fontSizeMax = 42f;
if ((Object)(object)val6 != (Object)null)
{
((TMP_Text)val11).font = val6;
}
}
}
private static void EnsureSprites()
{
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_0020: Expected O, but got Unknown
//IL_002b: Unknown result type (might be due to invalid IL or missing references)
//IL_0032: Expected O, but got Unknown
//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
//IL_010b: Unknown result type (might be due to invalid IL or missing references)
//IL_0127: Unknown result type (might be due to invalid IL or missing references)
//IL_0136: Unknown result type (might be due to invalid IL or missing references)
//IL_0142: Unknown result type (might be due to invalid IL or missing references)
//IL_0080: Unknown result type (might be due to invalid IL or missing references)
//IL_0079: Unknown result type (might be due to invalid IL or missing references)
//IL_009b: Unknown result type (might be due to invalid IL or missing references)
//IL_0094: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)_fillSprite != (Object)null)
{
return;
}
int num = 64;
int num2 = 12;
int num3 = 3;
Texture2D val = new Texture2D(num, num, (TextureFormat)4, false);
((Texture)val).filterMode = (FilterMode)1;
Texture2D val2 = new Texture2D(num, num, (TextureFormat)4, false);
((Texture)val2).filterMode = (FilterMode)1;
for (int i = 0; i < num; i++)
{
for (int j = 0; j < num; j++)
{
float num4 = RoundedRectSDF(j, i, num, num, num2);
bool flag = num4 <= 0f;
bool flag2 = flag && num4 > (float)(-num3);
val.SetPixel(j, i, flag ? Color.white : Color.clear);
val2.SetPixel(j, i, flag2 ? Color.white : Color.clear);
}
}
val.Apply();
val2.Apply();
float num5 = (float)num2 + 1f;
Vector4 val3 = default(Vector4);
((Vector4)(ref val3))..ctor(num5, num5, num5, num5);
_fillSprite = Sprite.Create(val, new Rect(0f, 0f, (float)num, (float)num), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0, val3);
_borderSprite = Sprite.Create(val2, new Rect(0f, 0f, (float)num, (float)num), new Vector2(0.5f, 0.5f), 100f, 0u, (SpriteMeshType)0, val3);
}
private static float RoundedRectSDF(int px, int py, int w, int h, int r)
{
bool num = px < r || px > w - r - 1;
bool flag = py < r || py > h - r - 1;
if (num && flag)
{
float num2 = ((px < r) ? r : (w - r - 1));
float num3 = ((py < r) ? r : (h - r - 1));
float num4 = (float)px - num2;
float num5 = (float)py - num3;
return Mathf.Sqrt(num4 * num4 + num5 * num5) - (float)r;
}
float num6 = px;
float num7 = w - 1 - px;
float num8 = py;
float num9 = h - 1 - py;
return 0f - Mathf.Min(Mathf.Min(num6, num7), Mathf.Min(num8, num9));
}
}
public enum VRKeybind
{
None,
BPlusY,
APlusX,
BothSticks,
BothTriggers,
DoubleTapStick,
DoubleTapLeftStick,
DoubleTapRightStick,
DoubleTapGrips,
DoubleTapTriggers,
TripleTapY,
TripleTapX,
TripleTapB,
TripleTapA,
LeftStick,
RightStick,
QuadTapRightGrip,
QuadTapLeftGrip,
YPlusA,
XPlusB
}
public static class VRInput
{
private class TapState
{
public float LastTapTime;
public int TapCount;
public bool RawDown;
public float DownSince;
public bool Debounced;
}
private const float TapWindow = 0.8f;
private const float GripThreshold = 0.8f;
private const float TriggerThreshold = 0.8f;
private const float MinHoldTime = 0.04f;
private static readonly TapState _dtStick = new TapState();
private static readonly TapState _dtLeftStick = new TapState();
private static readonly TapState _dtRightStick = new TapState();
private static readonly TapState _dtGrips = new TapState();
private static readonly TapState _dtTriggers = new TapState();
private static readonly TapState _ttY = new TapState();
private static readonly TapState _ttX = new TapState();
private static readonly TapState _ttB = new TapState();
private static readonly TapState _ttA = new TapState();
private static readonly TapState _qtRightGrip = new TapState();
private static readonly TapState _qtLeftGrip = new TapState();
private static readonly TapState[] _allTapStates = new TapState[11]
{
_dtStick, _dtLeftStick, _dtRightStick, _dtGrips, _dtTriggers, _ttY, _ttX, _ttB, _ttA, _qtRightGrip,
_qtLeftGrip
};
private static bool _gripsBlockedByTriggers;
private static bool _rightGripBlockedByTrigger;
private static bool _leftGripBlockedByTrigger;
private static bool _leftGripReleased = true;
private static bool _rightGripReleased = true;
private static bool _gripsValidPress;
private static bool _leftTriggerReleased = true;
private static bool _rightTriggerReleased = true;
private static bool _triggersValidPress;
public static bool IsKeybindHeld(VRKeybind keybind)
{
if (keybind == VRKeybind.None)
{
return false;
}
BaseController leftController = Player.LeftController;
BaseController rightController = Player.RightController;
return keybind switch
{
VRKeybind.BPlusY => rightController.GetBButton() && leftController.GetBButton(),
VRKeybind.APlusX => rightController.GetAButton() && leftController.GetAButton(),
VRKeybind.BothSticks => leftController.GetThumbStick() && rightController.GetThumbStick(),
VRKeybind.BothTriggers => leftController.GetPrimaryInteractionButtonAxis() > 0.8f && rightController.GetPrimaryInteractionButtonAxis() > 0.8f,
VRKeybind.LeftStick => leftController.GetThumbStick(),
VRKeybind.RightStick => rightController.GetThumbStick(),
VRKeybind.YPlusA => leftController.GetBButton() && rightController.GetAButton(),
VRKeybind.XPlusB => leftController.GetAButton() && rightController.GetBButton(),
_ => false,
};
}
public static bool IsKeybindJustPressed(VRKeybind keybind, ref bool previousState)
{
switch (keybind)
{
case VRKeybind.DoubleTapStick:
{
bool num6 = CheckMultiTap(_dtStick, IsEitherStickDown(), 2);
if (num6)
{
ResetAllTapStatesExcept(_dtStick);
}
return num6;
}
case VRKeybind.DoubleTapLeftStick:
{
bool num7 = CheckMultiTap(_dtLeftStick, Player.LeftController.GetThumbStick(), 2);
if (num7)
{
ResetAllTapStatesExcept(_dtLeftStick);
}
return num7;
}
case VRKeybind.DoubleTapRightStick:
{
bool num10 = CheckMultiTap(_dtRightStick, Player.RightController.GetThumbStick(), 2);
if (num10)
{
ResetAllTapStatesExcept(_dtRightStick);
}
return num10;
}
case VRKeybind.DoubleTapGrips:
{
if (AreBothTriggersRaw())
{
_gripsBlockedByTriggers = true;
return false;
}
if (_gripsBlockedByTriggers)
{
_gripsBlockedByTriggers = false;
bool flag2 = AreBothGripsDown();
_dtGrips.RawDown = flag2;
_dtGrips.Debounced = flag2;
return false;
}
bool num2 = CheckMultiTap(_dtGrips, AreBothGripsDown(), 2);
if (num2)
{
ResetAllTapStatesExcept(_dtGrips);
}
return num2;
}
case VRKeybind.DoubleTapTriggers:
{
bool num = CheckMultiTap(_dtTriggers, AreBothTriggersDown(), 2);
if (num)
{
ResetAllTapStatesExcept(_dtTriggers);
}
return num;
}
case VRKeybind.TripleTapY:
{
bool num9 = CheckMultiTap(_ttY, Player.LeftController.GetBButton(), 3);
if (num9)
{
ResetAllTapStatesExcept(_ttY);
}
return num9;
}
case VRKeybind.TripleTapX:
{
bool num5 = CheckMultiTap(_ttX, Player.LeftController.GetAButton(), 3);
if (num5)
{
ResetAllTapStatesExcept(_ttX);
}
return num5;
}
case VRKeybind.TripleTapB:
{
bool num3 = CheckMultiTap(_ttB, Player.RightController.GetBButton(), 3);
if (num3)
{
ResetAllTapStatesExcept(_ttB);
}
return num3;
}
case VRKeybind.TripleTapA:
{
bool num8 = CheckMultiTap(_ttA, Player.RightController.GetAButton(), 3);
if (num8)
{
ResetAllTapStatesExcept(_ttA);
}
return num8;
}
case VRKeybind.QuadTapRightGrip:
{
if (Player.RightController.GetPrimaryInteractionButtonAxis() > 0.8f)
{
_rightGripBlockedByTrigger = true;
return false;
}
if (_rightGripBlockedByTrigger)
{
_rightGripBlockedByTrigger = false;
bool flag4 = IsRightGripDown();
_qtRightGrip.RawDown = flag4;
_qtRightGrip.Debounced = flag4;
return false;
}
bool num11 = CheckMultiTap(_qtRightGrip, IsRightGripDown(), 4);
if (num11)
{
ResetAllTapStatesExcept(_qtRightGrip);
}
return num11;
}
case VRKeybind.QuadTapLeftGrip:
{
if (Player.LeftController.GetPrimaryInteractionButtonAxis() > 0.8f)
{
_leftGripBlockedByTrigger = true;
return false;
}
if (_leftGripBlockedByTrigger)
{
_leftGripBlockedByTrigger = false;
bool flag3 = IsLeftGripDown();
_qtLeftGrip.RawDown = flag3;
_qtLeftGrip.Debounced = flag3;
return false;
}
bool num4 = CheckMultiTap(_qtLeftGrip, IsLeftGripDown(), 4);
if (num4)
{
ResetAllTapStatesExcept(_qtLeftGrip);
}
return num4;
}
default:
{
bool flag = IsKeybindHeld(keybind);
bool result = flag && !previousState;
previousState = flag;
return result;
}
}
}
private static void ResetAllTapStatesExcept(TapState keep)
{
TapState[] allTapStates = _allTapStates;
foreach (TapState tapState in allTapStates)
{
if (tapState != keep)
{
tapState.TapCount = 0;
}
}
}
private static bool IsEitherStickDown()
{
if (!Player.LeftController.GetThumbStick())
{
return Player.RightController.GetThumbStick();
}
return true;
}
private static bool AreBothGripsDown()
{
if (AreBothTriggersRaw())
{
return false;
}
bool num = Player.LeftController.GetSecondaryInteractionButtonAxis() > 0.8f;
bool flag = Player.RightController.GetSecondaryInteractionButtonAxis() > 0.8f;
if (!num)
{
_leftGripReleased = true;
}
if (!flag)
{
_rightGripReleased = true;
}
if (!(num && flag))
{
_gripsValidPress = false;
return false;
}
if (_gripsValidPress)
{
return true;
}
if (_leftGripReleased && _rightGripReleased)
{
_leftGripReleased = false;
_rightGripReleased = false;
_gripsValidPress = true;
return true;
}
return false;
}
private static bool AreBothTriggersDown()
{
bool num = Player.LeftController.GetPrimaryInteractionButtonAxis() > 0.8f;
bool flag = Player.RightController.GetPrimaryInteractionButtonAxis() > 0.8f;
if (!num)
{
_leftTriggerReleased = true;
}
if (!flag)
{
_rightTriggerReleased = true;
}
if (!(num && flag))
{
_triggersValidPress = false;
return false;
}
if (_triggersValidPress)
{
return true;
}
if (_leftTriggerReleased && _rightTriggerReleased)
{
_leftTriggerReleased = false;
_rightTriggerReleased = false;
_triggersValidPress = true;
return true;
}
return false;
}
private static bool IsRightGripDown()
{
return Player.RightController.GetSecondaryInteractionButtonAxis() > 0.8f;
}
private static bool IsLeftGripDown()
{
return Player.LeftController.GetSecondaryInteractionButtonAxis() > 0.8f;
}
private static bool AreBothTriggersRaw()
{
if (Player.LeftController.GetPrimaryInteractionButtonAxis() > 0.8f)
{
return Player.RightController.GetPrimaryInteractionButtonAxis() > 0.8f;
}
return false;
}
private static bool CheckMultiTap(TapState state, bool rawDown, int requiredTaps)
{
float realtimeSinceStartup = Time.realtimeSinceStartup;
if (rawDown && !state.RawDown)
{
state.DownSince = realtimeSinceStartup;
}
state.RawDown = rawDown;
bool flag = rawDown && realtimeSinceStartup - state.DownSince >= 0.04f;
bool num = flag && !state.Debounced;
state.Debounced = flag;
if (!num)
{
if (state.TapCount > 0 && realtimeSinceStartup - state.LastTapTime > 0.8f)
{
state.TapCount = 0;
}
return false;
}
state.TapCount++;
state.LastTapTime = realtimeSinceStartup;
if (state.TapCount >= requiredTaps)
{
state.TapCount = 0;
return true;
}
return false;
}
}
}