This commit is contained in:
恍兮惚兮 2024-06-30 20:08:02 +08:00
parent 0c40cdc6dd
commit 38be8e7ff6
39 changed files with 599 additions and 414 deletions

View File

@ -7,7 +7,7 @@ from myutils.config import (
_TR, _TR,
savehook_new_list, savehook_new_list,
uid2gamepath, uid2gamepath,
gamepath2uid, findgameuidofpath,
savehook_new_data, savehook_new_data,
setlanguage, setlanguage,
static_data, static_data,
@ -20,7 +20,6 @@ from myutils.utils import (
kanjitrans, kanjitrans,
checkifnewgame, checkifnewgame,
checkpostusing, checkpostusing,
getpostfile,
stringfyerror, stringfyerror,
) )
from myutils.wrapper import threader from myutils.wrapper import threader
@ -43,7 +42,7 @@ from gui.attachprocessdialog import AttachProcessDialog
import windows import windows
import gobject import gobject
import winsharedutils import winsharedutils
from winsharedutils import pid_running from winsharedutils import collect_running_pids
from myutils.post import POSTSOLVE from myutils.post import POSTSOLVE
from myutils.utils import nowisdark from myutils.utils import nowisdark
@ -105,9 +104,11 @@ class MAINUI:
for item in static_data["transoptimi"]: for item in static_data["transoptimi"]:
name = item["name"] name = item["name"]
try: try:
mm = getpostfile(name) checkpath = "./LunaTranslator/transoptimi/" + name + ".py"
if not mm: if os.path.exists(checkpath) == False:
continue continue
mm = "transoptimi." + name
Process = importlib.import_module(mm).Process Process = importlib.import_module(mm).Process
def __(kls, _name): def __(kls, _name):
@ -475,12 +476,17 @@ class MAINUI:
use, self.settin_ui.voicelistsignal, self.settin_ui.mp3playsignal use, self.settin_ui.voicelistsignal, self.settin_ui.mp3playsignal
) )
def selectprocess(self, selectedp): def selectprocess(self, selectedp, title):
self.textsource = None self.textsource = None
pids, pexe, hwnd = selectedp pids, pexe, hwnd = selectedp
checkifnewgame(savehook_new_list, pexe, windows.GetWindowText(hwnd)) if len(collect_running_pids(pids)) == 0:
return
if not title:
title = windows.GetWindowText(hwnd)
checkifnewgame(savehook_new_list, pexe, title)
if globalconfig["sourcestatus2"]["texthook"]["use"]: if globalconfig["sourcestatus2"]["texthook"]["use"]:
self.textsource = texthook(pids, hwnd, pexe, gamepath2uid[pexe]) gameuid = findgameuidofpath(pexe, savehook_new_list)
self.textsource = texthook(pids, hwnd, pexe, gameuid)
self.textsource.start() self.textsource.start()
def starttextsource(self, use=None, checked=True): def starttextsource(self, use=None, checked=True):
@ -563,16 +569,9 @@ class MAINUI:
def fanyiinitmethod(self, classname): def fanyiinitmethod(self, classname):
try: try:
if classname == "selfbuild": if not os.path.exists("./LunaTranslator/translator/" + classname + ".py"):
if not os.path.exists("./userconfig/selfbuild.py"): return None
return None aclass = importlib.import_module("translator." + classname).TS
aclass = importlib.import_module("selfbuild").TS
else:
if not os.path.exists(
"./LunaTranslator/translator/" + classname + ".py"
):
return None
aclass = importlib.import_module("translator." + classname).TS
except Exception as e: except Exception as e:
print_exc() print_exc()
self.textgetmethod( self.textgetmethod(
@ -676,109 +675,101 @@ class MAINUI:
except: except:
print_exc() print_exc()
def onwindowloadautohook(self):
textsourceusing = globalconfig["sourcestatus2"]["texthook"]["use"]
if not (globalconfig["autostarthook"] and textsourceusing):
return
elif self.AttachProcessDialog and self.AttachProcessDialog.isVisible():
return
else:
try:
if self.textsource is None:
hwnd = windows.GetForegroundWindow()
pid = windows.GetWindowThreadProcessId(hwnd)
name_ = getpidexe(pid)
if (
name_
and name_ in gamepath2uid
and gamepath2uid[name_] in savehook_new_list
):
lps = ListProcess(False)
for pids, _exe in lps:
if _exe == name_:
# if any(map(testprivilege,pids)):
self.textsource = None
if globalconfig["sourcestatus2"]["texthook"]["use"]:
if globalconfig["startgamenototop"] == False:
idx = savehook_new_list.index(
gamepath2uid[name_]
)
savehook_new_list.insert(
0, savehook_new_list.pop(idx)
)
needinserthookcode = savehook_new_data[
gamepath2uid[name_]
]["needinserthookcode"]
self.textsource = texthook(
pids,
hwnd,
name_,
gamepath2uid[name_],
autostarthookcode=savehook_new_data[
gamepath2uid[name_]
]["hook"],
needinserthookcode=needinserthookcode,
)
self.textsource.start()
else:
pids = self.textsource.pids
if sum([int(pid_running(pid)) for pid in pids]) == 0:
self.textsource = None
self.translation_ui.thistimenotsetop = False
if globalconfig["keepontop"]:
self.translation_ui.settop()
except:
print_exc()
def autohookmonitorthread(self): def autohookmonitorthread(self):
def onwindowloadautohook():
textsourceusing = globalconfig["sourcestatus2"]["texthook"]["use"]
if not (globalconfig["autostarthook"] and textsourceusing):
return
elif self.AttachProcessDialog and self.AttachProcessDialog.isVisible():
return
if self.textsource is None:
hwnd = windows.GetForegroundWindow()
pid = windows.GetWindowThreadProcessId(hwnd)
name_ = getpidexe(pid)
if not name_:
return
uid = findgameuidofpath(name_, savehook_new_list)
if not uid:
return
lps = ListProcess(False)
for pids, _exe in lps:
if _exe != name_:
continue
if self.textsource is not None:
return
if not globalconfig["sourcestatus2"]["texthook"]["use"]:
return
if globalconfig["startgamenototop"] == False:
idx = savehook_new_list.index(uid)
savehook_new_list.insert(0, savehook_new_list.pop(idx))
needinserthookcode = savehook_new_data[uid]["needinserthookcode"]
self.textsource = texthook(
pids,
hwnd,
name_,
uid,
autostarthookcode=savehook_new_data[uid]["hook"],
needinserthookcode=needinserthookcode,
)
self.textsource.start()
else:
pids = self.textsource.pids
if len(collect_running_pids(pids)) != 0:
return
self.textsource = None
self.translation_ui.thistimenotsetop = False
if globalconfig["keepontop"]:
self.translation_ui.settop()
while self.isrunning: while self.isrunning:
self.onwindowloadautohook() try:
time.sleep( onwindowloadautohook()
0.5 except:
) # 太短了的话,中间存在一瞬间,后台进程比前台窗口内存占用要大。。。 print_exc()
time.sleep(0.5)
# 太短了的话,中间存在一瞬间,后台进程比前台窗口内存占用要大。。。
def autocheckhwndexists(self): def autocheckhwndexists(self):
def setandrefresh(bool): def setandrefresh(b):
if self.translation_ui.isbindedwindow != bool: if self.translation_ui.isbindedwindow != b:
self.translation_ui.isbindedwindow = bool self.translation_ui.isbindedwindow = b
self.translation_ui.refreshtooliconsignal.emit() self.translation_ui.refreshtooliconsignal.emit()
while self.isrunning: def __do():
if self.textsource: if not self.textsource:
hwnd = self.textsource.hwnd
if hwnd == 0:
if globalconfig["sourcestatus2"]["texthook"]["use"]:
fhwnd = windows.GetForegroundWindow()
pids = self.textsource.pids
if (
hwnd == 0
and windows.GetWindowThreadProcessId(fhwnd) in pids
):
if "once" not in dir(self.textsource):
self.textsource.once = True
self.textsource.hwnd = fhwnd
setandrefresh(True)
else:
setandrefresh(False)
else:
if windows.GetWindowThreadProcessId(hwnd) == 0:
self.textsource.hwnd = 0
setandrefresh(False)
elif "once" not in dir(self.textsource):
self.textsource.once = True
setandrefresh(True)
if len(self.textsource.pids):
_mute = winsharedutils.GetProcessMute(self.textsource.pids[0])
if self.translation_ui.processismuteed != _mute:
self.translation_ui.processismuteed = _mute
self.translation_ui.refreshtooliconsignal.emit()
else:
setandrefresh(False) setandrefresh(False)
return
hwnd = self.textsource.hwnd
if hwnd == 0:
if not globalconfig["sourcestatus2"]["texthook"]["use"]:
setandrefresh(False)
else:
fhwnd = windows.GetForegroundWindow()
pids = self.textsource.pids
notdone = "once" not in dir(self.textsource)
isgoodproc = windows.GetWindowThreadProcessId(fhwnd) in pids
if isgoodproc and notdone:
self.textsource.once = True
self.textsource.hwnd = fhwnd
setandrefresh(True)
else:
if windows.GetWindowThreadProcessId(hwnd) == 0:
self.textsource.hwnd = 0
setandrefresh(False)
elif "once" not in dir(self.textsource):
self.textsource.once = True
setandrefresh(True)
if len(self.textsource.pids):
_mute = winsharedutils.GetProcessMute(self.textsource.pids[0])
if self.translation_ui.processismuteed != _mute:
self.translation_ui.processismuteed = _mute
self.translation_ui.refreshtooliconsignal.emit()
while self.isrunning:
__do()
time.sleep(0.5) time.sleep(0.5)
@ -925,29 +916,28 @@ class MAINUI:
True, True,
) )
_hwnd = windows.GetForegroundWindow()
_pid = windows.GetWindowThreadProcessId(_hwnd)
try: try:
_hwnd = windows.GetForegroundWindow() if len(self.textsource.pids) == 0:
_pid = windows.GetWindowThreadProcessId(_hwnd) raise Exception()
if _pid in self.textsource.pids or _pid == os.getpid():
isok(self.textsource.gameuid)
else:
self.__currentexe = None
except:
name_ = getpidexe(_pid)
if not name_:
return
uids = findgameuidofpath(name_, findall=True)
try: try:
if len(self.textsource.pids) == 0: if len(uids):
raise Exception() for uid in uids:
if _pid in self.textsource.pids or _pid == os.getpid(): isok(uid)
isok(self.textsource.gameuid)
else: else:
self.__currentexe = None self.__currentexe = None
except: except:
name_ = getpidexe(_pid) print_exc()
if (
name_
and name_ in gamepath2uid
and gamepath2uid[name_] in savehook_new_list
):
isok(gamepath2uid[name_])
else:
self.__currentexe = None
except:
print_exc()
@threader @threader
def clickwordcallback(self, word, append): def clickwordcallback(self, word, append):

View File

@ -34,8 +34,13 @@ def gettranslationrecorddir(name):
return getcachedir(name, "translation_record") return getcachedir(name, "translation_record")
def gettempdir_1():
tgt = getcachedir("temp")
return tgt
def gettempdir(filename): def gettempdir(filename):
tgt = getcachedir(os.path.join(f"temp{os.getpid()}", filename)) tgt = getcachedir(os.path.join(f"temp/{os.getpid()}", filename))
return tgt return tgt

View File

