This commit is contained in:
恍兮惚兮 2024-02-12 14:39:49 +08:00
parent 24cd9b7c04
commit 77d889a758
33 changed files with 638 additions and 221 deletions

View File

@ -147,14 +147,22 @@ class MAINUI() :
return ss
def textgetmethod(self,text,is_auto_run=True,embedcallback=None,onlytrans=False):
_autolock(self.solvegottextlock)
needclear=True
if onlytrans==False:
self.currentsignature=time.time()
if type(text)==str:
if text[:len('<notrans>')]=='<notrans>':
if text.startswith('<notrans>'):
self.translation_ui.displayres.emit('',globalconfig['rawtextcolor'],text[len('<notrans>'):],onlytrans)
self.currenttext=text
self.currentread=text
return
elif text.startswith('<msg_warning_with_text>'):
length=len('<msg_warning_with_text>')
idx=text.find('</msg_warning_with_text>')
warningtext=text[length:idx]
text=text[idx+length+1:]
self.translation_ui.displaystatus.emit(warningtext,'red',True,False)
needclear=False
else:
msgs=[
('<msg_info_not_refresh>',globalconfig['rawtextcolor'],False),
@ -226,11 +234,11 @@ class MAINUI() :
print_exc()
hira=[]
if globalconfig['refresh_on_get_trans']==False:
self.translation_ui.displayraw1.emit(hira,text,globalconfig['rawtextcolor'] ,onlytrans)
self.translation_ui.displayraw1.emit(hira,text,globalconfig['rawtextcolor'] ,onlytrans,needclear)
_showrawfunction=None
_showrawfunction_sig=0
else:
_showrawfunction=functools.partial(self.translation_ui.displayraw1.emit,hira,text,globalconfig['rawtextcolor'],onlytrans )
_showrawfunction=functools.partial(self.translation_ui.displayraw1.emit,hira,text,globalconfig['rawtextcolor'],onlytrans,needclear)
_showrawfunction_sig=time.time()
text_solved,optimization_params= self.solvebeforetrans(text)

View File

@ -1,5 +1,5 @@
from PyQt5.QtWidgets import QWidget,QDesktopWidget,QMainWindow,QLabel,QPushButton,QStatusBar,QDialog,QApplication
from PyQt5.QtGui import QBitmap,QPainter,QPen,QBrush,QFont,QMouseEvent,QCursor
from PyQt5.QtGui import QBitmap,QPainter,QPen,QColor,QFont,QMouseEvent,QCursor
from PyQt5.QtCore import Qt,QPoint,QRect,QEvent,pyqtSignal
import gobject
@ -64,10 +64,10 @@ class rangeselct(QMainWindow) :
super(rangeselct, self).__init__(parent)
self.setWindowFlags(Qt.FramelessWindowHint | Qt.Tool)#|Qt.WindowStaysOnTopHint )
self.rectlabel=QLabel(self)
self.setAttribute(Qt.WA_TranslucentBackground)
def reset(self):
self.setStyleSheet('''background-color:black; ''')
self.setWindowOpacity(globalconfig['OCR_mask_Opacity'])
num_screens = QDesktopWidget().screenCount()
x,y,x2,y2=9999,9999,0,0
for i in range(num_screens):
@ -77,14 +77,15 @@ class rangeselct(QMainWindow) :
x2=max(x2,_rect.x()+_rect.width())
y2=max(y2,_rect.y()+_rect.height())
self.setGeometry(x,y,x2-x,y2-y)
self.rectlabel.setGeometry(x,y,x2-x,y2-y)
self.setCursor(Qt.CrossCursor)
self.image=QApplication.primaryScreen().grabWindow(0,x,y,x2-x,y2-y)
self.is_drawing = False
self.setMouseTracking(True)
self.start_point = QPoint()
self.end_point = QPoint()
self.startauto=False
self.clickrelease=False
self.rectlabel.setStyleSheet(" border:%spx solid %s; background-color: rgba(0,0,0, 0.01)" %(globalconfig['ocrrangewidth'],globalconfig['ocrrangecolor'] ))
def immediateend(self):
try:
@ -98,20 +99,16 @@ class rangeselct(QMainWindow) :
if self.is_drawing:
pp = QPainter(self )
pen = QPen()
pen.setStyle(Qt.NoPen)
pen = QPen(QColor(globalconfig['ocrrangecolor']))
pen.setWidth(globalconfig['ocrrangewidth'])
pp.setPen(pen)
brush = QBrush(Qt.white)
pp.setBrush(brush)
#print(QRect(self.start_point, self.end_point),self.image.size())
#pp.drawRect(QRect(self.start_point, self.end_point))
_x1=self.start_point.x()
_y1=self.start_point.y()
_x2=self.end_point.x()
_y2=self.end_point.y()
_sp=QPoint(min(_x1,_x2),min(_y1,_y2))
_ep=QPoint(max(_x1,_x2),max(_y1,_y2))
pp.drawPixmap(QRect(_sp,_ep),self.image.copy(QRect(_sp,_ep)))
_sp=QPoint(min(_x1,_x2)-globalconfig['ocrrangewidth'],min(_y1,_y2)-globalconfig['ocrrangewidth'])
_ep=QPoint(max(_x1,_x2)+globalconfig['ocrrangewidth'],max(_y1,_y2)+globalconfig['ocrrangewidth'])
self.rectlabel.setGeometry(QRect(_sp,_ep))
def mousePressEvent(self, event) :
if event.button() == Qt.LeftButton:
if self.clickrelease:

View File

@ -31,7 +31,8 @@ def gethookgrid(self) :
[],
[('区分人名和文本',5),getsimpleswitch(globalconfig,'allow_set_text_name')],
[('使用YAPI注入',5),getsimpleswitch(globalconfig,'use_yapi')],
[],
[('获取最新提取器核心&错误反馈&游戏支持',8),(makehtml("https://github.com/HIllya51/LunaHook"),8,"link")]
]
return grids
@ -180,7 +181,7 @@ def setTabOne_direct(self) :
],
[
('HOOK',3),(getsimpleswitch(globalconfig['sourcestatus2']['texthook'],'use',name='texthook',parent=self,callback= functools.partial(yuitsu_switch,self,globalconfig['sourcestatus2'],'sourceswitchs','texthook',gobject.baseobject.starttextsource),pair='sourceswitchs'),1), '',
('Experimental',3),(getsimpleswitch(globalconfig['sourcestatus2']['fridahook'],'use',name='fridahook',parent=self,callback= functools.partial(yuitsu_switch,self,globalconfig['sourcestatus2'],'sourceswitchs','fridahook',gobject.baseobject.starttextsource),pair='sourceswitchs'),1),
('FridaScripts',3),(getsimpleswitch(globalconfig['sourcestatus2']['fridahook'],'use',name='fridahook',parent=self,callback= functools.partial(yuitsu_switch,self,globalconfig['sourcestatus2'],'sourceswitchs','fridahook',gobject.baseobject.starttextsource),pair='sourceswitchs'),1),
] ,
@ -205,7 +206,7 @@ def setTabOne_lazy(self) :
tab=self.makesubtab_lazy(['HOOK设置','OCR设置','剪贴板','内嵌翻译','Experimental'],
tab=self.makesubtab_lazy(['HOOK设置','OCR设置','剪贴板','内嵌翻译','FridaScripts'],
[
lambda:self.makescroll(self.makegrid(gethookgrid(self))),
lambda:self.makescroll(self.makegrid(getocrgrid(self))),

View File

@ -66,7 +66,6 @@ def getocrgrid(self) :
[(("选取OCR范围后立即进行一次识别"),12),getsimpleswitch(globalconfig ,'ocrafterrangeselect')],
[(("选取OCR范围后显示范围框"),12),getsimpleswitch(globalconfig ,'showrangeafterrangeselect')],
[(("OCR识别易错内容修正"),12),getsimpleswitch(ocrerrorfix ,'use'),getcolorbutton(globalconfig,'',callback= functools.partial( postconfigdialog,self,ocrerrorfix['args'],'OCR识别易错内容修正'),icon='fa.gear',constcolor="#FF69B4")],
[(("范围选取遮罩透明度"),12),(getspinbox(0.01,1,globalconfig ,'OCR_mask_Opacity',double=True,step=0.01,dec=2),4),],
]
return grids

View File

@ -206,63 +206,15 @@ def setTabThree_lazy(self) :
]
commonfsgrid=[
[('缩放方式',4),(getsimplecombobox(_TRL(['Magpie10','ALT+ENTER', 'SW_SHOWMAXIMIZED','LosslessScaling']),globalconfig,'fullscreenmethod_3'),6)]
[('缩放方式',4),(getsimplecombobox(_TRL(['Magpie','ALT+ENTER', 'SW_SHOWMAXIMIZED','LosslessScaling','Magpie10_External']),globalconfig,'fullscreenmethod_3'),6)]
]
sfm=getsimplecombobox(['宽高比','全屏'],globalconfig['lossless'],'scalingFitMode')
sf=getspinbox(1,10,globalconfig['lossless'],'scaleFactor',double=True,step=0.1,dec=1)
rbs=getsimpleswitch(globalconfig['lossless'],'resizeBeforeScale')
wm=getsimpleswitch(globalconfig['lossless'],'windowedMode')
def setenables():
sfm.setEnabled(globalconfig['lossless']['scalingMode']==0)
sf.setEnabled(globalconfig['lossless']['scalingMode']==1)
rbs.setEnabled(globalconfig['lossless']['scalingMode']==1)
wm.setEnabled(globalconfig['lossless']['scalingMode']==1)
sharp=getspinbox(0,10,globalconfig['lossless'],'sharpness')
sub1=getsimpleswitch(globalconfig['lossless'],'scalingSubtype1',callback=lambda _:setsubtype())
sub2=getsimplecombobox(['','','','非常大','极大'],globalconfig['lossless'],'scalingSubtype2',callback=lambda _:setsubtype())
sub3=getsimpleswitch(globalconfig['lossless'],'scalingSubtype3',callback=lambda _:setsubtype())
vrs=getsimpleswitch(globalconfig['lossless'],'VRS')
def setsubtype():
vrs.setEnabled( globalconfig['lossless']['scalingType'] in [6])
sharp.setEnabled( globalconfig['lossless']['scalingType'] in [1,2,8,9])
sub1.setEnabled( globalconfig['lossless']['scalingType'] in [1])
sub2.setEnabled( globalconfig['lossless']['scalingType'] in [6])
sub3.setEnabled( globalconfig['lossless']['scalingType'] in [8])
if globalconfig['lossless']['scalingType']==1:
globalconfig['lossless']['scalingSubtype']=int(globalconfig['lossless']['scalingSubtype1'])
elif globalconfig['lossless']['scalingType']==6:
globalconfig['lossless']['scalingSubtype']=globalconfig['lossless']['scalingSubtype2']
elif globalconfig['lossless']['scalingType']==8:
globalconfig['lossless']['scalingSubtype']=int(globalconfig['lossless']['scalingSubtype3'])
setenables()
setsubtype()
losslessgrid=[
[('Magpie10_路径',4),(getcolorbutton(globalconfig,'',callback=lambda x: getsomepath1(self,'Magpie10_路径',globalconfig,'magpie10path','Magpie10_路径',isdir=True),icon='fa.gear',constcolor="#FF69B4"),1)],
[('Hook Magpie进程使其不会退出缩放',4),getsimpleswitch(globalconfig,'hookmagpie')],
[],
[('LosslessScaling_路径',4),(getcolorbutton(globalconfig,'',callback=lambda x: getsomepath1(self,'LosslessScaling_路径',globalconfig['lossless'],'path','LosslessScaling_路径',isdir=True),icon='fa.gear',constcolor="#FF69B4"),1)],
[('缩放模式',4),(getsimplecombobox(['自动','自定义'],globalconfig['lossless'],'scalingMode',lambda _: setenables()),6),''],
[('',4),(sfm,6)],
[('',4),('缩放系数',4),(sf,2)],
[('',4),('缩放前调整大小',4),(rbs,2)],
[('',4),('视窗模式',4),(wm,2)],
[('缩放类型',4),(getsimplecombobox(['Off','AMD FSR','NVIDIA Image Scaling','整数缩放','近邻缩放','xBR','Anime4K','锐化双线性','LS1','Bicubic CAS'],globalconfig['lossless'],'scalingType',callback=lambda _:setsubtype()),6)],
[('',4),('锐度',4),(sharp,2)],
[('',4),('优化版本',4),(sub1,2)],
[('',4),('尺寸',4),(sub2,2)],
[('',4),('性能',4),(sub3,2)],
[('',4),('VRS',4),(vrs,2)],
[('Frame Generation',4),(getsimplecombobox(['Off','LSFI'],globalconfig['lossless'],'frameGeneration'),6)],
[('光标选项',4)],
[('',4),('固定光标',4),(getsimpleswitch(globalconfig['lossless'],'clipCursor'),2)],
[('',4),('调整光标速度',4),(getsimpleswitch(globalconfig['lossless'],'cursorSensitivity'),2)],
[('',4),('隐藏光标',4),(getsimpleswitch(globalconfig['lossless'],'hideCursor'),2)],
[('',4),('缩放光标',4),(getsimpleswitch(globalconfig['lossless'],'scaleCursor'),2)],
[('渲染选项',4)],
[('',4),('Sycn Interval',4),(getspinbox(0,4,globalconfig['lossless'],'syncInterval'),2)],
[('',4),('双缓冲',4),(getsimpleswitch(globalconfig['lossless'],'doubleBuffering'),2)],
[('',4),('VRR支持',4),(getsimpleswitch(globalconfig['lossless'],'vrrSupport'),2)],
[('',4),('HDR支持',4),(getsimpleswitch(globalconfig['lossless'],'hdrSupport'),2)],
[('',4),('允许撕裂',4),(getsimpleswitch(globalconfig['lossless'],'allowTearing'),2)],
[('',4),('传统捕获API',4),(getsimpleswitch(globalconfig['lossless'],'legacyCaptureApi'),2)],
[('',4),('绘制帧率',4),(getsimpleswitch(globalconfig['lossless'],'drawFps'),2)],
[('Hook LosslessScaling进程使其不会退出缩放',4),getsimpleswitch(globalconfig,'hooklossless')],
]
tab=self.makesubtab_lazy(['文本设置', '界面设置','窗口缩放'],[
lambda:self.makescroll(self.makegrid(textgrid ) ),
@ -270,7 +222,7 @@ def setTabThree_lazy(self) :
lambda:self.makevbox(
[
self.makegrid(commonfsgrid ),
self.makesubtab_lazy(['Magpie10','LosslessScaling'],[
self.makesubtab_lazy(['Magpie','外部缩放软件'],[
lambda:self.makescroll(self.makegrid(innermagpie ) ),
lambda:self.makescroll(self.makegrid(losslessgrid ) )

View File

@ -29,7 +29,7 @@ from gui.usefulwidget import resizableframeless
from gui.dialog_savedgame import browserdialog
class QUnFrameWindow(resizableframeless):
displayres = pyqtSignal(str,str,str ,bool)
displayraw1 = pyqtSignal(list, str,str,bool )
displayraw1 = pyqtSignal(list, str,str,bool,bool)
displaystatus=pyqtSignal(str,str,bool,bool)
showhideuisignal=pyqtSignal()
hookfollowsignal=pyqtSignal(int,tuple)
@ -92,7 +92,7 @@ class QUnFrameWindow(resizableframeless):
except:
print_exc()
def showraw(self,hira,res,color ,onlyshowhist):
def showraw(self,hira,res,color ,onlyshowhist,clear):
#print(res,onlyshowhist)
gobject.baseobject.transhis.getnewsentencesignal.emit(res)
if onlyshowhist:
@ -102,11 +102,11 @@ class QUnFrameWindow(resizableframeless):
else:
_res=res
if globalconfig['isshowhira'] and globalconfig['isshowrawtext']:
self.showline(True,[hira,_res],color , 2 )
self.showline(clear,[hira,_res],color , 2 )
elif globalconfig['isshowrawtext']:
self.showline(True,[hira,_res],color,1)
self.showline(clear,[hira,_res],color,1)
else:
self.showline(True,None,None,1)
self.showline(clear,None,None,1)
gobject.baseobject.edittextui.getnewsentencesignal.emit(res)
def showstatus(self,res,color,clear,origin):

View File

@ -1,11 +1,12 @@
import os,json,math
import windows
from myutils.config import globalconfig ,magpie10_config
from myutils.hwnd import letfullscreen,recoverwindow,pid_running
from myutils.hwnd import letfullscreen,recoverwindow,ListProcess,injectdll
from traceback import print_exc
from myutils.subproc import subproc_w
import time,threading
import time,subprocess
from myutils.wrapper import threader
import re
class fullscreen():
def __init__(self,_externalfsend) -> None:
self.savewindowstatus=None
@ -17,93 +18,160 @@ class fullscreen():
self.__call__(self.lasthwnd,not self.status)
@property
def fsmethod(self):return globalconfig['fullscreenmethod_3']
# def runmagpie10(self):
# exes=[_[1] for _ in ListProcess()]
# if os.path.join(globalconfig['magpie10path'],'Magpie.exe').replace('/','\\') not in exes:
# subproc_w(os.path.join(globalconfig['magpie10path'],'Magpie.exe'),cwd=globalconfig['magpie10path'] ,name='magpie10' )
# def _1(self,hwnd,full):
# self.runmagpie10()
# windows.SetForegroundWindow(hwnd )
# time.sleep(0.1)
# configpath=os.path.join(globalconfig['magpie10path'],'config/config.json')
# if os.path.exists(configpath)==False:
# configpath=os.path.join(os.environ['LOCALAPPDATA'],'Magpie/config/config.json')
# if os.path.exists(configpath)==False:
# return
# with open(configpath,'r',encoding='utf8') as ff:
# config=json.load(ff)
# shortcuts=config['shortcuts']['scale']
# mp1={'SHIFT': 16, 'WIN': 91,'CTRL': 17,'ALT': 18}
# mp={
# 0x100:'WIN',
# 0x200:'CTRL',
# 0x400:'ALT',
# 0x800:'SHIFT'
# }
# for k in mp:
# if shortcuts&k !=0:
# windows.keybd_event(mp1[mp[k]],0,0,0)
# k2=shortcuts &0xff
# windows.keybd_event(k2,0,0,0)
# windows.keybd_event(k2, 0, windows.KEYEVENTF_KEYUP, 0)
# for k in mp:
# if shortcuts&k !=0:
# windows.keybd_event(mp1[mp[k]],0,windows.KEYEVENTF_KEYUP,0)
def _4(self,hwnd,full):
if full:
self.engine= subproc_w(r'./files/plugins/shareddllproxy64.exe lossless "{}" "{}" {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {}'.format(globalconfig['lossless']['path'],hwnd,
globalconfig['lossless']['scalingMode'],
globalconfig['lossless']['scalingFitMode'],
globalconfig['lossless']['scalingType'],
globalconfig['lossless']['scalingSubtype'],
globalconfig['lossless']['scaleFactor'],
globalconfig['lossless']['resizeBeforeScale'],
globalconfig['lossless']['windowedMode'],
globalconfig['lossless']['sharpness'],
globalconfig['lossless']['VRS'],
globalconfig['lossless']['clipCursor'],
globalconfig['lossless']['cursorSensitivity'],
globalconfig['lossless']['hideCursor'],
globalconfig['lossless']['scaleCursor'],
globalconfig['lossless']['doubleBuffering'],
globalconfig['lossless']['vrrSupport'],
globalconfig['lossless']['hdrSupport'],
globalconfig['lossless']['allowTearing'],
globalconfig['lossless']['legacyCaptureApi'],
globalconfig['lossless']['drawFps'],
globalconfig['lossless']['gpuId'],
globalconfig['lossless']['displayId'],
globalconfig['lossless']['captureOffsetLeft'],
globalconfig['lossless']['captureOffsetTop'],
globalconfig['lossless']['captureOffsetRight'],
globalconfig['lossless']['captureOffsetBottom'],
globalconfig['lossless']['multiDisplayMode'],
os.getpid(),
globalconfig['lossless']['frameGeneration'],
globalconfig['lossless']['syncInterval']),cwd=globalconfig['lossless']['path'])
self._waitenginestop()
else:
endevent =windows.AutoHandle(windows.CreateEvent(False, False,'LOSSLESS_WAITFOR_STOP_SIGNAL'+str(self.engine.pid)))
windows.SetEvent(endevent)
def _waitenginestop(self):
def _waitexternalend():
#self.engine.wait()
while pid_running(self.engine.pid):
time.sleep(0.5)
def internal_stopped(self):
self._externalfsend()
self.status=False
threading.Thread(target=_waitexternalend ).start()
@threader
def _wait_lossless_stop_external(self):
while windows.FindWindow("LosslessScaling",None)==0:
time.sleep(0.5)
while windows.FindWindow("LosslessScaling",None):
time.sleep(0.5)
self.internal_stopped()
def runlossless(self):
exes=[_[1] for _ in ListProcess()]
path=globalconfig['lossless']['path']
pexe=os.path.join(path,'LosslessScaling.exe')
if pexe.replace('/','\\') not in exes:
subproc_w(pexe,cwd=path ,name='LosslessScaling' )
time.sleep(1)
if globalconfig['hooklossless']:
for pid,exe in ListProcess():
if exe==pexe.replace('/','\\'):
dll=os.path.abspath('./files/plugins/hookmagpie.dll')
injecter=os.path.abspath('./files/plugins/shareddllproxy{}.exe'.format('64'))
injectdll(pid,injecter,dll)
break
def _external_lossless(self,hwnd,full):
if full:
self.runlossless()
#self._wait_lossless_stop_external()
windows.SetForegroundWindow(hwnd )
time.sleep(0.1)
configpath=os.path.join(os.environ['LOCALAPPDATA'],'Lossless Scaling/Settings.xml')
if os.path.exists(configpath)==False:
return
with open(configpath,'r',encoding='utf8') as ff:
config=ff.read()
Hotkey=re.findall('<Hotkey>(.*?)</Hotkey>',config)[0]
hotkHotkeyModifierKeysey=re.findall('<HotkeyModifierKeys>(.*?)</HotkeyModifierKeys>',config)[0]
mods=hotkHotkeyModifierKeysey.split(' ')
vkcode=windows.MapVirtualKey(Hotkey)
mp1={'Shift': 16, 'Windows': 91,'Control': 17,'Alt': 18}
for k in mods:
windows.keybd_event(mp1[k],0,0,0)
windows.keybd_event(vkcode,0,0,0)
windows.keybd_event(vkcode, 0, windows.KEYEVENTF_KEYUP, 0)
for k in mods:
windows.keybd_event(mp1[k],0, windows.KEYEVENTF_KEYUP,0)
def runmagpie10(self):
if windows.FindWindow('Magpie_Hotkey',None)==0:
subproc_w(os.path.join(globalconfig['magpie10path'],'Magpie.exe'),cwd=globalconfig['magpie10path'] ,name='magpie10' )
while windows.FindWindow('Magpie_Hotkey',None)==0:
time.sleep(0.5)
if globalconfig['hookmagpie']:
pid=windows.GetWindowThreadProcessId(windows.FindWindow('Magpie_Hotkey',None))
dll=os.path.abspath('./files/plugins/hookmagpie.dll')
injecter=os.path.abspath('./files/plugins/shareddllproxy{}.exe'.format('64'))
injectdll([pid],injecter,dll)
@threader
def _wait_magpie_stop_external(self):
while windows.FindWindow("Window_Magpie_967EB565-6F73-4E94-AE53-00CC42592A22",None)==0:
time.sleep(0.5)
while windows.FindWindow("Window_Magpie_967EB565-6F73-4E94-AE53-00CC42592A22",None):
time.sleep(0.5)
self.internal_stopped()
def _external_magpie10(self,hwnd,full):
configpath=os.path.join(globalconfig['magpie10path'],'config/config.json')
if os.path.exists(configpath)==False:
configpath=os.path.join(os.environ['LOCALAPPDATA'],'Magpie/config/config.json')
if os.path.exists(configpath)==False:
return
with open(configpath,'r',encoding='utf8') as ff:
config=json.load(ff)
autoRestore=config['autoRestore']
shortcuts=config['shortcuts']['scale']
mp1={'SHIFT': 16, 'WIN': 91,'CTRL': 17,'ALT': 18}
mp={
0x100:'WIN',
0x200:'CTRL',
0x400:'ALT',
0x800:'SHIFT'
}
if full:
self.runmagpie10()
if autoRestore==False:
self._wait_magpie_stop_external()
windows.SetForegroundWindow(hwnd )
time.sleep(0.1)
for k in mp:
if shortcuts&k !=0:
windows.keybd_event(mp1[mp[k]],0,0,0)
k2=shortcuts &0xff
windows.keybd_event(k2,0,0,0)
windows.keybd_event(k2, 0, windows.KEYEVENTF_KEYUP, 0)
for k in mp:
if shortcuts&k !=0:
windows.keybd_event(mp1[mp[k]],0,windows.KEYEVENTF_KEYUP,0)
# def _4(self,hwnd,full):
# if full:
# self.engine= subproc_w(r'./files/plugins/shareddllproxy64.exe lossless "{}" "{}" {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {}'.format(globalconfig['lossless']['path'],hwnd,
# globalconfig['lossless']['scalingMode'],
# globalconfig['lossless']['scalingFitMode'],
# globalconfig['lossless']['scalingType'],
# globalconfig['lossless']['scalingSubtype'],
# globalconfig['lossless']['scaleFactor'],
# globalconfig['lossless']['resizeBeforeScale'],
# globalconfig['lossless']['windowedMode'],
# globalconfig['lossless']['sharpness'],
# globalconfig['lossless']['VRS'],
# globalconfig['lossless']['clipCursor'],
# globalconfig['lossless']['cursorSensitivity'],
# globalconfig['lossless']['hideCursor'],
# globalconfig['lossless']['scaleCursor'],
# globalconfig['lossless']['doubleBuffering'],
# globalconfig['lossless']['vrrSupport'],
# globalconfig['lossless']['hdrSupport'],
# globalconfig['lossless']['allowTearing'],
# globalconfig['lossless']['legacyCaptureApi'],
# globalconfig['lossless']['drawFps'],
# globalconfig['lossless']['gpuId'],
# globalconfig['lossless']['displayId'],
# globalconfig['lossless']['captureOffsetLeft'],
# globalconfig['lossless']['captureOffsetTop'],
# globalconfig['lossless']['captureOffsetRight'],
# globalconfig['lossless']['captureOffsetBottom'],
# globalconfig['lossless']['multiDisplayMode'],
# os.getpid(),
# globalconfig['lossless']['frameGeneration'],
# globalconfig['lossless']['syncInterval']),cwd=globalconfig['lossless']['path'])
# self._waitenginestop()
# else:
# endevent =windows.AutoHandle(windows.CreateEvent(False, False,'LOSSLESS_WAITFOR_STOP_SIGNAL'+str(self.engine.pid)))
# windows.SetEvent(endevent)
@threader
def _waitenginestop_magpie(self):
self.engine.wait()
self._externalfsend()
self.status=False
def _0(self,hwnd,full):
self.internal_stopped()
def _magpie_builtin(self,hwnd,full):
if full:
profiles_index=globalconfig['profiles_index']
if profiles_index>len(magpie10_config['profiles']):
@ -128,25 +196,27 @@ class fullscreen():
# return
# WM_DESTORYHOST=RegisterWindowMessage( "MAGPIE_WM_DESTORYHOST")
# SendMessage(hwnd, WM_DESTORYHOST)
def _2(self,hwnd,full):
def _alt_enter(self,hwnd,full):
windows.SetForegroundWindow(hwnd )
windows.keybd_event(18,0,0,0) # alt
windows.keybd_event(13,0,0,0) # enter
windows.keybd_event(13, 0, windows.KEYEVENTF_KEYUP, 0)
windows.keybd_event(18, 0, windows.KEYEVENTF_KEYUP, 0)
def _3(self,hwnd,full):
def _SW_SHOWMAXIMIZED(self,hwnd,full):
if full:
self.savewindowstatus=letfullscreen(hwnd)
else:
recoverwindow(hwnd,self.savewindowstatus)
@threader
def __call__(self, hwnd=0,full=False):
try:
[
self._0,
self._2,
self._3,
self._4
self._magpie_builtin,
self._alt_enter,
self._SW_SHOWMAXIMIZED,
self._external_lossless,
self._external_magpie10
][self.fsmethod](hwnd,full)
self.status=full
self.lasthwnd=hwnd

View File

@ -3,7 +3,7 @@ import threading
from PyQt5.QtGui import QPixmap,QColor ,QIcon
from PyQt5.QtWidgets import QApplication
import gobject
import os
import os,subprocess
import time,winrtutils,winsharedutils,hashlib
from myutils.wrapper import threader
def pid_running(pid):
@ -200,7 +200,14 @@ def getScreenRate() :
windows.ReleaseDC(None, hDC);
__rate = round(dpiX, 2)
return __rate
def injectdll(injectpids,injecter,dll):
pid=' '.join([str(_) for _ in injectpids])
if any(map(testprivilege,injectpids))==False:
windows.ShellExecute(0,'runas',injecter,'dllinject {} "{}"'.format(pid,dll),None,windows.SW_HIDE)
else:
ret=subprocess.run('"{}" dllinject {} "{}"'.format(injecter,pid,dll)).returncode
if(ret==0):
windows.ShellExecute(0,'runas',injecter,'dllinject {} "{}"'.format(pid,dll),None,windows.SW_HIDE)
def mouseselectwindow(callback):

View File

@ -2,8 +2,6 @@ import os
from myutils.config import globalconfig,_TR,static_data
import requests
import base64
from ocrengines.baseocrclass import baseocr
from ctypes import CDLL,c_char_p ,create_string_buffer,c_uint32,POINTER,c_int32
import os
@ -54,14 +52,27 @@ class OCR(baseocr):
def initocr(self):
self._ocr=ocrwrapper()
self._savelang=None
self.isusingjaasen=False
self.checkchange()
def checkchange(self):
if self._savelang==self.srclang:
return
self.isusingjaasen=False
self._ocr.trydestroy()
path='./files/ocr/{}'.format(static_data["language_list_translator_inner"][globalconfig["srclang3"]])
innerlang=static_data["language_list_translator_inner"][globalconfig["srclang3"]]
path='./files/ocr/{}'.format(innerlang)
failed=False
if not(os.path.exists(path+'/det.onnx') and os.path.exists(path+'/rec.onnx') and os.path.exists(path+'/dict.txt') ):
failed=True
if(innerlang=='en'):
path2='./files/ocr/{}'.format('ja')
if (os.path.exists(path2+'/det.onnx') and os.path.exists(path2+'/rec.onnx') and os.path.exists(path2+'/dict.txt') ):
path=path2
failed=False
self.isusingjaasen=True
if failed:
raise Exception(_TR('未下载该语言的OCR模型,请从软件主页下载模型解压到files/ocr路径后使用') )
self._ocr.init(path+'/det.onnx',path+'/rec.onnx',path+'/dict.txt')
self._savelang=self.srclang
@ -78,4 +89,7 @@ class OCR(baseocr):
box.append([int(_) for _ in ls[i*2].split(',')])
text.append(ls[i*2+1])
return self.common_solve_text_orientation(box,text)
res=self.common_solve_text_orientation(box,text)
if self.isusingjaasen:
res='<msg_warning_with_text>'+_TR('找不到英语识别模型,正在使用日语模型作为代替,可能效果不佳')+'</msg_warning_with_text>'+res
return res

View File

@ -8,7 +8,7 @@ import windows,subprocess
from myutils.config import globalconfig ,savehook_new_data ,_TR,static_data
from textsource.textsourcebase import basetext
from myutils.utils import checkchaos
from myutils.hwnd import testprivilege
from myutils.hwnd import testprivilege,injectdll
from myutils.wrapper import threader
from ctypes import CDLL,c_bool,POINTER,Structure,c_int,pointer,c_wchar_p,c_uint64,sizeof,c_void_p,cast,c_wchar,c_uint32,c_uint8,c_uint,c_char,c_short
from ctypes.wintypes import DWORD,LPCWSTR,HANDLE
@ -158,13 +158,7 @@ class texthook(basetext ):
print(injecter,os.path.exists(injecter))
print(dll,os.path.exists(dll))
#subprocess.Popen('"{}" dllinject {} "{}"'.format(injecter,pid,dll))
pid=' '.join([str(_) for _ in injectpids])
if any(map(testprivilege,injectpids))==False:
windows.ShellExecute(0,'runas',injecter,'dllinject {} "{}"'.format(pid,dll),None,windows.SW_HIDE)
else:
ret=subprocess.run('"{}" dllinject {} "{}"'.format(injecter,pid,dll)).returncode
if(ret==0):
windows.ShellExecute(0,'runas',injecter,'dllinject {} "{}"'.format(pid,dll),None,windows.SW_HIDE)
injectdll(injectpids,injecter,dll)
@threader
def onprocconnect(self,pid):
self.connectedpids.append(pid)

View File

@ -3,7 +3,7 @@ from ctypes import c_int,POINTER,pointer,c_uint,windll,c_char_p,create_unicode_
from ctypes import Structure,c_int,POINTER,c_uint,WINFUNCTYPE,c_void_p,sizeof,byref
import ctypes
from traceback import print_exc
from ctypes.wintypes import RECT,POINT,HWND,BOOL,WORD,DWORD,BYTE ,LPCWSTR,HANDLE
from ctypes.wintypes import RECT,POINT,HWND,BOOL,WORD,DWORD,BYTE ,LPCWSTR,HANDLE,UINT
WAIT_TIMEOUT = 258
SW_HIDE = 0
@ -749,3 +749,11 @@ class AutoHandle(HANDLE):
_MapVirtualKey=_user32.MapVirtualKeyW
_MapVirtualKey.argtypes=UINT,UINT
_MapVirtualKey.restype=UINT
MAPVK_VK_TO_VSC=0
MAPVK_VSC_TO_VK=1
MAPVK_VK_TO_CHAR=2
def MapVirtualKey(char,uMapType=MAPVK_VK_TO_CHAR):
return _MapVirtualKey(ord(char),uMapType)

View File

@ -12,6 +12,8 @@
"read_translator": 0,
"disappear_delay": 5,
"network":0,
"hookmagpie":true,
"hooklossless":true,
"direct_filterrepeat":false,
"allow_set_text_name":false,
"embedded": {
@ -94,7 +96,6 @@
500,
500
],
"OCR_mask_Opacity":0.5,
"ocr_stable_sim": 0,
"ocr_diff_sim": 0.95,
"autorun": true,

View File

@ -1,5 +1,5 @@
{
"version":"v2.36.4",
"version":"v2.36.5",
"language_list_show":["简体中文","日本語","English","Русский язык","Español","한국어","Français","繁體中文","Tiếng Việt","Türkçe","Polski","Українська Мова","Italiano","اللغة العربية","ภาษาไทย"] ,
"language_list_translator":["简体中文","日文","英文","俄语","西班牙语","韩语","法语","繁体中文","越南语","土耳其语","波兰语","乌克兰语","意大利语","阿拉伯语","泰语"],
"language_list_translator_inner":["zh", "ja", "en","ru","es","ko","fr","cht","vi","tr","pl","uk","it","ar","th"],
@ -277,7 +277,8 @@
"./files/plugins/LunaHook/LunaHook32.dll",
"./files/plugins/LunaHook/LunaHook64.dll",
"./files/plugins/LoaderDll.dll",
"./files/plugins/LocaleEmulator.dll"
"./files/plugins/LocaleEmulator.dll",
"./files/plugins/hookmagpie.dll"
],
"64":[
"./files/plugins/DLL64/winsharedutils64.dll",

View File

@ -662,7 +662,6 @@
"Sakura部署教程": "ساكورا نشر البرنامج التعليمي",
"Github仓库": "مستودع جيتوب",
"利用上文信息翻译(通常会有一定的效果提升,但会导致变慢)": "استخدام المعلومات الواردة أعلاه في الترجمة ( عادة ما يكون هناك بعض التحسن ، ولكن يمكن أن يؤدي إلى إبطاء )",
"范围选取遮罩透明度": "مجموعة اختيار قناع الشفافية",
"文本缓冲区长度": "نص طول المخزن المؤقت",
"显示/隐藏历史翻译和调试输出": "عرض / إخفاء تاريخ الترجمة وتصحيح الأخطاء الناتج",
"历史翻译和调试输出": "تاريخ الترجمة وتصحيح الأخطاء الناتج",
@ -701,5 +700,10 @@
"语言自适应": "التكيف اللغوي",
"去除重复字符": "إزالة الأحرف المكررة",
"游戏内叠加层": "لعبة التراص الداخلي",
"内联效果参数": "مضمنة تأثير المعلمة"
"内联效果参数": "مضمنة تأثير المعلمة",
"获取最新提取器核心&错误反馈&游戏支持": "الحصول على أحدث المستخلص الأساسية و ردود فعل خاطئة و دعم اللعبة",
"外部缩放软件": "برامج التكبير الخارجي",
"Hook Magpie进程使其不会退出缩放": "هوك ماجي العملية بحيث لا تخرج من التكبير",
"Hook LosslessScaling进程使其不会退出缩放": "هوك looslessscaling العملية بحيث لا تخرج من التكبير",
"找不到英语识别模型,正在使用日语模型作为代替,可能效果不佳": "لا يمكن العثور على نموذج التعرف على اللغة الإنجليزية ، واستخدام نموذج اليابانية بدلا من ذلك ، قد لا تعمل بشكل جيد"
}

View File

@ -662,7 +662,6 @@
"Sakura部署教程": "Sakura部署教程",
"Github仓库": "Github倉庫",
"利用上文信息翻译(通常会有一定的效果提升,但会导致变慢)": "利用上文資訊翻譯(通常會有一定的效果提升,但會導致變慢)",
"范围选取遮罩透明度": "範圍選取遮罩透明度",
"文本缓冲区长度": "文字緩衝區長度",
"显示/隐藏历史翻译和调试输出": "顯示/隱藏歷史翻譯和調試輸出",
"历史翻译和调试输出": "歷史翻譯和調試輸出",
@ -701,5 +700,10 @@
"语言自适应": "語言自我調整",
"去除重复字符": "去除重複字元",
"游戏内叠加层": "遊戲內疊加層",
"内联效果参数": "內聯效果參數"
"内联效果参数": "內聯效果參數",
"获取最新提取器核心&错误反馈&游戏支持": "獲取最新提取器覈心&錯誤迴響&遊戲支持",
"外部缩放软件": "外部縮放軟件",
"Hook Magpie进程使其不会退出缩放": "Hook Magpie行程使其不會退出縮放",
"Hook LosslessScaling进程使其不会退出缩放": "Hook LosslessScaling行程使其不會退出縮放",
"找不到英语识别模型,正在使用日语模型作为代替,可能效果不佳": "找不到英語識別模型,正在使用日語模型作為代替,可能效果不佳"
}

View File

@ -662,7 +662,6 @@
"Sakura部署教程": "Sakura Deployment Tutorial",
"Github仓库": "Github warehouse",
"利用上文信息翻译(通常会有一定的效果提升,但会导致变慢)": "Translate using the information provided in the previous text (usually with some improvement in effectiveness, but it can lead to slower translation)",
"范围选取遮罩透明度": "Range selection mask transparency",
"文本缓冲区长度": "Text buffer length",
"显示/隐藏历史翻译和调试输出": "Show/hide historical translation and debugging output",
"历史翻译和调试输出": "Historical translation and debugging output",
@ -701,5 +700,10 @@
"语言自适应": "Language Adaptation",
"去除重复字符": "Remove duplicate characters",
"游戏内叠加层": "In-game overlay layer",
"内联效果参数": "Inline effect parameters"
"内联效果参数": "Inline effect parameters",
"获取最新提取器核心&错误反馈&游戏支持": "Get the latest extractor core&error feedback&game support",
"外部缩放软件": "External scaling software",
"Hook Magpie进程使其不会退出缩放": "Hook Magpie process prevents it from exiting scaling",
"Hook LosslessScaling进程使其不会退出缩放": "Hook LosslessScaling process prevents it from exiting scaling",
"找不到英语识别模型,正在使用日语模型作为代替,可能效果不佳": "Unable to find English recognition model, using Japanese model as a substitute, may not be effective"
}

View File

@ -662,7 +662,6 @@
"Sakura部署教程": "Guía de despliegue Sakura",
"Github仓库": "Almacén github",
"利用上文信息翻译(通常会有一定的效果提升,但会导致变慢)": "Traducción utilizando la información anterior (generalmente tiene un cierto efecto de mejora, pero puede causar lentitud)",
"范围选取遮罩透明度": "Transparencia de la máscara de selección de alcance",
"文本缓冲区长度": "Longitud del colchón de texto",
"显示/隐藏历史翻译和调试输出": "Mostrar / ocultar la traducción histórica y depurar la salida",
"历史翻译和调试输出": "Traducción histórica y salida de depuración",
@ -701,5 +700,10 @@
"语言自适应": "Adaptación lingüística",
"去除重复字符": "Eliminar caracteres duplicados",
"游戏内叠加层": "Capa superpuesta en el juego",
"内联效果参数": "Parámetros de efecto en línea"
"内联效果参数": "Parámetros de efecto en línea",
"获取最新提取器核心&错误反馈&游戏支持": "Obtener el último núcleo del extractor & comentarios erróneos & soporte del juego",
"外部缩放软件": "Software de zoom externo",
"Hook Magpie进程使其不会退出缩放": "El proceso Hook magpie hace que no salga del zoom",
"Hook LosslessScaling进程使其不会退出缩放": "El proceso Hook losslessscaling hace que no salga del zoom",
"找不到英语识别模型,正在使用日语模型作为代替,可能效果不佳": "No se puede encontrar el modelo de reconocimiento inglés, se está utilizando el modelo japonés como sustituto y puede no funcionar bien."
}

View File

@ -662,7 +662,6 @@
"Sakura部署教程": "Tutoriel de déploiement Sakura",
"Github仓库": "Entrepôt github",
"利用上文信息翻译(通常会有一定的效果提升,但会导致变慢)": "Utilisez les informations ci - dessus pour traduire (il y a généralement une certaine augmentation de l'effet, mais cela entraîne un ralentissement)",
"范围选取遮罩透明度": "Gamme sélectionner masque transparence",
"文本缓冲区长度": "Longueur du tampon de texte",
"显示/隐藏历史翻译和调试输出": "Afficher / masquer la traduction historique et la sortie de débogage",
"历史翻译和调试输出": "Traduction historique et sortie de débogage",
@ -701,5 +700,10 @@
"语言自适应": "Adaptation linguistique",
"去除重复字符": "Supprimer les caractères dupliqués",
"游戏内叠加层": "Couches superposées dans le jeu",
"内联效果参数": "Paramètres d'effet inline"
"内联效果参数": "Paramètres d'effet inline",
"获取最新提取器核心&错误反馈&游戏支持": "Obtenez le dernier extractor Core & BUG Feedback & Game support",
"外部缩放软件": "Logiciel de zoom externe",
"Hook Magpie进程使其不会退出缩放": "Le processus Hook Magpie ne quitte pas le zoom",
"Hook LosslessScaling进程使其不会退出缩放": "Hook losslesscaling processus pour ne pas quitter le zoom",
"找不到英语识别模型,正在使用日语模型作为代替,可能效果不佳": "Impossible de trouver le modèle de reconnaissance anglais, le modèle japonais est utilisé à la place, peut ne pas fonctionner correctement"
}

View File

@ -662,7 +662,6 @@
"Sakura部署教程": "Tutorial sull'implementazione di Sakura",
"Github仓库": "Magazzino Github",
"利用上文信息翻译(通常会有一定的效果提升,但会导致变慢)": "Tradurre utilizzando le informazioni fornite nel testo precedente (di solito con qualche miglioramento in efficacia, ma può portare a una traduzione più lenta)",
"范围选取遮罩透明度": "Trasparenza maschera di selezione intervallo",
"文本缓冲区长度": "Lunghezza buffer di testo",
"显示/隐藏历史翻译和调试输出": "Mostra/nasconde l'output storico di traduzione e debug",
"历史翻译和调试输出": "Risultato storico di traduzione e debug",
@ -701,5 +700,10 @@
"语言自适应": "Adattamento linguistico",
"去除重复字符": "Rimuovi caratteri duplicati",
"游戏内叠加层": "Livello di sovrapposizione in gioco",
"内联效果参数": "Parametri degli effetti in linea"
"内联效果参数": "Parametri degli effetti in linea",
"获取最新提取器核心&错误反馈&游戏支持": "Ottieni l'ultimo core&error feedback & supporto al gioco dell'estrattore",
"外部缩放软件": "Software di ridimensionamento esterno",
"Hook Magpie进程使其不会退出缩放": "Il processo Hook Magpie impedisce di uscire dalla scala",
"Hook LosslessScaling进程使其不会退出缩放": "Hook LosslessScaling processo impedisce di uscire dalla scalabilità",
"找不到英语识别模型,正在使用日语模型作为代替,可能效果不佳": "Impossibile trovare il modello di riconoscimento inglese, utilizzando il modello giapponese come sostituto, potrebbe non essere efficace"
}

View File

@ -662,7 +662,6 @@
"Sakura部署教程": "Sakura導入チュートリアル",
"Github仓库": "Github倉庫",
"利用上文信息翻译(通常会有一定的效果提升,但会导致变慢)": "上記の情報翻訳を利用する(通常は一定の効果が上がるが、遅くなる)",
"范围选取遮罩透明度": "範囲選択マスクの透明度",
"文本缓冲区长度": "テキストバッファ長",
"显示/隐藏历史翻译和调试输出": "履歴翻訳とデバッグ出力の表示/非表示",
"历史翻译和调试输出": "履歴翻訳とデバッグ出力",
@ -701,5 +700,10 @@
"语言自适应": "げんごてきおう",
"去除重复字符": "繰り返し文字を削除",
"游戏内叠加层": "ゲーム内のオーバーレイレイヤ",
"内联效果参数": "インラインエフェクトパラメータ"
"内联效果参数": "インラインエフェクトパラメータ",
"获取最新提取器核心&错误反馈&游戏支持": "最新の抽出コア&エラーフィードバック&ゲームサポートの取得",
"外部缩放软件": "外部ズームソフトウェア",
"Hook Magpie进程使其不会退出缩放": "Hook Magpieプロセスはスケールを終了しないようにする",
"Hook LosslessScaling进程使其不会退出缩放": "Hook LosslessScalingプロセスはスケーリングを終了しないようにする",
"找不到英语识别模型,正在使用日语模型作为代替,可能效果不佳": "英語認識モデルが見つからず、代わりに日本語モデルを使用しているため、効果がない可能性があります"
}

View File

@ -662,7 +662,6 @@
"Sakura部署教程": "Sakura 배포 자습서",
"Github仓库": "Github 창고",
"利用上文信息翻译(通常会有一定的效果提升,但会导致变慢)": "위의 정보를 사용하여 번역 (일반적으로 효과가 향상되지만 느려질 수 있음)",
"范围选取遮罩透明度": "범위 선택 마스크 투명도",
"文本缓冲区长度": "텍스트 버퍼 길이",
"显示/隐藏历史翻译和调试输出": "히스토리 번역 및 디버그 출력 표시 / 숨기기",
"历史翻译和调试输出": "역사 번역 및 디버그 출력",
@ -701,5 +700,10 @@
"语言自适应": "언어 적응",
"去除重复字符": "중복 문자 제거",
"游戏内叠加层": "게임 내 중첩층",
"内联效果参数": "인라인 효과 매개변수"
"内联效果参数": "인라인 효과 매개변수",
"获取最新提取器核心&错误反馈&游戏支持": "최신 추출기 코어 & 오류 피드백 & 게임 지원 받기",
"外部缩放软件": "외부 확대 / 축소 소프트웨어",
"Hook Magpie进程使其不会退出缩放": "Hook Magpie 프로세스로 인해 줌이 종료되지 않습니다.",
"Hook LosslessScaling进程使其不会退出缩放": "Hook LosslessScaling 프로세스로 인해 줌이 종료되지 않습니다.",
"找不到英语识别模型,正在使用日语模型作为代替,可能效果不佳": "영어 인식 모델을 찾을 수 없습니다. 대신 일본어 모델을 사용하고 있습니다. 효과가 없을 수 있습니다"
}

View File

@ -662,7 +662,6 @@
"Sakura部署教程": "Samouczek wdrażania Sakury",
"Github仓库": "Magazyn Github",
"利用上文信息翻译(通常会有一定的效果提升,但会导致变慢)": "Przetłumacz za pomocą informacji podanych w poprzednim tekście (zwykle z pewną poprawą skuteczności, ale może to prowadzić do wolniejszego tłumaczenia)",
"范围选取遮罩透明度": "Przejrzystość maski wyboru zakresu",
"文本缓冲区长度": "Długość bufora tekstu",
"显示/隐藏历史翻译和调试输出": "Pokaż/ukryj historyczne tłumaczenie i wyjście debugowania",
"历史翻译和调试输出": "Historiczne tłumaczenie i debugowanie",
@ -701,5 +700,10 @@
"语言自适应": "Dostosowanie języka",
"去除重复字符": "Usuń duplikaty znaków",
"游戏内叠加层": "Warstwa nakładki w grze",
"内联效果参数": "Parametry efektu liniowego"
"内联效果参数": "Parametry efektu liniowego",
"获取最新提取器核心&错误反馈&游戏支持": "Uzyskaj najnowszą informację zwrotną o błędach ekstraktora i wsparcie gry",
"外部缩放软件": "Oprogramowanie do skalowania zewnętrznego",
"Hook Magpie进程使其不会退出缩放": "Proces Hook Magpie zapobiega zakończeniu skalowania",
"Hook LosslessScaling进程使其不会退出缩放": "Proces Hook Losslessless Scaling zapobiega zakończeniu skalowania",
"找不到英语识别模型,正在使用日语模型作为代替,可能效果不佳": "Nie można znaleźć angielskiego modelu rozpoznawania, używając modelu japońskiego jako substytutu, może nie być skuteczny"
}

View File

@ -662,7 +662,6 @@
"Sakura部署教程": "Курс развертывания Sakura",
"Github仓库": "Склад Github",
"利用上文信息翻译(通常会有一定的效果提升,但会导致变慢)": "Использование вышеприведенного перевода информации (обычно имеет определенный эффект улучшения, но приводит к замедлению)",
"范围选取遮罩透明度": "Выберите прозрачность покрытия",
"文本缓冲区长度": "Длина буфера текста",
"显示/隐藏历史翻译和调试输出": "Показать / скрыть исторический перевод и отладочный вывод",
"历史翻译和调试输出": "Исторический перевод и отладка вывода",
@ -701,5 +700,10 @@
"语言自适应": "Язык адаптируется",
"去除重复字符": "Удалить повторяющиеся символы",
"游戏内叠加层": "Слой наложения внутри игры",
"内联效果参数": "Параметры эффекта подключения"
"内联效果参数": "Параметры эффекта подключения",
"获取最新提取器核心&错误反馈&游戏支持": "Получите последние ядра экстрактора и обратную связь с ошибками & Поддержка игры",
"外部缩放软件": "Программное обеспечение для внешнего масштабирования",
"Hook Magpie进程使其不会退出缩放": "Процесс Hook Magpie не выводит из масштабирования",
"Hook LosslessScaling进程使其不会退出缩放": "Процесс Hook LosslessScaling не выводит из масштабирования",
"找不到英语识别模型,正在使用日语模型作为代替,可能效果不佳": "Не найдена модель распознавания на английском языке, вместо нее используется японская модель, которая может быть неэффективной"
}

