Mouse is not updating on right / bottom screen edge (DPI scale > 100%)
The mouse does not update on the right and bottom edges of the screen.
function love.draw()
love.graphics.clear(0.1, 0.2, 0.3)
local sw, sh = love.graphics.getDimensions()
local mx, my = love.mouse.getPosition()
local time = love.timer.getTime()
love.graphics.setColor(0.3, 0.4, 0.5)
love.graphics.setLineWidth(5)
love.graphics.line(0, my, sw, my)
love.graphics.line(mx, 0, mx, sh)
love.graphics.circle("fill", mx, my, 20 + math.cos(time * 5) * 5)
love.graphics.circle("line", mx, my, 40 + math.sin(time * 5) * 10)
love.graphics.setColor(1, 1, 1)
love.graphics.print("Press F11 to toggle fullscreen.", 10, 10)
love.graphics.print("In fullscreen, move the mouse to each edge of the screen.", 10, 30)
love.graphics.print("Bug: The mouse is not updated on the right and bottom edges.", 10, 50)
love.graphics.print("Tested on Windows 11.", 10, 70)
end
function love.keypressed(key)
if key == "escape" then love.event.quit() end
if key == "f11" then love.window.setFullscreen(not love.window.getFullscreen()) end
end
Version 11.5 (2023-12-03) Windows 11
It's working as expected for me in Windows 10 with love 11.5 - in windowed mode, the mouse position isn't updated when the cursor is outside of the window (no matter what edge). In fullscreen it behaves the same, I have two monitors and if my mouse cursor goes past the right edge of the primary one where love is into my secondary monitor, then the mouse position in love doesn't update.
Additionally, if I hold my left mouse button down and move the cursor around, it updates the mouse position past the bounds of the window no matter the edge but still clamps it (this is new intended behaviour as of the latest SDL version).
Do you have a multi-monitor setup that extends past the bottom and right sides of the display where you made that recording, maybe?
love also has APIs like love.mouse.setRelativeMode and love.mouse.setGrabbed if you want to constrain the user's cursor to the window in a particular way.
I only have one monitor. The mouse is within the screen. In the gif video, you can see a bit of the cursor when moving on the right edge. I know that the mouse is not updating when moved outside. This is ok. But in this case, the mouse is still within the window. You can just detect this bug in fullscreen where you can't move outside.
One use case I'm thinking is an RTS/city building game where you can move the mouse on the edge to scroll the camera view. No mouse event (click or position) is working on the edge right or bottom.
function love.draw()
love.graphics.clear(0.1, 0.2, 0.3, 0.1)
local sw, sh = love.graphics.getDimensions()
local mx, my = love.mouse.getPosition()
love.graphics.setColor(0.3, 0.4, 0.5)
love.graphics.setLineWidth(5)
love.graphics.line(0, my, sw, my)
love.graphics.line(mx, 0, mx, sh)
love.graphics.circle("fill", mx, my, love.mouse.isDown(1) and 30 or 10)
end
function love.keypressed(key)
if key == "escape" then love.event.quit() end
if key == "f11" then love.window.setFullscreen(not love.window.getFullscreen()) end
end
As you can see in the code. You can now click the (left) mouse button to change the circle size. Try it on the edge. Unplug your second monitor and test it.
I don't know the source code but it looks like (pseudo code):
mosue_pos >= 0 and mouse_pos < screen_size
-- instead of
mosue_pos >= 0 and mouse_pos <= screen_size
You know what I mean? Or the game area is 1 pixel smaller that the screen. Or the window invisible border blocks the event. I don't know. But it's definitly a bug.
Like I said, it's working as expected on my system, I can't reproduce the problem you're describing - and also love doesn't have code like that itself (it just does what SDL and the OS do under the hood). So there's probably a difference between our two systems causing it. Maybe the OS itself considering you have windows 11 and I have windows 10, or maybe something else.
Do you use a DPI scale / display scale set to something other than 100%, for your monitor? Windows will handle a bunch of scaling itself and upscale love in that situation.
Indeed, I use 200% UI scaling for my 4k TV. For testing I changed it back to 100% and the problem no longer occurs. So it seems it's related to the UI scaling. Can someone reproduce this or explain what happened here? So, it's a bug. The question is, can we fix this in love2d? Any workaround?
Btw. t.window.highdpi = true does not work on Windows. I would expect an option to disable scaling for the application. I also tried variations with t.window.usedpiscale. It seems this is not supported in love2d. These options are for mobile, right? In e.g. Godot this option also works on Windows. Btw. this is one reason why the screen looks pixelated.
Btw. t.window.highdpi = true does not work on Windows.
That's correct, the version of SDL love uses doesn't support it on Windows with love 11's api.
It does work on macOS, iOS, Android, and Wayland (Linux). Microsoft ended up implementing app DPI scaling in a manner that's incompatible with how love sets it dynamically for the window though.
love 12 has a global per-app API for it instead, to accommodate Windows.
I just played around again and found this... (for the sake of completeness and possible bug fixes)
- It has nothing to do with the fullscreen. I was able to reproduce the same behavior with
mouse.setGrabbed. - If
isGrabbedthen the mouse also hangs on right / bottom edges. - If I click and hold the mouse button while moving the cursor around the edges and outside, it works without any problems.
In both cases (grabbed and pressing) the mouse position on edge is the same. But only pressing works as expected (mouse also works on edges). But you can also move the mouse outside the game (if windowed). So I guess it's a global mouse event. Only the last pixel on the right/bottom doesn't seem to be a part of the game view. So setGrabbed does also not work. ...
function love.load()
love.mouse.setGrabbed(true)
end
function love.draw()
love.graphics.clear(0.1, 0.2, 0.3, 0.1)
local sw, sh = love.graphics.getDimensions()
local mx, my = love.mouse.getPosition()
love.graphics.setColor(0.3, 0.4, 0.5)
love.graphics.setLineWidth(5)
love.graphics.line(0, my, sw, my)
love.graphics.line(mx, 0, mx, sh)
love.graphics.circle("fill", mx, my, love.mouse.isDown(1) and 30 or 10)
love.graphics.setColor(1, 1, 1)
love.graphics.print("ESC: Quit; F11: Fullscreen; F1: Grab/Free mouse", 10, 10)
love.graphics.print("Screen size: " .. sw .. ", " .. sh, 10, 30)
love.graphics.print("Mouse pos: " .. mx .. ", " .. my, 10, 50)
end
function love.keypressed(key)
if key == "escape" then love.event.quit() end
if key == "f11" then love.window.setFullscreen(not love.window.getFullscreen()) end
if key == "f1" then love.mouse.setGrabbed(not love.mouse.isGrabbed()) end
end