@ -32,8 +32,10 @@ class AttachProcessDialog(saveposwindow):
_pids = [pid] _pids = [pid]
self.processEdit.setText(name) self.processEdit.setText(name)
self.processIdEdit.setText(",".join([str(pid) for pid in _pids])) self.processIdEdit.setText(",".join([str(pid) for pid in _pids]))
[_.show() for _ in self.windowtextlayoutwidgets]
self.windowtext.setText(windows.GetWindowText(hwnd)) self.windowtext.setText(windows.GetWindowText(hwnd))
self.processEdit.setCursorPosition(0)
self.processIdEdit.setCursorPosition(0)
self.windowtext.setCursorPosition(0)
self.selectedp = (_pids, name, hwnd) self.selectedp = (_pids, name, hwnd)
def closeEvent(self, e): def closeEvent(self, e):
@ -80,10 +82,8 @@ class AttachProcessDialog(saveposwindow):
self.layout3.addWidget(self.processEdit) self.layout3.addWidget(self.processEdit)
self.windowtext = QLineEdit() self.windowtext = QLineEdit()
self.windowtextlayoutwidgets = [QLabel(_TR("窗口名")), self.windowtext] self.layout2.addWidget(QLabel(_TR("标题")))
[_.hide() for _ in self.windowtextlayoutwidgets] self.layout2.addWidget(self.windowtext)
self.layout2.addWidget(self.windowtextlayoutwidgets[0])
self.layout2.addWidget(self.windowtextlayoutwidgets[1])
self.processList = QListView() self.processList = QListView()
self.buttonBox = QDialogButtonBox() self.buttonBox = QDialogButtonBox()
self.buttonBox.setStandardButtons( self.buttonBox.setStandardButtons(
@ -109,15 +109,25 @@ class AttachProcessDialog(saveposwindow):
self.processList.clicked.connect(self.selectedfunc) self.processList.clicked.connect(self.selectedfunc)
self.processIdEdit.textEdited.connect(self.editpid) self.processIdEdit.textEdited.connect(self.editpid)
self.processEdit.setReadOnly(True) # self.processEdit.setReadOnly(True)
self.windowtext.setReadOnly(True) self.processEdit.textEdited.connect(self.filterproc)
def filterproc(self):
self.processIdEdit.clear()
self.windowtext.clear()
text = self.processEdit.text()
if len(text) == 0:
self.refreshfunction()
return
for row in range(self.model.rowCount()):
hide = not (text in self.model.item(row, 0).text())
self.processList.setRowHidden(row, hide)
def refreshfunction(self): def refreshfunction(self):
self.windowtext.clear() self.windowtext.clear()
self.processEdit.clear() self.processEdit.clear()
self.processIdEdit.clear() self.processIdEdit.clear()
[_.hide() for _ in self.windowtextlayoutwidgets]
self.selectedp = None self.selectedp = None
########################### ###########################
@ -151,15 +161,21 @@ class AttachProcessDialog(saveposwindow):
def editpid(self, process): def editpid(self, process):
pids = self.safesplit(process) pids = self.safesplit(process)
self.selectedp = (pids, getpidexe(pids[0]), self.guesshwnd(pids)) self.selectedp = (pids, getpidexe(pids[0]), self.guesshwnd(pids))
self.windowtext.setText(windows.GetWindowText(self.selectedp[-1]))
self.processEdit.setText(self.selectedp[1]) self.processEdit.setText(self.selectedp[1])
[_.hide() for _ in self.windowtextlayoutwidgets] self.windowtext.setCursorPosition(0)
self.processEdit.setCursorPosition(0)
def selectedfunc(self, index): def selectedfunc(self, index):
pids, pexe = self.processlist[index.row()] pids, pexe = self.processlist[index.row()]
self.processEdit.setText(pexe) self.processEdit.setText(pexe)
self.processIdEdit.setText(",".join([str(pid) for pid in pids])) self.processIdEdit.setText(",".join([str(pid) for pid in pids]))
[_.hide() for _ in self.windowtextlayoutwidgets]
self.selectedp = pids, pexe, self.guesshwnd(pids) self.selectedp = pids, pexe, self.guesshwnd(pids)
self.windowtext.setText(windows.GetWindowText(self.selectedp[-1]))
self.processEdit.setCursorPosition(0)
self.processIdEdit.setCursorPosition(0)
self.windowtext.setCursorPosition(0)
def guesshwnd(self, pids): def guesshwnd(self, pids):
for pid in pids: for pid in pids:
@ -175,10 +191,5 @@ class AttachProcessDialog(saveposwindow):
if self.selectedp[1] is None: if self.selectedp[1] is None:
getQMessageBox(self, "错误", "权限不足,请以管理员权限运行!") getQMessageBox(self, "错误", "权限不足,请以管理员权限运行!")
return return
# for pid in self.selectedp[0]:
# if(not testprivilege(pid)):
# getQMessageBox(self,"错误","权限不足,请使用管理员权限运行本程序!")
# return
self.close() self.close()
self.callback(self.selectedp) self.callback(self.selectedp, self.windowtext.text())

View File

@ -6,7 +6,6 @@ import windows, gobject, winsharedutils
from myutils.config import ( from myutils.config import (
savehook_new_list, savehook_new_list,
savehook_new_data, savehook_new_data,
gamepath2uid,
savegametaged, savegametaged,
uid2gamepath, uid2gamepath,
_TR, _TR,
@ -614,15 +613,14 @@ def maybehavebutton(self, gameuid, post):
class dialog_setting_game_internal(QWidget): class dialog_setting_game_internal(QWidget):
def selectexe(self): def selectexe(self):
f = QFileDialog.getOpenFileName(directory=uid2gamepath[self.gameuid]) originpath = uid2gamepath[self.gameuid]
f = QFileDialog.getOpenFileName(directory=originpath)
res = f[0] res = f[0]
if res == "": if res == "":
return return
# 修改路径允许路径重复
# 添加路径实际上也允许重复,只不过会去重。
res = os.path.normpath(res) res = os.path.normpath(res)
if res in gamepath2uid:
return
originpath = uid2gamepath[self.gameuid]
gamepath2uid[res] = gamepath2uid.pop(originpath)
uid2gamepath[self.gameuid] = res uid2gamepath[self.gameuid] = res
gobject.baseobject.resetgameinternal(originpath, res) gobject.baseobject.resetgameinternal(originpath, res)
_icon = getExeIcon(res, cache=True) _icon = getExeIcon(res, cache=True)
@ -715,13 +713,16 @@ class dialog_setting_game_internal(QWidget):
internallist=list(globalconfig["metadata"].keys()), internallist=list(globalconfig["metadata"].keys()),
), ),
) )
formLayout.addRow(None, QLabel())
for key in globalconfig["metadata"]: for key in globalconfig["metadata"]:
try: try:
idname = globalconfig["metadata"][key]["target"] idname = globalconfig["metadata"][key]["target"]
vndbid = QLineEdit(str(savehook_new_data[gameuid][idname])) vndbid = QLineEdit(str(savehook_new_data[gameuid][idname]))
if globalconfig["metadata"][key].get("idtype", 1) == 0: if globalconfig["metadata"][key].get("idtype", 1) == 0:
vndbid.setValidator(QIntValidator()) vndbid.setValidator(QIntValidator())
vndbid.setSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Fixed) vndbid.setSizePolicy(
QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Fixed
)
vndbid.textEdited.connect( vndbid.textEdited.connect(
functools.partial(idtypecheck, key, idname, gameuid) functools.partial(idtypecheck, key, idname, gameuid)
@ -730,6 +731,7 @@ class dialog_setting_game_internal(QWidget):
functools.partial(gamdidchangedtask, key, idname, gameuid) functools.partial(gamdidchangedtask, key, idname, gameuid)
) )
_vbox_internal = [ _vbox_internal = [
getsimpleswitch(globalconfig["metadata"][key], "auto"),
vndbid, vndbid,
getIconButton( getIconButton(
functools.partial(self.openrefmainpage, key, idname, gameuid), functools.partial(self.openrefmainpage, key, idname, gameuid),
@ -746,7 +748,7 @@ class dialog_setting_game_internal(QWidget):
try: try:
__settting = targetmod[key].querysettingwindow __settting = targetmod[key].querysettingwindow
_vbox_internal.insert( _vbox_internal.insert(
1, 2,
getIconButton( getIconButton(
functools.partial(__settting, self, gameuid), icon="fa.gear" functools.partial(__settting, self, gameuid), icon="fa.gear"
), ),
@ -1974,7 +1976,7 @@ class dialog_savedgame_new(QWidget):
menu = QMenu(self) menu = QMenu(self)
editname = QAction(_TR("修改列表名称")) editname = QAction(_TR("修改列表名称"))
addlist = QAction(_TR("添加列表")) addlist = QAction(_TR("创建列表"))
dellist = QAction(_TR("删除列表")) dellist = QAction(_TR("删除列表"))
startgame = QAction(_TR("开始游戏")) startgame = QAction(_TR("开始游戏"))
@ -2028,7 +2030,7 @@ class dialog_savedgame_new(QWidget):
elif action == editname or action == addlist: elif action == editname or action == addlist:
_dia = Prompt_dialog( _dia = Prompt_dialog(
self, self,
_TR("修改列表名称" if action == editname else "添加列表"), _TR("修改列表名称" if action == editname else "创建列表"),
"", "",
[ [
[ [
@ -2160,7 +2162,7 @@ class dialog_savedgame_new(QWidget):
self.simplebutton("删除游戏", True, self.clicked2, False) self.simplebutton("删除游戏", True, self.clicked2, False)
self.simplebutton("打开目录", True, self.clicked4, True) self.simplebutton("打开目录", True, self.clicked4, True)
self.simplebutton("添加到列表", False, self.addtolist, 1) self.simplebutton("添加到列表", True, self.addtolist, False)
if globalconfig["startgamenototop"]: if globalconfig["startgamenototop"]:
self.simplebutton("左移", True, functools.partial(self.moverank, -1), False) self.simplebutton("左移", True, functools.partial(self.moverank, -1), False)
self.simplebutton("右移", True, functools.partial(self.moverank, 1), False) self.simplebutton("右移", True, functools.partial(self.moverank, 1), False)
@ -2770,9 +2772,9 @@ class dialog_savedgame_v3(QWidget):
self.stack.directshow() self.stack.directshow()
def stack_showmenu(self, ispixmenu, p): def stack_showmenu(self, ispixmenu, p):
if not self.currentfocusuid:
return
menu = QMenu(self) menu = QMenu(self)
addlist = QAction(_TR("创建列表"))
startgame = QAction(_TR("开始游戏")) startgame = QAction(_TR("开始游戏"))
delgame = QAction(_TR("删除游戏")) delgame = QAction(_TR("删除游戏"))
opendir = QAction(_TR("打开目录")) opendir = QAction(_TR("打开目录"))
@ -2780,24 +2782,57 @@ class dialog_savedgame_v3(QWidget):
setimage = QAction(_TR("设为封面")) setimage = QAction(_TR("设为封面"))
deleteimage = QAction(_TR("删除图片")) deleteimage = QAction(_TR("删除图片"))
hualang = QAction(_TR("画廊")) hualang = QAction(_TR("画廊"))
exists = os.path.exists(uid2gamepath[self.currentfocusuid]) if not self.currentfocusuid:
if exists:
menu.addAction(startgame)
menu.addAction(delgame)
if exists:
menu.addAction(opendir)
menu.addSeparator() menu.addAction(addlist)
menu.addAction(addtolist) else:
exists = os.path.exists(uid2gamepath[self.currentfocusuid])
if exists:
menu.addAction(startgame)
menu.addAction(delgame)
if exists:
menu.addAction(opendir)
if ispixmenu:
menu.addSeparator() menu.addSeparator()
menu.addAction(setimage) menu.addAction(addtolist)
menu.addAction(deleteimage)
menu.addAction(hualang) if ispixmenu:
menu.addSeparator()
menu.addAction(setimage)
menu.addAction(deleteimage)
menu.addAction(hualang)
action = menu.exec(QCursor.pos()) action = menu.exec(QCursor.pos())
if action == startgame: if action == startgame:
startgamecheck(self, self.currentfocusuid) startgamecheck(self, self.currentfocusuid)
elif addlist == action:
_dia = Prompt_dialog(
self,
_TR("创建列表"),
"",
[
[
_TR("名称"),
(""),
],
],
)
if _dia.exec():
title = _dia.text[0].text()
if title != "":
i = calculatetagidx(None)
if action == addlist:
tag = {
"title": title,
"games": [],
"uid": str(uuid.uuid4()),
"opened": True,
}
savegametaged.insert(i, tag)
group0 = self.createtaglist(self.stack, title, tag["uid"], True)
self.stack.insertw(i, group0)
elif action == delgame: elif action == delgame:
self.shanchuyouxi() self.shanchuyouxi()
elif action == hualang: elif action == hualang:
@ -2885,7 +2920,7 @@ class dialog_savedgame_v3(QWidget):
) )
self.simplebutton("删除游戏", True, self.shanchuyouxi, False) self.simplebutton("删除游戏", True, self.shanchuyouxi, False)
self.simplebutton("打开目录", True, self.clicked4, True) self.simplebutton("打开目录", True, self.clicked4, True)
self.simplebutton("添加到列表", False, self.addtolist, 1) self.simplebutton("添加到列表", True, self.addtolist, False)
if globalconfig["startgamenototop"]: if globalconfig["startgamenototop"]:
self.simplebutton("上移", True, functools.partial(self.moverank, -1), False) self.simplebutton("上移", True, functools.partial(self.moverank, -1), False)
self.simplebutton("下移", True, functools.partial(self.moverank, 1), False) self.simplebutton("下移", True, functools.partial(self.moverank, 1), False)
@ -2945,7 +2980,7 @@ class dialog_savedgame_v3(QWidget):
self.reftagid = tagid self.reftagid = tagid
menu = QMenu(self) menu = QMenu(self)
editname = QAction(_TR("修改列表名称")) editname = QAction(_TR("修改列表名称"))
addlist = QAction(_TR("添加列表")) addlist = QAction(_TR("创建列表"))
dellist = QAction(_TR("删除列表")) dellist = QAction(_TR("删除列表"))
Upaction = QAction(_TR("上移")) Upaction = QAction(_TR("上移"))
Downaction = QAction(_TR("下移")) Downaction = QAction(_TR("下移"))
@ -2975,7 +3010,7 @@ class dialog_savedgame_v3(QWidget):
elif action == editname or action == addlist: elif action == editname or action == addlist:
_dia = Prompt_dialog( _dia = Prompt_dialog(
self, self,
_TR("修改列表名称" if action == editname else "添加列表"), _TR("修改列表名称" if action == editname else "创建列表"),
"", "",
[ [
[ [

View File

@ -22,7 +22,7 @@ def getall(l, item="fanyi", name=None):
continue continue
if name: if name:
_f = name % fanyi _f = name % fanyi
if fanyi != "selfbuild" and os.path.exists(_f) == False: if not os.path.exists(_f):
continue continue
i += 1 i += 1

View File

@ -34,14 +34,18 @@ from gui.usefulwidget import (
def __create(self): def __create(self):
self.selectbutton = getIconButton( self.selectbutton = getIconButton(
gobject.baseobject.createattachprocess, icon="fa.gear" gobject.baseobject.createattachprocess,
icon="fa.gear",
enable=globalconfig["sourcestatus2"]["texthook"]["use"],
) )
return self.selectbutton return self.selectbutton
def __create2(self): def __create2(self):
self.selecthookbutton = getIconButton( self.selecthookbutton = getIconButton(
lambda: gobject.baseobject.hookselectdialog.showsignal.emit(), icon="fa.gear" lambda: gobject.baseobject.hookselectdialog.showsignal.emit(),
icon="fa.gear",
enable=globalconfig["sourcestatus2"]["texthook"]["use"],
) )
return self.selecthookbutton return self.selecthookbutton

View File

@ -38,7 +38,7 @@ def initsome11(self, l, label=None):
continue continue
_f = "./Lunatranslator/translator/{}.py".format(fanyi) _f = "./Lunatranslator/translator/{}.py".format(fanyi)
if fanyi != "selfbuild" and os.path.exists(_f) == False: if not os.path.exists(_f):
continue continue
i += 1 i += 1
@ -128,12 +128,9 @@ def checkconnected(self):
for dev in develop: for dev in develop:
if not globalconfig["fanyi"][dev]["use"]: if not globalconfig["fanyi"][dev]["use"]:
continue continue
if dev == "selfbuild":
if not os.path.exists("./userconfig/selfbuild.py"): if not os.path.exists("./LunaTranslator/translator/" + dev + ".py"):
continue continue
else:
if not os.path.exists("./LunaTranslator/translator/" + dev + ".py"):
continue
needstart = True needstart = True
break break
try: try:
@ -218,7 +215,7 @@ def setTabTwo_lazy(self, basel):
"", "",
"模糊匹配_相似度_%", "模糊匹配_相似度_%",
D_getspinbox(0, 100, globalconfig, "premtsimi2"), D_getspinbox(0, 100, globalconfig, "premtsimi2"),
"" "",
], ],
[ [
(functools.partial(createbtnexport, self), 0), (functools.partial(createbtnexport, self), 0),
@ -229,7 +226,7 @@ def setTabTwo_lazy(self, basel):
"group", "group",
) )
], ],
[] [],
] ]
_items = [ _items = [
{ {

View File

@ -489,6 +489,11 @@ class AnkiWindow(QWidget):
cropbutton = QPushButton(qtawesome.icon("fa.crop"), "") cropbutton = QPushButton(qtawesome.icon("fa.crop"), "")
cropbutton.clicked.connect(self.crop) cropbutton.clicked.connect(self.crop)
grabwindowbtn = QPushButton(qtawesome.icon("fa.camera"), "")
grabwindowbtn.clicked.connect(
lambda: grabwindow(getimageformat(), self.editpath.setText)
)
self.audiopath = QLineEdit() self.audiopath = QLineEdit()
self.audiopath.setReadOnly(True) self.audiopath.setReadOnly(True)
self.audiopath_sentence = QLineEdit() self.audiopath_sentence = QLineEdit()
@ -566,6 +571,7 @@ class AnkiWindow(QWidget):
QLabel(_TR("截图")), QLabel(_TR("截图")),
self.editpath, self.editpath,
cropbutton, cropbutton,
grabwindowbtn,
getIconButton( getIconButton(
functools.partial( functools.partial(
self.selecfile, self.editpath self.selecfile, self.editpath

View File

@ -3,7 +3,14 @@ import time, functools, threading, os, sys, importlib, shutil
from traceback import print_exc from traceback import print_exc
import windows, qtawesome, gobject, winsharedutils import windows, qtawesome, gobject, winsharedutils
from myutils.wrapper import threader, trypass from myutils.wrapper import threader, trypass
from myutils.config import globalconfig, saveallconfig, _TR, static_data, gamepath2uid from myutils.config import (
globalconfig,
saveallconfig,
_TR,
static_data,
findgameuidofpath,
savehook_new_list,
)
from myutils.subproc import endsubprocs from myutils.subproc import endsubprocs
from myutils.ocrutil import ocr_run, imageCut from myutils.ocrutil import ocr_run, imageCut
from myutils.utils import loadpostsettingwindowmethod, str2rgba from myutils.utils import loadpostsettingwindowmethod, str2rgba
@ -12,13 +19,14 @@ from gui.setting_about import doupdate
from gui.dialog_memory import dialog_memory from gui.dialog_memory import dialog_memory
from gui.textbrowser import Textbrowser from gui.textbrowser import Textbrowser
from gui.rangeselect import rangeselct_function from gui.rangeselect import rangeselct_function
from gui.usefulwidget import resizableframeless, isinrect from gui.usefulwidget import resizableframeless, isinrect, getQMessageBox
from gui.edittext import edittrans from gui.edittext import edittrans
from gui.dialog_savedgame import browserdialog, dialog_savedgame_integrated from gui.dialog_savedgame import browserdialog, dialog_savedgame_integrated
class QUnFrameWindow(resizableframeless): class QUnFrameWindow(resizableframeless):
displayglobaltooltip = pyqtSignal(str) displayglobaltooltip = pyqtSignal(str)
displaymessagebox = pyqtSignal(str, str)
displayres = pyqtSignal(dict) displayres = pyqtSignal(dict)
displayraw1 = pyqtSignal(dict) displayraw1 = pyqtSignal(dict)
displaystatus = pyqtSignal(str, str, bool, bool) displaystatus = pyqtSignal(str, str, bool, bool)
@ -522,9 +530,13 @@ class QUnFrameWindow(resizableframeless):
def displayglobaltooltip_f(self, string): def displayglobaltooltip_f(self, string):
QToolTip.showText(QCursor.pos(), string, self) QToolTip.showText(QCursor.pos(), string, self)
def displaymessagebox_f(self, string1, string2):
getQMessageBox(self, string1, string2)
def initsignals(self): def initsignals(self):
self.hidesignal.connect(self.hide_) self.hidesignal.connect(self.hide_)
self.displayglobaltooltip.connect(self.displayglobaltooltip_f) self.displayglobaltooltip.connect(self.displayglobaltooltip_f)
self.displaymessagebox.connect(self.displaymessagebox_f)
self.ocr_once_signal.connect(self.ocr_once_function) self.ocr_once_signal.connect(self.ocr_once_function)
self.displaystatus.connect(self.showstatus) self.displaystatus.connect(self.showstatus)
self.showhideuisignal.connect(self.showhideui) self.showhideuisignal.connect(self.showhideui)
@ -797,7 +809,7 @@ class QUnFrameWindow(resizableframeless):
gobject.baseobject.textsource.hwnd = hwnd if pid != _pid else None gobject.baseobject.textsource.hwnd = hwnd if pid != _pid else None
if not globalconfig["sourcestatus2"]["texthook"]["use"]: if not globalconfig["sourcestatus2"]["texthook"]["use"]:
gobject.baseobject.textsource.pids = [pid] if pid != _pid else None gobject.baseobject.textsource.pids = [pid] if pid != _pid else None
gameuid = gamepath2uid.get(getpidexe(pid), None) gameuid = findgameuidofpath(getpidexe(pid), savehook_new_list)
if gameuid: if gameuid:
gobject.baseobject.textsource.gameuid = gameuid gobject.baseobject.textsource.gameuid = gameuid
self.isbindedwindow = pid != _pid self.isbindedwindow = pid != _pid
@ -1008,13 +1020,31 @@ class QUnFrameWindow(resizableframeless):
self.buttons[name] = button self.buttons[name] = button
def tryremoveuseless(self): def tryremoveuseless(self):
try:
allisremoved = True
tmpbase = gobject.gettempdir_1()
for f in os.listdir(tmpbase):
try:
pid = int(f)
except:
continue
if (pid != os.getpid()) and (winsharedutils.pid_running(pid)):
allisremoved = False
continue
try: try:
shutil.rmtree(gobject.gettempdir('')) shutil.rmtree(os.path.join(tmpbase, f))
except: except:
pass pass
try: if allisremoved:
os.remove("./cache/Updater.exe") try:
shutil.rmtree(tmpbase)
except:
pass
try:
os.remove("./cache/Updater.exe")
except:
pass
except: except:
pass pass

View File

@ -71,7 +71,7 @@ class bgmsettings(QDialog):
if vid in collect: if vid in collect:
gameuid = collect[vid] gameuid = collect[vid]
else: else:
gameuid = initanewitem(f"bgm_{vid}_{time.time()}", title) gameuid = initanewitem(title)
savehook_new_data[gameuid][self._ref.idname] = vid savehook_new_data[gameuid][self._ref.idname] = vid
gamdidchangedtask(self._ref.typename, self._ref.idname, gameuid) gamdidchangedtask(self._ref.typename, self._ref.idname, gameuid)
reflist.insert(0, gameuid) reflist.insert(0, gameuid)
@ -203,9 +203,8 @@ class searcher(common):
vndbtags = [_["name"] for _ in response["tags"]] vndbtags = [_["name"] for _ in response["tags"]]
developers = [] developers = []
for _ in response["infobox"]: for _ in response["infobox"]:
if _["key"] == "游戏开发商": if _["key"] in ["游戏开发商", "开发", "发行"]:
developers = [_["value"]] developers += [_["value"]]
break
return { return {
# "namemap": namemap, # "namemap": namemap,
"title": response["name"], "title": response["name"],

View File

@ -72,7 +72,7 @@ class steamsettings(QDialog):
if vid in collect: if vid in collect:
gameuid = collect[vid] gameuid = collect[vid]
else: else:
gameuid = initanewitem(f"steam_{vid}_{time.time()}", title) gameuid = initanewitem(title)
savehook_new_data[gameuid][self._ref.idname] = vid savehook_new_data[gameuid][self._ref.idname] = vid
gamdidchangedtask(self._ref.typename, self._ref.idname, gameuid) gamdidchangedtask(self._ref.typename, self._ref.idname, gameuid)
reflist.insert(0, gameuid) reflist.insert(0, gameuid)

View File

@ -232,7 +232,7 @@ class vndbsettings(QDialog):
if vid in collect: if vid in collect:
gameuid = collect[vid] gameuid = collect[vid]
else: else:
gameuid = initanewitem(f"vndb_{vid}_{time.time()}", title) gameuid = initanewitem(title)
savehook_new_data[gameuid][self._ref.idname] = vid savehook_new_data[gameuid][self._ref.idname] = vid
gamdidchangedtask(self._ref.typename, self._ref.idname, gameuid) gamdidchangedtask(self._ref.typename, self._ref.idname, gameuid)
reflist.insert(0, gameuid) reflist.insert(0, gameuid)

View File

@ -52,7 +52,7 @@ if _savehook:
savehook_new_list = _savehook[0] savehook_new_list = _savehook[0]
savehook_new_data = _savehook[1] savehook_new_data = _savehook[1]
savegametaged = _savehook[2] savegametaged = _savehook[2]
gamepath2uid = _savehook[3] # gamepath2uid = _savehook[3] 不再使用允许重复的path
else: else:
_savehook = tryreadconfig("savehook_new_1.39.4.json", default=[[], {}]) _savehook = tryreadconfig("savehook_new_1.39.4.json", default=[[], {}])
@ -73,23 +73,23 @@ else:
savegametaged = [None] savegametaged = [None]
# 将savehook_new_data转换为新的格式 # 将savehook_new_data转换为新的格式
gamepath2uid = {} __gamepath2uid = {}
__savehook_new_data = {} __savehook_new_data = {}
for k in savehook_new_data: for k in savehook_new_data:
uid = f"{time.time()}_{uuid.uuid4()}" uid = f"{time.time()}_{uuid.uuid4()}"
__savehook_new_data[uid] = savehook_new_data[k] __savehook_new_data[uid] = savehook_new_data[k]
__savehook_new_data[uid].update(gamepath=k) __savehook_new_data[uid].update(gamepath=k)
gamepath2uid[k] = uid __gamepath2uid[k] = uid
savehook_new_data = __savehook_new_data savehook_new_data = __savehook_new_data
# 将global游戏表和自定义子列表都转换成新格式 # 将global游戏表和自定义子列表都转换成新格式
def parselist(ls): def parselist(ls):
for i in range(len(ls)): for i in range(len(ls)):
ori = ls[i] ori = ls[i]
if ori not in gamepath2uid: if ori not in __gamepath2uid:
continue continue
ls[i] = gamepath2uid[ori] ls[i] = __gamepath2uid[ori]
parselist(savehook_new_list) parselist(savehook_new_list)
for sub in savegametaged: for sub in savegametaged:
@ -100,9 +100,9 @@ translatorsetting = tryreadconfig("translatorsetting.json")
ocrsetting = tryreadconfig("ocrsetting.json") ocrsetting = tryreadconfig("ocrsetting.json")
def getdefaultsavehook(gamepath, title=None): def getdefaultsavehook(title=None):
default = { default = {
# "gamepath": gamepath, "gamepath": "", # 不要直接访问要通过uid2gamepath来间接访问
"hooksetting_follow_default": True, "hooksetting_follow_default": True,
"hooksetting_private": {}, # 显示时再加载缺省用global中的键 "hooksetting_private": {}, # 显示时再加载缺省用global中的键
"textproc_follow_default": True, "textproc_follow_default": True,
@ -167,12 +167,6 @@ def getdefaultsavehook(gamepath, title=None):
} }
if title and len(title): if title and len(title):
default["title"] = title # metadata default["title"] = title # metadata
else:
default["title"] = (
os.path.basename(os.path.dirname(gamepath))
+ "/"
+ os.path.basename(gamepath)
)
return default return default
@ -205,6 +199,34 @@ class __uid2gamepath:
uid2gamepath = __uid2gamepath() uid2gamepath = __uid2gamepath()
def findgameuidofpath(gamepath, targetlist=None, findall=False):
# 一般只在save_game_list里查找用于从getpidexe获取uid
# 因为有可能有过去的不再使用的uid发生碰撞。
# 只在添加游戏时,全面查找。
if not gamepath:
if findall:
return []
else:
return None
# 遍历的速度非常快1w条的速度也就0.001x秒
# 但1w条数据时load/dump的速度就有点慢了能2秒多
checkin = targetlist
if checkin is None:
checkin = savehook_new_data.keys()
collect = []
for uid in checkin:
if savehook_new_data[uid]["gamepath"] == gamepath:
if findall:
collect.append(uid)
else:
return uid
if findall:
return collect
else:
return None
def syncconfig(config1, default, drop=False, deep=0, skipdict=False): def syncconfig(config1, default, drop=False, deep=0, skipdict=False):
for key in default: for key in default:
@ -404,11 +426,15 @@ def _TRL(kk):
return x return x
def safesave(fname, js): def safesave(fname, js, beatiful=True):
# 有时保存时意外退出会导致config文件被清空 # 有时保存时意外退出会导致config文件被清空
os.makedirs("./userconfig", exist_ok=True) os.makedirs("./userconfig", exist_ok=True)
with open(fname + ".tmp", "w", encoding="utf-8") as ff: with open(fname + ".tmp", "w", encoding="utf-8") as ff:
ff.write(json.dumps(js, ensure_ascii=False, sort_keys=False, indent=4)) if beatiful:
ff.write(json.dumps(js, ensure_ascii=False, sort_keys=False, indent=4))
else:
# savegamedata 1w条时indent=4要2秒不indent 0.37秒不ensure_ascii 0.27秒,用不着数据库了
ff.write(json.dumps(js, sort_keys=False))
if os.path.exists(fname): if os.path.exists(fname):
os.remove(fname) os.remove(fname)
os.rename(fname + ".tmp", fname) os.rename(fname + ".tmp", fname)
@ -426,7 +452,8 @@ def saveallconfig():
safesave("./userconfig/ocrsetting.json", ocrsetting) safesave("./userconfig/ocrsetting.json", ocrsetting)
safesave( safesave(
"./userconfig/savegamedata_5.3.1.json", "./userconfig/savegamedata_5.3.1.json",
[savehook_new_list, savehook_new_data, savegametaged, gamepath2uid], [savehook_new_list, savehook_new_data, savegametaged, None],
beatiful=False,
) )
safesave( safesave(
"./files/lang/{}.json".format(getlanguse()), "./files/lang/{}.json".format(getlanguse()),

View File

@ -84,25 +84,33 @@ def getprocesslist():
def getpidexe(pid): def getpidexe(pid):
hwnd1 = windows.AutoHandle( hwnd1 = windows.AutoHandle(
windows.OpenProcess(windows.PROCESS_ALL_ACCESS, False, (pid)) windows.OpenProcess(windows.PROCESS_ALL_ACCESS, False, pid)
) )
if hwnd1 == 0: if not hwnd1:
hwnd1 = windows.OpenProcess( hwnd1 = windows.OpenProcess(
windows.PROCESS_QUERY_LIMITED_INFORMATION, False, (pid) windows.PROCESS_QUERY_LIMITED_INFORMATION, False, pid
) )
if hwnd1 == 0: if not hwnd1:
name_ = None name_ = None
else: else:
name_ = windows.GetProcessFileName(hwnd1) name_ = windows.GetProcessFileName(hwnd1)
return name_ return name_
def testprivilege(pid): def test_injectable_1(pid):
hwnd1 = windows.AutoHandle( return bool(
windows.OpenProcess(windows.PROCESS_INJECT_ACCESS, False, (pid)) windows.AutoHandle(
windows.OpenProcess(windows.PROCESS_INJECT_ACCESS, False, pid)
)
) )
return hwnd1 != 0
def test_injectable(pids):
for pid in pids:
if not test_injectable_1(pid):
return False
return True
def ListProcess(filt=True): def ListProcess(filt=True):
@ -128,18 +136,13 @@ def ListProcess(filt=True):
pass pass
kv = {} kv = {}
for pid, exe in ret: for pid, exe in ret:
if exe in kv: if exe not in kv:
kv[exe]["pid"].append(pid) kv[exe] = []
else:
kv[exe] = {"pid": [pid]} kv[exe].append(pid)
# for exe in kv:
# if len(kv[exe]['pid'])>1:
# mems=[getprocessmem(_) for _ in kv[exe]['pid']]
# _i=argsort(mems)
# kv[exe]['pid']=[kv[exe]['pid'][_i[-1]]]
xxx = [] xxx = []
for exe in kv: for exe in kv:
xxx.append([kv[exe]["pid"], exe]) xxx.append([kv[exe], exe])
return xxx return xxx
@ -184,28 +187,26 @@ def getExeIcon(name, icon=True, cache=False):
def injectdll(injectpids, injecter, dll): def injectdll(injectpids, injecter, dll):
pid = " ".join([str(_) for _ in injectpids]) pid = " ".join([str(_) for _ in injectpids])
if any(map(testprivilege, injectpids)) == False: for _ in (0,):
windows.ShellExecute( if not test_injectable(injectpids):
0, break
"runas",
injecter,
'dllinject {} "{}"'.format(pid, dll),
None,
windows.SW_HIDE,
)
else:
ret = subprocess.run( ret = subprocess.run(
'"{}" dllinject {} "{}"'.format(injecter, pid, dll) '"{}" dllinject {} "{}"'.format(injecter, pid, dll)
).returncode ).returncode
if ret == 0: if ret:
windows.ShellExecute( return
0, pids = winsharedutils.collect_running_pids(injectpids)
"runas", pid = " ".join([str(_) for _ in pids])
injecter,
'dllinject {} "{}"'.format(pid, dll), windows.ShellExecute(
None, 0,
windows.SW_HIDE, "runas",
) injecter,
'dllinject {} "{}"'.format(pid, dll),
None,
windows.SW_HIDE,
)
def mouseselectwindow(callback): def mouseselectwindow(callback):

View File

@ -1,8 +1,8 @@
import re, codecs, inspect import re, codecs, inspect
from traceback import print_exc from traceback import print_exc
from collections import Counter from collections import Counter
import importlib, gobject import gobject
from myutils.utils import getfilemd5, LRUCache, getlangsrc from myutils.utils import checkchaos, checkmd5reloadmodule, LRUCache, getlangsrc
from myutils.config import ( from myutils.config import (
postprocessconfig, postprocessconfig,
globalconfig, globalconfig,
@ -322,9 +322,6 @@ def lines_threshold(line, args):
return line return line
from myutils.utils import checkchaos
def _remove_chaos(line): def _remove_chaos(line):
newline = "" newline = ""
for c in line: for c in line:
@ -334,12 +331,16 @@ def _remove_chaos(line):
return newline return newline
_selfdefpost = None def _mypostloader(line, file, module):
_selfdefpostmd5 = None
isnew, _ = checkmd5reloadmodule(file, module)
# 这个是单独函数的模块不需要用isnew来判断是否需要重新初始化
if not _:
return line
return _.POSTSOLVE(line)
def POSTSOLVE(line): def POSTSOLVE(line):
global _selfdefpostmd5, _selfdefpost
if line == "": if line == "":
return "" return ""
functions = { functions = {
@ -367,6 +368,7 @@ def POSTSOLVE(line):
"dedump": dedump, "dedump": dedump,
"length_threshold": length_threshold, "length_threshold": length_threshold,
"lines_threshold": lines_threshold, "lines_threshold": lines_threshold,
"_11": _mypostloader,
} }
useranklist = globalconfig["postprocess_rank"] useranklist = globalconfig["postprocess_rank"]
usedpostprocessconfig = postprocessconfig usedpostprocessconfig = postprocessconfig
@ -394,22 +396,6 @@ def POSTSOLVE(line):
) )
except: except:
print_exc() print_exc()
try:
md5 = getfilemd5(usemypostpath)
if md5 != _selfdefpostmd5:
_ = importlib.import_module(usemodule)
_ = importlib.reload(_)
_selfdefpostmd5 = md5
_selfdefpost = _
else:
_ = _selfdefpost
functions.update({"_11": _.POSTSOLVE})
except ModuleNotFoundError:
pass
except:
print_exc()
pass
for postitem in useranklist: for postitem in useranklist:
if postitem not in functions: if postitem not in functions:
continue continue
@ -418,20 +404,20 @@ def POSTSOLVE(line):
if usedpostprocessconfig[postitem]["use"]: if usedpostprocessconfig[postitem]["use"]:
try: try:
_f = functions[postitem] _f = functions[postitem]
sig = inspect.signature(_f)
np = len(sig.parameters)
if np == 1:
line = functions[postitem](line)
elif np == 2:
line = functions[postitem](
line, usedpostprocessconfig[postitem].get("args", {})
)
else:
raise Exception("unsupported parameters num")
except Exception as e:
print_exc()
if postitem == "_11": if postitem == "_11":
raise e line = functions[postitem](line, usemypostpath, usemodule)
else:
sig = inspect.signature(_f)
np = len(sig.parameters)
if np == 1:
line = functions[postitem](line)
elif np == 2:
line = functions[postitem](
line, usedpostprocessconfig[postitem].get("args", {})
)
else:
raise Exception("unsupported parameters num")
except:
print_exc()
return line return line

View File

@ -13,9 +13,9 @@ from myutils.config import (
globalconfig, globalconfig,
static_data, static_data,
getlanguse, getlanguse,
savehook_new_data,
uid2gamepath, uid2gamepath,
gamepath2uid, savehook_new_data,
findgameuidofpath,
getdefaultsavehook, getdefaultsavehook,
) )
from ctypes import c_float, pointer, c_void_p from ctypes import c_float, pointer, c_void_p
@ -127,9 +127,6 @@ class PriorityQueue:
return bool(len(self._heap) == 0) return bool(len(self._heap) == 0)
searchvndbqueue = PriorityQueue()
def guessmaybetitle(gamepath, title): def guessmaybetitle(gamepath, title):
__t = [] __t = []
@ -167,14 +164,20 @@ def guessmaybetitle(gamepath, title):
targetmod = {} targetmod = {}
def trysearchforid(gameuid, searchargs: list): def dispatchsearchfordata(gameuid, target, vid):
targetmod[target].dispatchsearchfordata(gameuid, vid)
def trysearchforid_1(gameuid, searchargs: list):
infoid = None infoid = None
primitivtemetaorigin = globalconfig["primitivtemetaorigin"] primitivtemetaorigin = globalconfig["primitivtemetaorigin"]
__ = list(targetmod.keys()) __ = [primitivtemetaorigin]
if primitivtemetaorigin not in __: for k in targetmod:
primitivtemetaorigin = __[0] if k == primitivtemetaorigin:
__.remove(primitivtemetaorigin) continue
__.insert(0, primitivtemetaorigin) if not globalconfig["metadata"][k]["auto"]:
continue
__.append(k)
for key in __: for key in __:
vid = None vid = None
@ -195,28 +198,15 @@ def trysearchforid(gameuid, searchargs: list):
if key == primitivtemetaorigin: if key == primitivtemetaorigin:
break break
if infoid: if infoid:
searchvndbqueue.put((1, gameuid, infoid)) key, vid = infoid
return infoid dispatchsearchfordata(gameuid, key, vid)
gobject.baseobject.translation_ui.displayglobaltooltip.emit(
f"{key}: found {vid}"
)
def everymethodsthread(): def trysearchforid(gameuid, searchargs: list):
while True: threading.Thread(target=trysearchforid_1, args=(gameuid, searchargs)).start()
_ = searchvndbqueue.get()
_type, gameuid, arg = _
try:
if _type == 0:
infoid = trysearchforid(gameuid, arg)
key, vid = infoid
gobject.baseobject.translation_ui.displayglobaltooltip.emit(
f"{key}: found {vid}"
)
elif _type == 1:
key, vid = arg
targetmod[key].dispatchsearchfordata(gameuid, vid)
except:
print_exc()
def idtypecheck(key, idname, gameuid, vid): def idtypecheck(key, idname, gameuid, vid):
@ -237,30 +227,43 @@ def idtypecheck(key, idname, gameuid, vid):
def gamdidchangedtask(key, idname, gameuid): def gamdidchangedtask(key, idname, gameuid):
vid = savehook_new_data[gameuid][idname] vid = savehook_new_data[gameuid][idname]
searchvndbqueue.put((1, gameuid, (key, vid)), 1) dispatchsearchfordata(gameuid, key, vid)
def titlechangedtask(gameuid, title): def titlechangedtask(gameuid, title):
savehook_new_data[gameuid]["title"] = title savehook_new_data[gameuid]["title"] = title
savehook_new_data[gameuid]["istitlesetted"] = True savehook_new_data[gameuid]["istitlesetted"] = True
searchvndbqueue.put((0, gameuid, [title]), 1) trysearchforid(gameuid, [title])
def initanewitem(gamepath, title): def initanewitem(title):
uid = f"{time.time()}_{uuid.uuid4()}" uid = f"{time.time()}_{uuid.uuid4()}"
gamepath2uid[gamepath] = uid savehook_new_data[uid] = getdefaultsavehook(title)
savehook_new_data[uid] = getdefaultsavehook(gamepath, title)
uid2gamepath[uid] = gamepath
return uid return uid
def checkifnewgame(targetlist, gamepath, title=None): def checkifnewgame(targetlist, gamepath, title=None):
if gamepath not in gamepath2uid: # 用于添加游戏时,全局查找是否有过历史记录
uid = initanewitem(gamepath, title) uids = findgameuidofpath(gamepath, findall=True)
searchvndbqueue.put((0, uid, [title] + guessmaybetitle(gamepath, title))) print(uids)
if len(uids) == 0:
uid = initanewitem(title)
if title is None:
savehook_new_data[uid]["title"] = (
os.path.basename(os.path.dirname(gamepath))
+ "/"
+ os.path.basename(gamepath)
)
uid2gamepath[uid] = gamepath
trysearchforid(uid, [title] + guessmaybetitle(gamepath, title))
isnew = True
else: else:
uid = gamepath2uid[gamepath] isnew = True
isnew = uid not in targetlist for uid in uids:
if uid in targetlist:
isnew = False
break
if isnew: if isnew:
targetlist.insert(0, uid) targetlist.insert(0, uid)
return uid return uid
@ -414,7 +417,10 @@ class Process:
pass pass
""" """
) )
os.startfile(p) # os.startfile(p)
threading.Thread(
target=os.system, args=(f'notepad "{os.path.normpath(p)}"',)
).start()
return p return p
@ -619,24 +625,11 @@ def checkpostusing(name):
return use and checkpostlangmatch(name) return use and checkpostlangmatch(name)
def getpostfile(name): def loadpostsettingwindowmethod(name):
if name == "myprocess": checkpath = "./LunaTranslator/transoptimi/" + name + ".py"
mm = "myprocess"
checkpath = "./userconfig/myprocess.py"
else:
mm = "transoptimi." + name
checkpath = "./LunaTranslator/transoptimi/" + name + ".py"
if os.path.exists(checkpath) == False: if os.path.exists(checkpath) == False:
return None return None
return mm mm = "transoptimi." + name
def loadpostsettingwindowmethod(name):
if name == "myprocess":
return lambda _: selectdebugfile("./userconfig/myprocess.py")
mm = getpostfile(name)
if not mm:
return None
try: try:
Process = importlib.import_module(mm).Process Process = importlib.import_module(mm).Process
@ -739,5 +732,29 @@ for k in globalconfig["metadata"]:
except: except:
print_exc() print_exc()
globalcachedmodule = {}
threading.Thread(target=everymethodsthread).start()
def checkmd5reloadmodule(filename, module):
if not os.path.exists(filename):
# reload重新加载不存在的文件时不会报错。
return True, None
key = (filename, module)
md5 = getfilemd5(filename)
cachedmd5 = globalcachedmodule.get(key, {}).get("md5", None)
if md5 != cachedmd5:
try:
_ = importlib.import_module(module)
_ = importlib.reload(_)
except ModuleNotFoundError:
return True, None
# 不要捕获其他错误,缺少模块时直接跳过,只报实现错误
# except:
# print_exc()
# return True, None
globalcachedmodule[key] = {"md5": md5, "module": _}
return True, _
else:
return False, globalcachedmodule.get(key, {}).get("module", None)

View File

@ -8,9 +8,10 @@ from winsharedutils import Is64bit
from myutils.config import globalconfig, savehook_new_data, static_data from myutils.config import globalconfig, savehook_new_data, static_data
from textsource.textsourcebase import basetext from textsource.textsourcebase import basetext
from myutils.utils import checkchaos from myutils.utils import checkchaos
from myutils.hwnd import injectdll from myutils.hwnd import injectdll, test_injectable
from myutils.wrapper import threader from myutils.wrapper import threader
from myutils.utils import getfilemd5 from myutils.utils import getfilemd5
from traceback import print_exc
from ctypes import ( from ctypes import (
CDLL, CDLL,
@ -151,6 +152,7 @@ class texthook(basetext):
gobject.baseobject.hookselectdialog.realshowhide.emit(True) gobject.baseobject.hookselectdialog.realshowhide.emit(True)
self.delaycollectallselectedoutput() self.delaycollectallselectedoutput()
self.declare() self.declare()
self.prepares()
def checkmd5prefix(self, gamepath): def checkmd5prefix(self, gamepath):
md5 = getfilemd5(gamepath) md5 = getfilemd5(gamepath)
@ -229,7 +231,7 @@ class texthook(basetext):
self.Luna_FreePtr(ws) self.Luna_FreePtr(ws)
return string return string
def Luna_Startup(self): def prepares(self):
procs = [ procs = [
ProcessEvent(self.onprocconnect), ProcessEvent(self.onprocconnect),
ProcessEvent(self.connectedpids.remove), ProcessEvent(self.connectedpids.remove),
@ -243,15 +245,14 @@ class texthook(basetext):
self.keepref += procs self.keepref += procs
ptrs = [cast(_, c_void_p).value for _ in procs] ptrs = [cast(_, c_void_p).value for _ in procs]
self.Luna_Start(*ptrs) self.Luna_Start(*ptrs)
def start(self):
self.Luna_Startup()
self.setsettings() self.setsettings()
def start_unsafe(self):
caninject = test_injectable(self.pids)
injectpids = [] injectpids = []
for pid in self.pids: for pid in self.pids:
if self.config["use_yapi"]: if caninject and self.config["use_yapi"]:
self.Luna_Inject(pid, os.path.abspath("./files/plugins/LunaHook")) self.Luna_Inject(pid, os.path.abspath("./files/plugins/LunaHook"))
else: else:
if self.Luna_CreatePipeAndCheck(pid): if self.Luna_CreatePipeAndCheck(pid):
@ -264,9 +265,17 @@ class texthook(basetext):
dll = os.path.abspath( dll = os.path.abspath(
"./files/plugins/LunaHook/LunaHook{}.dll".format(arch) "./files/plugins/LunaHook/LunaHook{}.dll".format(arch)
) )
# subprocess.Popen('"{}" dllinject {} "{}"'.format(injecter,pid,dll))
injectdll(injectpids, injecter, dll) injectdll(injectpids, injecter, dll)
def start(self):
try:
self.start_unsafe()
except:
print_exc()
gobject.baseobject.translation_ui.displaymessagebox.emit(
"错误", "权限不足,请以管理员权限运行!"
)
def onprocconnect(self, pid): def onprocconnect(self, pid):
self.connectedpids.append(pid) self.connectedpids.append(pid)
time.sleep(savehook_new_data[self.gameuid]["inserthooktimeout"] / 1000) time.sleep(savehook_new_data[self.gameuid]["inserthooktimeout"] / 1000)

View File

@ -0,0 +1,27 @@
from translator.basetranslator import basetrans
from myutils.utils import checkmd5reloadmodule
class TS(basetrans):
def mayreinit(self):
isnew, module = checkmd5reloadmodule("./userconfig/selfbuild.py", "selfbuild")
if not isnew:
return
if module:
self.internal = module.TS("selfbuild")
def inittranslator(self):
self.internal = None
self.mayreinit()
def langmap(self):
self.mayreinit()
if not self.internal:
return {}
return self.internal.langmap()
def translate(self, content):
self.mayreinit()
if not self.internal:
return ""
return self.internal.translate(content)

View File

@ -0,0 +1,31 @@
from myutils.utils import selectdebugfile, checkmd5reloadmodule
class Process:
@staticmethod
def get_setting_window(parent_window):
return selectdebugfile("./userconfig/myprocess.py")
def process_after(self, res, contenxt):
self.mayreinit()
if not self.internal:
return res
return self.internal.process_after(res, contenxt)
def process_before(self, s):
self.mayreinit()
if not self.internal:
return s, None
return self.internal.process_before(s)
def __init__(self) -> None:
self.internal = None
self.mayreinit()
def mayreinit(self):
isnew, module = checkmd5reloadmodule("./userconfig/myprocess.py", "myprocess")
if not isnew:
return
if module:
self.internal = module.Process()

View File

@ -900,6 +900,9 @@ def ScreenToClient(hwnd, x, y):
return (P.x, P.y) return (P.x, P.y)
INVALID_HANDLE_VALUE = -1
class AutoHandle(HANDLE): class AutoHandle(HANDLE):
def __new__(cls, value) -> None: def __new__(cls, value) -> None:
instance = super().__new__(cls, value) instance = super().__new__(cls, value)
@ -909,6 +912,9 @@ class AutoHandle(HANDLE):
if self: if self:
CloseHandle(self) CloseHandle(self)
def __bool__(self):
return (self.value != INVALID_HANDLE_VALUE) and (self.value != None)
_MapVirtualKey = _user32.MapVirtualKeyW _MapVirtualKey = _user32.MapVirtualKeyW
_MapVirtualKey.argtypes = UINT, UINT _MapVirtualKey.argtypes = UINT, UINT

View File

@ -339,6 +339,16 @@ pid_running = utilsdll.pid_running
pid_running.argtypes = (DWORD,) pid_running.argtypes = (DWORD,)
pid_running.restype = c_bool pid_running.restype = c_bool
def collect_running_pids(pids):
_ = []
for __ in pids:
if not pid_running(__):
continue
_.append(__)
return _
getpidhwndfirst = utilsdll.getpidhwndfirst getpidhwndfirst = utilsdll.getpidhwndfirst
getpidhwndfirst.argtypes = (DWORD,) getpidhwndfirst.argtypes = (DWORD,)
getpidhwndfirst.restype = HWND getpidhwndfirst.restype = HWND

View File

@ -232,6 +232,7 @@
}, },
"metadata": { "metadata": {
"vndb": { "vndb": {
"auto": true,
"name": "vndb", "name": "vndb",
"downloadtasks": [], "downloadtasks": [],
"searchfordatatasks": [], "searchfordatatasks": [],
@ -243,6 +244,7 @@
} }
}, },
"dlsite": { "dlsite": {
"auto": false,
"name": "dlsite", "name": "dlsite",
"downloadtasks": [], "downloadtasks": [],
"searchfordatatasks": [], "searchfordatatasks": [],
@ -250,6 +252,7 @@
"target": "dlsiteid" "target": "dlsiteid"
}, },
"bangumi": { "bangumi": {
"auto": true,
"name": "bangumi", "name": "bangumi",
"downloadtasks": [], "downloadtasks": [],
"searchfordatatasks": [], "searchfordatatasks": [],
@ -261,6 +264,7 @@
} }
}, },
"fanza": { "fanza": {
"auto": false,
"name": "FanzaGames", "name": "FanzaGames",
"downloadtasks": [], "downloadtasks": [],
"searchfordatatasks": [], "searchfordatatasks": [],
@ -268,6 +272,7 @@
"target": "fanzaid" "target": "fanzaid"
}, },
"steam": { "steam": {
"auto": false,
"name": "steam", "name": "steam",
"downloadtasks": [], "downloadtasks": [],
"searchfordatatasks": [], "searchfordatatasks": [],

View File

@ -485,7 +485,6 @@
"进程号": "رقم العملية", "进程号": "رقم العملية",
"最长翻译字数": "أقصى عدد من الكلمات المترجمة", "最长翻译字数": "أقصى عدد من الكلمات المترجمة",
"过滤控制字符": "تصفية السيطرة الشخصية", "过滤控制字符": "تصفية السيطرة الشخصية",
"窗口名": "اسم النافذة",
"法语": "الفرنسية .", "法语": "الفرنسية .",
"分词": "اسم الفاعل", "分词": "اسم الفاعل",
"用户词典1": "قاموس المستخدم", "用户词典1": "قاموس المستخدم",
@ -716,7 +715,6 @@
"过滤历史重复": "تصفية التاريخ تكرار", "过滤历史重复": "تصفية التاريخ تكرار",
"缓存条数": "عدد شرائط التخزين المؤقت", "缓存条数": "عدد شرائط التخزين المؤقت",
"腾讯OCR": "تينسنت التعرف الضوئي على الحروف", "腾讯OCR": "تينسنت التعرف الضوئي على الحروف",
"添加列表": "إضافة قائمة",
"删除列表": "حذف قائمة", "删除列表": "حذف قائمة",
"上移": "رفع", "上移": "رفع",
"下移": "نزولا", "下移": "نزولا",
@ -813,5 +811,6 @@
"上传游戏": "تحميل العاب", "上传游戏": "تحميل العاب",
"以当前md5复制选中行": "حدد صف مع نسخة MD5 الحالي", "以当前md5复制选中行": "حدد صف مع نسخة MD5 الحالي",
"修改列表名称": "تعديل اسم القائمة", "修改列表名称": "تعديل اسم القائمة",
"滚动到最后": "انتقل إلى آخر" "滚动到最后": "انتقل إلى آخر",
"创建列表": "إنشاء قائمة"
} }

View File

@ -388,7 +388,6 @@
"错误": "錯誤", "错误": "錯誤",
"所选文件格式错误!": "所選檔案格式錯誤!", "所选文件格式错误!": "所選檔案格式錯誤!",
"进程号": "行程號", "进程号": "行程號",
"窗口名": "視窗名",
"无法识别的路径!": "無法識別的路徑!", "无法识别的路径!": "無法識別的路徑!",
"进程": "行程", "进程": "行程",
"到进程": "到行程", "到进程": "到行程",
@ -716,7 +715,6 @@
"过滤历史重复": "過濾歷史重複", "过滤历史重复": "過濾歷史重複",
"缓存条数": "緩存條數", "缓存条数": "緩存條數",
"腾讯OCR": "騰訊OCR", "腾讯OCR": "騰訊OCR",
"添加列表": "添加清單",
"删除列表": "删除清單", "删除列表": "删除清單",
"上移": "上移", "上移": "上移",
"下移": "下移", "下移": "下移",
@ -813,5 +811,6 @@
"上传游戏": "上傳遊戲", "上传游戏": "上傳遊戲",
"以当前md5复制选中行": "以當前md5複製選中行", "以当前md5复制选中行": "以當前md5複製選中行",
"修改列表名称": "修改清單名稱", "修改列表名称": "修改清單名稱",
"滚动到最后": "滾動到最後" "滚动到最后": "滾動到最後",
"创建列表": "創建清單"
} }

View File

@ -388,7 +388,6 @@
"错误": "Error", "错误": "Error",
"所选文件格式错误!": "Invalid File Format Selected!", "所选文件格式错误!": "Invalid File Format Selected!",
"进程号": "Process ID", "进程号": "Process ID",
"窗口名": "Window name",
"无法识别的路径!": "Unrecognizable Path!", "无法识别的路径!": "Unrecognizable Path!",
"进程": "Process", "进程": "Process",
"到进程": "Select Process", "到进程": "Select Process",
@ -558,7 +557,6 @@
"点击单词复制": "Copy On Click", "点击单词复制": "Copy On Click",
"窗口背景透明": "Window Background Transparency", "窗口背景透明": "Window Background Transparency",
"背景窗口透明": "Background Window Transparency", "背景窗口透明": "Background Window Transparency",
"指定模式": "Specify Mode",
"搜索范围": "Search Range", "搜索范围": "Search Range",
"搜索方式": "Search Method", "搜索方式": "Search Method",
"使用翻译缓存": "Use Translation Cache", "使用翻译缓存": "Use Translation Cache",
@ -716,7 +714,6 @@
"过滤历史重复": "Filter Historical Duplicates", "过滤历史重复": "Filter Historical Duplicates",
"缓存条数": "Number of Cached Items", "缓存条数": "Number of Cached Items",
"腾讯OCR": "Tencent OCR", "腾讯OCR": "Tencent OCR",
"添加列表": "Add List",
"删除列表": "Delete List", "删除列表": "Delete List",
"上移": "Move Up", "上移": "Move Up",
"下移": "Move Down", "下移": "Move Down",
@ -813,5 +810,7 @@
"上传游戏": "Upload Game", "上传游戏": "Upload Game",
"以当前md5复制选中行": "Copy Selected Row with Current MD5", "以当前md5复制选中行": "Copy Selected Row with Current MD5",
"修改列表名称": "Modify List Name", "修改列表名称": "Modify List Name",
"滚动到最后": "Scroll to End" "滚动到最后": "Scroll to End",
"指定模块": "Specify modules",
"创建列表": "Create List"
} }

View File

@ -388,7 +388,6 @@
"错误": "Error", "错误": "Error",
"所选文件格式错误!": "¡¡ el archivo seleccionado tiene un formato incorrecto!", "所选文件格式错误!": "¡¡ el archivo seleccionado tiene un formato incorrecto!",
"进程号": "Número de proceso", "进程号": "Número de proceso",
"窗口名": "Nombre de la ventana",
"无法识别的路径!": "¡Caminos no reconocibles!", "无法识别的路径!": "¡Caminos no reconocibles!",
"进程": "Proceso", "进程": "Proceso",
"到进程": "Al proceso", "到进程": "Al proceso",
@ -716,7 +715,6 @@
"过滤历史重复": "Filtrar repetición histórica", "过滤历史重复": "Filtrar repetición histórica",
"缓存条数": "Número de barras de caché", "缓存条数": "Número de barras de caché",
"腾讯OCR": "Tencent OCR", "腾讯OCR": "Tencent OCR",
"添加列表": "Añadir lista",
"删除列表": "Eliminar lista", "删除列表": "Eliminar lista",
"上移": "Subir", "上移": "Subir",
"下移": "Bajar", "下移": "Bajar",
@ -813,5 +811,6 @@
"上传游戏": "Sube el juego", "上传游戏": "Sube el juego",
"以当前md5复制选中行": "Copiar la línea seleccionada con el MD5 actual", "以当前md5复制选中行": "Copiar la línea seleccionada con el MD5 actual",
"修改列表名称": "Modificar el nombre de la lista", "修改列表名称": "Modificar el nombre de la lista",
"滚动到最后": "Rodar hasta el final" "滚动到最后": "Rodar hasta el final",
"创建列表": "Crear lista"
} }

View File

@ -388,7 +388,6 @@
"错误": "Erreur", "错误": "Erreur",
"所选文件格式错误!": "Mauvais format de fichier sélectionné!", "所选文件格式错误!": "Mauvais format de fichier sélectionné!",
"进程号": "Numéro de processus", "进程号": "Numéro de processus",
"窗口名": "Nom de la fenêtre",
"无法识别的路径!": "Un chemin méconnaissable!", "无法识别的路径!": "Un chemin méconnaissable!",
"进程": "Processus", "进程": "Processus",
"到进程": "Au processus", "到进程": "Au processus",
@ -716,7 +715,6 @@
"过滤历史重复": "Filtrer historique répétition", "过滤历史重复": "Filtrer historique répétition",
"缓存条数": "Nombre de barres de cache", "缓存条数": "Nombre de barres de cache",
"腾讯OCR": "OCR Tencent", "腾讯OCR": "OCR Tencent",
"添加列表": "Ajouter une liste",
"删除列表": "Supprimer une liste", "删除列表": "Supprimer une liste",
"上移": "Déplacement vers le Haut", "上移": "Déplacement vers le Haut",
"下移": "Descendre", "下移": "Descendre",
@ -813,5 +811,6 @@
"上传游戏": "Télécharger un jeu", "上传游戏": "Télécharger un jeu",
"以当前md5复制选中行": "Copier la ligne sélectionnée avec le MD5 actuel", "以当前md5复制选中行": "Copier la ligne sélectionnée avec le MD5 actuel",
"修改列表名称": "Modifier le nom de la Liste", "修改列表名称": "Modifier le nom de la Liste",
"滚动到最后": "Rouler jusqu'à la fin" "滚动到最后": "Rouler jusqu'à la fin",
"创建列表": "Créer une liste"
} }

View File

@ -376,7 +376,6 @@
"错误": "errore", "错误": "errore",
"所选文件格式错误!": "Il formato del file selezionato non è corretto!", "所选文件格式错误!": "Il formato del file selezionato non è corretto!",
"进程号": "Numero del processo", "进程号": "Numero del processo",
"窗口名": "Nome finestra",
"无法识别的路径!": "Percorso sconosciuto!", "无法识别的路径!": "Percorso sconosciuto!",
"进程": "processo", "进程": "processo",
"到进程": "Da elaborare", "到进程": "Da elaborare",
@ -716,7 +715,6 @@
"过滤历史重复": "Filtra duplicati storici", "过滤历史重复": "Filtra duplicati storici",
"缓存条数": "Numero di voci della cache", "缓存条数": "Numero di voci della cache",
"腾讯OCR": "Tencent OCR", "腾讯OCR": "Tencent OCR",
"添加列表": "Aggiungi elenco",
"删除列表": "Elimina elenco", "删除列表": "Elimina elenco",
"上移": "Sposta su", "上移": "Sposta su",
"下移": "Sposta giù", "下移": "Sposta giù",
@ -813,5 +811,6 @@
"上传游戏": "Carica gioco", "上传游戏": "Carica gioco",
"以当前md5复制选中行": "Copia la riga selezionata con l'MD5 corrente", "以当前md5复制选中行": "Copia la riga selezionata con l'MD5 corrente",
"修改列表名称": "Modifica nome elenco", "修改列表名称": "Modifica nome elenco",
"滚动到最后": "Scorri fino alla fine" "滚动到最后": "Scorri fino alla fine",
"创建列表": "Crea elenco"
} }

View File

@ -388,7 +388,6 @@
"错误": "エラー", "错误": "エラー",
"所选文件格式错误!": "選択したファイルフォーマットが間違っています!", "所选文件格式错误!": "選択したファイルフォーマットが間違っています!",
"进程号": "プロセス番号", "进程号": "プロセス番号",
"窗口名": "ウィンドウ名",
"无法识别的路径!": "認識できないパス!", "无法识别的路径!": "認識できないパス!",
"进程": "プロセス", "进程": "プロセス",
"到进程": "プロセスへ", "到进程": "プロセスへ",
@ -716,7 +715,6 @@
"过滤历史重复": "フィルタ履歴の繰り返し", "过滤历史重复": "フィルタ履歴の繰り返し",
"缓存条数": "キャッシュ・エントリ数", "缓存条数": "キャッシュ・エントリ数",
"腾讯OCR": "テンセントOCR", "腾讯OCR": "テンセントOCR",
"添加列表": "リストの追加",
"删除列表": "リストの削除", "删除列表": "リストの削除",
"上移": "上へ移動", "上移": "上へ移動",
"下移": "下へ移動", "下移": "下へ移動",
@ -813,5 +811,6 @@
"上传游戏": "ゲームをアップロード", "上传游戏": "ゲームをアップロード",
"以当前md5复制选中行": "選択した行を現在のmd 5でコピー", "以当前md5复制选中行": "選択した行を現在のmd 5でコピー",
"修改列表名称": "リスト名の変更", "修改列表名称": "リスト名の変更",
"滚动到最后": "最後までスクロール" "滚动到最后": "最後までスクロール",
"创建列表": "リストの作成"
} }

View File

@ -388,7 +388,6 @@
"错误": "오류", "错误": "오류",
"所选文件格式错误!": "선택한 파일의 형식이 잘못되었습니다!", "所选文件格式错误!": "선택한 파일의 형식이 잘못되었습니다!",
"进程号": "프로세스 번호", "进程号": "프로세스 번호",
"窗口名": "창 이름",
"无法识别的路径!": "인식할 수 없는 경로!", "无法识别的路径!": "인식할 수 없는 경로!",
"进程": "프로세스", "进程": "프로세스",
"到进程": "프로세스로", "到进程": "프로세스로",
@ -716,7 +715,6 @@
"过滤历史重复": "반복된 기록 필터링", "过滤历史重复": "반복된 기록 필터링",
"缓存条数": "캐시 바 수", "缓存条数": "캐시 바 수",
"腾讯OCR": "텐센트 OCR", "腾讯OCR": "텐센트 OCR",
"添加列表": "목록 추가",
"删除列表": "목록 삭제", "删除列表": "목록 삭제",
"上移": "위로 이동", "上移": "위로 이동",
"下移": "아래로 이동", "下移": "아래로 이동",
@ -813,5 +811,6 @@
"上传游戏": "게임 업로드", "上传游戏": "게임 업로드",
"以当前md5复制选中行": "선택된 행을 현재 md5로 복사", "以当前md5复制选中行": "선택된 행을 현재 md5로 복사",
"修改列表名称": "목록 이름 수정", "修改列表名称": "목록 이름 수정",
"滚动到最后": "끝까지 스크롤" "滚动到最后": "끝까지 스크롤",
"创建列表": "목록 만들기"
} }

View File

@ -388,7 +388,6 @@
"错误": "błąd", "错误": "błąd",
"所选文件格式错误!": "Wybrany format pliku jest niepoprawny!", "所选文件格式错误!": "Wybrany format pliku jest niepoprawny!",
"进程号": "Numer procesu", "进程号": "Numer procesu",
"窗口名": "Nazwa okna",
"无法识别的路径!": "Nierozpoznana ścieżka!", "无法识别的路径!": "Nierozpoznana ścieżka!",
"进程": "proces", "进程": "proces",
"到进程": "Do przetwarzania", "到进程": "Do przetwarzania",
@ -716,7 +715,6 @@
"过滤历史重复": "Filtruj duplikaty historyczne", "过滤历史重复": "Filtruj duplikaty historyczne",
"缓存条数": "Liczba wpisów pamięci podręcznej", "缓存条数": "Liczba wpisów pamięci podręcznej",
"腾讯OCR": "Dziesięć OCR", "腾讯OCR": "Dziesięć OCR",
"添加列表": "Dodaj listę",
"删除列表": "Usuń listę", "删除列表": "Usuń listę",
"上移": "Przesuń się w górę", "上移": "Przesuń się w górę",
"下移": "Przesuń w dół", "下移": "Przesuń w dół",
@ -813,5 +811,6 @@
"上传游戏": "Przesyłaj grę", "上传游戏": "Przesyłaj grę",
"以当前md5复制选中行": "Kopiuj zaznaczony wiersz z bieżącym MD5", "以当前md5复制选中行": "Kopiuj zaznaczony wiersz z bieżącym MD5",
"修改列表名称": "Zmień nazwę listy", "修改列表名称": "Zmień nazwę listy",
"滚动到最后": "Przewiń do końca" "滚动到最后": "Przewiń do końca",
"创建列表": "Utwórz listę"
} }

View File

@ -388,7 +388,6 @@
"错误": "Ошибка", "错误": "Ошибка",
"所选文件格式错误!": "Ошибка формата выбранного файла!", "所选文件格式错误!": "Ошибка формата выбранного файла!",
"进程号": "Номер процесса", "进程号": "Номер процесса",
"窗口名": "Имя окна",
"无法识别的路径!": "Невозможно определить путь!", "无法识别的路径!": "Невозможно определить путь!",
"进程": "Процесс", "进程": "Процесс",
"到进程": "К процессу", "到进程": "К процессу",
@ -716,7 +715,6 @@
"过滤历史重复": "Фильтровать повторение истории", "过滤历史重复": "Фильтровать повторение истории",
"缓存条数": "Количество кэшированных записей", "缓存条数": "Количество кэшированных записей",
"腾讯OCR": "Скачать OCR", "腾讯OCR": "Скачать OCR",
"添加列表": "Добавить список",
"删除列表": "Удалить список", "删除列表": "Удалить список",
"上移": "Переместить вверх", "上移": "Переместить вверх",
"下移": "Переместить вниз", "下移": "Переместить вниз",
@ -813,5 +811,6 @@
"上传游戏": "Загрузить игру", "上传游戏": "Загрузить игру",
"以当前md5复制选中行": "Копировать выделенную строку в текущем MD5", "以当前md5复制选中行": "Копировать выделенную строку в текущем MD5",
"修改列表名称": "Изменить имя списка", "修改列表名称": "Изменить имя списка",
"滚动到最后": "Прокрутить до конца" "滚动到最后": "Прокрутить до конца",
"创建列表": "Создать список"
} }

View File

@ -59,7 +59,6 @@
"插值算法": "อัลกอริทึมการแทรก", "插值算法": "อัลกอริทึมการแทรก",
"显示帧率": "แสดงอัตราเฟรม", "显示帧率": "แสดงอัตราเฟรม",
"最新版本": "รุ่นล่าสุด", "最新版本": "รุ่นล่าสุด",
"窗口名": "ชื่อหน้าต่าง",
"搜索": "ค้นหา", "搜索": "ค้นหา",
"游戏信息": "ข้อมูลเกม", "游戏信息": "ข้อมูลเกม",
"特殊码": "รหัสพิเศษ", "特殊码": "รหัสพิเศษ",
@ -716,7 +715,6 @@
"过滤历史重复": "ประวัติการกรอง ทำซ้ำ", "过滤历史重复": "ประวัติการกรอง ทำซ้ำ",
"缓存条数": "จำนวนแถบแคช", "缓存条数": "จำนวนแถบแคช",
"腾讯OCR": "Tencent โอซีอาร์", "腾讯OCR": "Tencent โอซีอาร์",
"添加列表": "เพิ่มรายการ",
"删除列表": "ลบรายการ", "删除列表": "ลบรายการ",
"上移": "เลื่อนขึ้น", "上移": "เลื่อนขึ้น",
"下移": "เลื่อนลง", "下移": "เลื่อนลง",
@ -813,5 +811,6 @@
"上传游戏": "อัปโหลดเกม", "上传游戏": "อัปโหลดเกม",
"以当前md5复制选中行": "คัดลอกแถวที่เลือกด้วย md5 ปัจจุบัน", "以当前md5复制选中行": "คัดลอกแถวที่เลือกด้วย md5 ปัจจุบัน",
"修改列表名称": "แก้ไขชื่อรายการ", "修改列表名称": "แก้ไขชื่อรายการ",
"滚动到最后": "เลื่อนไปจนสุด" "滚动到最后": "เลื่อนไปจนสุด",
"创建列表": "สร้างรายการ"
} }

