Last active
July 21, 2023 13:42
-
-
Save louisameline/1213bb112c6cb12a98b2ab525dfb8b07 to your computer and use it in GitHub Desktop.
Electron: workaround for issue #611
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Work around for https://github.com/electron/electron/issues/611 | |
* This snippet will check if the cursor has left the window, and trigger | |
* mouse events accordingly. It even works with -webkit-app-region areas, | |
* which usually don't send any mouse events, so it's pretty cool. You | |
* can see the result in this gif: http://s214903023.onlinehome.fr/divers/fix.gif | |
* Help is welcome for improvement, for example to remove the dependency to | |
* jQuery. | |
* | |
* Caveats:it triggers too many events. For example when the mouse | |
* comes back to the window, the mouseenter listener of the hovered element | |
* may be triggered twice, depending on whether the cursor was already on | |
* the element when it left the window, that kind of things. It would be too | |
* tricky to catch every unwanted events. But too many events are better | |
* than none, right? Just need to ignore the extra ones. | |
*/ | |
// the interval at which we'll check if the mouse has left the window | |
var intervalValue = 1000, | |
// if the position checker should run even when the window is not | |
// focused. The pro is that app regions will work better, you can | |
// be sure that they (and their ancestors) will get a mouseenter | |
// event when the mouse comes back. The con is that the window will | |
// get events when the mouse is over it... even when another window | |
// is actually inbetween (like in the gif). | |
regionAppOptimized = false, | |
window = electron.remote.getCurrentWindow(), | |
mouseIsOut = function(){ | |
var systemMouseCoord = electron.screen.getCursorScreenPoint(), | |
winCoord = window.getPosition(), | |
winSize = window.getSize(); | |
return (systemMouseCoord.x < winCoord[0] | |
|| systemMouseCoord.x > winCoord[0] + winSize[0] | |
|| systemMouseCoord.y < winCoord[1] | |
|| systemMouseCoord.y > winCoord[1] + winSize[1] | |
); | |
}, | |
out = mouseIsOut(), | |
windowMouseCoord, | |
lastEl; | |
setInterval(function(){ | |
// if the mouse is outside of the window | |
if(mouseIsOut()){ | |
// if the mouse was previously inside | |
if(out === false){ | |
out = true; | |
// if we've located the mouse previously (unless the user opened the window and | |
// left after using the tab key or something, it should be ok) | |
if(windowMouseCoord){ | |
// trigger the mouseout event on the last element where we know the mouse was | |
lastEl = document.elementFromPoint(windowMouseCoord.x, windowMouseCoord.y); | |
$(lastEl) | |
// also triggers mouseout | |
.trigger('mouseleave', true) | |
// this will prevent the bubbling of the event that has just been faked | |
.one('mouseout', function(e, fake){ | |
if(!fake){ | |
e.preventDefault(); | |
e.stopImmediatePropagation(); | |
} | |
}); | |
} | |
} | |
} | |
else { | |
if(out === true){ | |
if(window.isFocused() || regionAppOptimized){ | |
out = false; | |
// if the interval sees the return of the mouse before the mouse listener | |
// does, that's because the mouse is near the edges in resize mode or over | |
// an app-region area that swallows mouse events, so we need to trigger a | |
// mouseover ourselves. | |
// determine the coordinates of the mouse relatively to the window | |
var systemMouseCoord = that.app.model.electron.screen.getCursorScreenPoint(), | |
winCoord = window.getPosition(), | |
actualWindowMouseCoord = { | |
x: systemMouseCoord.x - winCoord[0], | |
y: systemMouseCoord.y - winCoord[1] | |
}, | |
element = document.elementFromPoint(actualWindowMouseCoord.x, actualWindowMouseCoord.y); | |
// element is null if the mouse is in the window but not in the document | |
if(element){ | |
$(element).trigger('mouseover', true); | |
// save the mouse position although there was no mouse move event | |
windowMouseCoord = actualWindowMouseCoord; | |
} | |
} | |
} | |
} | |
}, intervalValue); | |
$(document.body).mousemove(function(e){ | |
// we need to record the mouse position at all times | |
windowMouseCoord = { | |
x: e.pageX, | |
y: e.pageY | |
}; | |
// if this listener catches the return of the mouse before our interval does | |
if(out){ | |
// the mousemove events are sometimes deferred and actually happen after the | |
// mouse has left the window (and after our interval detected it), so we need | |
// to make sure this event is the sign of a returning mouse | |
if(!mouseIsOut()){ | |
out = false; | |
// if the window was loaded with the mouse outside of it, it will work | |
// fine when it comes in it | |
if(lastEl){ | |
// the current element below the cursor | |
var element = document.elementFromPoint(e.pageX, e.pageY); | |
// the system will trigger nothing here, let's do this ourselves | |
if(element === lastEl){ | |
// also triggers mouseenters | |
$(element).trigger('mouseover', true); | |
} | |
// if the former element was a descendant, a mouse over event will be | |
// triggered by the system but no mouseenters at all, so we simulate them | |
else if($.contains(element, lastEl)){ | |
// will bubble up on ancestors | |
$(element).trigger('mouseenter', true); | |
} | |
// if the former element was an ancestor, the system will have triggered a | |
// bubbling mouseover and a mouseenter on the element, but not on its | |
// ancestors, so we also trigger a mouseenter here | |
else if($.contains(lastEl, element)){ | |
// will bubble up on ancestors | |
$(element).trigger('mouseenter', true); | |
} | |
// if the elements are not parents, the system will act as expected | |
else {} | |
} | |
} | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
It works for me. BTW, the
that
andelectron
may not be defined before running it. And it would be better if you rename thewindow
variable to something else.