From 4717b9aa1b495dc3ed9cc831afa9dd6fdcd1426b Mon Sep 17 00:00:00 2001 From: narzoul Date: Wed, 24 Oct 2018 13:10:56 +0200 Subject: [PATCH] Fixed caret display issues --- DDrawCompat/DDraw/RealPrimarySurface.cpp | 2 + DDrawCompat/Gdi/Caret.cpp | 153 +++++++++++------------ DDrawCompat/Gdi/Caret.h | 1 + 3 files changed, 73 insertions(+), 83 deletions(-) diff --git a/DDrawCompat/DDraw/RealPrimarySurface.cpp b/DDrawCompat/DDraw/RealPrimarySurface.cpp index 4179222..3581bf3 100644 --- a/DDrawCompat/DDraw/RealPrimarySurface.cpp +++ b/DDrawCompat/DDraw/RealPrimarySurface.cpp @@ -15,6 +15,7 @@ #include "DDraw/Surfaces/PrimarySurface.h" #include "DDraw/Types.h" #include "Gdi/AccessGuard.h" +#include "Gdi/Caret.h" #include "Gdi/Gdi.h" #include "Gdi/VirtualScreen.h" #include "Gdi/Window.h" @@ -459,6 +460,7 @@ namespace Sleep(msPresentDelayAfterVBlank); DDraw::ScopedThreadLock lock; + Gdi::Caret::blink(); waitForVBlank = Time::qpcToMs(Time::queryPerformanceCounter() - D3dDdi::KernelModeThunks::getQpcLastVerticalBlank()) >= msPresentDelayAfterVBlank; diff --git a/DDrawCompat/Gdi/Caret.cpp b/DDrawCompat/Gdi/Caret.cpp index 27b7fac..e626c4f 100644 --- a/DDrawCompat/Gdi/Caret.cpp +++ b/DDrawCompat/Gdi/Caret.cpp @@ -3,19 +3,16 @@ #include #include "Common/Hook.h" -#include "Common/ScopedCriticalSection.h" -#include "Gdi/AccessGuard.h" +#include "Common/Time.h" +#include "DDraw/ScopedThreadLock.h" #include "Gdi/Caret.h" -#include "Gdi/Dc.h" -#include "Gdi/Gdi.h" + +extern "C" IMAGE_DOS_HEADER __ImageBase; namespace { - HWINEVENTHOOK g_compatGdiCaretGeneralEventHook = nullptr; - HWINEVENTHOOK g_compatGdiCaretLocationChangeEventHook = nullptr; - - template - using FuncPtr = Result(WINAPI *)(Params...); + HWINEVENTHOOK g_caretGeneralEventHook = nullptr; + HWINEVENTHOOK g_caretLocationChangeEventHook = nullptr; struct CaretData { @@ -25,58 +22,36 @@ namespace long width; long height; bool isVisible; - - bool operator==(const CaretData& rhs) const - { - return hwnd == rhs.hwnd && - left == rhs.left && - top == rhs.top && - width == rhs.width && - height == rhs.height && - isVisible == rhs.isVisible; - } + bool isDrawn; }; CaretData g_caret = {}; - CRITICAL_SECTION g_caretCriticalSection; - - void updateCaret(); + long long g_qpcLastBlink = 0; - void CALLBACK compatGdiCaretEvent(HWINEVENTHOOK, DWORD, HWND, LONG idObject, LONG, DWORD, DWORD) + void updateCaret(DWORD threadId); + + void CALLBACK caretEvent(HWINEVENTHOOK, DWORD, HWND hwnd, LONG idObject, LONG, DWORD, DWORD) { if (OBJID_CARET == idObject) { - updateCaret(); + DDraw::ScopedThreadLock lock; + updateCaret(GetWindowThreadProcessId(hwnd, nullptr)); } } - template - Result WINAPI compatGdiCaretFunc(Params... params) + void drawCaret() { - Result result = Compat::getOrigFuncPtr()(params...); - updateCaret(); - return result; + HDC dc = GetDC(g_caret.hwnd); + PatBlt(dc, g_caret.left, g_caret.top, g_caret.width, g_caret.height, PATINVERT); + ReleaseDC(g_caret.hwnd, dc); } - void drawCaret(const CaretData& caret) - { - if (caret.isVisible) - { - HDC dc = GetDC(caret.hwnd); - HDC compatDc = Gdi::Dc::getDc(dc); - CALL_ORIG_FUNC(PatBlt)( - compatDc, caret.left, caret.top, caret.width, caret.height, PATINVERT); - Gdi::Dc::releaseDc(dc); - ReleaseDC(caret.hwnd, dc); - } - } - - CaretData getCaretData() + CaretData getCaretData(DWORD threadId) { GUITHREADINFO gti = {}; gti.cbSize = sizeof(gti); - GetGUIThreadInfo(Gdi::getGdiThreadId(), >i); + GetGUIThreadInfo(threadId, >i); CaretData caretData = {}; caretData.hwnd = gti.hwndCaret; @@ -88,63 +63,75 @@ namespace return caretData; } - template - OrigFuncPtr getCompatGdiCaretFuncPtr(FuncPtr) + void updateCaret(DWORD threadId) { - return &compatGdiCaretFunc; - } - - void updateCaret() - { - Compat::ScopedCriticalSection lock(g_caretCriticalSection); - - CaretData newCaret = getCaretData(); - if (newCaret == g_caret) + DDraw::ScopedThreadLock lock; + if (g_caret.isDrawn) { - return; + drawCaret(); } - if ((g_caret.isVisible || newCaret.isVisible)) - { - Gdi::GdiAccessGuard accessGuard(Gdi::ACCESS_WRITE); - drawCaret(g_caret); - drawCaret(newCaret); - } + g_caret = getCaretData(threadId); - g_caret = newCaret; + if (g_caret.isVisible) + { + g_caret.isDrawn = true; + drawCaret(); + g_qpcLastBlink = Time::queryPerformanceCounter(); + } } } -#define HOOK_GDI_CARET_FUNCTION(module, func) \ - Compat::hookFunction( \ - #module, #func, getCompatGdiCaretFuncPtr(&func)); - namespace Gdi { namespace Caret { + void blink() + { + DDraw::ScopedThreadLock lock; + if (!g_caret.isVisible) + { + return; + } + + UINT caretBlinkTime = GetCaretBlinkTime(); + if (INFINITE == caretBlinkTime) + { + return; + } + + const long long qpcNow = Time::queryPerformanceCounter(); + if (Time::qpcToMs(qpcNow - g_qpcLastBlink) >= caretBlinkTime) + { + g_qpcLastBlink = qpcNow; + + GUITHREADINFO gti = {}; + gti.cbSize = sizeof(gti); + GetGUIThreadInfo(GetWindowThreadProcessId(g_caret.hwnd, nullptr), >i); + if (!(gti.flags & (GUI_INMENUMODE | GUI_POPUPMENUMODE | GUI_SYSTEMMENUMODE))) + { + g_caret.isDrawn = !g_caret.isDrawn; + drawCaret(); + } + } + } + void installHooks() { - InitializeCriticalSection(&g_caretCriticalSection); - - HOOK_GDI_CARET_FUNCTION(user32, CreateCaret); - HOOK_GDI_CARET_FUNCTION(user32, DestroyCaret); - HOOK_GDI_CARET_FUNCTION(user32, HideCaret); - HOOK_GDI_CARET_FUNCTION(user32, SetCaretPos); - HOOK_GDI_CARET_FUNCTION(user32, ShowCaret); - - const DWORD threadId = Gdi::getGdiThreadId(); - g_compatGdiCaretGeneralEventHook = SetWinEventHook(EVENT_OBJECT_CREATE, EVENT_OBJECT_HIDE, - nullptr, &compatGdiCaretEvent, 0, threadId, WINEVENT_OUTOFCONTEXT); - g_compatGdiCaretLocationChangeEventHook = SetWinEventHook( - EVENT_OBJECT_LOCATIONCHANGE, EVENT_OBJECT_LOCATIONCHANGE, nullptr, &compatGdiCaretEvent, - 0, threadId, WINEVENT_OUTOFCONTEXT); + g_caretGeneralEventHook = SetWinEventHook( + EVENT_OBJECT_SHOW, EVENT_OBJECT_HIDE, + reinterpret_cast(&__ImageBase), &caretEvent, + GetCurrentProcessId(), 0, WINEVENT_INCONTEXT); + g_caretLocationChangeEventHook = SetWinEventHook( + EVENT_OBJECT_LOCATIONCHANGE, EVENT_OBJECT_LOCATIONCHANGE, + reinterpret_cast(&__ImageBase), &caretEvent, + GetCurrentProcessId(), 0, WINEVENT_INCONTEXT); } void uninstallHooks() { - UnhookWinEvent(g_compatGdiCaretLocationChangeEventHook); - UnhookWinEvent(g_compatGdiCaretGeneralEventHook); + UnhookWinEvent(g_caretLocationChangeEventHook); + UnhookWinEvent(g_caretGeneralEventHook); } } } diff --git a/DDrawCompat/Gdi/Caret.h b/DDrawCompat/Gdi/Caret.h index f6a753e..47d818f 100644 --- a/DDrawCompat/Gdi/Caret.h +++ b/DDrawCompat/Gdi/Caret.h @@ -4,6 +4,7 @@ namespace Gdi { namespace Caret { + void blink(); void installHooks(); void uninstallHooks(); }