diff --git a/Dalamud/Game/Gui/Internal/DalamudIME.cs b/Dalamud/Game/Gui/Internal/DalamudIME.cs index ab36c4211..ed8dcdfcd 100644 --- a/Dalamud/Game/Gui/Internal/DalamudIME.cs +++ b/Dalamud/Game/Gui/Internal/DalamudIME.cs @@ -58,15 +58,73 @@ namespace Dalamud.Game.Gui.Internal Marshal.FreeHGlobal((IntPtr)this.cursorPos); } + private unsafe void LoadCand(IntPtr hWnd) + { + if (hWnd == IntPtr.Zero) + return; + + var hIMC = ImmGetContext(hWnd); + if (hIMC == IntPtr.Zero) + return; + + var size = ImmGetCandidateListW(hIMC, 0, IntPtr.Zero, 0); + if (size == 0) + return; + + var candlistPtr = Marshal.AllocHGlobal((int)size); + size = ImmGetCandidateListW(hIMC, 0, candlistPtr, (uint)size); + + var candlist = this.ImmCandNative = Marshal.PtrToStructure(candlistPtr); + var pageSize = candlist.PageSize; + var candCount = candlist.Count; + + if (pageSize > 0 && candCount > 1) + { + var dwOffsets = new int[candCount]; + for (var i = 0; i < candCount; i++) + { + dwOffsets[i] = Marshal.ReadInt32(candlistPtr + ((i + 6) * sizeof(int))); + } + + var pageStart = candlist.PageStart; + + var cand = new string[pageSize]; + this.ImmCand.Clear(); + + for (var i = 0; i < pageSize; i++) + { + var offStart = dwOffsets[i + pageStart]; + var offEnd = i + pageStart + 1 < candCount ? dwOffsets[i + pageStart + 1] : size; + + var pStrStart = candlistPtr + (int)offStart; + var pStrEnd = candlistPtr + (int)offEnd; + + var len = (int)(pStrEnd.ToInt64() - pStrStart.ToInt64()); + if (len > 0) + { + var candBytes = new byte[len]; + Marshal.Copy(pStrStart, candBytes, 0, len); + + var candStr = Encoding.Unicode.GetString(candBytes); + cand[i] = candStr; + + this.ImmCand.Add(candStr); + } + } + + Marshal.FreeHGlobal(candlistPtr); + } + } + /// /// Processes window messages. /// /// Handle of the window. /// Type of window message. - /// wParam. - /// lParam. + /// wParam or the pointer to it. + /// lParam or the pointer to it. /// Return value, if not doing further processing. - public unsafe IntPtr? ProcessWndProcW(IntPtr hWnd, User32.WindowMessage msg, void* wParam, void* lParam) + public unsafe IntPtr? ProcessWndProcW(IntPtr hWnd, User32.WindowMessage msg, void* wParamPtr, void* lParamPtr) { try { @@ -74,6 +132,18 @@ namespace Dalamud.Game.Gui.Internal { var io = ImGui.GetIO(); var wmsg = (WindowsMessage)msg; + long wParam = (long)wParamPtr, lParam = (long)lParamPtr; + try + { + wParam = Marshal.ReadInt32((IntPtr)wParamPtr); + } + catch { } + + try + { + lParam = Marshal.ReadInt32((IntPtr)lParamPtr); + } + catch { } switch (wmsg) { @@ -82,73 +152,18 @@ namespace Dalamud.Game.Gui.Internal { case IMECommand.ChangeCandidate: this.ToggleWindow(true); - - if (hWnd == IntPtr.Zero) - return IntPtr.Zero; - - var hIMC = ImmGetContext(hWnd); - if (hIMC == IntPtr.Zero) - return IntPtr.Zero; - - var size = ImmGetCandidateListW(hIMC, 0, IntPtr.Zero, 0); - if (size == 0) - break; - - var candlistPtr = Marshal.AllocHGlobal((int)size); - size = ImmGetCandidateListW(hIMC, 0, candlistPtr, (uint)size); - - var candlist = this.ImmCandNative = Marshal.PtrToStructure(candlistPtr); - var pageSize = candlist.PageSize; - var candCount = candlist.Count; - - if (pageSize > 0 && candCount > 1) - { - var dwOffsets = new int[candCount]; - for (var i = 0; i < candCount; i++) - { - dwOffsets[i] = Marshal.ReadInt32(candlistPtr + ((i + 6) * sizeof(int))); - } - - var pageStart = candlist.PageStart; - - var cand = new string[pageSize]; - this.ImmCand.Clear(); - - for (var i = 0; i < pageSize; i++) - { - var offStart = dwOffsets[i + pageStart]; - var offEnd = i + pageStart + 1 < candCount ? dwOffsets[i + pageStart + 1] : size; - - var pStrStart = candlistPtr + (int)offStart; - var pStrEnd = candlistPtr + (int)offEnd; - - var len = (int)(pStrEnd.ToInt64() - pStrStart.ToInt64()); - if (len > 0) - { - var candBytes = new byte[len]; - Marshal.Copy(pStrStart, candBytes, 0, len); - - var candStr = Encoding.Unicode.GetString(candBytes); - cand[i] = candStr; - - this.ImmCand.Add(candStr); - } - } - - Marshal.FreeHGlobal(candlistPtr); - } - + this.LoadCand(hWnd); break; case IMECommand.OpenCandidate: this.ToggleWindow(true); this.ImmCandNative = default; - this.ImmCand.Clear(); + // this.ImmCand.Clear(); break; case IMECommand.CloseCandidate: this.ToggleWindow(false); this.ImmCandNative = default; - this.ImmCand.Clear(); + // this.ImmCand.Clear(); break; default: @@ -157,6 +172,33 @@ namespace Dalamud.Game.Gui.Internal break; case WindowsMessage.WM_IME_COMPOSITION: + if (((long)(IMEComposition.CompStr | IMEComposition.CompAttr | IMEComposition.CompClause | + IMEComposition.CompReadAttr | IMEComposition.CompReadClause | IMEComposition.CompReadStr) & (long)(IntPtr)lParam) > 0) + { + var hIMC = ImmGetContext(hWnd); + if (hIMC == IntPtr.Zero) + return IntPtr.Zero; + + var dwSize = ImmGetCompositionStringW(hIMC, IMEComposition.CompStr, IntPtr.Zero, 0); + var unmanagedPointer = Marshal.AllocHGlobal((int)dwSize); + ImmGetCompositionStringW(hIMC, IMEComposition.CompStr, unmanagedPointer, (uint)dwSize); + + var bytes = new byte[dwSize]; + Marshal.Copy(unmanagedPointer, bytes, 0, (int)dwSize); + Marshal.FreeHGlobal(unmanagedPointer); + + var lpstr = Encoding.Unicode.GetString(bytes); + this.ImmComp = lpstr; + if (lpstr == string.Empty) + { + this.ToggleWindow(false); + } + else + { + this.LoadCand(hWnd); + } + } + if (((long)(IntPtr)lParam & (long)IMEComposition.ResultStr) > 0) { var hIMC = ImmGetContext(hWnd); @@ -180,27 +222,6 @@ namespace Dalamud.Game.Gui.Internal this.ToggleWindow(false); } - if (((long)(IMEComposition.CompStr | IMEComposition.CompAttr | IMEComposition.CompClause | - IMEComposition.CompReadAttr | IMEComposition.CompReadClause | IMEComposition.CompReadStr) & (long)(IntPtr)lParam) > 0) - { - var hIMC = ImmGetContext(hWnd); - if (hIMC == IntPtr.Zero) - return IntPtr.Zero; - - var dwSize = ImmGetCompositionStringW(hIMC, IMEComposition.CompStr, IntPtr.Zero, 0); - var unmanagedPointer = Marshal.AllocHGlobal((int)dwSize); - ImmGetCompositionStringW(hIMC, IMEComposition.CompStr, unmanagedPointer, (uint)dwSize); - - var bytes = new byte[dwSize]; - Marshal.Copy(unmanagedPointer, bytes, 0, (int)dwSize); - Marshal.FreeHGlobal(unmanagedPointer); - - var lpstr = Encoding.Unicode.GetString(bytes); - this.ImmComp = lpstr; - if (lpstr == string.Empty) - this.ToggleWindow(false); - } - break; default: diff --git a/Dalamud/Interface/Internal/InterfaceManager.cs b/Dalamud/Interface/Internal/InterfaceManager.cs index aae840239..27414b71e 100644 --- a/Dalamud/Interface/Internal/InterfaceManager.cs +++ b/Dalamud/Interface/Internal/InterfaceManager.cs @@ -62,6 +62,7 @@ namespace Dalamud.Interface.Internal private readonly SwapChainVtableResolver address; private readonly Hook dispatchMessageWHook; private readonly Hook setCursorHook; + private Hook processMessageHook; private RawDX11Scene? scene; private Hook? presentHook; @@ -97,6 +98,8 @@ namespace Dalamud.Interface.Internal [UnmanagedFunctionPointer(CallingConvention.StdCall)] private delegate IntPtr DispatchMessageWDelegate(ref User32.MSG msg); + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + private delegate IntPtr ProcessMessageDelegate(IntPtr hWnd, uint msg, ulong wParam, ulong lParam, IntPtr handeled); /// /// This event gets called each frame to facilitate ImGui drawing. /// @@ -217,6 +220,7 @@ namespace Dalamud.Interface.Internal this.presentHook?.Dispose(); this.resizeBuffersHook?.Dispose(); this.dispatchMessageWHook.Dispose(); + this.processMessageHook?.Dispose(); }).Wait(); this.scene?.Dispose(); @@ -920,10 +924,15 @@ namespace Dalamud.Interface.Internal Log.Verbose($"Present address 0x{this.presentHook!.Address.ToInt64():X}"); Log.Verbose($"ResizeBuffers address 0x{this.resizeBuffersHook!.Address.ToInt64():X}"); + var wndProcAddress = sigScanner.ScanText("E8 ?? ?? ?? ?? 80 7C 24 ?? ?? 74 ?? B8"); + Log.Verbose($"WndProc address 0x{wndProcAddress.ToInt64():X}"); + this.processMessageHook = Hook.FromAddress(wndProcAddress, this.ProcessMessageDetour); + this.setCursorHook.Enable(); this.presentHook.Enable(); this.resizeBuffersHook.Enable(); this.dispatchMessageWHook.Enable(); + this.processMessageHook.Enable(); }); } @@ -944,16 +953,18 @@ namespace Dalamud.Interface.Internal this.isRebuildingFonts = false; } + private unsafe IntPtr ProcessMessageDetour(IntPtr hWnd, uint msg, ulong wParam, ulong lParam, IntPtr handeled) + { + var ime = Service.GetNullable(); + var res = ime?.ProcessWndProcW(hWnd, (User32.WindowMessage)msg, (void*)wParam, (void*)lParam); + return this.processMessageHook.Original(hWnd, msg, wParam, lParam, handeled); + } + private unsafe IntPtr DispatchMessageWDetour(ref User32.MSG msg) { if (msg.hwnd == this.GameWindowHandle && this.scene != null) { - var ime = Service.GetNullable(); - var res = ime?.ProcessWndProcW(msg.hwnd, msg.message, (void*)msg.wParam, (void*)msg.lParam); - if (res != null) - return res.Value; - - res = this.scene.ProcessWndProcW(msg.hwnd, msg.message, (void*)msg.wParam, (void*)msg.lParam); + var res = this.scene.ProcessWndProcW(msg.hwnd, msg.message, (void*)msg.wParam, (void*)msg.lParam); if (res != null) return res.Value; }