Managing Mouse Focus with SDL2

Learn how to track and respond to mouse focus events in SDL2, including handling multiple windows and customizing focus-related click behavior.

Ryan McCombe
Updated

In desktop environments, users can have multiple windows open at once. On most platforms, only a single window can have input focus at a time, which is typically gained by the user clicking on the window:

This is referred to as input focus, and we covered it in more detail in our earlier lesson on keyboard input:

Managing Window Input Focus

Learn how to manage and control window input focus in SDL applications, including how to create, detect, and manipulate window focus states.

In this lesson, we'll introduce the related concept of mouse focus. A window has mouse focus if the user's pointer is currently hovering over it. The window with mouse focus is not necessarily the same as the window with input focus.

Tracking Mouse Focus Using the Event Loop

Let's begin with a basic application loop. SDL dispatches window events (SDL_WindowEvent) when a window gains and loses mouse focus, so we'll look out for those in our event loop:

#include <SDL.h>
#include "Window.h"

void HandleWindowEvent(SDL_WindowEvent& E) {
  // ...
}

int main(int argc, char** argv) {
  SDL_Init(SDL_INIT_VIDEO);
  Window GameWindow;
  SDL_Event E;

  while (true) {
    while (SDL_PollEvent(&E)) {
      if (E.type == SDL_WINDOWEVENT) {
        HandleWindowEvent(E.window);
      }
    }
    GameWindow.Update();
  }

  SDL_Quit();
  return 0;
}

We can check if the event specifically relates to a window gaining or losing focus by comparing the event property of the SDL_WindowEvent to SDL_WINDOWEVENT_ENTER or SDL_WINDOWEVENT_LEAVE respectively:

#include <SDL.h>
#include <iostream>
#include "Window.h"

void HandleWindowEvent(SDL_WindowEvent& E) {
  if (E.event == SDL_WINDOWEVENT_ENTER) {
    std::cout << "Mouse Entered Window\n";
  } else if (E.event == SDL_WINDOWEVENT_LEAVE) {
    std::cout << "Mouse Left Window\n";
  }
}

int main(int argc, char** argv) {/*...*/}
Mouse Entered Window
Mouse Left Window

Using SDL_GetWindowFlags()

As with most things in SDL, we don't need to monitor events to retrieve the state of its internally-managed objects, like an SDL_Window. Instead, we can directly query the state of those objects at any time.

SDL_Window objects keep track of whether or not they have focus within their window flags. As we covered in the previous chapter, we can access those flags by passing the SDL_Window pointer to SDL_GetWindowFlags():

SDLWindow* Window{SDL_CreateWindow(
  "Some Window",
  200, 200,
  700, 300, 0
)};

SDL_WindowFlags Flags{
  SDL_GetWindowFlags(Window)
};

The SDL_WindowFlags type is a bit mask in the form of a 32-bit unsigned integer. We can examine the state of any flag using the & operator. SDL provides the SDL_WINDOW_MOUSE_FOCUS helper to give us easy access to the flag that tracks whether the window has mouse focus:

bool hasFocus{
  SDL_GetWindowFlags(Window) &
    SDL_WINDOW_MOUSE_FOCUS
};

In practice, this state-checking approach is appropriate when we need to check if the window has focus as part of our reaction to some other event. The following example checks if our window has mouse focus when the user presses a keyboard button:

#include <SDL.h>
#include <iostream>
#include "Window.h"

void LogFocus(SDL_Window* Window) {
  std::cout << "\nMouse focus: ";
  if (SDL_GetWindowFlags(Window) &
    SDL_WINDOW_MOUSE_FOCUS) {
    std::cout << "yes";
  } else {
    std::cout << "no";
  }
}

int main(int argc, char** argv) {
  SDL_Init(SDL_INIT_VIDEO);
  Window GameWindow;

  SDL_Event E;
  while (true) {
    while (SDL_PollEvent(&E)) {
      if (E.type == SDL_KEYDOWN) {
        LogFocus(GameWindow.SDLWindow);
      }
    }
    GameWindow.Update();
  }

  SDL_Quit();
  return 0;
}
Mouse focus: no
Mouse focus: no
Mouse focus: yes

In the following example, we create a timer that checks every second (1,000 milliseconds) if our window has mouse focus:

#include <SDL.h>
#include <iostream>
#include "Window.h"

Uint32 MonitorWindow(Uint32 Timer, void* Win) {
  auto* Window{static_cast<SDL_Window*>(Win)};

  if (SDL_GetWindowFlags(Window) &
    SDL_WINDOW_MOUSE_FOCUS) {
    std::cout << "Focus\n";
  } else {
    std::cout << "No Focus\n";
  }

  return Timer;
}

int main(int argc, char** argv) {/*...*/}
No Focus
Focus
Focus

Using SDL_GetMouseFocus()

