using System; using System.Collections.Generic; using System.Linq; using System.Numerics; using gaemstone.Client.Utility; using gaemstone.ECS; using ImGuiNET; using Silk.NET.GLFW; using Silk.NET.Input; using static gaemstone.Client.Components.InputComponents; using static gaemstone.Client.Systems.ImGuiManager; namespace gaemstone.Client.Systems; [Module] [DependsOn] [DependsOn] public class ImGuiInputDebug { private bool _isOpen = false; [System] public void ShowInputDebugWindow(Universe universe, ImGuiData _) { var input = universe.LookupByType(); if (input == null) return; if (!ImGuiUtility.UIButtonToggle(1, ForkAwesome.Gamepad, "Input Information", ref _isOpen)) return; var center = ImGui.GetMainViewport().GetCenter(); ImGui.SetNextWindowPos(center, ImGuiCond.Appearing, new(0.5f, 0.5f)); ImGui.PushFont(ImGui.GetIO().Fonts.Fonts[1]); if (ImGui.Begin($"{ForkAwesome.Gamepad} Input Information", ref _isOpen, ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoResize)) { ImGui.PushFont(ImGui.GetIO().Fonts.Fonts[0]); if (universe.LookupByType() is EntityRef keyboard) DrawKeyboard(keyboard); if (universe.LookupByType() is EntityRef mouse) { ImGui.BeginChild("Mouse Info", new(160, 180), true); ImGui.Text("Position: " + (Vector2?)mouse.LookupChild("Position")?.GetOrNull()); ImGui.Text("Delta: " + (Vector2?)mouse.LookupChild("Delta" )?.GetOrNull()); ImGui.Text("Wheel: " + (float?) mouse.LookupChild("Wheel" )?.GetOrNull()); ImGui.Spacing(); var buttons = mouse.LookupChild("Buttons")?.GetChildren().ToArray() ?? Array.Empty(); ImGui.Text("Buttons: " + string.Join(" ", buttons .Where (button => button.Has()) .Select(button => $"{button.Name} ({button.GetOrThrow().Duration.TotalSeconds:f2}s)"))); ImGui.Text(" Pressed: " + string.Join(" ", buttons .Where (button => button.Has()) .Select(button => button.Name))); ImGui.Text(" Released: " + string.Join(" ", buttons .Where (button => button.Has()) .Select(button => button.Name))); ImGui.EndChild(); } for (var index = 0; input.LookupChild("Gamepad" + index) is EntityRef gamepad; index++) { ImGui.SameLine(); ImGui.BeginChild($"{gamepad.Name} Info", new(160, 180), true); var buttons = gamepad.LookupChild("Buttons")?.GetChildren().ToArray() ?? Array.Empty(); ImGui.Text("Buttons: " + string.Join(" ", buttons.Where(b => b.Has()) .Select(b => $"{b.Name} ({b.GetOrThrow().Duration.TotalSeconds:f2}s)"))); ImGui.Text(" Pressed: " + string.Join(" ", buttons.Where(b => b.Has()).Select(b => b.Name))); ImGui.Text(" Released: " + string.Join(" ", buttons.Where(b => b.Has()).Select(b => b.Name))); ImGui.Spacing(); ImGui.Text("Triggers:"); for (var i = 0; gamepad.LookupChild("Trigger" + i) is EntityRef trigger; i++) { var text = $" {i}: {(float?)trigger.GetOrNull() ?? default:f2}"; if (trigger.Has()) text += " pressed!"; else if (trigger.Has()) text += " released!"; else if (trigger.GetOrNull() is Active active) text += $" ({active.Duration.TotalSeconds:f2}s)"; ImGui.Text(text); } ImGui.Text("Thumbsticks:"); for (var i = 0; gamepad.LookupChild("Thumbstick" + i) is EntityRef thumbstick; i++) ImGui.Text($" {i}: {(Vector2?)thumbstick.GetOrNull() ?? default:f2}"); ImGui.EndChild(); } ImGui.PopFont(); } ImGui.PopFont(); ImGui.End(); } private const float U = 1.00f; private const float SM = 1.25f; // Spacing (invisible) private const float I = -0.50f; private const float _ = -1.00f; private const float ER = -1.25f; // Special private const float T = -11.00f; private const float ENT = -11.50f; private static readonly float[][] KeyboardLayout = { new[] { U, _, U, U, U, U,I,U, U, U, U,I, U, U, U, U, I,U, U, U }, new[] { U, U, U, U, U, U, U, U, U, U, U, U, U, 2.0f, I,U, U, U,I, U, U, U, U }, new[] { 1.5f, U, U, U, U, U, U, U, U, U, U, U, U, ENT, I,U, U, U,I, U, U, U, T }, new[] { 1.75f, U, U, U, U, U, U, U, U, U, U, U, U, ER, I,_, _, _,I, U, U, U, _ }, new[] { SM, U, U, U, U, U, U, U, U, U, U, U, 2.75f, I,_, U, _,I, U, U, U, T }, new[] { SM, SM, SM, 6.25f, SM, SM, SM, SM, I,U, U, U,I, 2.0f, U, _ }, }; private static readonly Key?[][] KeyboardKeys = { new Key?[] { Key.Escape, null, Key.F1, Key.F2, Key.F3, Key.F4, null, Key.F5, Key.F6, Key.F7, Key.F8, null, Key.F9, Key.F10, Key.F11, Key.F12, null, Key.PrintScreen, Key.ScrollLock, Key.Pause }, new Key?[] { Key.GraveAccent, Key.Number1, Key.Number2, Key.Number3, Key.Number4, Key.Number5, Key.Number6, Key.Number7, Key.Number8, Key.Number9, Key.Number0, Key.Minus, Key.Equal, Key.Backspace, null, Key.Insert, Key.Home, Key.PageUp, null, Key.NumLock, Key.KeypadDivide, Key.KeypadMultiply, Key.KeypadSubtract }, new Key?[] { Key.Tab, Key.Q, Key.W, Key.E, Key.R, Key.T, Key.Y, Key.U, Key.I, Key.O, Key.P, Key.LeftBracket, Key.RightBracket, Key.Enter, null, Key.Delete, Key.End, Key.PageDown, null, Key.Keypad7, Key.Keypad8, Key.Keypad9, Key.KeypadAdd }, new Key?[] { Key.CapsLock, Key.A, Key.S, Key.D, Key.F, Key.G, Key.H, Key.J, Key.K, Key.L, Key.Semicolon, Key.Apostrophe, Key.BackSlash, null, null, null, null, null, null, Key.Keypad4, Key.Keypad5, Key.Keypad6, null }, new Key?[] { Key.ShiftLeft, Key.World1, Key.Z, Key.X, Key.C, Key.V, Key.B, Key.N, Key.M, Key.Comma, Key.Period, Key.Slash, Key.ShiftRight, null, null, Key.Up, null, null, Key.Keypad1, Key.Keypad2, Key.Keypad3, Key.KeypadEnter }, new Key?[] { Key.ControlLeft, Key.SuperLeft, Key.AltLeft, Key.Space, Key.AltRight, Key.SuperRight, Key.Menu, Key.ControlRight, null, Key.Left, Key.Down, Key.Right, null, Key.Keypad0, Key.KeypadDecimal, null }, }; private static readonly Dictionary KeyToNameMapping = new() { [Key.Escape] = "Esc", [Key.PrintScreen] = "Prn\nScr", [Key.ScrollLock] = "Scr\nLck", [Key.Pause] = "Pause", [Key.F1] = "F1", [Key.F2] = "F2", [Key.F3] = "F3", [Key.F4] = "F4", [Key.F5] = "F5", [Key.F6] = "F6", [Key.F7] = "F7", [Key.F8] = "F8", [Key.F9] = "F9", [Key.F10] = "F10", [Key.F11] = "F11", [Key.F12] = "F12", [Key.Tab] = "Tab", [Key.CapsLock] = "Caps\nLock", [Key.Menu] = "Menu", [Key.Backspace] = "Backspace", [Key.Enter] = "Enter", [Key.ControlLeft] = "Ctrl", [Key.ControlRight] = "Ctrl", [Key.ShiftLeft] = "Shift", [Key.ShiftRight] = "Shift", [Key.AltLeft] = "Alt", [Key.AltRight] = "Alt", [Key.SuperLeft] = "Super", [Key.SuperRight] = "Super", [Key.Insert] = "Ins", [Key.Delete] = "Del", [Key.Home] = "Home", [Key.End] = "End", [Key.PageUp] = "PgUp", [Key.PageDown] = "PgDn", [Key.NumLock] = "Num\nLck", [Key.KeypadEnter] = "=", }; public static void DrawKeyboard(EntityRef keyboard) { const float UnitKeySize = 32.0f; var GLFW = Glfw.GetApi(); var draw = ImGui.GetWindowDrawList(); var offset = ImGui.GetCursorScreenPos(); var current = Vector2.Zero; foreach (var (widths, keys) in KeyboardLayout.Zip(KeyboardKeys)) { foreach (var (width, key) in widths.Zip(keys)) { var active = (key != null) && (keyboard.LookupChild(key.Value.ToString())?.Has() == true); var keySize = new Vector2(width, 1.0f); if (width == T) keySize = new Vector2((-keySize.X - 10), 2.0f); else if (width < -10) keySize = new Vector2((-keySize.X - 10), 1.0f); else if (width < 0) { current += new Vector2(-keySize.X * UnitKeySize, 0); continue; } var label = (key != null) ? KeyToNameMapping.GetValueOrDefault(key.Value) ?? GLFW.GetKeyName((int)key.Value, 0)?.ToUpper() : null; if (width == ENT) { DrawButton(draw, label, active, (offset + current, keySize * UnitKeySize), (offset + current + new Vector2(0.25f * UnitKeySize, 0), (keySize + new Vector2(-0.25f, 1)) * UnitKeySize)); } else DrawButton(draw, label, active, (offset + current, keySize * UnitKeySize)); current += new Vector2(keySize.X * UnitKeySize, 0); } current = new Vector2(0, current.Y + UnitKeySize); if (widths == KeyboardLayout[0]) current += new Vector2(0, UnitKeySize / 2); } ImGui.Dummy(new Vector2(23, 6.5f) * UnitKeySize); } private static void DrawButton(ImDrawListPtr draw, string? label, bool active, params (Vector2 Pos, Vector2 Size)[] parts) { const int Rounding = 3; var Border = new Vector2(1, 1); var LabelOffset = new Vector2(7, 3); var FaceStartOffset = new Vector2(5, 3); var FaceEndOffset = new Vector2(5, 6); var BorderColor = Color.FromGrayscale(0.10f); var LabelColor = Color.FromGrayscale(0.25f); var OuterKeyColorActive = Color.FromRGB(0.8f, 0.4f, 0.4f); var OuterKeyColorInactive = Color.FromGrayscale(0.8f); var InnerKeyColorActive = Color.FromRGB(1.0f, 0.0f, 0.0f); var InnerKeyColorInactive = Color.FromGrayscale(1.0f); var outerKeyColor = active ? OuterKeyColorActive : OuterKeyColorInactive; var innerKeyColor = active ? InnerKeyColorActive : InnerKeyColorInactive; foreach (var (pos, size) in parts) draw.AddRectFilled(pos, pos + size, BorderColor.RGBA, Rounding); foreach (var (pos, size) in parts) draw.AddRectFilled(pos + Border, pos + size - Border, outerKeyColor.RGBA, Rounding); foreach (var (pos, size) in parts) draw.AddRectFilled(pos + FaceStartOffset, pos + size - FaceEndOffset, innerKeyColor.RGBA, Rounding - 1); if (label != null) { var pos = parts[0].Pos + LabelOffset; var height = ImGui.GetTextLineHeight() - 4; foreach (var line in label.Split('\n')) { draw.AddText(pos, LabelColor.RGBA, line); pos += new Vector2(0, height); } } } }