View File

@ -388,7 +388,6 @@
"错误": "hata", "错误": "hata",
"所选文件格式错误!": "Seçili dosya format ı yanlış!", "所选文件格式错误!": "Seçili dosya format ı yanlış!",
"进程号": "İşlem numarası", "进程号": "İşlem numarası",
"窗口名": "Pencere İsmi",
"无法识别的路径!": "Bilinmeyen yol!", "无法识别的路径!": "Bilinmeyen yol!",
"进程": "işlem", "进程": "işlem",
"到进程": "İşleme", "到进程": "İşleme",
@ -716,7 +715,6 @@
"过滤历史重复": "Tarihi çizgileri sil", "过滤历史重复": "Tarihi çizgileri sil",
"缓存条数": "Cache girişlerinin sayısı", "缓存条数": "Cache girişlerinin sayısı",
"腾讯OCR": "Tencent OCR", "腾讯OCR": "Tencent OCR",
"添加列表": "Liste Ekle",
"删除列表": "Listeyi sil", "删除列表": "Listeyi sil",
"上移": "Yukarı Taşı", "上移": "Yukarı Taşı",
"下移": "Aşağı taşın", "下移": "Aşağı taşın",
@ -813,5 +811,6 @@
"上传游戏": "Oyunu yükle", "上传游戏": "Oyunu yükle",
"以当前md5复制选中行": "Seçili satırı mevcut MD5 ile kopyalayın", "以当前md5复制选中行": "Seçili satırı mevcut MD5 ile kopyalayın",
"修改列表名称": "Liste ismini değiştir", "修改列表名称": "Liste ismini değiştir",
"滚动到最后": "Sonuna doğru yürüt" "滚动到最后": "Sonuna doğru yürüt",
"创建列表": "Liste oluştur"
} }

