Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ChineseInputPlus v2.1.0
BepInEx/plugins/ChineseInputPlus/ChineseInputPlus.dll
Decompiled 9 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyVersion("0.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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 ChineseInputPlus { internal static class ImeState { private static Type _keyboardType; private static PropertyInfo _currentProperty; private static MethodInfo _setImeEnabled; private static object _keyboard; private static bool? _lastState; private static FieldInfo _chatActiveField; private static FieldInfo _chatStateField; private static FieldInfo _chatInstanceField; public static void Init() { try { _keyboardType = Type.GetType("UnityEngine.InputSystem.Keyboard, Unity.InputSystem"); if (_keyboardType != null) { _currentProperty = _keyboardType.GetProperty("current", BindingFlags.Static | BindingFlags.Public); _setImeEnabled = _keyboardType.GetMethod("SetIMEEnabled", BindingFlags.Instance | BindingFlags.Public); } } catch (Exception ex) { ChineseInputPlugin.Log.LogDebug((object)("[中文输入] 初始化 InputSystem IME 失败:" + ex.Message)); } try { Type typeFromHandle = typeof(ChatManager); _chatActiveField = typeFromHandle.GetField("chatActive", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _chatStateField = typeFromHandle.GetField("chatState", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _chatInstanceField = typeFromHandle.GetField("instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } catch (Exception ex2) { ChineseInputPlugin.Log.LogDebug((object)("[中文输入] 初始化聊天状态失败:" + ex2.Message)); } } public static bool ChatActive() { try { ChatManager val = (ChatManager)((_chatInstanceField != null) ? ((object)/*isinst with value type is only supported in some contexts*/) : ((object)ChatManager.instance)); if ((Object)(object)val == (Object)null) { return false; } bool flag = default(bool); int num; if (_chatActiveField != null) { object value = _chatActiveField.GetValue(val); if (value is bool) { flag = (bool)value; num = 1; } else { num = 0; } } else { num = 0; } if (((uint)num & (flag ? 1u : 0u)) != 0) { return true; } if (_chatStateField != null) { object value2 = _chatStateField.GetValue(val); if (value2 != null && value2.ToString() == "Active") { return true; } } } catch { } return false; } public static void Tick(bool menuInputActive) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) if (ChineseInputPlugin.Cfg == null) { return; } bool flag = ChineseInputPlugin.Cfg.ChatImeSupport.Value && ChatActive(); bool flag2 = menuInputActive || flag; try { IMECompositionMode val = (IMECompositionMode)(flag2 ? 1 : 0); if (Input.imeCompositionMode != val) { Input.imeCompositionMode = val; } } catch { } ApplyInputSystemIme(flag2); } private static void ApplyInputSystemIme(bool enabled) { if (_setImeEnabled == null || _currentProperty == null) { return; } try { if (_keyboard == null || _lastState != enabled) { _keyboard = _currentProperty.GetValue(null); } if (_keyboard != null && _lastState != enabled) { _setImeEnabled.Invoke(_keyboard, new object[1] { enabled }); _lastState = enabled; } } catch (Exception ex) { ChineseInputPlugin.Log.LogDebug((object)("[中文输入] 切换 InputSystem IME 失败:" + ex.Message)); } } } internal static class MenuInputHandler { private static readonly Dictionary<int, string> BaseTexts = new Dictionary<int, string>(); private static readonly Dictionary<int, bool> Composing = new Dictionary<int, bool>(); public static bool TryHandle(MenuTextInput input) { if ((Object)(object)input == (Object)null || !ChineseInputPlugin.Cfg.Enabled.Value) { return false; } MenuManager instance = MenuManager.instance; if ((Object)(object)instance == (Object)null || !IsTextInputActive(instance)) { return false; } try { instance.TextInputActive(); } catch { } if (ChineseInputPlugin.Cfg.RemoveUpperCase.Value && MenuFields.UpperOnly != null) { MenuFields.UpperOnly.SetValue(input, false); } if (ChineseInputPlugin.Cfg.ImeComposition.Value) { Input.imeCompositionMode = (IMECompositionMode)1; MoveCompositionCursor(input); string compositionString = Input.compositionString; int instanceID = ((Object)input).GetInstanceID(); if (!string.IsNullOrEmpty(compositionString)) { if (!Composing.TryGetValue(instanceID, out var value) || !value) { BaseTexts[instanceID] = CurrentText(input); Composing[instanceID] = true; } string text = Clamp(BaseTexts[instanceID] + compositionString, MaxLength(input)); SetText(input, text); return true; } if (Composing.TryGetValue(instanceID, out var value2) && value2) { Composing[instanceID] = false; SetText(input, BaseTexts[instanceID] ?? string.Empty); return false; } } if (ChineseInputPlugin.Cfg.EnablePaste.Value && PastePressed()) { string text2 = ClipboardText(); if (!string.IsNullOrEmpty(text2)) { string text3 = Clamp(CurrentText(input) + text2, MaxLength(input)); SetText(input, text3); return true; } } return false; } public static bool IsMenuInputActive() { if (ChineseInputPlugin.Cfg == null || !ChineseInputPlugin.Cfg.Enabled.Value) { return false; } MenuManager instance = MenuManager.instance; return (Object)(object)instance != (Object)null && IsTextInputActive(instance); } private static bool IsTextInputActive(MenuManager manager) { try { int result; if (!(MenuFields.TextInputActive == null)) { object value = MenuFields.TextInputActive.GetValue(manager); bool flag = default(bool); int num; if (value is bool) { flag = (bool)value; num = 1; } else { num = 0; } result = num & (flag ? 1 : 0); } else { result = 1; } return (byte)result != 0; } catch { return true; } } private static void MoveCompositionCursor(MenuTextInput input) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) try { object? obj = MenuFields.TextMain?.GetValue(input); Component val = (Component)((obj is Component) ? obj : null); if (!((Object)(object)val == (Object)null)) { Vector3 position = val.transform.position; Input.compositionCursorPos = new Vector2(position.x, (float)Screen.height - position.y); } } catch { } } private static string CurrentText(MenuTextInput input) { try { return (MenuFields.TextCurrent?.GetValue(input) as string) ?? string.Empty; } catch { return string.Empty; } } private static int MaxLength(MenuTextInput input) { try { return (MenuFields.MaxLength?.GetValue(input) is int num && num > 0) ? num : 0; } catch { return 0; } } private static void SetText(MenuTextInput input, string text) { try { MenuFields.TextCurrent?.SetValue(input, text); MenuFields.InputTextSet?.Invoke(input, null); } catch (Exception ex) { ChineseInputPlugin.Log.LogDebug((object)("[中文输入] 写入失败:" + ex.Message)); } } private static string Clamp(string text, int maxLength) { if (string.IsNullOrEmpty(text)) { return string.Empty; } text = text.Replace("\r", string.Empty).Replace("\n", string.Empty).Replace("\t", string.Empty); if (maxLength > 0 && text.Length > maxLength) { text = text.Substring(0, maxLength); } return text; } private static bool PastePressed() { return (Input.GetKey((KeyCode)306) || Input.GetKey((KeyCode)305) || Input.GetKey((KeyCode)310)) && Input.GetKeyDown((KeyCode)118); } private static string ClipboardText() { try { string systemCopyBuffer = GUIUtility.systemCopyBuffer; if (string.IsNullOrEmpty(systemCopyBuffer)) { return string.Empty; } StringBuilder stringBuilder = new StringBuilder(systemCopyBuffer.Length); string text = systemCopyBuffer; foreach (char c in text) { if (!char.IsControl(c)) { stringBuilder.Append(c); } } return stringBuilder.ToString().Trim(); } catch { return string.Empty; } } } internal static class MenuFields { private const BindingFlags Flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; public static readonly FieldInfo TextCurrent = typeof(MenuTextInput).GetField("textCurrent", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); public static readonly FieldInfo UpperOnly = typeof(MenuTextInput).GetField("upperOnly", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); public static readonly FieldInfo MaxLength = typeof(MenuTextInput).GetField("maxLength", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); public static readonly FieldInfo TextMain = typeof(MenuTextInput).GetField("textMain", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); public static readonly MethodInfo InputTextSet = typeof(MenuTextInput).GetMethod("InputTextSet", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); public static readonly FieldInfo TextInputActive = typeof(MenuManager).GetField("textInputActive", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); public static readonly FieldInfo Instance = typeof(MenuManager).GetField("instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); public static void LogAvailability() { ChineseInputPlugin.Log.LogInfo((object)("[中文输入] 字段探测:textCurrent=" + Mark(TextCurrent) + ", upperOnly=" + Mark(UpperOnly) + ", maxLength=" + Mark(MaxLength) + ", textMain=" + Mark(TextMain) + ", InputTextSet=" + Mark(InputTextSet) + ", textInputActive=" + Mark(TextInputActive))); } private static string Mark(MemberInfo member) { return (member == null) ? "缺失" : "OK"; } } [BepInPlugin("xingKong.ChineseInputPlus", "REPO Chinese Input Plus", "2.1.0")] [BepInProcess("REPO.exe")] public class ChineseInputPlugin : BaseUnityPlugin { public const string PluginGuid = "xingKong.ChineseInputPlus"; public const string PluginName = "REPO Chinese Input Plus"; public const string PluginVersion = "2.1.0"; internal static ManualLogSource Log; internal static PluginConfig Cfg; private Harmony _harmony; private void Awake() { //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; Cfg = new PluginConfig(((BaseUnityPlugin)this).Config); MenuFields.LogAvailability(); ImeState.Init(); LogChatCapability(); _harmony = new Harmony("xingKong.ChineseInputPlus"); try { _harmony.PatchAll(typeof(MenuTextInputPatches)); Log.LogInfo((object)"[中文输入] 已挂接 MenuTextInput.Start / Update。"); } catch (Exception arg) { Log.LogError((object)$"[中文输入] 挂接失败:{arg}"); } Log.LogInfo((object)"REPO Chinese Input Plus v2.1.0 已加载(0.5.1 适配版,菜单输入框)。"); } private void Update() { bool menuInputActive = MenuInputHandler.IsMenuInputActive(); ImeState.Tick(menuInputActive); } private void OnDestroy() { try { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } catch { } } private void LogChatCapability() { try { Type typeFromHandle = typeof(ChatManager); bool flag = typeFromHandle.GetMethod("OnCompositionChange", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) != null; bool flag2 = typeFromHandle.GetMethod("ChatPasteLogic", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) != null; Log.LogInfo((object)$"[中文输入] 聊天框原生支持:IME={flag}, 粘贴={flag2};插件会在聊天激活时强制开启 IME。"); } catch (Exception ex) { Log.LogDebug((object)("[中文输入] 检测聊天能力失败:" + ex.Message)); } } } internal static class MenuTextInputPatches { [HarmonyPatch(typeof(MenuTextInput), "Start")] [HarmonyPostfix] private static void StartPostfix(MenuTextInput __instance) { if (ChineseInputPlugin.Cfg != null && ChineseInputPlugin.Cfg.RemoveUpperCase.Value && MenuFields.UpperOnly != null) { MenuFields.UpperOnly.SetValue(__instance, false); } } [HarmonyPatch(typeof(MenuTextInput), "Update")] [HarmonyPrefix] private static bool UpdatePrefix(MenuTextInput __instance) { return !MenuInputHandler.TryHandle(__instance); } } internal sealed class PluginConfig { public readonly ConfigEntry<bool> Enabled; public readonly ConfigEntry<bool> ImeComposition; public readonly ConfigEntry<bool> EnablePaste; public readonly ConfigEntry<bool> RemoveUpperCase; public readonly ConfigEntry<bool> ChatImeSupport; public PluginConfig(ConfigFile cfg) { Enabled = cfg.Bind<bool>("1. 通用", "启用", true, "总开关。只影响菜单输入框(房间名/玩家名/存档名/密码)。"); ImeComposition = cfg.Bind<bool>("2. 输入", "启用输入法组合", true, "支持拼音/日文/韩文输入法的组合显示与提交。关闭后只能粘贴中文。"); EnablePaste = cfg.Bind<bool>("2. 输入", "Ctrl+V 粘贴", true, "在菜单输入框里粘贴剪贴板文本(自动去掉换行与控制字符,并遵守长度上限)。"); RemoveUpperCase = cfg.Bind<bool>("2. 输入", "去掉强制大写", true, "菜单输入框原本会把字母强制转大写,开启后保留原始大小写,也才能输入汉字。"); ChatImeSupport = cfg.Bind<bool>("2. 输入", "聊天框输入法支持", true, "聊天框激活时强制开启 IME,支持中文、日文、韩文等任意输入法语言的组合与提交(0.5.1 原生只在启动时开一次,之后聊天框拿不到 IME)。"); } } }