View File

@ -662,7 +662,6 @@
"Sakura部署教程": "Sakura Deployment กวดวิชา",
"Github仓库": "คลังสินค้า Github",
"利用上文信息翻译(通常会有一定的效果提升,但会导致变慢)": "ใช้ประโยชน์จากการแปลข้อมูลข้างต้น (มักจะมีผลบางอย่างเพิ่มขึ้น แต่ทำให้ช้าลง)",
"范围选取遮罩透明度": "ช่วงการเลือกหน้ากาก ความโปร่งใส",
"文本缓冲区长度": "ความยาวบัฟเฟอร์ข้อความ",
"显示/隐藏历史翻译和调试输出": "แสดง / ซ่อนการแปลประวัติและการแก้จุดบกพร่องเอาท์พุท",
"历史翻译和调试输出": "การแปลประวัติและการแก้จุดบกพร่องเอาท์พุท",
@ -701,5 +700,10 @@
"语言自适应": "การปรับภาษา",
"去除重复字符": "ลบอักขระที่ซ้ำกัน",
"游戏内叠加层": "ซ้อนทับในเกม",
"内联效果参数": "พารามิเตอร์ผลกระทบแบบอินไลน์"
"内联效果参数": "พารามิเตอร์ผลกระทบแบบอินไลน์",
"获取最新提取器核心&错误反馈&游戏支持": "รับแกนดูดล่าสุดและข้อเสนอแนะข้อผิดพลาดและการสนับสนุนเกม",
"外部缩放软件": "ซอฟต์แวร์ซูมภายนอก",
"Hook Magpie进程使其不会退出缩放": "กระบวนการ Hook Magpie ทำให้ไม่ออกจากการซูม",
"Hook LosslessScaling进程使其不会退出缩放": "Hook LosslessScaling กระบวนการทำให้มันไม่ออกจากซูม",
"找不到英语识别模型,正在使用日语模型作为代替,可能效果不佳": "ไม่พบแบบจำลองการจำแนกภาษาอังกฤษและใช้แบบจำลองภาษาญี่ปุ่นแทนอาจไม่ได้ผล"
}

