Quick answer: The Mouse Leave event fires when the cursor leaves an instance’s bounding box, not the application window. For window-level exit detection, poll window_has_focus() each step or compare mouse_x/mouse_y against window bounds.
Here is how to fix GameMaker GMS2 games that need to know when the cursor leaves the window. You hook up Mouse Leave Event expecting window-exit notification, but it only fires when the cursor leaves the current instance. The fix uses polling and async events.
The Symptom
You want to pause the game when the player’s mouse leaves the window. You add Mouse Leave Event to the controller object. It fires multiple times per second whenever the cursor leaves any instance, but never when leaving the window.
What Causes This
Mouse Leave is per-instance. The classic event tracks an instance’s bounding box, useful for hovering over UI buttons. Not for window-level events.
No window-level event. GameMaker does not expose a built-in window-leave event. Polling is the workaround.
Focus state separate from cursor position. Alt-tabbing changes focus without moving the cursor. Window position changes do not affect cursor relativity.
The Fix
Step 1: Poll window_has_focus.
// Step event of oController
if (window_has_focus_prev && !window_has_focus()) {
// Just lost focus
on_window_blur();
}
if (!window_has_focus_prev && window_has_focus()) {
// Just gained focus
on_window_focus();
}
window_has_focus_prev = window_has_focus();
Tracks edge transitions of focus state.
Step 2: Poll mouse position against window bounds.
var _w = window_get_width();
var _h = window_get_height();
var _gx = device_mouse_x_to_gui(0);
var _gy = device_mouse_y_to_gui(0);
var _inside = (_gx >= 0 && _gx < _w && _gy >= 0 && _gy < _h);
if (mouse_inside_prev && !_inside) on_mouse_leave_window();
if (!mouse_inside_prev && _inside) on_mouse_enter_window();
mouse_inside_prev = _inside;
Step 3: Pause on focus loss.
function on_window_blur() {
instance_deactivate_all(true); // pause everything
audio_pause_all();
}
function on_window_focus() {
instance_activate_all();
audio_resume_all();
}
Step 4: Use Async System events for OS-level signals.
// Async - System event of oController
switch (async_load[? "event_type"]) {
case "window_focus":
on_window_focus();
break;
case "window_blur":
on_window_blur();
break;
}
Async System events provide platform-specific signals on supported targets (HTML5 typically).
Step 5: For fullscreen edge cases, clamp. Fullscreen multi-monitor setups can give weird mouse coords. Clamp to window dimensions before testing inside.
Use Cases
Pause on focus loss for single-player games. Mute on cursor exit for tab-friendly indie. Disable input on focus loss to avoid stray clicks affecting the game while alt-tabbed.
“Mouse Leave is for instances. Window focus is a poll. Track the previous-frame state and detect transitions.”
Related Issues
For surface lifecycle, see Surface Lost After Resize. For shader uniforms, see Shader Uniform Per Frame.
window_has_focus polling. Edge-detect transitions. Pause and mute on blur. Resume on focus.