View File

@ -376,7 +376,6 @@
"错误": "помилка", "错误": "помилка",
"所选文件格式错误!": "Вибраний формат файла неправильний!", "所选文件格式错误!": "Вибраний формат файла неправильний!",
"进程号": "Номер процесу", "进程号": "Номер процесу",
"窗口名": "Назва вікна",
"无法识别的路径!": "Нерозпізнаний шлях!", "无法识别的路径!": "Нерозпізнаний шлях!",
"进程": "процес", "进程": "процес",
"到进程": "Процес", "到进程": "Процес",
@ -716,7 +715,6 @@
"过滤历史重复": "Фільтрувати історичні дублікати", "过滤历史重复": "Фільтрувати історичні дублікати",
"缓存条数": "Кількість записів кешу", "缓存条数": "Кількість записів кешу",
"腾讯OCR": "Похильний OCR", "腾讯OCR": "Похильний OCR",
"添加列表": "Додати список",
"删除列表": "Вилучити список", "删除列表": "Вилучити список",
"上移": "Пересунути вгору", "上移": "Пересунути вгору",
"下移": "Пересунути вниз", "下移": "Пересунути вниз",
@ -813,5 +811,6 @@
"上传游戏": "Вивантажити гру", "上传游戏": "Вивантажити гру",
"以当前md5复制选中行": "Копіювати вибраний рядок поточним MD5", "以当前md5复制选中行": "Копіювати вибраний рядок поточним MD5",
"修改列表名称": "Змінити назву списку", "修改列表名称": "Змінити назву списку",
"滚动到最后": "Пересунутися до кінця" "滚动到最后": "Пересунутися до кінця",
"创建列表": "Створити список"
} }

