Windows prefers WebView2, Linux uses QtWebEngine only; pythonnet deps are win32-marked. Each QtWebEngine instance gets its own profile under data/webengine, and Chromium flags are sanitized before QApplication (--no-sandbox accepted only for explicit root/container use).
77 lines
3.3 KiB
Python
77 lines
3.3 KiB
Python
from PyQt6.QtWebEngineCore import QWebEnginePage, QWebEngineScript, QWebEngineProfile
|
||
from PyQt6.QtCore import QUrl
|
||
from PyQt6.QtGui import QDesktopServices
|
||
|
||
class CustomWebPage(QWebEnginePage):
|
||
"""
|
||
自定义网页类,集中约束内置 QtWebEngine 的不合规浏览器行为:
|
||
|
||
1. 拦截所有外部链接跳转,改用系统默认浏览器打开;
|
||
2. 禁用 Ctrl/Meta + 滚轮 及 Ctrl + +/-/0 快捷键的页面缩放
|
||
(浏览器式缩放对桌面聊天工具无意义且易误触)。
|
||
"""
|
||
def __init__(self, profile_or_parent=None, parent=None):
|
||
# P1-03:兼容两种调用 —— 新式 CustomWebPage(profile, parent) 与旧式 CustomWebPage(parent)。
|
||
# profile 缺省 None → QtWebEngine 默认 profile;main_window 传入本实例独立 profile。
|
||
if isinstance(profile_or_parent, QWebEngineProfile):
|
||
profile, par = profile_or_parent, parent
|
||
else:
|
||
profile, par = None, profile_or_parent
|
||
if parent is not None:
|
||
raise TypeError("CustomWebPage(profile, parent) 或 CustomWebPage(parent)")
|
||
if profile is not None:
|
||
super().__init__(profile, par)
|
||
else:
|
||
super().__init__(par)
|
||
self._inject_zoom_lock()
|
||
|
||
def _inject_zoom_lock(self):
|
||
"""
|
||
🌟 缩放锁定:通过网页脚本在文档创建阶段(DocumentCreation)注入监听,
|
||
使用隔离世界(ApplicationWorld)注入,不污染页面自身逻辑。
|
||
|
||
原理:Chromium 的 Ctrl+滚轮缩放会先经过页面 wheel 事件的
|
||
preventDefault() 判定 —— 页面阻止即取消缩放,这是地图类应用
|
||
禁用缩放的官方做法;Ctrl+=/-/0 快捷键同理用 keydown 拦截。
|
||
"""
|
||
script = QWebEngineScript()
|
||
script.setName("haocode_zoom_lock")
|
||
script.setInjectionPoint(QWebEngineScript.InjectionPoint.DocumentCreation)
|
||
script.setWorldId(QWebEngineScript.ScriptWorldId.ApplicationWorld)
|
||
script.setRunsOnSubFrames(True)
|
||
script.setSourceCode(r"""
|
||
(function () {
|
||
if (window.__haocodeZoomLocked) return; // 防重复注入
|
||
window.__haocodeZoomLocked = true;
|
||
|
||
// 1) Ctrl/Meta + 滚轮 → 阻止缩放
|
||
document.addEventListener('wheel', function (e) {
|
||
if (e.ctrlKey || e.metaKey) {
|
||
e.preventDefault();
|
||
e.stopPropagation();
|
||
}
|
||
}, { passive: false }); // 必须非被动,preventDefault 才有效
|
||
|
||
// 2) Ctrl + = / + / - / 0 → 阻止缩放快捷键
|
||
document.addEventListener('keydown', function (e) {
|
||
if ((e.ctrlKey || e.metaKey) && ['+', '-', '=', '0'].indexOf(e.key) >= 0) {
|
||
e.preventDefault();
|
||
}
|
||
}, false);
|
||
})();
|
||
""")
|
||
self.scripts().insert(script)
|
||
|
||
def acceptNavigationRequest(self, url: QUrl, nav_type, is_main_frame):
|
||
# 如果是本地文件(我们自己的 index.html),允许加载
|
||
if url.scheme() == "file":
|
||
return True
|
||
|
||
# 如果是外部链接(http/https),用系统浏览器打开
|
||
if url.scheme() in ["http", "https"]:
|
||
print(f"[System]: 在系统浏览器中打开 -> {url.toString()}")
|
||
QDesktopServices.openUrl(url)
|
||
return False # 阻止在应用内跳转
|
||
|
||
# 其他情况(如 javascript:void(0)),允许
|
||
return True |