1
0
mirror of https://github.com/narzoul/DDrawCompat synced 2024-12-30 08:55:36 +01:00
2021-03-01 22:59:07 +01:00

121 lines
2.6 KiB
C++

#include <Windows.h>
#include <Common/Hook.h>
#include <Common/Time.h>
#include <D3dDdi/ScopedCriticalSection.h>
#include <Dll/Dll.h>
#include <Gdi/Caret.h>
#include <Gdi/Gdi.h>
namespace
{
struct CaretData
{
HWND hwnd;
long left;
long top;
long width;
long height;
bool isVisible;
bool isDrawn;
};
CaretData g_caret = {};
long long g_qpcLastBlink = 0;
void updateCaret(DWORD threadId);
void CALLBACK caretEvent(HWINEVENTHOOK, DWORD, HWND hwnd, LONG idObject, LONG, DWORD, DWORD)
{
if (OBJID_CARET == idObject)
{
updateCaret(GetWindowThreadProcessId(hwnd, nullptr));
}
}
void drawCaret()
{
HDC dc = GetDCEx(g_caret.hwnd, nullptr, DCX_CACHE | DCX_USESTYLE);
PatBlt(dc, g_caret.left, g_caret.top, g_caret.width, g_caret.height, PATINVERT);
CALL_ORIG_FUNC(ReleaseDC)(g_caret.hwnd, dc);
}
CaretData getCaretData(DWORD threadId)
{
GUITHREADINFO gti = {};
gti.cbSize = sizeof(gti);
GetGUIThreadInfo(threadId, &gti);
CaretData caretData = {};
caretData.hwnd = gti.hwndCaret;
caretData.left = gti.rcCaret.left;
caretData.top = gti.rcCaret.top;
caretData.width = gti.rcCaret.right - gti.rcCaret.left;
caretData.height = gti.rcCaret.bottom - gti.rcCaret.top;
caretData.isVisible = gti.flags & GUI_CARETBLINKING;
return caretData;
}
void updateCaret(DWORD threadId)
{
D3dDdi::ScopedCriticalSection lock;
if (g_caret.isDrawn)
{
drawCaret();
}
g_caret = getCaretData(threadId);
if (g_caret.isVisible)
{
g_caret.isDrawn = true;
drawCaret();
g_qpcLastBlink = Time::queryPerformanceCounter();
}
}
}
namespace Gdi
{
namespace Caret
{
void blink()
{
D3dDdi::ScopedCriticalSection 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), &gti);
if (!(gti.flags & (GUI_INMENUMODE | GUI_POPUPMENUMODE | GUI_SYSTEMMENUMODE)))
{
g_caret.isDrawn = !g_caret.isDrawn;
drawCaret();
}
}
}
void installHooks()
{
SetWinEventHook(EVENT_OBJECT_SHOW, EVENT_OBJECT_HIDE,
Dll::g_currentModule, &caretEvent, GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
SetWinEventHook(EVENT_OBJECT_LOCATIONCHANGE, EVENT_OBJECT_LOCATIONCHANGE,
Dll::g_currentModule, &caretEvent, GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
}
}
}