View File

@ -662,7 +662,6 @@
"Sakura部署教程": "Sakura Deployment Tutorial",
"Github仓库": "Github deposu",
"利用上文信息翻译(通常会有一定的效果提升,但会导致变慢)": "Önceki metinde verilen bilgileri kullanarak çevirin (genelde etkinliğinde bazı gelişmelerle, fakat daha yavaş çeviriye yol açabilir)",
"范围选取遮罩透明度": "Aralık seçim maskesi transparency",
"文本缓冲区长度": "Metin buffer uzunluğu",
"显示/隐藏历史翻译和调试输出": "Tarihi çevirimi ve arızasızlandırma çıkışını göster/gizle",
"历史翻译和调试输出": "Tarihi çeviri ve hata ayıklama çıkışı",
@ -701,5 +700,10 @@
"语言自适应": "Dil Yönetimi",
"去除重复字符": "Çift karakterleri sil",
"游戏内叠加层": "Oyun üzerindeki katı",
"内联效果参数": "İçeri etkisi parametreleri"
"内联效果参数": "İçeri etkisi parametreleri",
"获取最新提取器核心&错误反馈&游戏支持": "Son ekstraktör çekirdek&hata geri veri&oyunu desteğini alın",
"外部缩放软件": "Dışarı skalama yazılımı",
"Hook Magpie进程使其不会退出缩放": "Hook Magpie süreci ölçeklenmesini engelledi",
"Hook LosslessScaling进程使其不会退出缩放": "Hook LosslessScaling süreç ölçeklenmesini engelledi",
"找不到英语识别模型,正在使用日语模型作为代替,可能效果不佳": "İngilizce tanıma modeli bulamadı. Japon modeli yerine koyarak kullanarak etkili olabilir."
}

