summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Scripts/Editor/LinuxTabFix.cs94
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