mirror of
https://github.com/HIllya51/LunaHook.git
synced 2024-11-27 15:54:03 +08:00
312 lines
8.4 KiB
C++
312 lines
8.4 KiB
C++
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();
|
||
void ReplaceFunction(PVOID *oldf, PVOID newf)
|
||
{
|
||
|
||
RemoveHook((uintptr_t)*oldf);
|
||
DetourTransactionBegin();
|
||
DetourUpdateThread(GetCurrentThread());
|
||
DetourAttach((PVOID *)oldf, (PVOID)newf);
|
||
DetourTransactionCommit();
|
||
}
|
||
void attachFunction(uintptr_t _hook_font_flag)
|
||
{
|
||
for (auto &_func : funcs)
|
||
{
|
||
if (_func.first & _hook_font_flag)
|
||
{
|
||
if (_func.second.attached)
|
||
continue;
|
||
_func.second.attached = true;
|
||
*_func.second.oldFunction = _func.second.addr;
|
||
replacedfuns.push_back(_func.first);
|
||
ReplaceFunction((PVOID *)_func.second.oldFunction, (PVOID)_func.second.newFunction);
|
||
}
|
||
}
|
||
}
|
||
void detachall()
|
||
{
|
||
DetourTransactionBegin();
|
||
DetourUpdateThread(GetCurrentThread());
|
||
for (auto _flag : replacedfuns)
|
||
{
|
||
auto info = funcs.at(_flag);
|
||
DetourDetach((PVOID *)info.oldFunction, (PVOID)info.newFunction);
|
||
}
|
||
DetourTransactionCommit();
|
||
}
|
||
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)
|
||
{
|
||
|
||
switch (embedsharedmem->spaceadjustpolicy)
|
||
{
|
||
case 0:
|
||
return text;
|
||
case 1:
|
||
return alwaysInsertSpacesSTD(text);
|
||
case 2:
|
||
return insertSpacesAfterUnencodableSTD(text, hp);
|
||
default:
|
||
return text;
|
||
}
|
||
}
|
||
std::wstring limitTextWidth(const std::wstring &text, int size)
|
||
{
|
||
auto lines = strSplit(text, L"\n");
|
||
std::for_each(lines.begin(), lines.end(), [=](auto &line)
|
||
{
|
||
if(line.size()<=size)
|
||
return;
|
||
std::wstring ret;
|
||
for(int i=0;i<line.size();i++){
|
||
ret+=line[i];
|
||
if((i<line.size()-1) &&( ((1+i)%size)==0)){
|
||
ret+=L'\n';
|
||
}
|
||
}
|
||
line=ret; });
|
||
std::wstring ret;
|
||
for (int i = 0; i < lines.size(); i++)
|
||
{
|
||
ret += lines[i];
|
||
if (i < lines.size() - 1)
|
||
ret += L'\n';
|
||
}
|
||
return ret;
|
||
}
|
||
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)
|
||
{
|
||
StringReplacer((wchar_t *)data, len, hp.newlineseperator, wcslen(hp.newlineseperator), L"\n", 1);
|
||
}
|
||
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];
|
||
StringReplacer((char *)data, len, newlineseperatorA.c_str(), newlineseperatorA.size(), "\n", 1);
|
||
}
|
||
}
|
||
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 (embedsharedmem->line_text_length_limit)
|
||
translate = limitTextWidth(translate, embedsharedmem->line_text_length_limit);
|
||
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;
|
||
} |