View File

@ -662,7 +662,6 @@
"Sakura部署教程": "Навчення розробки Sakura",
"Github仓库": "Сховище Github",
"利用上文信息翻译(通常会有一定的效果提升,但会导致变慢)": "Переклад за допомогою інформації, наданої у попередньому тексті (зазвичай, з деяким покращенням ефективності, але це може призвести до повільнішого перекладу)",
"范围选取遮罩透明度": "Прозорість маски вибору діапазону",
"文本缓冲区长度": "Довжина текстового буфера",
"显示/隐藏历史翻译和调试输出": "Показувати/сховати історичний переклад і вивід зневаджування",
"历史翻译和调试输出": "Історічний переклад і вивід зневаджування",
@ -701,5 +700,10 @@
"语言自适应": "Адаптація мови",
"去除重复字符": "Вилучити дублікатні символи",
"游戏内叠加层": "Шир перекладу у грі",
"内联效果参数": "Параметри вхідних ефектів"
"内联效果参数": "Параметри вхідних ефектів",
"获取最新提取器核心&错误反馈&游戏支持": "Отримати останню підтримку гри для відтворення & помилок ядра екстрактора",
"外部缩放软件": "Зовнішнє програмне забезпечення масштабу",
"Hook Magpie进程使其不会退出缩放": "Процес Hook Magpie забороняє їй вийти з масштабу",
"Hook LosslessScaling进程使其不会退出缩放": "Процес безвтратного розміруScaling забороняє їй вийти з розміру",
"找不到英语识别模型,正在使用日语模型作为代替,可能效果不佳": "Не вдалося знайти англійську модель розпізнавання, використовуючи японську модель як заміну, може бути неефективною"
}

