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
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:
parent
c612072dc8
commit
810baf65d9
5 changed files with 482 additions and 25 deletions
186
src/webdrop_bridge/ui/mouse_event_emulator.js
Normal file
186
src/webdrop_bridge/ui/mouse_event_emulator.js
Normal 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);
|
||||
}
|
||||
}
|
||||
})();
|
||||
Loading…
Add table
Add a link
Reference in a new issue