mirror of
https://github.com/HIllya51/LunaTranslator.git
synced 2025-01-15 00:43:59 +08:00
update
This commit is contained in:
parent
24cd9b7c04
commit
77d889a758
@ -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)
|
||||
|
@ -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:
|
||||
|
@ -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))),
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 ) )
|
||||
|
||||
|
@ -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):
|
||||
|
@ -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'
|
||||
# }
|
||||
|
||||
def internal_stopped(self):
|
||||
self._externalfsend()
|
||||
self.status=False
|
||||
|
||||
@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):
|
||||
|
||||
# for k in mp:
|
||||
# if shortcuts&k !=0:
|
||||
# windows.keybd_event(mp1[mp[k]],0,0,0)
|
||||
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]
|
||||
|
||||
|
||||
# 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):
|
||||
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)
|
||||
self._externalfsend()
|
||||
self.status=False
|
||||
threading.Thread(target=_waitexternalend ).start()
|
||||
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
|
||||
|
@ -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):
|
||||
|
||||
|
@ -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
|
@ -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)
|
||||
|
@ -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
|
||||
@ -748,4 +748,12 @@ class AutoHandle(HANDLE):
|
||||
CloseHandle(self)
|
||||
|
||||
|
||||
|
||||
|
||||
_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)
|
@ -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,
|
||||
|
@ -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",
|
||||
|
@ -662,7 +662,6 @@
|
||||
"Sakura部署教程": "ساكورا نشر البرنامج التعليمي",
|
||||
"Github仓库": "مستودع جيتوب",
|
||||
"利用上文信息翻译(通常会有一定的效果提升,但会导致变慢)": "استخدام المعلومات الواردة أعلاه في الترجمة ( عادة ما يكون هناك بعض التحسن ، ولكن يمكن أن يؤدي إلى إبطاء )",
|
||||
"范围选取遮罩透明度": "مجموعة اختيار قناع الشفافية",
|
||||
"文本缓冲区长度": "نص طول المخزن المؤقت",
|
||||
"显示/隐藏历史翻译和调试输出": "عرض / إخفاء تاريخ الترجمة وتصحيح الأخطاء الناتج",
|
||||
"历史翻译和调试输出": "تاريخ الترجمة وتصحيح الأخطاء الناتج",
|
||||
@ -701,5 +700,10 @@
|
||||
"语言自适应": "التكيف اللغوي",
|
||||
"去除重复字符": "إزالة الأحرف المكررة",
|
||||
"游戏内叠加层": "لعبة التراص الداخلي",
|
||||
"内联效果参数": "مضمنة تأثير المعلمة"
|
||||
"内联效果参数": "مضمنة تأثير المعلمة",
|
||||
"获取最新提取器核心&错误反馈&游戏支持": "الحصول على أحدث المستخلص الأساسية و ردود فعل خاطئة و دعم اللعبة",
|
||||
"外部缩放软件": "برامج التكبير الخارجي",
|
||||
"Hook Magpie进程使其不会退出缩放": "هوك ماجي العملية بحيث لا تخرج من التكبير",
|
||||
"Hook LosslessScaling进程使其不会退出缩放": "هوك looslessscaling العملية بحيث لا تخرج من التكبير",
|
||||
"找不到英语识别模型,正在使用日语模型作为代替,可能效果不佳": "لا يمكن العثور على نموذج التعرف على اللغة الإنجليزية ، واستخدام نموذج اليابانية بدلا من ذلك ، قد لا تعمل بشكل جيد"
|
||||
}
|
@ -662,7 +662,6 @@
|
||||
"Sakura部署教程": "Sakura部署教程",
|
||||
"Github仓库": "Github倉庫",
|
||||
"利用上文信息翻译(通常会有一定的效果提升,但会导致变慢)": "利用上文資訊翻譯(通常會有一定的效果提升,但會導致變慢)",
|
||||
"范围选取遮罩透明度": "範圍選取遮罩透明度",
|
||||
"文本缓冲区长度": "文字緩衝區長度",
|
||||
"显示/隐藏历史翻译和调试输出": "顯示/隱藏歷史翻譯和調試輸出",
|
||||
"历史翻译和调试输出": "歷史翻譯和調試輸出",
|
||||
@ -701,5 +700,10 @@
|
||||
"语言自适应": "語言自我調整",
|
||||
"去除重复字符": "去除重複字元",
|
||||
"游戏内叠加层": "遊戲內疊加層",
|
||||
"内联效果参数": "內聯效果參數"
|
||||
"内联效果参数": "內聯效果參數",
|
||||
"获取最新提取器核心&错误反馈&游戏支持": "獲取最新提取器覈心&錯誤迴響&遊戲支持",
|
||||
"外部缩放软件": "外部縮放軟件",
|
||||
"Hook Magpie进程使其不会退出缩放": "Hook Magpie行程使其不會退出縮放",
|
||||
"Hook LosslessScaling进程使其不会退出缩放": "Hook LosslessScaling行程使其不會退出縮放",
|
||||
"找不到英语识别模型,正在使用日语模型作为代替,可能效果不佳": "找不到英語識別模型,正在使用日語模型作為代替,可能效果不佳"
|
||||
}
|
@ -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"
|
||||
}
|
@ -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."
|
||||
}
|
@ -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"
|
||||
}
|
@ -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"
|
||||
}
|
@ -662,7 +662,6 @@
|
||||
"Sakura部署教程": "Sakura導入チュートリアル",
|
||||
"Github仓库": "Github倉庫",
|
||||
"利用上文信息翻译(通常会有一定的效果提升,但会导致变慢)": "上記の情報翻訳を利用する(通常は一定の効果が上がるが、遅くなる)",
|
||||
"范围选取遮罩透明度": "範囲選択マスクの透明度",
|
||||
"文本缓冲区长度": "テキストバッファ長",
|
||||
"显示/隐藏历史翻译和调试输出": "履歴翻訳とデバッグ出力の表示/非表示",
|
||||
"历史翻译和调试输出": "履歴翻訳とデバッグ出力",
|
||||
@ -701,5 +700,10 @@
|
||||
"语言自适应": "げんごてきおう",
|
||||
"去除重复字符": "繰り返し文字を削除",
|
||||
"游戏内叠加层": "ゲーム内のオーバーレイレイヤ",
|
||||
"内联效果参数": "インラインエフェクトパラメータ"
|
||||
"内联效果参数": "インラインエフェクトパラメータ",
|
||||
"获取最新提取器核心&错误反馈&游戏支持": "最新の抽出コア&エラーフィードバック&ゲームサポートの取得",
|
||||
"外部缩放软件": "外部ズームソフトウェア",
|
||||
"Hook Magpie进程使其不会退出缩放": "Hook Magpieプロセスはスケールを終了しないようにする",
|
||||
"Hook LosslessScaling进程使其不会退出缩放": "Hook LosslessScalingプロセスはスケーリングを終了しないようにする",
|
||||
"找不到英语识别模型,正在使用日语模型作为代替,可能效果不佳": "英語認識モデルが見つからず、代わりに日本語モデルを使用しているため、効果がない可能性があります"
|
||||
}
|
@ -662,7 +662,6 @@
|
||||
"Sakura部署教程": "Sakura 배포 자습서",
|
||||
"Github仓库": "Github 창고",
|
||||
"利用上文信息翻译(通常会有一定的效果提升,但会导致变慢)": "위의 정보를 사용하여 번역 (일반적으로 효과가 향상되지만 느려질 수 있음)",
|
||||
"范围选取遮罩透明度": "범위 선택 마스크 투명도",
|
||||
"文本缓冲区长度": "텍스트 버퍼 길이",
|
||||
"显示/隐藏历史翻译和调试输出": "히스토리 번역 및 디버그 출력 표시 / 숨기기",
|
||||
"历史翻译和调试输出": "역사 번역 및 디버그 출력",
|
||||
@ -701,5 +700,10 @@
|
||||
"语言自适应": "언어 적응",
|
||||
"去除重复字符": "중복 문자 제거",
|
||||
"游戏内叠加层": "게임 내 중첩층",
|
||||
"内联效果参数": "인라인 효과 매개변수"
|
||||
"内联效果参数": "인라인 효과 매개변수",
|
||||
"获取最新提取器核心&错误反馈&游戏支持": "최신 추출기 코어 & 오류 피드백 & 게임 지원 받기",
|
||||
"外部缩放软件": "외부 확대 / 축소 소프트웨어",
|
||||
"Hook Magpie进程使其不会退出缩放": "Hook Magpie 프로세스로 인해 줌이 종료되지 않습니다.",
|
||||
"Hook LosslessScaling进程使其不会退出缩放": "Hook LosslessScaling 프로세스로 인해 줌이 종료되지 않습니다.",
|
||||
"找不到英语识别模型,正在使用日语模型作为代替,可能效果不佳": "영어 인식 모델을 찾을 수 없습니다. 대신 일본어 모델을 사용하고 있습니다. 효과가 없을 수 있습니다"
|
||||
}
|
@ -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"
|
||||
}
|
@ -662,7 +662,6 @@
|
||||
"Sakura部署教程": "Курс развертывания Sakura",
|
||||
"Github仓库": "Склад Github",
|
||||
"利用上文信息翻译(通常会有一定的效果提升,但会导致变慢)": "Использование вышеприведенного перевода информации (обычно имеет определенный эффект улучшения, но приводит к замедлению)",
|
||||
"范围选取遮罩透明度": "Выберите прозрачность покрытия",
|
||||
"文本缓冲区长度": "Длина буфера текста",
|
||||
"显示/隐藏历史翻译和调试输出": "Показать / скрыть исторический перевод и отладочный вывод",
|
||||
"历史翻译和调试输出": "Исторический перевод и отладка вывода",
|
||||
@ -701,5 +700,10 @@
|
||||
"语言自适应": "Язык адаптируется",
|
||||
"去除重复字符": "Удалить повторяющиеся символы",
|
||||
"游戏内叠加层": "Слой наложения внутри игры",
|
||||
"内联效果参数": "Параметры эффекта подключения"
|
||||
"内联效果参数": "Параметры эффекта подключения",
|
||||
"获取最新提取器核心&错误反馈&游戏支持": "Получите последние ядра экстрактора и обратную связь с ошибками & Поддержка игры",
|
||||
"外部缩放软件": "Программное обеспечение для внешнего масштабирования",
|
||||
"Hook Magpie进程使其不会退出缩放": "Процесс Hook Magpie не выводит из масштабирования",
|
||||
"Hook LosslessScaling进程使其不会退出缩放": "Процесс Hook LosslessScaling не выводит из масштабирования",
|
||||
"找不到英语识别模型,正在使用日语模型作为代替,可能效果不佳": "Не найдена модель распознавания на английском языке, вместо нее используется японская модель, которая может быть неэффективной"
|
||||
}
|
@ -662,7 +662,6 @@
|
||||
"Sakura部署教程": "Sakura Deployment กวดวิชา",
|
||||
"Github仓库": "คลังสินค้า Github",
|
||||
"利用上文信息翻译(通常会有一定的效果提升,但会导致变慢)": "ใช้ประโยชน์จากการแปลข้อมูลข้างต้น (มักจะมีผลบางอย่างเพิ่มขึ้น แต่ทำให้ช้าลง)",
|
||||
"范围选取遮罩透明度": "ช่วงการเลือกหน้ากาก ความโปร่งใส",
|
||||
"文本缓冲区长度": "ความยาวบัฟเฟอร์ข้อความ",
|
||||
"显示/隐藏历史翻译和调试输出": "แสดง / ซ่อนการแปลประวัติและการแก้จุดบกพร่องเอาท์พุท",
|
||||
"历史翻译和调试输出": "การแปลประวัติและการแก้จุดบกพร่องเอาท์พุท",
|
||||
@ -701,5 +700,10 @@
|
||||
"语言自适应": "การปรับภาษา",
|
||||
"去除重复字符": "ลบอักขระที่ซ้ำกัน",
|
||||
"游戏内叠加层": "ซ้อนทับในเกม",
|
||||
"内联效果参数": "พารามิเตอร์ผลกระทบแบบอินไลน์"
|
||||
"内联效果参数": "พารามิเตอร์ผลกระทบแบบอินไลน์",
|
||||
"获取最新提取器核心&错误反馈&游戏支持": "รับแกนดูดล่าสุดและข้อเสนอแนะข้อผิดพลาดและการสนับสนุนเกม",
|
||||
"外部缩放软件": "ซอฟต์แวร์ซูมภายนอก",
|
||||
"Hook Magpie进程使其不会退出缩放": "กระบวนการ Hook Magpie ทำให้ไม่ออกจากการซูม",
|
||||
"Hook LosslessScaling进程使其不会退出缩放": "Hook LosslessScaling กระบวนการทำให้มันไม่ออกจากซูม",
|
||||
"找不到英语识别模型,正在使用日语模型作为代替,可能效果不佳": "ไม่พบแบบจำลองการจำแนกภาษาอังกฤษและใช้แบบจำลองภาษาญี่ปุ่นแทนอาจไม่ได้ผล"
|
||||
}
|
@ -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."
|
||||
}
|
@ -662,7 +662,6 @@
|
||||
"Sakura部署教程": "Навчення розробки Sakura",
|
||||
"Github仓库": "Сховище Github",
|
||||
"利用上文信息翻译(通常会有一定的效果提升,但会导致变慢)": "Переклад за допомогою інформації, наданої у попередньому тексті (зазвичай, з деяким покращенням ефективності, але це може призвести до повільнішого перекладу)",
|
||||
"范围选取遮罩透明度": "Прозорість маски вибору діапазону",
|
||||
"文本缓冲区长度": "Довжина текстового буфера",
|
||||
"显示/隐藏历史翻译和调试输出": "Показувати/сховати історичний переклад і вивід зневаджування",
|
||||
"历史翻译和调试输出": "Історічний переклад і вивід зневаджування",
|
||||
@ -701,5 +700,10 @@
|
||||
"语言自适应": "Адаптація мови",
|
||||
"去除重复字符": "Вилучити дублікатні символи",
|
||||
"游戏内叠加层": "Шир перекладу у грі",
|
||||
"内联效果参数": "Параметри вхідних ефектів"
|
||||
"内联效果参数": "Параметри вхідних ефектів",
|
||||
"获取最新提取器核心&错误反馈&游戏支持": "Отримати останню підтримку гри для відтворення & помилок ядра екстрактора",
|
||||
"外部缩放软件": "Зовнішнє програмне забезпечення масштабу",
|
||||
"Hook Magpie进程使其不会退出缩放": "Процес Hook Magpie забороняє їй вийти з масштабу",
|
||||
"Hook LosslessScaling进程使其不会退出缩放": "Процес безвтратного розміруScaling забороняє їй вийти з розміру",
|
||||
"找不到英语识别模型,正在使用日语模型作为代替,可能效果不佳": "Не вдалося знайти англійську модель розпізнавання, використовуючи японську модель як заміну, може бути неефективною"
|
||||
}
|
@ -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"
|
||||
}
|
@ -661,7 +661,6 @@
|
||||
"Sakura部署教程": "",
|
||||
"Github仓库": "",
|
||||
"利用上文信息翻译(通常会有一定的效果提升,但会导致变慢)": "",
|
||||
"范围选取遮罩透明度": "",
|
||||
"文本缓冲区长度": "",
|
||||
"显示/隐藏历史翻译和调试输出": "",
|
||||
"历史翻译和调试输出": "",
|
||||
@ -701,5 +700,10 @@
|
||||
"API接口格式如下,可根据自己的设置进行修改IP和端口。": "",
|
||||
"去除重复字符": "",
|
||||
"游戏内叠加层": "",
|
||||
"内联效果参数": ""
|
||||
"内联效果参数": "",
|
||||
"获取最新提取器核心&错误反馈&游戏支持": "",
|
||||
"外部缩放软件": "",
|
||||
"Hook Magpie进程使其不会退出缩放": "",
|
||||
"Hook LosslessScaling进程使其不会退出缩放": "",
|
||||
"找不到英语识别模型,正在使用日语模型作为代替,可能效果不佳": ""
|
||||
}
|
@ -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)
|
||||
|
@ -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
1
plugins/hookmagpie/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
minhook
|
9
plugins/hookmagpie/CMakeLists.txt
Normal file
9
plugins/hookmagpie/CMakeLists.txt
Normal 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()
|
||||
|
||||
|
295
plugins/hookmagpie/hookmagpie.cpp
Normal file
295
plugins/hookmagpie/hookmagpie.cpp
Normal 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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user