From 10ba876bcd8bb3ed68b36ee9cea64accf93fbf18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=81=8D=E5=85=AE=E6=83=9A=E5=85=AE?= <1173718158@qq.com> Date: Tue, 7 Jan 2025 20:18:35 +0800 Subject: [PATCH] . --- cpp/wcocr/wcocr.cpp | 10 ++-- cpp/winsharedutils/SimpleBrowser.cpp | 64 ++++++++++++------------ cpp/winsharedutils/webview2_extra.cpp | 65 ++++++++++++++++--------- py/LunaTranslator/gui/showword.py | 62 ++--------------------- py/LunaTranslator/gui/showwordfast.html | 47 ------------------ py/LunaTranslator/gui/usefulwidget.py | 61 ++++++++++++++--------- py/LunaTranslator/winsharedutils.py | 5 +- 7 files changed, 126 insertions(+), 188 deletions(-) delete mode 100644 py/LunaTranslator/gui/showwordfast.html diff --git a/cpp/wcocr/wcocr.cpp b/cpp/wcocr/wcocr.cpp index d4c2e2db..69b6e8ae 100644 --- a/cpp/wcocr/wcocr.cpp +++ b/cpp/wcocr/wcocr.cpp @@ -16,20 +16,18 @@ DECLARE_API void *wcocr_init(const wchar_t *wexe, const wchar_t *wwcdir) } } -DECLARE_API void wcocr_destroy(void *pobj) +DECLARE_API void wcocr_destroy(CWeChatOCR *pobj) { if (!pobj) return; - auto obj = reinterpret_cast(pobj); - delete obj; + delete pobj; } -DECLARE_API bool wcocr_ocr(void *pobj, const char *u8path, void (*cb)(int, int, int, int, LPCSTR)) +DECLARE_API bool wcocr_ocr(CWeChatOCR *pobj, const char *u8path, void (*cb)(int, int, int, int, LPCSTR)) { if (!pobj) return false; - auto obj = reinterpret_cast(pobj); CWeChatOCR::result_t res; - if (!obj->doOCR(u8path, &res)) + if (!pobj->doOCR(u8path, &res)) return false; for (auto &blk : res.ocr_response) { diff --git a/cpp/winsharedutils/SimpleBrowser.cpp b/cpp/winsharedutils/SimpleBrowser.cpp index 50c3bc6f..37bb8c55 100644 --- a/cpp/winsharedutils/SimpleBrowser.cpp +++ b/cpp/winsharedutils/SimpleBrowser.cpp @@ -201,18 +201,16 @@ DECLARE_API void *html_new(HWND parent) return s_pWebBrowser; } -DECLARE_API void html_navigate(void *web, wchar_t *path) +DECLARE_API void html_navigate(MWebBrowserEx *ww, wchar_t *path) { - if (!web) + if (!ww) return; - auto ww = static_cast(web); ww->Navigate2(path); } -DECLARE_API void html_resize(void *web, int x, int y, int w, int h) +DECLARE_API void html_resize(MWebBrowserEx *ww, int x, int y, int w, int h) { - if (!web) + if (!ww) return; - auto ww = static_cast(web); RECT r; r.left = x; r.top = y; @@ -220,37 +218,33 @@ DECLARE_API void html_resize(void *web, int x, int y, int w, int h) r.bottom = y + h; ww->MoveWindow(r); } -DECLARE_API void html_release(void *web) +DECLARE_API void html_release(MWebBrowserEx *ww) { - if (!web) + if (!ww) return; - auto ww = static_cast(web); ww->Destroy(); // ww->Release(); Destroy减少引用计数,自动del } -DECLARE_API void html_get_current_url(void *web, void (*cb)(LPCWSTR)) +DECLARE_API void html_get_current_url(MWebBrowserEx *ww, void (*cb)(LPCWSTR)) { - if (!web) + if (!ww) return; - auto ww = static_cast(web); CComBSTR _u; CHECK_FAILURE_NORET(ww->get_LocationURL(&_u)); cb(_u); } -DECLARE_API void html_set_html(void *web, wchar_t *html) +DECLARE_API void html_set_html(MWebBrowserEx *ww, wchar_t *html) { - if (!web) + if (!ww) return; - auto ww = static_cast(web); ww->SetHtml(html); } -DECLARE_API void html_add_menu(void *web, int index, const wchar_t *label, void (*callback)(const wchar_t *)) +DECLARE_API void html_add_menu(MWebBrowserEx *ww, int index, const wchar_t *label, void (*callback)(const wchar_t *)) { - if (!web) + if (!ww) return; - auto ww = static_cast(web); std::optional _label; if (label) _label = label; @@ -259,37 +253,33 @@ DECLARE_API void html_add_menu(void *web, int index, const wchar_t *label, void ww->menuitems.insert(ptr, {_label, command}); ww->menucallbacks[command] = callback; } -DECLARE_API void html_get_select_text(void *web, void (*cb)(LPCWSTR)) +DECLARE_API void html_get_select_text(MWebBrowserEx *ww, void (*cb)(LPCWSTR)) { - if (!web) + if (!ww) return; - auto ww = static_cast(web); CComBSTR selectedText; CHECK_FAILURE_NORET(ww->getselectedtext(&selectedText)); cb(selectedText); } -DECLARE_API void html_bind_function(void *web, const wchar_t *name, void (*function)(wchar_t **, int)) +DECLARE_API void html_bind_function(MWebBrowserEx *ww, const wchar_t *name, void (*function)(wchar_t **, int)) { - if (!web) + if (!ww) return; - auto ww = static_cast(web); ww->jsobj->bindfunction(name, function); } -DECLARE_API bool html_check_ctrlc(void *web) +DECLARE_API bool html_check_ctrlc(MWebBrowserEx *ww) { - if (!web) + if (!ww) return false; - auto ww = static_cast(web); return GetAsyncKeyState(VK_CONTROL) && GetAsyncKeyState(67) && (ww->GetIEServerWindow() == GetFocus()); } -DECLARE_API void html_eval(void *web, const wchar_t *js) +DECLARE_API void html_eval(MWebBrowserEx *ww, const wchar_t *js) { - if (!web) + if (!ww) return; - auto ww = static_cast(web); CComPtr pDocument; CHECK_FAILURE_NORET(ww->GetIHTMLDocument2(&pDocument)); CComPtr scriptDispatch; @@ -319,3 +309,17 @@ DECLARE_API void html_eval(void *web, const wchar_t *js) dispid, IID_NULL, 0, DISPATCH_METHOD, ¶ms, &result, &excepInfo, &nArgErr); } +DECLARE_API void html_get_html(MWebBrowserEx *ww, void (*cb)(LPCWSTR)) +{ + if (!ww) + return; + CComPtr pDocument; + CHECK_FAILURE_NORET(ww->GetIHTMLDocument2(&pDocument)); + CComPtr pDocument3; + CHECK_FAILURE_NORET(pDocument.QueryInterface(&pDocument3)); + CComPtr ele; + CHECK_FAILURE_NORET(pDocument3->get_documentElement(&ele)); + CComBSTR data; + CHECK_FAILURE_NORET(ele->get_outerHTML(&data)); + cb(data); +} \ No newline at end of file diff --git a/cpp/winsharedutils/webview2_extra.cpp b/cpp/winsharedutils/webview2_extra.cpp index 8160f607..9e7177d5 100644 --- a/cpp/winsharedutils/webview2_extra.cpp +++ b/cpp/winsharedutils/webview2_extra.cpp @@ -10,13 +10,14 @@ using namespace Microsoft::WRL; #else typedef int COREWEBVIEW2_PREFERRED_COLOR_SCHEME; typedef int EventRegistrationToken; +typedef int ICoreWebView2Controller; #endif -DECLARE_API void set_transparent_background(void *m_host) +DECLARE_API void set_transparent_background(ICoreWebView2Controller *m_host) { #ifndef WINXP COREWEBVIEW2_COLOR color; ZeroMemory(&color, sizeof(color)); - wil::com_ptr m_controller(reinterpret_cast(m_host)); + wil::com_ptr m_controller(m_host); wil::com_ptr coreWebView2 = m_controller.try_query(); if (coreWebView2) @@ -26,10 +27,10 @@ DECLARE_API void set_transparent_background(void *m_host) #endif } -DECLARE_API void put_PreferredColorScheme(void *m_host, COREWEBVIEW2_PREFERRED_COLOR_SCHEME scheme) +DECLARE_API void put_PreferredColorScheme(ICoreWebView2Controller *m_host, COREWEBVIEW2_PREFERRED_COLOR_SCHEME scheme) { #ifndef WINXP - wil::com_ptr m_controller(reinterpret_cast(m_host)); + wil::com_ptr m_controller(m_host); wil::com_ptr coreWebView2; [&]() { @@ -45,13 +46,13 @@ DECLARE_API void put_PreferredColorScheme(void *m_host, COREWEBVIEW2_PREFERRED_C }(); #endif } -DECLARE_API void *add_ZoomFactorChanged(void *m_host, void (*signal)(double)) +DECLARE_API void *add_ZoomFactorChanged(ICoreWebView2Controller *m_host, void (*signal)(double)) { #ifndef WINXP EventRegistrationToken *m_zoomFactorChangedToken = new EventRegistrationToken; // Register a handler for the ZoomFactorChanged event. // This handler just announces the new level of zoom on the window's title bar. - reinterpret_cast(m_host)->add_ZoomFactorChanged( + m_host->add_ZoomFactorChanged( Callback( [signal](ICoreWebView2Controller *sender, IUnknown *args) -> HRESULT { @@ -70,34 +71,34 @@ DECLARE_API void *add_ZoomFactorChanged(void *m_host, void (*signal)(double)) return NULL; #endif } -DECLARE_API void remove_ZoomFactorChanged(void *m_host, EventRegistrationToken *token) +DECLARE_API void remove_ZoomFactorChanged(ICoreWebView2Controller *m_host, EventRegistrationToken *token) { #ifndef WINXP - reinterpret_cast(m_host)->remove_ZoomFactorChanged(*token); + m_host->remove_ZoomFactorChanged(*token); delete token; #endif } -DECLARE_API double get_ZoomFactor(void *m_host) +DECLARE_API double get_ZoomFactor(ICoreWebView2Controller *m_host) { #ifndef WINXP double zoomFactor; - reinterpret_cast(m_host)->get_ZoomFactor(&zoomFactor); + m_host->get_ZoomFactor(&zoomFactor); return zoomFactor; #else return 1; #endif } -DECLARE_API void put_ZoomFactor(void *m_host, double zoomFactor) +DECLARE_API void put_ZoomFactor(ICoreWebView2Controller *m_host, double zoomFactor) { #ifndef WINXP - reinterpret_cast(m_host)->put_ZoomFactor(zoomFactor); + m_host->put_ZoomFactor(zoomFactor); #endif } // https://github.com/MicrosoftEdge/WebView2Feedback/blob/main/specs/WebMessageObjects.md -DECLARE_API void remove_WebMessageReceived(void *m_host, EventRegistrationToken *token) +DECLARE_API void remove_WebMessageReceived(ICoreWebView2Controller *m_host, EventRegistrationToken *token) { #ifndef WINXP - wil::com_ptr m_controller(reinterpret_cast(m_host)); + wil::com_ptr m_controller(m_host); wil::com_ptr m_webView; [&]() { @@ -109,10 +110,10 @@ DECLARE_API void remove_WebMessageReceived(void *m_host, EventRegistrationToken #endif } -DECLARE_API void *add_WebMessageReceived(void *m_host, void (*callback)(const wchar_t *)) +DECLARE_API void *add_WebMessageReceived(ICoreWebView2Controller *m_host, void (*callback)(const wchar_t *)) { #ifndef WINXP - wil::com_ptr m_controller(reinterpret_cast(m_host)); + wil::com_ptr m_controller(m_host); wil::com_ptr coreWebView4 = m_controller.try_query(); if (coreWebView4) @@ -188,20 +189,19 @@ struct contextcallbackdatas }; // https://learn.microsoft.com/zh-cn/microsoft-edge/webview2/how-to/context-menus?tabs=cpp // https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/icorewebview2_11?view=webview2-1.0.2849.39 -DECLARE_API void add_menu_list(void *ptr, int index, const wchar_t *label, void (*callback)(const wchar_t *)) +DECLARE_API void add_menu_list(contextcallbackdatas *ptr, int index, const wchar_t *label, void (*callback)(const wchar_t *)) { if (!ptr) return; - auto token = reinterpret_cast(ptr); - token->menus.insert(token->menus.begin() + index, std::make_pair(label, callback)); + ptr->menus.insert(ptr->menus.begin() + index, std::make_pair(label, callback)); } -DECLARE_API void *add_ContextMenuRequested(void *m_host) +DECLARE_API void *add_ContextMenuRequested(ICoreWebView2Controller *m_host) { #ifndef WINXP contextcallbackdatas *data = new contextcallbackdatas; [=]() { - wil::com_ptr m_controller(reinterpret_cast(m_host)); + wil::com_ptr m_controller(m_host); wil::com_ptr m_webView; CHECK_FAILURE(m_controller->get_CoreWebView2(&m_webView)); auto m_webView2_11 = m_webView.try_query(); @@ -280,10 +280,10 @@ DECLARE_API void *add_ContextMenuRequested(void *m_host) return NULL; #endif } -DECLARE_API void remove_ContextMenuRequested(void *m_host, contextcallbackdatas *data) +DECLARE_API void remove_ContextMenuRequested(ICoreWebView2Controller *m_host, contextcallbackdatas *data) { #ifndef WINXP - wil::com_ptr m_controller(reinterpret_cast(m_host)); + wil::com_ptr m_controller(m_host); wil::com_ptr m_webView; [&]() { @@ -296,4 +296,21 @@ DECLARE_API void remove_ContextMenuRequested(void *m_host, contextcallbackdatas }(); delete data; #endif -} \ No newline at end of file +} +DECLARE_API void get_root_html(ICoreWebView2Controller *m_host, void (*cb)(LPCWSTR)) +{ +#ifndef WINXP + wil::com_ptr m_controller(m_host); + wil::com_ptr m_webView; + + CHECK_FAILURE_NORET(m_controller->get_CoreWebView2(&m_webView)); + CHECK_FAILURE_NORET(m_webView->ExecuteScript(L"document.documentElement.outerHTML", Callback( + [=](HRESULT errorCode, + LPCWSTR resultObjectAsJson) + { + cb(resultObjectAsJson); + return S_OK; + }) + .Get())); +#endif +} diff --git a/py/LunaTranslator/gui/showword.py b/py/LunaTranslator/gui/showword.py index 4cf53786..9b6a7ac3 100644 --- a/py/LunaTranslator/gui/showword.py +++ b/py/LunaTranslator/gui/showword.py @@ -1063,67 +1063,15 @@ class showdiction(QWidget): class showwordfastwebview(auto_select_webview): - def reloaddata(self): - if isinstance(self.internal, mshtmlWidget): - super().reloaddata() - - def _maybecreate_internal(self): - self.needreset = True - super()._maybecreate_internal() - if isinstance(self.internal, WebivewWidget): - if self.lastaction: - super().reloaddata() - else: - self.setframework() def __init__(self, parent, dyna=False): - self.needreset = False super().__init__(parent, dyna) - self.on_load.connect(self.checkurlchange) - def setframework(self, html=None): - path = os.path.join(os.path.dirname(__file__), "showwordfast.html") - if html: - with open(path, "r", encoding="utf8") as ff: - html = ff.read().replace( - '
', - '
{}
'.format(html), - ) - md5 = hashlib.md5(html.encode("utf8", errors="ignore")).hexdigest() - path = gobject.gettempdir(md5 + ".html") - with open(path, "w", encoding="utf8") as ff: - ff.write(html) - self.internal.navigate(os.path.abspath(path)) - - def checkurlchange(self, url: str): - if url == "about:blank": - pass - elif not url.startswith("file:"): - self.needreset = True - - def setHtml(self, html): - # webview2 sethtml谜之很慢,navigate和eval比较快 - if isinstance(self.internal, mshtmlWidget): - super().setHtml(html) - elif isinstance(self.internal, WebivewWidget): - self.lastaction = 1, html - self.internal.set_zoom(self.internalsavedzoom) - if self.needreset: - self.needreset = False - self.setframework(html) - else: - self.internal.eval("_clear_all()") - self.internal.eval("_set_extra_html('{}')".format(quote(html))) - - def clear(self): - if isinstance(self.internal, mshtmlWidget): - super().clear() - elif isinstance(self.internal, WebivewWidget): - self.lastaction = None - if self.needreset: - self.needreset = False - self.setframework() - self.internal.eval("_clear_all()") + def _createwebview(self): + web = super()._createwebview() + if isinstance(web, WebivewWidget): + web.html_limit = 1 + return web class searchwordW(closeashidewindow): diff --git a/py/LunaTranslator/gui/showwordfast.html b/py/LunaTranslator/gui/showwordfast.html deleted file mode 100644 index 191ee3f2..00000000 --- a/py/LunaTranslator/gui/showwordfast.html +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - -
- - - \ No newline at end of file diff --git a/py/LunaTranslator/gui/usefulwidget.py b/py/LunaTranslator/gui/usefulwidget.py index 05591858..e25444fa 100644 --- a/py/LunaTranslator/gui/usefulwidget.py +++ b/py/LunaTranslator/gui/usefulwidget.py @@ -1,7 +1,7 @@ from qtsymbols import * import os, re, functools, hashlib, json, math, csv, io, pickle from traceback import print_exc -import windows, qtawesome, winsharedutils, gobject +import windows, qtawesome, winsharedutils, gobject, threading from webviewpy import webview_native_handle_kind_t, Webview from myutils.config import _TR, globalconfig from myutils.wrapper import Singleton_close, tryprint @@ -1100,6 +1100,9 @@ class abstractwebview(QWidget): html_limit = 2 * 1024 * 1024 # 必须的接口 + def getHtml(self, callback): + return + def setHtml(self, html): pass @@ -1181,6 +1184,14 @@ class WebivewWidget(abstractwebview): # https://github.com/MicrosoftEdge/WebView2Feedback/issues/1355#issuecomment-1384161283 dropfilecallback = pyqtSignal(str) + def getHtml(self, callback): + def __(html): + callback(json.loads(html)) + + cb = winsharedutils.html_get_select_text_cb(__) + winsharedutils.get_root_html(self.get_controller(), cb) + self.callbacks.append(cb) + def __del__(self): if not self.webview: return @@ -1392,6 +1403,10 @@ class QWebWrap(abstractwebview): class mshtmlWidget(abstractwebview): + def getHtml(self, callback): + cb = winsharedutils.html_get_select_text_cb(callback) + winsharedutils.html_get_html(self.browser, cb) + self.callbacks.append(cb) def eval(self, js): winsharedutils.html_eval(self.browser, js) @@ -1505,7 +1520,6 @@ class auto_select_webview(QWidget): def eval(self, js): self.internal.eval(js) - self.evals.append(js) def bind(self, funcname, function): self.bindinfo.append((funcname, function)) @@ -1516,16 +1530,13 @@ class auto_select_webview(QWidget): self.internal.add_menu(index, label, callback) def clear(self): - self.lastaction = None self.internal.setHtml(self.internal.parsehtml("")) # 夜间 def navigate(self, url): - self.lastaction = 0, url self.internal.set_zoom(self.internalsavedzoom) self.internal.navigate(url) def setHtml(self, html): - self.lastaction = 1, html self.internal.set_zoom(self.internalsavedzoom) html = self.internal.parsehtml(html) if len(html) < self.internal.html_limit: @@ -1547,15 +1558,14 @@ class auto_select_webview(QWidget): def __init__(self, parent, dyna=False) -> None: super().__init__(parent) self.addmenuinfo = [] - self.evals = [] self.bindinfo = [] self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) self.internal = None + self.saveurl = None layout = QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) self.internalsavedzoom = 1 - self.lastaction = None self._maybecreate_internal() if dyna: switchtypes.append(self) @@ -1569,31 +1579,36 @@ class auto_select_webview(QWidget): self.internalsavedzoom = zoom self.on_ZoomFactorChanged.emit(zoom) - def _maybecreate_internal(self): - if self.internal: - self.layout().removeWidget(self.internal) + def _gethtmlcallback(self, html): + self.layout().removeWidget(self.internal) + self._createinternal() + self.internal.setHtml(html) + + def _on_load(self, url): + self.saveurl = url + self.on_load.emit(url) + + def _createinternal(self): self.internal = self._createwebview() self.internal.set_zoom(self.internalsavedzoom) - self.internal.on_load.connect(self.on_load) + self.internal.on_load.connect(self._on_load) self.internal.on_ZoomFactorChanged.connect(self.internalzoomchanged) self.layout().addWidget(self.internal) for _ in self.addmenuinfo: self.internal.add_menu(*_) for _ in self.bindinfo: self.internal.bind(*_) - for _ in self.evals: - self.internal.eval(_) - self.reloaddata() - def reloaddata(self): - if self.lastaction: - action, arg = self.lastaction - if action == 0: - self.navigate(arg) - elif action == 1: - self.setHtml(arg) - else: - self.clear() + def _maybecreate_internal(self): + if self.internal: + if self.saveurl and self.saveurl != "about:blank": + self.layout().removeWidget(self.internal) + self._createinternal() + self.internal.navigate(self.saveurl) + else: + self.internal.getHtml(self._gethtmlcallback) + return + self._createinternal() def _createwebview(self): contex = globalconfig["usewebview"] diff --git a/py/LunaTranslator/winsharedutils.py b/py/LunaTranslator/winsharedutils.py index c8bb14a2..e2151e48 100644 --- a/py/LunaTranslator/winsharedutils.py +++ b/py/LunaTranslator/winsharedutils.py @@ -105,7 +105,8 @@ html_get_select_text = utilsdll.html_get_select_text html_get_select_text_cb = CFUNCTYPE(None, c_wchar_p) html_get_select_text.argtypes = (c_void_p, c_void_p) - +html_get_html = utilsdll.html_get_html +html_get_html.argtypes = (c_void_p, c_void_p) html_bind_function_FT = CFUNCTYPE(None, POINTER(c_wchar_p), c_int) html_bind_function = utilsdll.html_bind_function html_bind_function.argtypes = c_void_p, c_wchar_p, html_bind_function_FT @@ -285,6 +286,8 @@ remove_ContextMenuRequested = utilsdll.remove_ContextMenuRequested remove_ContextMenuRequested.argtypes = c_void_p, c_void_p add_menu_list = utilsdll.add_menu_list add_menu_list.argtypes = (c_void_p, c_int, c_wchar_p, add_ContextMenuRequested_cb) +get_root_html = utilsdll.get_root_html +get_root_html.argtypes = c_void_p, c_void_p StartCaptureAsync_cb = CFUNCTYPE(None, c_void_p, c_size_t) StartCaptureAsync = utilsdll.StartCaptureAsync StartCaptureAsync.argtypes = (StartCaptureAsync_cb,)