mirror of
https://github.com/HIllya51/LunaHook.git
synced 2024-12-27 05:34:14 +08:00
286 lines
7.7 KiB
C++
286 lines
7.7 KiB
C++
#include "MinHook.h"
|
||
|
||
DynamicShiftJISCodec *dynamiccodec = new DynamicShiftJISCodec(932);
|
||
|
||
void cast_back(const HookParam &hp, void *data, size_t *len, const std::wstring &trans, bool normal)
|
||
{
|
||
|
||
if ((hp.type & EMBED_CODEC_UTF16) || (hp.type & CODEC_UTF16))
|
||
{ // renpy
|
||
write_string_overwrite(data, len, trans);
|
||
}
|
||
else
|
||
{
|
||
std::string astr;
|
||
if (hp.type & EMBED_DYNA_SJIS && !normal)
|
||
{
|
||
astr = dynamiccodec->encodeSTD(trans, 0);
|
||
}
|
||
else
|
||
{
|
||
astr = WideStringToString(trans, hp.codepage ? hp.codepage : ((hp.type & CODEC_UTF8) ? CP_UTF8 : embedsharedmem->codepage));
|
||
}
|
||
write_string_overwrite(data, len, astr);
|
||
}
|
||
}
|
||
|
||
struct FunctionInfo
|
||
{
|
||
const char *name; // for debugging purpose
|
||
uintptr_t *oldFunction,
|
||
newFunction;
|
||
bool attached;
|
||
uintptr_t addr;
|
||
explicit FunctionInfo(const uintptr_t _addr = 0, const char *name = "", uintptr_t *oldFunction = nullptr, uintptr_t newFunction = 0,
|
||
bool attached = false)
|
||
: name(name), oldFunction(oldFunction), newFunction(newFunction), attached(attached), addr(_addr)
|
||
{
|
||
}
|
||
};
|
||
std::unordered_map<uintptr_t, FunctionInfo> funcs; // attached functions
|
||
std::vector<uintptr_t> replacedfuns; // attached functions
|
||
bool _1f()
|
||
{
|
||
#define ADD_FUN(_f) funcs[F_##_f] = FunctionInfo((uintptr_t)_f, #_f, (uintptr_t *)&Hijack::old##_f, (uintptr_t)Hijack::new##_f);
|
||
ADD_FUN(CreateFontA)
|
||
ADD_FUN(CreateFontW)
|
||
ADD_FUN(CreateFontIndirectA)
|
||
ADD_FUN(CreateFontIndirectW)
|
||
ADD_FUN(GetGlyphOutlineA)
|
||
ADD_FUN(GetGlyphOutlineW)
|
||
ADD_FUN(GetTextExtentPoint32A)
|
||
ADD_FUN(GetTextExtentPoint32W)
|
||
ADD_FUN(GetTextExtentExPointA)
|
||
ADD_FUN(GetTextExtentExPointW)
|
||
// ADD_FUN(GetCharABCWidthsA)
|
||
// ADD_FUN(GetCharABCWidthsW)
|
||
ADD_FUN(TextOutA)
|
||
ADD_FUN(TextOutW)
|
||
ADD_FUN(ExtTextOutA)
|
||
ADD_FUN(ExtTextOutW)
|
||
ADD_FUN(DrawTextA)
|
||
ADD_FUN(DrawTextW)
|
||
ADD_FUN(DrawTextExA)
|
||
ADD_FUN(DrawTextExW)
|
||
ADD_FUN(CharNextA)
|
||
// ADD_FUN(CharNextW)
|
||
// ADD_FUN(CharNextExA)
|
||
// ADD_FUN(CharNextExW)
|
||
ADD_FUN(CharPrevA)
|
||
// ADD_FUN(CharPrevW)
|
||
ADD_FUN(MultiByteToWideChar)
|
||
ADD_FUN(WideCharToMultiByte)
|
||
#undef ADD_FUN
|
||
return 0;
|
||
}
|
||
bool _1 = _1f();
|
||
bool ReplaceFunction(PVOID oldf, PVOID newf, PVOID *pOrigin)
|
||
{
|
||
PVOID oldx;
|
||
if (!pOrigin)
|
||
pOrigin = &oldx;
|
||
RemoveHook((uintptr_t)oldf);
|
||
if (MH_OK == MH_CreateHook(oldf, newf, pOrigin))
|
||
return MH_OK == MH_EnableHook(oldf);
|
||
else
|
||
{
|
||
MH_RemoveHook(oldf);
|
||
return false;
|
||
}
|
||
}
|
||
void attachFunction(uintptr_t _hook_font_flag)
|
||
{
|
||
for (auto &_func : funcs)
|
||
{
|
||
if (_func.first & _hook_font_flag)
|
||
{
|
||
if (_func.second.attached)
|
||
continue;
|
||
|
||
if (ReplaceFunction((PVOID)_func.second.addr, (PVOID)_func.second.newFunction, (PVOID *)_func.second.oldFunction))
|
||
{
|
||
_func.second.attached = true;
|
||
replacedfuns.push_back(_func.first);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
void detachall()
|
||
{
|
||
for (auto _flag : replacedfuns)
|
||
{
|
||
auto info = funcs.at(_flag);
|
||
if (MH_OK == MH_DisableHook((LPVOID)info.addr))
|
||
MH_RemoveHook((LPVOID)info.addr);
|
||
}
|
||
}
|
||
void solvefont(HookParam hp)
|
||
{
|
||
if (hp.hook_font)
|
||
{
|
||
attachFunction(hp.hook_font);
|
||
}
|
||
if (hp.hook_font & F_MultiByteToWideChar)
|
||
disable_mbwc = true;
|
||
if (hp.hook_font & F_WideCharToMultiByte)
|
||
disable_wcmb = true;
|
||
|
||
if (auto current_patch_fun = patch_fun.exchange(nullptr))
|
||
{
|
||
current_patch_fun();
|
||
dont_detach = true;
|
||
}
|
||
}
|
||
static std::wstring alwaysInsertSpacesSTD(const std::wstring &text)
|
||
{
|
||
std::wstring ret;
|
||
for (auto c : text)
|
||
{
|
||
ret.push_back(c);
|
||
if (c >= 32) // ignore non-printable characters
|
||
ret.push_back(L' '); // or insert \u3000 if needed
|
||
}
|
||
return ret;
|
||
}
|
||
bool charEncodableSTD(const wchar_t &ch, UINT codepage)
|
||
{
|
||
|
||
if (ch <= 127) // ignore ascii characters
|
||
return true;
|
||
std::wstring s;
|
||
s.push_back(ch);
|
||
return StringToWideString(WideStringToString(s, codepage), codepage).value() == s;
|
||
}
|
||
static std::wstring insertSpacesAfterUnencodableSTD(const std::wstring &text, HookParam hp)
|
||
{
|
||
|
||
std::wstring ret;
|
||
for (const wchar_t &c : text)
|
||
{
|
||
ret.push_back(c);
|
||
if (!charEncodableSTD(c, hp.codepage ? hp.codepage : embedsharedmem->codepage))
|
||
ret.push_back(L' ');
|
||
}
|
||
return ret;
|
||
}
|
||
std::wstring adjustSpacesSTD(const std::wstring &text, HookParam hp)
|
||
{
|
||
if (hp.type & EMBED_INSERT_SPACE_ALWAYS)
|
||
return alwaysInsertSpacesSTD(text);
|
||
else if (hp.type & EMBED_INSERT_SPACE_AFTER_UNENCODABLE)
|
||
return insertSpacesAfterUnencodableSTD(text, hp);
|
||
return text;
|
||
}
|
||
bool isPauseKeyPressed()
|
||
{
|
||
return WinKey::isKeyControlPressed() || WinKey::isKeyShiftPressed() && !WinKey::isKeyReturnPressed();
|
||
}
|
||
inline UINT64 djb2_n2(const unsigned char *str, size_t len, UINT64 hash = 5381)
|
||
{
|
||
int i = 0;
|
||
while (len--)
|
||
{
|
||
hash = ((hash << 5) + hash) + (*str++); // hash * 33 + c
|
||
}
|
||
return hash;
|
||
}
|
||
std::unordered_map<UINT64, std::wstring> translatecache;
|
||
bool check_is_thread_selected(const ThreadParam &tp)
|
||
{
|
||
for (int i = 0; i < 10; i++)
|
||
if (embedsharedmem->use[i])
|
||
if ((embedsharedmem->addr[i] == tp.addr) && (embedsharedmem->ctx1[i] == tp.ctx) && (embedsharedmem->ctx2[i] == tp.ctx2))
|
||
return true;
|
||
return false;
|
||
}
|
||
bool check_embed_able(const ThreadParam &tp)
|
||
{
|
||
return host_connected && check_is_thread_selected(tp) && ((isPauseKeyPressed() == false) ? true : !embedsharedmem->fastskipignore);
|
||
}
|
||
bool waitforevent(UINT32 timems, const ThreadParam &tp, const std::wstring &origin)
|
||
{
|
||
char eventname[1000];
|
||
sprintf(eventname, LUNA_EMBED_notify_event, GetCurrentProcessId(), djb2_n2((const unsigned char *)(origin.c_str()), origin.size() * 2));
|
||
auto event = win_event(eventname);
|
||
while (timems)
|
||
{
|
||
if (check_embed_able(tp) == false)
|
||
return false;
|
||
auto sleepstep = min(100, timems);
|
||
if (event.wait(sleepstep))
|
||
return true;
|
||
timems -= sleepstep;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
void TextHook::parsenewlineseperator(void *data, size_t *len)
|
||
{
|
||
if (!(hp.newlineseperator))
|
||
return;
|
||
|
||
if (hp.type & CODEC_UTF16)
|
||
{
|
||
StringCharReplacer((wchar_t *)data, len, hp.newlineseperator, wcslen(hp.newlineseperator), L'\n');
|
||
}
|
||
else if (hp.type & CODEC_UTF32)
|
||
return;
|
||
else
|
||
{
|
||
// ansi/utf8,newlineseperator都是简单字符
|
||
std::string newlineseperatorA;
|
||
for (int i = 0; i < wcslen(hp.newlineseperator); i++)
|
||
newlineseperatorA += (char)hp.newlineseperator[i];
|
||
StringCharReplacer((char *)data, len, newlineseperatorA.c_str(), newlineseperatorA.size(), '\n');
|
||
}
|
||
}
|
||
UINT64 texthash(void *data, size_t len)
|
||
{
|
||
UINT64 sum = 0;
|
||
auto u8data = (UINT8 *)data;
|
||
for (int i = 0; i < len; i++)
|
||
{
|
||
sum += u8data[i];
|
||
sum = sum << 1;
|
||
}
|
||
return sum;
|
||
}
|
||
bool checktranslatedok(void *data, size_t len)
|
||
{
|
||
ZeroMemory(embedsharedmem->text, sizeof(embedsharedmem->text)); // clear trans before call
|
||
if (len > 1000)
|
||
return true;
|
||
return (translatecache.find(texthash(data, len)) != translatecache.end());
|
||
}
|
||
bool TextHook::waitfornotify(TextOutput_T *buffer, void *data, size_t *len, ThreadParam tp)
|
||
{
|
||
std::wstring origin;
|
||
if (auto t = commonparsestring(data, *len, &hp, embedsharedmem->codepage))
|
||
origin = t.value();
|
||
else
|
||
return false;
|
||
|
||
std::wstring translate;
|
||
auto hash = texthash(data, *len);
|
||
if (translatecache.find(hash) != translatecache.end())
|
||
{
|
||
translate = translatecache.at(hash);
|
||
}
|
||
else
|
||
{
|
||
if (waitforevent(embedsharedmem->waittime, tp, origin) == false)
|
||
return false;
|
||
translate = embedsharedmem->text;
|
||
if ((translate.size() == 0))
|
||
return false;
|
||
translatecache.insert(std::make_pair(hash, translate));
|
||
}
|
||
if (hp.newlineseperator)
|
||
strReplace(translate, L"\n", hp.newlineseperator);
|
||
translate = adjustSpacesSTD(translate, hp);
|
||
if (embedsharedmem->keeprawtext)
|
||
translate = origin + L" " + translate;
|
||
solvefont(hp);
|
||
cast_back(hp, data, len, translate, false);
|
||
return true;
|
||
} |