View File

@ -388,7 +388,6 @@
"错误": "Lỗi", "错误": "Lỗi",
"所选文件格式错误!": "Lỗi định dạng tập tin đã chọn!", "所选文件格式错误!": "Lỗi định dạng tập tin đã chọn!",
"进程号": "Số tiến trình", "进程号": "Số tiến trình",
"窗口名": "Tên cửa sổ",
"无法识别的路径!": "Đường không nhận ra!", "无法识别的路径!": "Đường không nhận ra!",
"进程": "Quy trình", "进程": "Quy trình",
"到进程": "Tiến trình", "到进程": "Tiến trình",
@ -716,7 +715,6 @@
"过滤历史重复": "Lọc lịch sử lặp lại", "过滤历史重复": "Lọc lịch sử lặp lại",
"缓存条数": "Số thanh bộ nhớ cache", "缓存条数": "Số thanh bộ nhớ cache",
"腾讯OCR": "Thông tin OCR", "腾讯OCR": "Thông tin OCR",
"添加列表": "Thêm danh sách",
"删除列表": "Xoá danh sách", "删除列表": "Xoá danh sách",
"上移": "Di chuyển lên", "上移": "Di chuyển lên",
"下移": "Di chuyển xuống", "下移": "Di chuyển xuống",
@ -813,5 +811,6 @@
"上传游戏": "Tải lên trò chơi", "上传游戏": "Tải lên trò chơi",
"以当前md5复制选中行": "Dòng đã chọn sao chép md5 hiện tại", "以当前md5复制选中行": "Dòng đã chọn sao chép md5 hiện tại",
"修改列表名称": "Thay đổi tên danh sách", "修改列表名称": "Thay đổi tên danh sách",
"滚动到最后": "Cuộn đến cuối" "滚动到最后": "Cuộn đến cuối",
"创建列表": "Tạo danh sách"
} }

