feat: implement mouse event emulator for Qt WebEngineView to enhance hover effects
Some checks are pending
Tests & Quality Checks / Test on Python 3.11 (push) Waiting to run
Tests & Quality Checks / Test on Python 3.12 (push) Waiting to run
Tests & Quality Checks / Test on Python 3.11-1 (push) Waiting to run
Tests & Quality Checks / Test on Python 3.12-1 (push) Waiting to run
Tests & Quality Checks / Test on Python 3.10 (push) Waiting to run
Tests & Quality Checks / Test on Python 3.11-2 (push) Waiting to run
Tests & Quality Checks / Test on Python 3.12-2 (push) Waiting to run
Tests & Quality Checks / Build Artifacts (push) Blocked by required conditions
Tests & Quality Checks / Build Artifacts-1 (push) Blocked by required conditions

This commit is contained in:
claudi 2026-03-04 14:49:40 +01:00
parent c612072dc8
commit 810baf65d9
5 changed files with 482 additions and 25 deletions

View file

@ -534,8 +534,8 @@ class MainWindow(QMainWindow):
def _install_bridge_script(self) -> None:
"""Install the drag bridge JavaScript via QWebEngineScript.
Uses DocumentCreation injection point to ensure script runs as early as possible,
before any page scripts that might interfere with drag events.
Uses Deferred injection point to ensure script runs after the DOM is ready,
allowing proper event listener registration without race conditions.
Embeds qwebchannel.js inline to avoid CSP issues with qrc:// URLs.
Injects configuration that bridge script uses for dynamic URL pattern matching.
@ -544,7 +544,9 @@ class MainWindow(QMainWindow):
script = QWebEngineScript()
script.setName("webdrop-bridge")
script.setInjectionPoint(QWebEngineScript.InjectionPoint.DocumentCreation)
# Use Deferred instead of DocumentCreation to allow DOM to be ready first
# This prevents race conditions with JavaScript event listeners
script.setInjectionPoint(QWebEngineScript.InjectionPoint.Deferred)
script.setWorldId(QWebEngineScript.ScriptWorldId.MainWorld)
script.setRunsOnSubFrames(False)
@ -633,18 +635,47 @@ class MainWindow(QMainWindow):
else:
logger.debug("Download interceptor not found (optional)")
# Combine: qwebchannel.js + config + bridge script + download interceptor
# Load mouse event emulator for hover effect support
mouse_emulator_search_paths = []
mouse_emulator_search_paths.append(Path(__file__).parent / "mouse_event_emulator.js")
if hasattr(sys, "_MEIPASS"):
mouse_emulator_search_paths.append(
Path(sys._MEIPASS) / "webdrop_bridge" / "ui" / "mouse_event_emulator.js" # type: ignore
)
mouse_emulator_search_paths.append(
exe_dir / "webdrop_bridge" / "ui" / "mouse_event_emulator.js"
)
mouse_emulator_code = ""
for path in mouse_emulator_search_paths:
if path.exists():
try:
with open(path, "r", encoding="utf-8") as f:
mouse_emulator_code = f.read()
logger.debug(f"Loaded mouse event emulator from {path}")
break
except (OSError, IOError) as e:
logger.warning(f"Mouse event emulator exists but failed to load: {e}")
if not mouse_emulator_code:
logger.debug("Mouse event emulator not found (optional)")
# Combine: qwebchannel.js + config + bridge script + download interceptor + mouse emulator
combined_code = qwebchannel_code + "\n\n" + config_code + "\n\n" + bridge_code
if download_interceptor_code:
combined_code += "\n\n" + download_interceptor_code
# Add mouse event emulator last to ensure it runs after all other scripts
if mouse_emulator_code:
combined_code += "\n\n" + mouse_emulator_code
logger.debug(
f"Combined script size: {len(combined_code)} chars "
f"(qwebchannel: {len(qwebchannel_code)}, "
f"config: {len(config_code)}, "
f"bridge: {len(bridge_code)}, "
f"interceptor: {len(download_interceptor_code)})"
f"interceptor: {len(download_interceptor_code)}, "
f"mouse_emulator: {len(mouse_emulator_code)})"
)
logger.debug(f"URL mappings in config: {len(self.config.url_mappings)}")
for i, mapping in enumerate(self.config.url_mappings):