improvements in thread safety and repetition detection in textthread
This commit is contained in:
parent
8880d27dc5
commit
f080656e60
@ -120,7 +120,7 @@ namespace
|
|||||||
SetWindowsHookExW(WH_GETMESSAGE, [](int statusCode, WPARAM wParam, LPARAM lParam)
|
SetWindowsHookExW(WH_GETMESSAGE, [](int statusCode, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
if (statusCode == HC_ACTION && wParam == PM_REMOVE && ((MSG*)lParam)->message == WM_CLIPBOARDUPDATE)
|
if (statusCode == HC_ACTION && wParam == PM_REMOVE && ((MSG*)lParam)->message == WM_CLIPBOARDUPDATE)
|
||||||
if (auto text = Util::GetClipboardText()) Host::GetThread(CLIPBOARD)->PushSentence(text.value());
|
if (auto text = Util::GetClipboardText()) Host::GetThread(CLIPBOARD)->AddSentence(text.value());
|
||||||
return CallNextHookEx(NULL, statusCode, wParam, lParam);
|
return CallNextHookEx(NULL, statusCode, wParam, lParam);
|
||||||
}, NULL, GetCurrentThreadId());
|
}, NULL, GetCurrentThreadId());
|
||||||
}
|
}
|
||||||
@ -206,6 +206,6 @@ namespace Host
|
|||||||
|
|
||||||
void AddConsoleOutput(std::wstring text)
|
void AddConsoleOutput(std::wstring text)
|
||||||
{
|
{
|
||||||
GetThread(CONSOLE)->PushSentence(text);
|
GetThread(CONSOLE)->AddSentence(text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ TextThread::TextThread(ThreadParam tp, HookParam hp, std::optional<std::wstring>
|
|||||||
tp(tp),
|
tp(tp),
|
||||||
hp(hp)
|
hp(hp)
|
||||||
{
|
{
|
||||||
CreateTimerQueueTimer(timer, NULL, [](void* This, BOOLEAN) { ((TextThread*)This)->Flush(); }, this, 25, 25, WT_EXECUTELONGFUNCTION);
|
CreateTimerQueueTimer(&timer, NULL, [](void* This, BOOLEAN) { ((TextThread*)This)->Flush(); }, this, 10, 10, WT_EXECUTELONGFUNCTION);
|
||||||
OnCreate(this);
|
OnCreate(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -19,6 +19,11 @@ TextThread::~TextThread()
|
|||||||
OnDestroy(this);
|
OnDestroy(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TextThread::AddSentence(const std::wstring& sentence)
|
||||||
|
{
|
||||||
|
queuedSentences->push_back(sentence);
|
||||||
|
}
|
||||||
|
|
||||||
void TextThread::Push(const BYTE* data, int len)
|
void TextThread::Push(const BYTE* data, int len)
|
||||||
{
|
{
|
||||||
if (len < 0) return;
|
if (len < 0) return;
|
||||||
@ -26,29 +31,27 @@ void TextThread::Push(const BYTE* data, int len)
|
|||||||
if (hp.type & USING_UNICODE) buffer += std::wstring((wchar_t*)data, len / 2);
|
if (hp.type & USING_UNICODE) buffer += std::wstring((wchar_t*)data, len / 2);
|
||||||
else if (auto converted = Util::StringToWideString(std::string((char*)data, len), hp.codepage ? hp.codepage : defaultCodepage)) buffer += converted.value();
|
else if (auto converted = Util::StringToWideString(std::string((char*)data, len), hp.codepage ? hp.codepage : defaultCodepage)) buffer += converted.value();
|
||||||
else Host::AddConsoleOutput(INVALID_CODEPAGE);
|
else Host::AddConsoleOutput(INVALID_CODEPAGE);
|
||||||
if (std::all_of(buffer.begin(), buffer.end(), [&](wchar_t c) { return repeatingChars.count(c) > 0; })) buffer.clear();
|
|
||||||
lastPushTime = GetTickCount();
|
lastPushTime = GetTickCount();
|
||||||
}
|
|
||||||
|
|
||||||
void TextThread::PushSentence(std::wstring sentence)
|
if (std::all_of(buffer.begin(), buffer.end(), [&](wchar_t c) { return repeatingChars.count(c) > 0; })) buffer.clear();
|
||||||
{
|
if (Util::RemoveRepetition(buffer)) // repetition detected, which means the entire sentence has already been received
|
||||||
LOCK(bufferMutex);
|
{
|
||||||
buffer += sentence;
|
repeatingChars = std::unordered_set(buffer.begin(), buffer.end());
|
||||||
lastPushTime = 0;
|
AddSentence(buffer);
|
||||||
|
buffer.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextThread::Flush()
|
void TextThread::Flush()
|
||||||
{
|
{
|
||||||
std::wstring sentence;
|
std::vector<std::wstring> sentences;
|
||||||
{
|
queuedSentences->swap(sentences);
|
||||||
LOCK(bufferMutex);
|
for (auto sentence : sentences)
|
||||||
if (buffer.empty()) return;
|
if (Output(this, sentence)) storage->append(sentence);
|
||||||
if (buffer.size() < maxBufferSize && GetTickCount() - lastPushTime < flushDelay) return;
|
|
||||||
sentence = buffer;
|
|
||||||
buffer.clear();
|
|
||||||
|
|
||||||
if (Util::RemoveRepetition(sentence)) repeatingChars = std::unordered_set(sentence.begin(), sentence.end());
|
LOCK(bufferMutex);
|
||||||
else repeatingChars.clear();
|
if (buffer.empty()) return;
|
||||||
}
|
if (buffer.size() < maxBufferSize && GetTickCount() - lastPushTime < flushDelay) return;
|
||||||
if (Output(this, sentence)) storage->append(sentence);
|
AddSentence(buffer);
|
||||||
|
buffer.clear();
|
||||||
}
|
}
|
||||||
|
@ -19,9 +19,8 @@ public:
|
|||||||
TextThread(ThreadParam tp, HookParam hp, std::optional<std::wstring> name = {});
|
TextThread(ThreadParam tp, HookParam hp, std::optional<std::wstring> name = {});
|
||||||
~TextThread();
|
~TextThread();
|
||||||
|
|
||||||
|
void AddSentence(const std::wstring& sentence);
|
||||||
void Push(const BYTE* data, int len);
|
void Push(const BYTE* data, int len);
|
||||||
// Flushes ASAP
|
|
||||||
void PushSentence(std::wstring sentence);
|
|
||||||
|
|
||||||
ThreadSafe<std::wstring> storage;
|
ThreadSafe<std::wstring> storage;
|
||||||
const int64_t handle;
|
const int64_t handle;
|
||||||
@ -37,5 +36,6 @@ private:
|
|||||||
std::unordered_set<wchar_t> repeatingChars;
|
std::unordered_set<wchar_t> repeatingChars;
|
||||||
std::mutex bufferMutex;
|
std::mutex bufferMutex;
|
||||||
DWORD lastPushTime;
|
DWORD lastPushTime;
|
||||||
|
ThreadSafe<std::vector<std::wstring>> queuedSentences;
|
||||||
AutoHandle<TimerDeleter> timer = NULL; // this needs to be last so it's destructed first
|
AutoHandle<TimerDeleter> timer = NULL; // this needs to be last so it's destructed first
|
||||||
};
|
};
|
||||||
|
@ -9,7 +9,7 @@ template<typename E, typename M = std::mutex>
|
|||||||
class ThreadSafe
|
class ThreadSafe
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
template <typename ...Args> ThreadSafe(Args ...args) : contents(args...) {}
|
template <typename... Args> ThreadSafe(Args&&... args) : contents(std::forward<Args>(args)...) {}
|
||||||
auto operator->()
|
auto operator->()
|
||||||
{
|
{
|
||||||
struct
|
struct
|
||||||
@ -33,7 +33,7 @@ class AutoHandle
|
|||||||
public:
|
public:
|
||||||
AutoHandle(HANDLE h) : h(h) {}
|
AutoHandle(HANDLE h) : h(h) {}
|
||||||
operator HANDLE() { return h.get(); }
|
operator HANDLE() { return h.get(); }
|
||||||
operator PHANDLE() { return &h._Myptr(); }
|
PHANDLE operator&() { return &h._Myptr(); }
|
||||||
operator bool() { return h.get() != NULL && h.get() != INVALID_HANDLE_VALUE; }
|
operator bool() { return h.get() != NULL && h.get() != INVALID_HANDLE_VALUE; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Loading…
Reference in New Issue
Block a user