SDL also provides the SDL_GetMouseFocus() function, which returns the SDL_Window* with mouse focus, or a nullptr if no window has focus.

This example is very similar to the previous one, except we've updated our implementation to use SDL_GetMouseFocus() instead of SDL_GetWindowFlags().

#include <SDL.h>
#include <iostream>
#include "Window.h"

Uint32 MonitorWindow(Uint32 Timer, void* Win) {
  auto* Window{static_cast<SDL_Window*>(Win)};

  if (Window == SDL_GetMouseFocus()) {
    std::cout << "Focus\n";
  } else {
    std::cout << "No Focus\n";
  }
  return Timer;
}

int main(int argc, char** argv) {/*...*/}
No Focus
Focus
Focus

Whilst the SDL_GetWindowFlags() example lets us determine if a specific window has focus, SDL_GetMouseFocus() is primarily useful when we want to know which window has focus. This is typically used in applications where we manage multiple windows, including utility windows.

The following program creates two windows and, on every iteration of our application loop, reports which one of them has mouse focus:

#include <SDL.h>
#include <iostream>
#include "Window.h"

int main(int argc, char** argv) {
  SDL_Init(SDL_INIT_VIDEO);
  Window Window1;
  Window Window2;

  SDL_Event E;
  while (true) {
    while (SDL_PollEvent(&E)) {
      // ...
    }

    SDL_Window* Focused{SDL_GetMouseFocus()};

    if (Focused == Window1.SDLWindow) {
      std::cout << "Window 1 has focus\n";
    } else if (Focused == Window2.SDLWindow) {
      std::cout << "Window 2 has focus\n";
    } else {
      std::cout << "Neither has focus\n";
    }

    Window1.Update();
    Window2.Update();
  }

  SDL_Quit();
  return 0;
}
Window 1 has focus
Window 1 has focus
Neither has focus
Window 2 has focus

Click Events when Switching Input Focus

The most common way a user will switch their input focus is by left-clicking on the window with their mouse. By default, SDL does not report these clicks - you won't get a mouse click event when the user clicks to set input focus to your window.

This is typically a sensible default for games. For example, if we're working on a first-person shooter, we want players to be able to switch focus to our window by clicking on it, and we won't want that click to also fire their weapon.

However, we can change this behavior by setting the SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH hint to "1":

#include <SDL.h>
#include <iostream>
#include "Window.h"


int main(int argc, char** argv) {
  SDL_SetHint(
    SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH,
    "1"
  );
  SDL_Init(SDL_INIT_VIDEO);
  Window GameWindow;

  SDL_Event E;

  while (true) {
    while (SDL_PollEvent(&E)) {
      switch (E.type) {
      case SDL_WINDOWEVENT:
        if (E.window.event ==
          SDL_WINDOWEVENT_FOCUS_GAINED) {
          std::cout << "Input Focus Event\n";
        }
        break;

      case SDL_MOUSEBUTTONDOWN:
        if (E.button.button ==
          SDL_BUTTON_LEFT) {
          std::cout << "Also a Click Event\n";
        }
        break;

      default:
        break;
      }
    }
    GameWindow.Update();
  }

  SDL_Quit();
  return 0;
}
Input Focus Event
Also a Click Event

We can set it to "0" to restore the default behavior:

SDL_SetHint(
  SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH,
  "0"
);

Summary

Mouse focus management is crucial for creating responsive multi-window applications in SDL2, allowing you to track which window the mouse is hovering over and respond appropriately. Here are the key topics covered:

  • Using SDL_WindowEvent to detect when the mouse enters or leaves a window
  • Checking window focus state using SDL_GetWindowFlags() and the SDL_WINDOW_MOUSE_FOCUS flag
  • Using SDL_GetMouseFocus() to determine which window currently has mouse focus
  • Customizing click-through behavior during focus changes with SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH
Next Lesson
Lesson 73 of 129

Mouse Input Constraints

Implement mouse constraints in SDL2 to control cursor movement using window grabs and rectangular bounds

Questions & Answers

Answers are generated by AI models and may not have been reviewed. Be mindful when running any code on your device.

Auto-Focus Windows on Mouse Hover
Can I make my game window automatically gain input focus when the mouse hovers over it?
Mouse Focus with Overlapping Windows
When using SDL_GetMouseFocus(), what happens if the mouse is over where two windows overlap?
Mouse Focus in Fullscreen Mode
How do I handle mouse focus in fullscreen mode? Does it work differently?
Custom Mouse Focus Regions
Can I customize which parts of my window respond to mouse focus? Like having some transparent areas that don't trigger focus events?
Picture-in-Picture Windows
How would I implement a picture-in-picture feature where a smaller window always stays on top of the main window?
Disabling Mouse Focus Events
How can I make certain windows in my game ignore mouse focus completely?
Or Ask your Own Question
Purchase the course to ask your own questions