2024-07-21 21:04:12 +08:00
|
|
|
|
DynamicShiftJISCodec *dynamiccodec = new DynamicShiftJISCodec(932);
|
2024-02-07 20:59:24 +08:00
|
|
|
|
|
2024-07-21 21:04:12 +08:00
|
|
|
|
void cast_back(const HookParam &hp, void *data, size_t *len, const std::wstring &trans, bool normal)
|
|
|
|
|
{
|
2024-02-07 20:59:24 +08:00
|
|
|
|
|
2024-07-21 21:04:12 +08:00
|
|
|
|
if ((hp.type & EMBED_CODEC_UTF16) || (hp.type & CODEC_UTF16))
|
|
|
|
|
{ // renpy
|
|
|
|
|
write_string_overwrite(data, len, trans);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2024-02-07 20:59:24 +08:00
|
|
|
|
std::string astr;
|
2024-07-21 21:04:12 +08:00
|
|
|
|
if (hp.type & EMBED_DYNA_SJIS && !normal)
|
|
|
|
|
{
|
|
|
|
|
astr = dynamiccodec->encodeSTD(trans, 0);
|
2024-02-07 20:59:24 +08:00
|
|
|
|
}
|
2024-07-21 21:04:12 +08:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
astr = WideStringToString(trans, hp.codepage ? hp.codepage : ((hp.type & CODEC_UTF8) ? CP_UTF8 : embedsharedmem->codepage));
|
2024-02-07 20:59:24 +08:00
|
|
|
|
}
|
2024-07-21 21:04:12 +08:00
|
|
|
|
write_string_overwrite(data, len, astr);
|
|
|
|
|
}
|
2024-02-07 20:59:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
2024-07-21 21:04:12 +08:00
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
};
|
2024-02-07 20:59:24 +08:00
|
|
|
|
std::unordered_map<uintptr_t, FunctionInfo> funcs; // attached functions
|
2024-07-21 21:04:12 +08:00
|
|
|
|
std::vector<uintptr_t> replacedfuns; // attached functions
|
2024-02-07 20:59:24 +08:00
|
|
|
|
bool _1f()
|
|
|
|
|
{
|
2024-07-21 21:04:12 +08:00
|
|
|
|
#define ADD_FUN(_f) funcs[F_##_f] = FunctionInfo((uintptr_t)_f, #_f, (uintptr_t *)&Hijack::old##_f, (uintptr_t)Hijack::new##_f);
|
2024-02-07 20:59:24 +08:00
|
|
|
|
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)
|
2024-07-21 21:04:12 +08:00
|
|
|
|
// ADD_FUN(GetCharABCWidthsA)
|
|
|
|
|
// ADD_FUN(GetCharABCWidthsW)
|
2024-02-07 20:59:24 +08:00
|
|
|
|
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)
|
2024-07-21 21:04:12 +08:00
|
|
|
|
// ADD_FUN(CharNextW)
|
|
|
|
|
// ADD_FUN(CharNextExA)
|
|
|
|
|
// ADD_FUN(CharNextExW)
|
2024-02-07 20:59:24 +08:00
|
|
|
|
ADD_FUN(CharPrevA)
|
2024-07-21 21:04:12 +08:00
|
|
|
|
// ADD_FUN(CharPrevW)
|
2024-02-07 20:59:24 +08:00
|
|
|
|
ADD_FUN(MultiByteToWideChar)
|
|
|
|
|
ADD_FUN(WideCharToMultiByte)
|
|
|
|
|
#undef ADD_FUN
|
2024-07-21 21:04:12 +08:00
|
|
|
|
return 0;
|
2024-02-07 20:59:24 +08:00
|
|
|
|
}
|
2024-07-21 21:04:12 +08:00
|
|
|
|
bool _1 = _1f();
|
|
|
|
|
void ReplaceFunction(PVOID *oldf, PVOID newf)
|
|
|
|
|
{
|
|
|
|
|
|
2024-02-07 20:59:24 +08:00
|
|
|
|
RemoveHook((uintptr_t)*oldf);
|
|
|
|
|
DetourTransactionBegin();
|
2024-07-21 21:04:12 +08:00
|
|
|
|
DetourUpdateThread(GetCurrentThread());
|
|
|
|
|
DetourAttach((PVOID *)oldf, (PVOID)newf);
|
2024-02-07 20:59:24 +08:00
|
|
|
|
DetourTransactionCommit();
|
|
|
|
|
}
|
|
|
|
|
void attachFunction(uintptr_t _hook_font_flag)
|
|
|
|
|
{
|
2024-07-21 21:04:12 +08:00
|
|
|
|
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;
|
2024-02-07 20:59:24 +08:00
|
|
|
|
replacedfuns.push_back(_func.first);
|
2024-07-21 21:04:12 +08:00
|
|
|
|
ReplaceFunction((PVOID *)_func.second.oldFunction, (PVOID)_func.second.newFunction);
|
2024-02-07 20:59:24 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-07-21 21:04:12 +08:00
|
|
|
|
void detachall()
|
|
|
|
|
{
|
2024-02-07 20:59:24 +08:00
|
|
|
|
DetourTransactionBegin();
|
|
|
|
|
DetourUpdateThread(GetCurrentThread());
|
2024-07-21 21:04:12 +08:00
|
|
|
|
for (auto _flag : replacedfuns)
|
|
|
|
|
{
|
|
|
|
|
auto info = funcs.at(_flag);
|
|
|
|
|
DetourDetach((PVOID *)info.oldFunction, (PVOID)info.newFunction);
|
|
|
|
|
}
|
|
|
|
|
DetourTransactionCommit();
|
2024-02-07 20:59:24 +08:00
|
|
|
|
}
|
2024-07-21 21:04:12 +08:00
|
|
|
|
void solvefont(HookParam hp)
|
|
|
|
|
{
|
|
|
|
|
if (hp.hook_font)
|
|
|
|
|
{
|
|
|
|
|
attachFunction(hp.hook_font);
|
2024-02-07 20:59:24 +08:00
|
|
|
|
}
|
2024-07-21 21:04:12 +08:00
|
|
|
|
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))
|
|
|
|
|
{
|
2024-02-07 20:59:24 +08:00
|
|
|
|
current_patch_fun();
|
2024-07-21 21:04:12 +08:00
|
|
|
|
dont_detach = true;
|
2024-02-07 20:59:24 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2024-07-21 21:04:12 +08:00
|
|
|
|
static std::wstring alwaysInsertSpacesSTD(const std::wstring &text)
|
|
|
|
|
{
|
|
|
|
|
std::wstring ret;
|
|
|
|
|
for (auto c : text)
|
2024-02-07 20:59:24 +08:00
|
|
|
|
{
|
2024-07-21 21:04:12 +08:00
|
|
|
|
ret.push_back(c);
|
|
|
|
|
if (c >= 32) // ignore non-printable characters
|
|
|
|
|
ret.push_back(L' '); // or insert \u3000 if needed
|
2024-02-07 20:59:24 +08:00
|
|
|
|
}
|
2024-07-21 21:04:12 +08:00
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
bool charEncodableSTD(const wchar_t &ch, UINT codepage)
|
2024-02-07 20:59:24 +08:00
|
|
|
|
{
|
2024-07-21 21:04:12 +08:00
|
|
|
|
|
|
|
|
|
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)
|
2024-02-07 20:59:24 +08:00
|
|
|
|
{
|
2024-07-21 21:04:12 +08:00
|
|
|
|
ret.push_back(c);
|
|
|
|
|
if (!charEncodableSTD(c, hp.codepage ? hp.codepage : embedsharedmem->codepage))
|
|
|
|
|
ret.push_back(L' ');
|
2024-02-07 20:59:24 +08:00
|
|
|
|
}
|
2024-07-21 21:04:12 +08:00
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
std::wstring adjustSpacesSTD(const std::wstring &text, HookParam hp)
|
2024-02-07 20:59:24 +08:00
|
|
|
|
{
|
2024-07-21 21:04:12 +08:00
|
|
|
|
|
2024-02-07 20:59:24 +08:00
|
|
|
|
switch (embedsharedmem->spaceadjustpolicy)
|
|
|
|
|
{
|
2024-07-21 21:04:12 +08:00
|
|
|
|
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)
|
2024-07-01 18:15:00 +08:00
|
|
|
|
{
|
2024-07-21 21:04:12 +08:00
|
|
|
|
auto lines = strSplit(text, L"\n");
|
|
|
|
|
std::for_each(lines.begin(), lines.end(), [=](auto &line)
|
|
|
|
|
{
|
2024-07-01 18:15:00 +08:00
|
|
|
|
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';
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-07-21 21:04:12 +08:00
|
|
|
|
line=ret; });
|
2024-07-01 18:15:00 +08:00
|
|
|
|
std::wstring ret;
|
2024-07-21 21:04:12 +08:00
|
|
|
|
for (int i = 0; i < lines.size(); i++)
|
|
|
|
|
{
|
|
|
|
|
ret += lines[i];
|
|
|
|
|
if (i < lines.size() - 1)
|
|
|
|
|
ret += L'\n';
|
2024-07-01 18:15:00 +08:00
|
|
|
|
}
|
|
|
|
|
return ret;
|
2024-07-21 21:04:12 +08:00
|
|
|
|
}
|
2024-02-07 20:59:24 +08:00
|
|
|
|
bool isPauseKeyPressed()
|
|
|
|
|
{
|
2024-07-21 21:04:12 +08:00
|
|
|
|
return WinKey::isKeyControlPressed() || WinKey::isKeyShiftPressed() && !WinKey::isKeyReturnPressed();
|
2024-02-07 20:59:24 +08:00
|
|
|
|
}
|
2024-07-21 21:04:12 +08:00
|
|
|
|
inline UINT64 djb2_n2(const unsigned char *str, size_t len, UINT64 hash = 5381)
|
2024-02-07 20:59:24 +08:00
|
|
|
|
{
|
2024-07-21 21:04:12 +08:00
|
|
|
|
int i = 0;
|
|
|
|
|
while (len--)
|
|
|
|
|
{
|
|
|
|
|
hash = ((hash << 5) + hash) + (*str++); // hash * 33 + c
|
|
|
|
|
}
|
|
|
|
|
return hash;
|
2024-02-07 20:59:24 +08:00
|
|
|
|
}
|
2024-07-21 21:04:12 +08:00
|
|
|
|
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))
|
2024-02-07 20:59:24 +08:00
|
|
|
|
return true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2024-07-21 21:04:12 +08:00
|
|
|
|
bool check_embed_able(const ThreadParam &tp)
|
|
|
|
|
{
|
|
|
|
|
return host_connected && check_is_thread_selected(tp) && ((isPauseKeyPressed() == false) ? true : !embedsharedmem->fastskipignore);
|
2024-02-07 20:59:24 +08:00
|
|
|
|
}
|
2024-07-21 21:04:12 +08:00
|
|
|
|
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;
|
2024-02-07 20:59:24 +08:00
|
|
|
|
}
|
2024-02-28 23:33:52 +08:00
|
|
|
|
|
2024-07-21 21:04:12 +08:00
|
|
|
|
void TextHook::parsenewlineseperator(void *data, size_t *len)
|
2024-02-28 23:33:52 +08:00
|
|
|
|
{
|
2024-07-21 21:04:12 +08:00
|
|
|
|
if (!(hp.newlineseperator))
|
|
|
|
|
return;
|
2024-02-28 23:33:52 +08:00
|
|
|
|
|
|
|
|
|
if (hp.type & CODEC_UTF16)
|
|
|
|
|
{
|
2024-07-21 21:04:12 +08:00
|
|
|
|
StringReplacer((wchar_t *)data, len, hp.newlineseperator, wcslen(hp.newlineseperator), L"\n", 1);
|
2024-02-28 23:33:52 +08:00
|
|
|
|
}
|
2024-07-21 21:04:12 +08:00
|
|
|
|
else if (hp.type & CODEC_UTF32)
|
|
|
|
|
return;
|
2024-02-28 23:33:52 +08:00
|
|
|
|
else
|
|
|
|
|
{
|
2024-07-21 21:04:12 +08:00
|
|
|
|
// ansi/utf8,newlineseperator都是简单字符
|
2024-02-28 23:33:52 +08:00
|
|
|
|
std::string newlineseperatorA;
|
2024-07-21 21:04:12 +08:00
|
|
|
|
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);
|
2024-02-28 23:33:52 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2024-07-21 21:04:12 +08:00
|
|
|
|
UINT64 texthash(void *data, size_t len)
|
2024-03-08 22:22:26 +08:00
|
|
|
|
{
|
2024-07-21 21:04:12 +08:00
|
|
|
|
UINT64 sum = 0;
|
|
|
|
|
auto u8data = (UINT8 *)data;
|
|
|
|
|
for (int i = 0; i < len; i++)
|
|
|
|
|
{
|
|
|
|
|
sum += u8data[i];
|
|
|
|
|
sum = sum << 1;
|
2024-03-08 22:22:26 +08:00
|
|
|
|
}
|
|
|
|
|
return sum;
|
|
|
|
|
}
|
2024-07-21 21:04:12 +08:00
|
|
|
|
bool checktranslatedok(void *data, size_t len)
|
2024-03-08 22:22:26 +08:00
|
|
|
|
{
|
2024-07-21 21:04:12 +08:00
|
|
|
|
ZeroMemory(embedsharedmem->text, sizeof(embedsharedmem->text)); // clear trans before call
|
|
|
|
|
if (len > 1000)
|
|
|
|
|
return true;
|
|
|
|
|
return (translatecache.find(texthash(data, len)) != translatecache.end());
|
2024-03-08 22:22:26 +08:00
|
|
|
|
}
|
2024-07-21 21:04:12 +08:00
|
|
|
|
bool TextHook::waitfornotify(TextOutput_T *buffer, void *data, size_t *len, ThreadParam tp)
|
|
|
|
|
{
|
2024-02-08 21:48:24 +08:00
|
|
|
|
std::wstring origin;
|
2024-07-21 21:04:12 +08:00
|
|
|
|
if (auto t = commonparsestring(data, *len, &hp, embedsharedmem->codepage))
|
|
|
|
|
origin = t.value();
|
|
|
|
|
else
|
|
|
|
|
return false;
|
2024-02-07 20:59:24 +08:00
|
|
|
|
|
|
|
|
|
std::wstring translate;
|
2024-07-21 21:04:12 +08:00
|
|
|
|
auto hash = texthash(data, *len);
|
|
|
|
|
if (translatecache.find(hash) != translatecache.end())
|
|
|
|
|
{
|
|
|
|
|
translate = translatecache.at(hash);
|
2024-02-07 20:59:24 +08:00
|
|
|
|
}
|
2024-07-21 21:04:12 +08:00
|
|
|
|
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));
|
2024-02-07 20:59:24 +08:00
|
|
|
|
}
|
2024-07-21 21:04:12 +08:00
|
|
|
|
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;
|
2024-02-07 20:59:24 +08:00
|
|
|
|
solvefont(hp);
|
2024-07-21 21:04:12 +08:00
|
|
|
|
cast_back(hp, data, len, translate, false);
|
|
|
|
|
return true;
|
2024-02-07 20:59:24 +08:00
|
|
|
|
}
|