diff options
| -rw-r--r-- | Scripts/Editor/LinuxTabFix.cs | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/Scripts/Editor/LinuxTabFix.cs b/Scripts/Editor/LinuxTabFix.cs new file mode 100644 index 0000000..0fa3228 --- /dev/null +++ b/Scripts/Editor/LinuxTabFix.cs @@ -0,0 +1,94 @@ +// Source: https://gist.githubusercontent.com/s-ilent/067d4e477041d52d2f8eabd78927d1a4/raw/568c222044a8ce3c33426c495cccbfe7c3a0c733/LinuxTabFix.cs +#if UNITY_EDITOR +using UnityEditor; +using UnityEngine; +using UnityEngine.UIElements; +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; + +/// <summary> +/// Linux Editor Tab Navigation Patch for Unity (2022.3+, Unity 6). +/// Restores missing ASCII '\t' character codes stripped by Linux window backend +/// and manages focus handshakes between IMGUIContainers in UI Toolkit windows. +/// </summary> +[InitializeOnLoad] +public static class LinuxTabFix +{ + private static readonly ConditionalWeakTable<IMGUIContainer, object> patchedContainers + = new ConditionalWeakTable<IMGUIContainer, object>(); + + static LinuxTabFix() + { + // Ensure idempotent event subscription across domain reloads + EditorApplication.update -= ApplyTabPatchToFocusedWindow; + EditorApplication.update += ApplyTabPatchToFocusedWindow; + } + + private static void ApplyTabPatchToFocusedWindow() + { + EditorWindow focusedWindow = EditorWindow.focusedWindow; + if (focusedWindow == null) return; + + VisualElement root = focusedWindow.rootVisualElement; + if (root == null) return; + + List<IMGUIContainer> containers = root.Query<IMGUIContainer>().ToList(); + int count = containers.Count; + + for (int i = 0; i < count; i++) + { + IMGUIContainer container = containers[i]; + if (container == null) continue; + + int currentIndex = i; + + // Patch unhandled containers without modifying container properties + if (!patchedContainers.TryGetValue(container, out _)) + { + patchedContainers.Add(container, null); + Action originalHandler = container.onGUIHandler; + + container.onGUIHandler = () => + { + Event e = Event.current; + + if (e != null && e.type == EventType.KeyDown && e.keyCode == KeyCode.Tab) + { + // Restore character code stripped by Linux native window backend + if (e.character == 0) + { + e.character = '\t'; + } + + bool isShift = e.shift; + + // Execute original IMGUI pass + originalHandler?.Invoke(); + + // When boundary is reached, transfer focus to adjacent container + if (GUIUtility.keyboardControl == 0) + { + int targetIndex = isShift ? currentIndex - 1 : currentIndex + 1; + + if (targetIndex >= 0 && targetIndex < count && targetIndex < containers.Count) + { + IMGUIContainer targetContainer = containers[targetIndex]; + if (targetContainer != null) + { + targetContainer.Focus(); + focusedWindow.Repaint(); + } + } + } + + return; + } + + originalHandler?.Invoke(); + }; + } + } + } +} +#endif |