View File

@ -662,7 +662,6 @@
"Sakura部署教程": "Hướng dẫn triển khai Sakura",
"Github仓库": "Kho Github",
"利用上文信息翻译(通常会有一定的效果提升,但会导致变慢)": "Sử dụng thông tin trên để dịch (thường có một số hiệu ứng tăng lên, nhưng có thể dẫn đến chậm hơn)",
"范围选取遮罩透明度": "Phạm vi chọn Mask Transparency",
"文本缓冲区长度": "Chiều dài bộ đệm văn bản",
"显示/隐藏历史翻译和调试输出": "Hiển thị/ẩn lịch sử dịch và đầu ra gỡ lỗi",
"历史翻译和调试输出": "Lịch sử dịch và gỡ lỗi đầu ra",
@ -701,5 +700,10 @@
"语言自适应": "Thích nghi ngôn ngữ",
"去除重复字符": "Loại bỏ các ký tự trùng lặp",
"游戏内叠加层": "Lớp phủ trong trò chơi",
"内联效果参数": "Tham số hiệu ứng nội tuyến"
"内联效果参数": "Tham số hiệu ứng nội tuyến",
"获取最新提取器核心&错误反馈&游戏支持": "Nhận lõi Extractor mới nhất&Phản hồi lỗi&Hỗ trợ trò chơi",
"外部缩放软件": "Phần mềm Zoom ngoài",
"Hook Magpie进程使其不会退出缩放": "Quá trình Hook Magpie làm cho nó không thoát khỏi zoom",
"Hook LosslessScaling进程使其不会退出缩放": "Quá trình Hook LosslessScaling làm cho nó không thoát khỏi zoom",
"找不到英语识别模型,正在使用日语模型作为代替,可能效果不佳": "Không tìm thấy mô hình nhận dạng tiếng Anh, đang sử dụng mô hình tiếng Nhật thay thế và có thể không hoạt động tốt"
}

