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

@ -0,0 +1,186 @@
// Mouse Event Emulator for Qt WebEngineView
// Qt WebEngineView may not forward all mouse events to JavaScript properly
// This script uses polling with document.elementFromPoint() to detect hover changes
// and manually dispatches mouseover/mouseenter/mouseleave events.
// ALSO: Injects a CSS stylesheet that simulates :hover effects using classes
(function() {
try {
if (window.__mouse_emulator_injected) return;
window.__mouse_emulator_injected = true;
console.log("[MouseEventEmulator] Initialized - polling for hover state changes");
// ========================================================
// PART 1: Inject CSS stylesheet for hover simulation
// ========================================================
var style = document.createElement("style");
style.type = "text/css";
style.id = "__mouse_emulator_hover_styles";
style.innerHTML = `
/* Checkbox hover simulation */
input[type="checkbox"].__mouse_hover {
cursor: pointer;
}
/* Link hover simulation */
a.__mouse_hover {
text-decoration: underline;
}
`;
if (document.head) {
document.head.insertBefore(style, document.head.firstChild);
} else {
document.body.insertBefore(style, document.body.firstChild);
}
// ========================================================
// PART 2: Track hover state and apply hover class
// ========================================================
var lastElement = null;
var lastX = -1;
var lastY = -1;
// High-frequency polling to detect element changes at mouse position
var pollIntervalId = setInterval(function() {
if (!window.__lastMousePos) {
window.__lastMousePos = { x: 0, y: 0 };
}
var x = window.__lastMousePos.x;
var y = window.__lastMousePos.y;
lastX = x;
lastY = y;
var element = document.elementFromPoint(x, y);
if (!element || element === document || element.tagName === "HTML") {
if (lastElement && lastElement !== document) {
try {
lastElement.classList.remove("__mouse_hover");
var leaveEvent = new MouseEvent("mouseleave", {
bubbles: true,
cancelable: true,
view: window,
});
lastElement.dispatchEvent(leaveEvent);
} catch (err) {
console.warn("[MouseEventEmulator] Error in leave handler:", err);
}
lastElement = null;
}
return;
}
// Element changed
if (element !== lastElement) {
// Remove hover class from previous element
if (lastElement && lastElement !== document && lastElement !== element) {
try {
lastElement.classList.remove("__mouse_hover");
var leaveEvent = new MouseEvent("mouseleave", {
bubbles: true,
cancelable: true,
view: window,
clientX: x,
clientY: y,
});
lastElement.dispatchEvent(leaveEvent);
} catch (err) {
console.warn("[MouseEventEmulator] Error dispatching mouseleave:", err);
}
}
// Add hover class and dispatch events for new element
if (element) {
try {
element.classList.add("__mouse_hover");
var overEvent = new MouseEvent("mouseover", {
bubbles: true,
cancelable: true,
view: window,
clientX: x,
clientY: y,
});
element.dispatchEvent(overEvent);
var enterEvent = new MouseEvent("mouseenter", {
bubbles: false,
cancelable: true,
view: window,
clientX: x,
clientY: y,
});
element.dispatchEvent(enterEvent);
var moveEvent = new MouseEvent("mousemove", {
bubbles: true,
cancelable: true,
view: window,
clientX: x,
clientY: y,
});
element.dispatchEvent(moveEvent);
} catch (err) {
console.warn("[MouseEventEmulator] Error dispatching mouse events:", err);
}
}
lastElement = element;
}
}, 50);
// Track mouse position from all available events
document.addEventListener(
"mousemove",
function(e) {
window.__lastMousePos = { x: e.clientX, y: e.clientY };
},
true
);
document.addEventListener(
"mousedown",
function(e) {
window.__lastMousePos = { x: e.clientX, y: e.clientY };
},
true
);
document.addEventListener(
"mouseup",
function(e) {
window.__lastMousePos = { x: e.clientX, y: e.clientY };
},
true
);
document.addEventListener(
"mouseover",
function(e) {
window.__lastMousePos = { x: e.clientX, y: e.clientY };
},
true
);
document.addEventListener(
"mouseenter",
function(e) {
window.__lastMousePos = { x: e.clientX, y: e.clientY };
},
true
);
console.log("[MouseEventEmulator] Ready - polling enabled for hover state detection");
} catch (e) {
console.error("[MouseEventEmulator] FATAL ERROR:", e);
if (e.stack) {
console.error("[MouseEventEmulator] Stack:", e.stack);
}
}
})();