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

121 lines
2.6 KiB
C++
Raw Normal View History

#include <Windows.h>
2020-05-05 20:36:49 +02:00
#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;
2018-10-24 13:10:56 +02:00
bool isDrawn;
};
CaretData g_caret = {};
2018-10-24 13:10:56 +02:00
long long g_qpcLastBlink = 0;
void updateCaret(DWORD threadId);
2018-10-24 13:10:56 +02:00
void CALLBACK caretEvent(HWINEVENTHOOK, DWORD, HWND hwnd, LONG idObject, LONG, DWORD, DWORD)
{
if (OBJID_CARET == idObject)
{
2018-10-24 13:10:56 +02:00
updateCaret(GetWindowThreadProcessId(hwnd, nullptr));
}
}
2018-10-24 13:10:56 +02:00
void drawCaret()
{
HDC dc = GetDCEx(g_caret.hwnd, nullptr, DCX_CACHE | DCX_USESTYLE);
2018-10-24 13:10:56 +02:00
PatBlt(dc, g_caret.left, g_caret.top, g_caret.width, g_caret.height, PATINVERT);
2018-11-25 16:15:53 +01:00
CALL_ORIG_FUNC(ReleaseDC)(g_caret.hwnd, dc);
}
2018-10-24 13:10:56 +02:00
CaretData getCaretData(DWORD threadId)
{
GUITHREADINFO gti = {};
gti.cbSize = sizeof(gti);
2018-10-24 13:10:56 +02:00
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;
}
2018-10-24 13:10:56 +02:00
void updateCaret(DWORD threadId)
{
D3dDdi::ScopedCriticalSection lock;
2018-10-24 13:10:56 +02:00
if (g_caret.isDrawn)
{
2018-10-24 13:10:56 +02:00
drawCaret();
}
2018-10-24 13:10:56 +02:00
g_caret = getCaretData(threadId);
if (g_caret.isVisible)
{
2018-10-24 13:10:56 +02:00
g_caret.isDrawn = true;
drawCaret();
g_qpcLastBlink = Time::queryPerformanceCounter();
}
}
}
namespace Gdi
{
namespace Caret
{
2018-10-24 13:10:56 +02:00
void blink()
{
D3dDdi::ScopedCriticalSection lock;
2018-10-24 13:10:56 +02:00
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()
{
2021-03-01 22:59:07 +01:00
SetWinEventHook(EVENT_OBJECT_SHOW, EVENT_OBJECT_HIDE,
2020-05-05 20:36:49 +02:00
Dll::g_currentModule, &caretEvent, GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
2021-03-01 22:59:07 +01:00
SetWinEventHook(EVENT_OBJECT_LOCATIONCHANGE, EVENT_OBJECT_LOCATIONCHANGE,
2020-05-05 20:36:49 +02:00
Dll::g_currentModule, &caretEvent, GetCurrentProcessId(), 0, WINEVENT_INCONTEXT);
}
}
}