View File

@ -661,7 +661,6 @@
"Sakura部署教程": "",
"Github仓库": "",
"利用上文信息翻译(通常会有一定的效果提升,但会导致变慢)": "",
"范围选取遮罩透明度": "",
"文本缓冲区长度": "",
"显示/隐藏历史翻译和调试输出": "",
"历史翻译和调试输出": "",
@ -701,5 +700,10 @@
"API接口格式如下可根据自己的设置进行修改IP和端口。": "",
"去除重复字符": "",
"游戏内叠加层": "",
"内联效果参数": ""
"内联效果参数": "",
"获取最新提取器核心&错误反馈&游戏支持": "",
"外部缩放软件": "",
"Hook Magpie进程使其不会退出缩放": "",
"Hook LosslessScaling进程使其不会退出缩放": "",
"找不到英语识别模型,正在使用日语模型作为代替,可能效果不佳": ""
}

View File

@ -6,7 +6,7 @@ if x86:
nuitkadist=r'..\build\x86\LunaTranslator_main.dist'
targetdir=r'..\build\LunaTranslator_x86'
launch=r'..\plugins\builds\_x86'
downlevel=f'C:\Windows\SysWOW64\downlevel'
downlevel=r'C:\Windows\SysWOW64\downlevel'
target='LunaTranslator_x86.zip'
baddll='DLL64'
else:
@ -15,7 +15,7 @@ else:
launch=r'..\plugins\builds\_x64'
nuitkadist=r'..\build\x64\LunaTranslator_main.dist'
targetdir=r'..\build\LunaTranslator'
downlevel=f'C:\Windows\system32\downlevel'
downlevel=r'C:\Windows\system32\downlevel'
targetdir_in=rf'{targetdir}\LunaTranslator'
def get_import_table(file_path):
pe = pefile.PE(file_path)

