On most platforms, multiple applications can be open at once. However, when the user is providing input on their keyboard, they typically only intend to provide that input to one of the open applications.
Users can select which application is active by, for example, clicking within its window.
Operating systems typically apply more vibrant styling to the active window. In the following example, the left window is inactive, while the right is active.
Accordingly, the user will not expect the left window to react to keyboard events, as their input is likely intended for the right window instead:
The SDL_WindowFlags
mask includes a bit dedicated to whether or not the window has input focus. The SDL_WINDOW_INPUT_FOCUS
variable is available to represent this bit.
Accordingly, we can specify that our window should have input focus as soon as it is created by using this variable with SDL_CreateWindow()
:
// Window.h
#pragma once
#include <SDL.h>
class Window {
public:
Window(){
SDLWindow = SDL_CreateWindow(
"Hello Window",
100, 100, 700, 300,
SDL_WINDOW_INPUT_FOCUS
);
}
// ...
private:
SDL_Window* SDLWindow{nullptr};
// ...
};
We can combine SDL_WINDOW_INPUT_FOCUS
with other window flags using the |
operator. For example, to create a window that is both resizable and grabs focus when created, we could use this:
SDL_CreateWindow(
"Hello Window", 100, 100, 700, 300,
SDL_WINDOW_INPUT_FOCUS | SDL_WINDOW_RESIZABLE
);
SDL keeps the window flags bitset up to date through the lifecycle of our program. We can get the current window flags at any time using the SDL_GetWindowFlags()
function. We pass the pointer to our window - that is, the SDL_Window*
value returned from SDL_CreateWindow()
:
SDL_GetWindowFlags()
returns a bit mask in the form of a Uint32
(a 32-bit unsigned integer):
#include <iostream>
#include <SDL.h>
#include "Window.h"
int main(int argc, char** argv) {
SDL_Init(SDL_INIT_VIDEO);
Window GameWindow;
SDL_Event Event;
std::cout << "Window Flags: "
<< SDL_GetWindowFlags(GameWindow.SDLWindow);
while (true) {/*...*/}
SDL_Quit();
return 0;
}
Window Flags: 516
We can use the value returned by this function with the &
operator to determine if any flag is currently set, Below, we use this technique to determine if the window currently has input focus:
#include <iostream>
#include <SDL.h>
#include "Window.h"
int main(int argc, char** argv) {
SDL_Init(SDL_INIT_VIDEO);
Window GameWindow;
SDL_Event Event;
Uint32 Flags{
SDL_GetWindowFlags(GameWindow.SDLWindow)};
if (Flags & SDL_WINDOW_INPUT_FOCUS) {
std::cout << "Window has input focus";
}
while (true) {/*...*/}
SDL_Quit();
return 0;
}
Window has input focus
SDL_GetKeyboardFocus()
Alternatively, we can determine which window currently has focus using the GetKeyboardFocus()
function:
#include <iostream>
#include <SDL.h>
#include "Window.h"
int main(int argc, char** argv) {
SDL_Init(SDL_INIT_VIDEO);
Window GameWindow;
SDL_Event Event;
std::cout << "Window with focus: "
<< SDL_GetKeyboardFocus();
while (true) {/*...*/}
SDL_Quit();
return 0;
}
Window with focus: 0000022391741BF8
This returns a SDL_Window*
, which we can compare to any other SDL_Window*
to understand whether or not it has focus:
#include <iostream>
#include <SDL.h>
#include "Window.h"
int main(int argc, char** argv) {
SDL_Init(SDL_INIT_VIDEO);
Window GameWindow;
SDL_Event Event;
SDL_Window* Focused{SDL_GetKeyboardFocus()};
if (Focused == GameWindow.SDLWindow) {
std::cout << "GameWindow has input focus";
}
while (true) {/*...*/}
SDL_Quit();
return 0;
}
GameWindow has input focus
We can also keep track of whether or not our window has focus using the event loop. When our window gains or loses focus, SDL broadcasts an SDL_WINDOWEVENT
.
To determine whether the event was caused by a window gaining or losing input focus, we can compare the Event.window.event
property to SDL_WINDOWEVENT_FOCUS_GAINED
and SDL_WINDOWEVENT_FOCUS_LOST
constants respectively:
#include <iostream>
#include <SDL.h>
#include "Window.h"
void HandleWindowEvent(SDL_WindowEvent& E) {
if (E.event == SDL_WINDOWEVENT_FOCUS_GAINED) {
std::cout << "Window gained input focus\n";
}
if (E.event == SDL_WINDOWEVENT_FOCUS_LOST) {
std::cout << "Window lost input focus\n";
}
}
int main(int argc, char** argv) {
SDL_Init(SDL_INIT_VIDEO);
Window GameWindow;
SDL_Event Event;
while (true) {
while (SDL_PollEvent(&Event)) {
if (Event.type == SDL_WINDOWEVENT)
HandleWindowEvent(Event.window);
}
}
SDL_Quit();
return 0;
}
Window gained input focus
Window lost input focus
Window gained input focus
When we want input focus to shift to our application, we can use the SDL_RaiseWindow()
function, passing a pointer to our SDL_Window
:
SDL_Window* MyWindow{GameWindow.SDLWindow};
SDL_RaiseWindow(MyWindow);
In addition to grabbing focus, SDL_RaiseWindow()
will also move the window to be in front of any other windows that might be obscuring it. This ensures the user is aware that it has taken focus, and will now be handling their input.
In the following example, our window automatically grabs input focus 5 seconds after it loses it. Window events have a windowID
property, representing which window caused the event. We can pass this ID to the SDL_GetWindowFromID()
function to retrieve the SDL_Window*
associated with that ID:
#include <iostream>
#include <SDL.h>
#include <chrono>
#include <thread>
#include "Window.h"
void HandleWindowEvent(SDL_WindowEvent& E) {
if (E.event == SDL_WINDOWEVENT_FOCUS_GAINED) {
std::cout << "Window gained input focus\n";
}
if (E.event == SDL_WINDOWEVENT_FOCUS_LOST) {
std::cout << "Window lost input focus\n";
using namespace std::chrono_literals;
std::this_thread::sleep_for(5s);
SDL_RaiseWindow(SDL_GetWindowFromID(E.windowID));
}
}
int main(int argc, char** argv) {/*...*/}
Window gained input focus
Window lost input focus
Window gained input focus
Naturally, we should be cautious with grabbing input focus. Having our application jump to the top and grab focus is disruptive for users and is rarely warranted.
Most platforms provide a mechanism for windows to request the user’s attention in less disruptive ways. This is called "flashing" the window, but the specific visual effect that "flashing" has varies from platform to platform.
On Windows, for example, flashing a window means it will be highlighted with a colored blinking animation in the user’s task bar:
The SDL_FlashWindow()
function let’s us access these attention-grabbing mechanisms:
SDL_FlashWindow(Window, SDL_FLASH_BRIEFLY);
Our first argument is the SDL_Window*
we want to attract attention, and the second argument is one of three possible values:
SDL_FLASH_BRIEFLY
- Briefly flash the window to attract attentionSDL_FLASH_UNTIL_FOCUSED
- Attract attention continuously until the user focuses our window, or until we cancel the flashingSDL_FLASH_CANCEL
- Stop flashingWe cover window management in more detail in a dedicated chapter later in the course.
SDL_SetWindowInputFocus()
SDL includes the SDL_SetWindowInputFocus()
function, which can be a bit confusing. In principle, we can use it the same way as SDL_RaiseWindow()
:
#include <iostream>
#include <SDL.h>
#include <chrono>
#include <thread>
#include "Window.h"
void HandleWindowEvent(SDL_WindowEvent& E) {
if (E.event == SDL_WINDOWEVENT_FOCUS_GAINED) {
std::cout << "Window gained input focus\n";
}
if (E.event == SDL_WINDOWEVENT_FOCUS_LOST) {
std::cout << "Window lost input focus\n";
using namespace std::chrono_literals;
std::this_thread::sleep_for(5s);
SDL_SetWindowInputFocus(
SDL_GetWindowFromID(E.windowID));
}
}
int main(int argc, char** argv) {/*...*/}
However, in practice, this is rarely appropriate for two reasons:
The SDL_RaiseWindow()
function alleviates both of these problems so, if we need to grab focus, we should prefer it over SDL_SetWindowInputFocus()
.
SDL only creates keyboard events if they happen when our application has focus. As such, when we’re reacting to input using the event loop, we do not need to check if our window has input focus.
If we received the event, we can assume our application had focus when it happened, so the input was intended for our application.
#include <iostream>
#include <SDL.h>
#include <chrono>
#include <thread>
#include "Window.h"
void HandleKeyboardEvent(SDL_KeyboardEvent& E) {
std::cout << "Keyboard input detected\n";
}
void HandleWindowEvent(SDL_WindowEvent& E) {
if (E.event == SDL_WINDOWEVENT_FOCUS_GAINED) {
std::cout << "Window gained input focus\n";
}
if (E.event == SDL_WINDOWEVENT_FOCUS_LOST) {
std::cout << "Window lost input focus\n";
}
}
int main(int argc, char** argv) {
SDL_Init(SDL_INIT_VIDEO);
Window GameWindow;
SDL_Event Event;
while (true) {
while (SDL_PollEvent(&Event)) {
if (Event.type == SDL_WINDOWEVENT)
HandleWindowEvent(Event.window);
if (Event.type == SDL_KEYDOWN)
HandleKeyboardEvent(Event.key);
}
}
SDL_Quit();
return 0;
}
Window gained input focus
Keyboard input detected
Keyboard input detected
Keyboard input detected
Window lost input focus
Window gained input focus
Keyboard input detected
In this lesson, we explored how to manage window input focus using SDL. The key takeaways include:
SDL_CreateWindow()
.SDL_GetWindowFlags()
and SDL_GetKeyboardFocus()
.SDL_RaiseWindow()
to grab input focus and bring the window to the front.SDL_SetWindowInputFocus()
.Learn how to manage and control window input focus in SDL applications, including how to create, detect, and manipulate window focus states.
Learn C++ and SDL development by creating hands on, practical projects inspired by classic retro games