using System; using System.Collections.Generic; using System.Linq; using System.Reflection; #if UNITY_EDITOR using System.ComponentModel; #endif namespace UnityEngine.InputSystem.Utilities { /// /// A table mapping names to types in a case-insensitive mapping. /// internal struct TypeTable { public Dictionary table; public IEnumerable names => table.Keys.Select(x => x.ToString()); public IEnumerable internedNames => table.Keys; // In the editor, we want to keep track of when the same type gets registered multiple times // with different names so that we can keep the aliases out of the UI. #if UNITY_EDITOR public HashSet aliases; #endif // Strong coupling to Input Manager which is always the owner private InputManager m_Manager; public void Initialize(InputManager manager) { table = new Dictionary(); #if UNITY_EDITOR aliases = new HashSet(); #endif m_Manager = manager; } public InternedString FindNameForType(Type type) { if (type == null) throw new ArgumentNullException(nameof(type)); foreach (var pair in table) if (pair.Value == type) return pair.Key; return new InternedString(); } public void AddTypeRegistration(string name, Type type) { if (string.IsNullOrEmpty(name)) throw new ArgumentException("Name cannot be null or empty", nameof(name)); if (type == null) throw new ArgumentNullException(nameof(type)); var internedName = new InternedString(name); #if UNITY_EDITOR // First check if the name has already been added to the table // This allows safely calling this function multiple times with same name // and prevents adding an alias to itself Type originalType; if (table.TryGetValue(internedName, out originalType)) { // We don't warn about overriding any existing name/type mapping as that was previously supported table.Remove(internedName); } else { if (table.ContainsValue(type)) aliases.Add(internedName); } #endif table[internedName] = type; } public Type LookupTypeRegistration(string name) { if (string.IsNullOrEmpty(name)) return null; if (table == null) throw new InvalidOperationException("Input System not yet initialized"); return TryLookupTypeRegistration(new InternedString(name)); } private Type TryLookupTypeRegistration(InternedString internedName) { if (!table.TryGetValue(internedName, out var type)) { // Failed to look-up type, either type do not exist or it is a custom type that has not been registered. // Check whether we have attempted to load custom types and otherwise lazily load types only when // relevant and reattempt looking up type by name. (ISXB-1766) if (m_Manager != null) { if (m_Manager.RegisterCustomTypes()) table.TryGetValue(internedName, out type); } } return type; } #if UNITY_EDITOR public bool ShouldHideInUI(string name) { // Always hide aliases. if (aliases.Contains(new InternedString(name))) return true; // Hide entries that have [DesignTimeVisible(false)] on the type. var type = LookupTypeRegistration(name); var attribute = type?.GetCustomAttribute(); return !(attribute?.Visible ?? true); } #endif } }