I thought this one would be easy, but it turns out it's not.
Take the following situation: a primary desktop on the bottom, and a secondary desktop above that primary desktop.
The objective is to get the mouse X and Y position relative to the screen hosting the window on the secondary desktop. The naive approach would be:
const onMouseMove = e => {
const hostScreenX = e.screenX;
const hostScreenY = e.screenY;
document.body.innerHTML = `${hostScreenX}x${hostScreenY}`;
};
window.addEventListener("mousemove", onMouseMove, false);
Turns out this returns a negative number for screenY
when running on the secondary screen (the top one). The primary screen is seen as the "zero boundary" and everything before that is in a negative space.
We can account for this using screen.availTop
and screen.availLeft
:
const onMouseMove = e => {
const hostScreenX = e.screenX - window.screen.availLeft;
const hostScreenY = e.screenY - window.screen.availTop;
document.body.innerHTML = `${hostScreenX}x${hostScreenY}`;
};
window.addEventListener("mousemove", onMouseMove, false);
Much better, except it's actually incorrect: because the availTop space includes the space of the permanent operating system UI (on MacOS the toolbar, and on Windows the toolbar if you moved the toolbar from the default bottom to the top), we are incorrectly subtracting the toolbar space.
E.g. on MacOS in chrome when moving the mouse to the far top this would give us a hostScreenY
of 80, whereas it should be 103 (the macos toolbar is 23 pixels).
You might then think that we can solve for this by adding back the difference in height - availHeight:
const onMouseMove = e => {
const hostScreenX = e.screenX - window.screen.availLeft + (window.screen.width - window.screen.availWidth);
const hostScreenY = e.screenY - window.screen.availTop + (window.screen.height - window.screen.availHeight);
document.body.innerHTML = `${hostScreenX}x${hostScreenY}`;
};
window.addEventListener("mousemove", onMouseMove, false);
And indeed this seems to be perfect on MacOS.
The problem is that this assumes that the toolbar of the operating system is on the top of the screen, which is usually not true on Windows (though sometimes it is if you move your toolbar to the top). As a result, the values are offset by the toolbar space.
How can we get the screenX and screenY relative to the screen hosting the current window when using secondary (or even tertiary) monitors on the mousemove event in Javascript?