View File

@ -60,7 +60,6 @@
"插值算法": "", "插值算法": "",
"显示帧率": "", "显示帧率": "",
"最新版本": "", "最新版本": "",
"窗口名": "",
"搜索": "", "搜索": "",
"游戏信息": "", "游戏信息": "",
"特殊码": "", "特殊码": "",
@ -724,7 +723,7 @@
"过滤历史重复": "", "过滤历史重复": "",
"缓存条数": "", "缓存条数": "",
"腾讯OCR": "", "腾讯OCR": "",
"添加列表": "", "创建列表": "",
"删除列表": "", "删除列表": "",
"上移": "", "上移": "",
"下移": "", "下移": "",

View File

@ -28,7 +28,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/version)
include(generate_product_version) include(generate_product_version)
set(VERSION_MAJOR 5) set(VERSION_MAJOR 5)
set(VERSION_MINOR 5) set(VERSION_MINOR 6)
set(VERSION_PATCH 0) set(VERSION_PATCH 0)
add_library(pch pch.cpp) add_library(pch pch.cpp)

View File

@ -55,7 +55,9 @@ DECLARE void recoverwindow(HWND hwnd, windowstatus status)
DECLARE bool pid_running(DWORD pid) DECLARE bool pid_running(DWORD pid)
{ {
DWORD code; DWORD code;
GetExitCodeProcess(AutoHandle(OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid)), &code); GetExitCodeProcess(AutoHandle(OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid)), &code);
// 句柄必須具有 PROCESS_QUERY_INFORMATION 或 PROCESS_QUERY_LIMITED_INFORMATION 訪問許可權。 如需詳細資訊,請參閱 處理安全性和訪問許可權。
// Windows Server 2003 和 Windows XP 句柄必須具有 PROCESS_QUERY_INFORMATION 訪問許可權。
return code == STILL_ACTIVE; return code == STILL_ACTIVE;
// auto process = AutoHandle(OpenProcess(SYNCHRONIZE, FALSE, pid)); // auto process = AutoHandle(OpenProcess(SYNCHRONIZE, FALSE, pid));
// DWORD ret = WaitForSingleObject(process, 0); // DWORD ret = WaitForSingleObject(process, 0);
@ -95,7 +97,9 @@ DECLARE bool Is64bit(DWORD pid)
GetNativeSystemInfo(&sysinfo); GetNativeSystemInfo(&sysinfo);
if (sysinfo.wProcessorArchitecture == 9 || sysinfo.wProcessorArchitecture == 6) if (sysinfo.wProcessorArchitecture == 9 || sysinfo.wProcessorArchitecture == 6)
{ {
auto hprocess = AutoHandle(OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid)); auto hprocess = AutoHandle(OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid));
// 進程的控制碼。 控制碼必須具有PROCESS_QUERY_INFORMATION或PROCESS_QUERY_LIMITED_INFORMATION存取權限。 如需詳細資訊,請參閱 處理安全性和存取權限。
// Windows Server 2003 和 Windows XP 控制碼必須具有PROCESS_QUERY_INFORMATION存取權限。
BOOL b; BOOL b;
IsWow64Process(hprocess, &b); IsWow64Process(hprocess, &b);
return !b; return !b;