View File

@ -28,4 +28,4 @@ add_subdirectory(exec)
add_subdirectory(shareddllproxy)
add_subdirectory(winrtutils)
add_subdirectory(winsharedutils)
add_subdirectory(hookmagpie)

1
plugins/hookmagpie/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
minhook

View File

@ -0,0 +1,9 @@
if(${CMAKE_SIZEOF_VOID_P} EQUAL 8)
add_library(hookmagpie MODULE hookmagpie.cpp)
add_subdirectory(minhook)
target_link_libraries(hookmagpie minhook ${Detours})
endif()

View File

@ -0,0 +1,295 @@
#include <iostream>
#include<windows.h>
#include<thread>
#include<detours.h>
#include<string>
#include<assert.h>
#include<MinHook.h>
namespace Win32Utils{
static HANDLE SafeHandle(HANDLE h) noexcept { return (h == INVALID_HANDLE_VALUE) ? nullptr : h; }
struct HandleCloser { void operator()(HANDLE h) noexcept { assert(h != INVALID_HANDLE_VALUE); if (h) CloseHandle(h); } };
using ScopedHandle = std::unique_ptr<std::remove_pointer<HANDLE>::type, HandleCloser>;
std::wstring GetPathOfWnd(HWND hWnd) {
ScopedHandle hProc;
DWORD dwProcId = 0;
if (GetWindowThreadProcessId(hWnd, &dwProcId)) {
hProc.reset(SafeHandle(OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, dwProcId)));
if (!hProc) {
}
} else {
}
if (!hProc) {
static const auto getProcessHandleFromHwnd = (HANDLE (WINAPI*)(HWND))GetProcAddress(
LoadLibraryEx(L"Oleacc.dll", NULL, 0), "GetProcessHandleFromHwnd");
if (getProcessHandleFromHwnd) {
hProc.reset(getProcessHandleFromHwnd(hWnd));
if (!hProc) {
}
}
if (!hProc) {
return {};
}
}
std::wstring fileName(MAX_PATH, 0);
DWORD size = MAX_PATH;
if (!QueryFullProcessImageName(hProc.get(), 0, fileName.data(), &size)) {
return {};
}
fileName.resize(size);
return fileName;
}
}
namespace StrUtils{
template<typename CHAR_T>
static void ToLowerCase(std::basic_string<CHAR_T>& str) noexcept {
for (CHAR_T& c : str) {
c = tolower(c);
}
}
}
static std::wstring GetExeName(HWND hWnd) noexcept {
std::wstring exeName = Win32Utils::GetPathOfWnd(hWnd);
exeName = exeName.substr(exeName.find_last_of(L'\\') + 1);
StrUtils::ToLowerCase(exeName);
return exeName;
}
bool(*IsValidSrcWindow)(HWND);
struct hook_stack
{
#ifndef _WIN64
uintptr_t _eflags; //pushfd
uintptr_t edi, // pushad
esi,
ebp,
esp,
ebx,
edx,
ecx, // this
eax; // 0x28
#else
uintptr_t r15,
r14,
r13,
r12,
r11,
r10,
r9,
r8,
rdi,
rsi,
rbp,
rsp,
rdx,
rcx,
rbx,
rax;
#endif
uintptr_t eflags; // pushaf
union
{
uintptr_t stack[1]; // beginning of the runtime stack
uintptr_t retaddr;
BYTE base[1];
};
};
uintptr_t findEnclosingAlignedFunction_strict(uintptr_t start, uintptr_t back_range)
{
start &= ~0xf;
for (uintptr_t i = start, j = start - back_range; i > j; i-=0x10) {
DWORD k = *(DWORD *)(i-4);
if (k == 0xcccccccc
|| k == 0x90909090
|| k == 0xccccccc3
|| k == 0x909090c3
)
return i;
}
return 0;
}
bool checkislunawindow(HWND hwndSrc)
{
wchar_t title[100];
GetWindowText(hwndSrc,title,100);
if (wcscmp(title,L"LunaTranslator")==0||GetExeName(hwndSrc) == L"lunatranslator_main.exe"||GetExeName(hwndSrc) == L"lunatranslator.exe")
return true;
else return false;
}
class hooks{
public:
void IsValidSrcWindow_hooked(uintptr_t lpDataBase)
{
auto stack=(hook_stack*)(lpDataBase-sizeof(hook_stack)+sizeof(uintptr_t));
auto hwndSrc=(HWND)(stack->rcx);
if (checkislunawindow(hwndSrc))
{
//MessageBoxW(0,GetExeName(hwndSrc).c_str(),L"",0);
stack->rcx=(uintptr_t)FindWindow(L"Shell_TrayWnd",nullptr);
}
}
hooks(LPVOID location){
BYTE common_hook[] = {
0x9c, // push rflags
0x50, // push rax
0x53, // push rbx
0x51, // push rcx
0x52, // push rdx
0x54, // push rsp
0x55, // push rbp
0x56, // push rsi
0x57, // push rdi
0x41, 0x50, // push r8
0x41, 0x51, // push r9
0x41, 0x52, // push r10
0x41, 0x53, // push r11
0x41, 0x54, // push r12
0x41, 0x55, // push r13
0x41, 0x56, // push r14
0x41, 0x57, // push r15
// https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention
// https://stackoverflow.com/questions/43358429/save-value-of-xmm-registers
0x48, 0x83, 0xec, 0x20, // sub rsp,0x20
0xf3, 0x0f, 0x7f, 0x24, 0x24, // movdqu [rsp],xmm4
0xf3, 0x0f, 0x7f, 0x6c, 0x24, 0x10, // movdqu [rsp+0x10],xmm5
0x48, 0x8d, 0x94, 0x24, 0xa8, 0x00, 0x00, 0x00, // lea rdx,[rsp+0xa8]
0x48, 0xb9, 0,0,0,0,0,0,0,0, // mov rcx,@this
0x48, 0xb8, 0,0,0,0,0,0,0,0, // mov rax,@TextHook::Send
0x48, 0x89, 0xe3, // mov rbx,rsp
0x48, 0x83, 0xe4, 0xf0, // and rsp,0xfffffffffffffff0 ; align stack
0xff, 0xd0, // call rax
0x48, 0x89, 0xdc, // mov rsp,rbx
0xf3, 0x0f, 0x6f, 0x6c, 0x24, 0x10, // movdqu xmm5,XMMWORD PTR[rsp + 0x10]
0xf3, 0x0f, 0x6f, 0x24, 0x24, // movdqu xmm4,XMMWORD PTR[rsp]
0x48, 0x83, 0xc4, 0x20, // add rsp,0x20
0x41, 0x5f, // pop r15
0x41, 0x5e, // pop r14
0x41, 0x5d, // pop r13
0x41, 0x5c, // pop r12
0x41, 0x5b, // pop r11
0x41, 0x5a, // pop r10
0x41, 0x59, // pop r9
0x41, 0x58, // pop r8
0x5f, // pop rdi
0x5e, // pop rsi
0x5d, // pop rbp
0x5c, // pop rsp
0x5a, // pop rdx
0x59, // pop rcx
0x5b, // pop rbx
0x58, // pop rax
0x9d, // pop rflags
0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp qword ptr [rip]
0,0,0,0,0,0,0,0 // @original
};
int this_offset = 50, send_offset = 60, original_offset = 126;
DWORD _;
VirtualProtect(location, 10, PAGE_EXECUTE_READWRITE, &_);
auto trampoline=VirtualAlloc(0,sizeof(common_hook),MEM_COMMIT,PAGE_EXECUTE_READWRITE);
void* original;
MH_STATUS error;
if ((error = MH_CreateHook(location, trampoline, &original)) != MH_OK)
return;
*(hooks**)(common_hook + this_offset) = this;
*(void(hooks::**)(uintptr_t))(common_hook + send_offset) = &hooks::IsValidSrcWindow_hooked;
*(void**)(common_hook + original_offset) = original;
memcpy(trampoline, common_hook, sizeof(common_hook));
MH_EnableHook(location);
}
};
void starthookmagpie()
{
uintptr_t IsValidSrcWindow=0;
wchar_t target[]=L"Shell_TrayWnd";
auto base=(uintptr_t)GetModuleHandle(L"Magpie.App.dll");
BYTE lea[]={0x48,0x8D,0x05};
//.text:0000000180146AD0 48 8D 05 91 87 10 00 lea rax, aShellTraywnd ; "Shell_TrayWnd"
//.rdata:000000018024F268 53 00 68 00 65 00 6C 00 6C 00+text "UTF-16LE", 'Shell_TrayWnd',0
__try{
for(int i=0;i<0x1000000;i++)
{
if(memcmp(lea,(LPVOID)(i+base),3)==0)
{
auto addr=base+i;
auto leastr=(*(int*)(addr+3))+7+addr;
if(IsBadReadPtr((LPVOID)leastr,sizeof(target))==0)
if(wcscmp((wchar_t*)leastr,target)==0)
{
IsValidSrcWindow=findEnclosingAlignedFunction_strict(addr,0x1000);
break;
}
}
}
}__except(EXCEPTION_EXECUTE_HANDLER) { return; }
if(IsValidSrcWindow==0)return;
//IsValidSrcWindow=(decltype(IsValidSrcWindow))((uintptr_t)GetModuleHandle(L"Magpie.App.dll")+0x180146860-0x180000000);
MH_Initialize();
hooks _((LPVOID)IsValidSrcWindow);
// DetourTransactionBegin();
// DetourUpdateThread(GetCurrentThread());
// DetourAttach(&(PVOID&)IsValidSrcWindow,IsValidSrcWindow_hooked);
// DetourTransactionCommit();
}
auto GetClassNameWs=GetClassNameW;
int
WINAPI
GetClassNameWH(
_In_ HWND hWnd,
_Out_writes_to_(nMaxCount, return) LPWSTR lpClassName,
_In_ int nMaxCount
){
if(checkislunawindow(hWnd)){
wcscpy(lpClassName,L"ApplicationManager_ImmersiveShellWindow");
return TRUE;
}
else
return GetClassNameWs(hWnd,lpClassName,nMaxCount);
}
void starthooklossless()
{
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)GetClassNameWs, GetClassNameWH);
DetourTransactionCommit();
}
void starthook()
{
if(GetModuleHandle(L"Magpie.App.dll"))
starthookmagpie();
else if(GetModuleHandle(L"Lossless.dll"))
starthooklossless();
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
starthook();
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}