mirror of
https://github.com/narzoul/DDrawCompat
synced 2024-12-30 08:55:36 +01:00
Fixed caret display issues
This commit is contained in:
parent
2f00b74a56
commit
4717b9aa1b
@ -15,6 +15,7 @@
|
|||||||
#include "DDraw/Surfaces/PrimarySurface.h"
|
#include "DDraw/Surfaces/PrimarySurface.h"
|
||||||
#include "DDraw/Types.h"
|
#include "DDraw/Types.h"
|
||||||
#include "Gdi/AccessGuard.h"
|
#include "Gdi/AccessGuard.h"
|
||||||
|
#include "Gdi/Caret.h"
|
||||||
#include "Gdi/Gdi.h"
|
#include "Gdi/Gdi.h"
|
||||||
#include "Gdi/VirtualScreen.h"
|
#include "Gdi/VirtualScreen.h"
|
||||||
#include "Gdi/Window.h"
|
#include "Gdi/Window.h"
|
||||||
@ -459,6 +460,7 @@ namespace
|
|||||||
Sleep(msPresentDelayAfterVBlank);
|
Sleep(msPresentDelayAfterVBlank);
|
||||||
|
|
||||||
DDraw::ScopedThreadLock lock;
|
DDraw::ScopedThreadLock lock;
|
||||||
|
Gdi::Caret::blink();
|
||||||
waitForVBlank = Time::qpcToMs(Time::queryPerformanceCounter() -
|
waitForVBlank = Time::qpcToMs(Time::queryPerformanceCounter() -
|
||||||
D3dDdi::KernelModeThunks::getQpcLastVerticalBlank()) >= msPresentDelayAfterVBlank;
|
D3dDdi::KernelModeThunks::getQpcLastVerticalBlank()) >= msPresentDelayAfterVBlank;
|
||||||
|
|
||||||
|
@ -3,19 +3,16 @@
|
|||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
|
||||||
#include "Common/Hook.h"
|
#include "Common/Hook.h"
|
||||||
#include "Common/ScopedCriticalSection.h"
|
#include "Common/Time.h"
|
||||||
#include "Gdi/AccessGuard.h"
|
#include "DDraw/ScopedThreadLock.h"
|
||||||
#include "Gdi/Caret.h"
|
#include "Gdi/Caret.h"
|
||||||
#include "Gdi/Dc.h"
|
|
||||||
#include "Gdi/Gdi.h"
|
extern "C" IMAGE_DOS_HEADER __ImageBase;
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
HWINEVENTHOOK g_compatGdiCaretGeneralEventHook = nullptr;
|
HWINEVENTHOOK g_caretGeneralEventHook = nullptr;
|
||||||
HWINEVENTHOOK g_compatGdiCaretLocationChangeEventHook = nullptr;
|
HWINEVENTHOOK g_caretLocationChangeEventHook = nullptr;
|
||||||
|
|
||||||
template <typename Result, typename... Params>
|
|
||||||
using FuncPtr = Result(WINAPI *)(Params...);
|
|
||||||
|
|
||||||
struct CaretData
|
struct CaretData
|
||||||
{
|
{
|
||||||
@ -25,58 +22,36 @@ namespace
|
|||||||
long width;
|
long width;
|
||||||
long height;
|
long height;
|
||||||
bool isVisible;
|
bool isVisible;
|
||||||
|
bool isDrawn;
|
||||||
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;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
CaretData g_caret = {};
|
CaretData g_caret = {};
|
||||||
CRITICAL_SECTION g_caretCriticalSection;
|
long long g_qpcLastBlink = 0;
|
||||||
|
|
||||||
void updateCaret();
|
|
||||||
|
|
||||||
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)
|
if (OBJID_CARET == idObject)
|
||||||
{
|
{
|
||||||
updateCaret();
|
DDraw::ScopedThreadLock lock;
|
||||||
|
updateCaret(GetWindowThreadProcessId(hwnd, nullptr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OrigFuncPtr, OrigFuncPtr origFunc, typename Result, typename... Params>
|
void drawCaret()
|
||||||
Result WINAPI compatGdiCaretFunc(Params... params)
|
|
||||||
{
|
{
|
||||||
Result result = Compat::getOrigFuncPtr<OrigFuncPtr, origFunc>()(params...);
|
HDC dc = GetDC(g_caret.hwnd);
|
||||||
updateCaret();
|
PatBlt(dc, g_caret.left, g_caret.top, g_caret.width, g_caret.height, PATINVERT);
|
||||||
return result;
|
ReleaseDC(g_caret.hwnd, dc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawCaret(const CaretData& caret)
|
CaretData getCaretData(DWORD threadId)
|
||||||
{
|
|
||||||
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()
|
|
||||||
{
|
{
|
||||||
GUITHREADINFO gti = {};
|
GUITHREADINFO gti = {};
|
||||||
gti.cbSize = sizeof(gti);
|
gti.cbSize = sizeof(gti);
|
||||||
GetGUIThreadInfo(Gdi::getGdiThreadId(), >i);
|
GetGUIThreadInfo(threadId, >i);
|
||||||
|
|
||||||
CaretData caretData = {};
|
CaretData caretData = {};
|
||||||
caretData.hwnd = gti.hwndCaret;
|
caretData.hwnd = gti.hwndCaret;
|
||||||
@ -88,63 +63,75 @@ namespace
|
|||||||
return caretData;
|
return caretData;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OrigFuncPtr, OrigFuncPtr origFunc, typename Result, typename... Params>
|
void updateCaret(DWORD threadId)
|
||||||
OrigFuncPtr getCompatGdiCaretFuncPtr(FuncPtr<Result, Params...>)
|
|
||||||
{
|
{
|
||||||
return &compatGdiCaretFunc<OrigFuncPtr, origFunc, Result, Params...>;
|
DDraw::ScopedThreadLock lock;
|
||||||
}
|
if (g_caret.isDrawn)
|
||||||
|
|
||||||
void updateCaret()
|
|
||||||
{
|
|
||||||
Compat::ScopedCriticalSection lock(g_caretCriticalSection);
|
|
||||||
|
|
||||||
CaretData newCaret = getCaretData();
|
|
||||||
if (newCaret == g_caret)
|
|
||||||
{
|
{
|
||||||
return;
|
drawCaret();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((g_caret.isVisible || newCaret.isVisible))
|
g_caret = getCaretData(threadId);
|
||||||
{
|
|
||||||
Gdi::GdiAccessGuard accessGuard(Gdi::ACCESS_WRITE);
|
|
||||||
drawCaret(g_caret);
|
|
||||||
drawCaret(newCaret);
|
|
||||||
}
|
|
||||||
|
|
||||||
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<decltype(&func), &func>( \
|
|
||||||
#module, #func, getCompatGdiCaretFuncPtr<decltype(&func), &func>(&func));
|
|
||||||
|
|
||||||
namespace Gdi
|
namespace Gdi
|
||||||
{
|
{
|
||||||
namespace Caret
|
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()
|
void installHooks()
|
||||||
{
|
{
|
||||||
InitializeCriticalSection(&g_caretCriticalSection);
|
g_caretGeneralEventHook = SetWinEventHook(
|
||||||
|
EVENT_OBJECT_SHOW, EVENT_OBJECT_HIDE,
|
||||||
HOOK_GDI_CARET_FUNCTION(user32, CreateCaret);
|
reinterpret_cast<HMODULE>(&__ImageBase), &caretEvent,
|
||||||
HOOK_GDI_CARET_FUNCTION(user32, DestroyCaret);
|
GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
|
||||||
HOOK_GDI_CARET_FUNCTION(user32, HideCaret);
|
g_caretLocationChangeEventHook = SetWinEventHook(
|
||||||
HOOK_GDI_CARET_FUNCTION(user32, SetCaretPos);
|
EVENT_OBJECT_LOCATIONCHANGE, EVENT_OBJECT_LOCATIONCHANGE,
|
||||||
HOOK_GDI_CARET_FUNCTION(user32, ShowCaret);
|
reinterpret_cast<HMODULE>(&__ImageBase), &caretEvent,
|
||||||
|
GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void uninstallHooks()
|
void uninstallHooks()
|
||||||
{
|
{
|
||||||
UnhookWinEvent(g_compatGdiCaretLocationChangeEventHook);
|
UnhookWinEvent(g_caretLocationChangeEventHook);
|
||||||
UnhookWinEvent(g_compatGdiCaretGeneralEventHook);
|
UnhookWinEvent(g_caretGeneralEventHook);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ namespace Gdi
|
|||||||
{
|
{
|
||||||
namespace Caret
|
namespace Caret
|
||||||
{
|
{
|
||||||
|
void blink();
|
||||||
void installHooks();
|
void installHooks();
|
||||||
void uninstallHooks();
|
void uninstallHooks();
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user