SDL2 doesn't directly support custom focus regions, but you can achieve this using a combination of window flags and shapes. The key is to use SDL_SetWindowShape()
with a surface that defines which parts of your window are "active".
Here's how to create a window with a custom shape that only responds to mouse focus in specific areas:
#include <SDL.h>
#include <iostream>
// Helper function to create a shape mask
SDL_Surface* CreateShapeMask(
int width, int height) {
SDL_Surface* Mask = SDL_CreateRGBSurface(
0, width, height, 32, 0xFF000000,
0x00FF0000, 0x0000FF00, 0x000000FF);
// Make the surface fully transparent
SDL_FillRect(Mask, nullptr, 0x00000000);
// Create a rectangular active region in the center
SDL_Rect ActiveRegion = {
width / 4, height / 4, width / 2,
height / 2};
SDL_FillRect(Mask, &ActiveRegion, 0xFFFFFFFF);
return Mask;
}
int main(int argc, char** argv) {
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
std::cerr << "Failed to initialize SDL: "
<< SDL_GetError() << "\n";
return -1;
}
SDL_Window* Window = SDL_CreateShapedWindow(
"Shaped Window", 100, 100, 400,
300, SDL_WINDOW_SHOWN);
if (!Window) {
std::cerr
<< "Failed to create shaped window: "
<< SDL_GetError() << "\n";
SDL_Quit();
return -1;
}
// Create and apply the shape mask
SDL_Surface* ShapeMask = CreateShapeMask(
400, 300);
// Define the shape mode
SDL_WindowShapeMode ShapeMode;
ShapeMode.mode = ShapeModeBinarizeAlpha;
ShapeMode.parameters.binarizationCutoff = 128;
if (SDL_SetWindowShape(Window, ShapeMask,
&ShapeMode) != 0) {
std::cerr << "Failed to set window shape: "
<< SDL_GetError() << "\n";
SDL_FreeSurface(ShapeMask);
SDL_DestroyWindow(Window);
SDL_Quit();
return -1;
}
SDL_Event E;
bool Running = true;
while (Running) {
while (SDL_PollEvent(&E)) {
if (E.type == SDL_QUIT) {
Running = false;
} else if (
E.type == SDL_WINDOWEVENT) {
if (E.window.event ==
SDL_WINDOWEVENT_ENTER) {
std::cout <<
"Mouse entered active region\n";
} else if (E.window.event ==
SDL_WINDOWEVENT_LEAVE) {
std::cout <<
"Mouse left active region\n";
}
}
}
SDL_Window* FocusedWindow =
SDL_GetMouseFocus();
if (FocusedWindow == Window) {
// Mouse is over an active part of window
}
}
SDL_FreeSurface(ShapeMask);
SDL_DestroyWindow(Window);
SDL_Quit();
return 0;
}
Mouse entered active region
Mouse left active region
Mouse entered active region
Note that shaped windows have some limitations:
For more complex scenarios, you might want to handle the focus detection yourself by checking the mouse position against your custom regions:
#include <SDL.h>
#include <iostream>
#include <vector>
#include "Window.h"
struct FocusRegion {
SDL_Rect Bounds;
std::string Name;
};
bool IsPointInRect(
int x, int y, const SDL_Rect& rect
) {
return x >= rect.x &&
x < rect.x + rect.w &&
y >= rect.y &&
y < rect.y + rect.h;
}
int main(int argc, char** argv) {
SDL_Init(SDL_INIT_VIDEO);
Window GameWindow;
std::vector<FocusRegion> ActiveRegions{
{{10, 10, 100, 100}, "Top Left"},
{{200, 10, 100, 100}, "Top Right"},
{{100, 100, 200, 100}, "Center"}};
SDL_Event E;
while (true) {
while (SDL_PollEvent(&E)) {
if (E.type == SDL_MOUSEMOTION) {
int MouseX, MouseY;
SDL_GetMouseState(&MouseX, &MouseY);
for (const auto& Region :
ActiveRegions) {
if (IsPointInRect(MouseX, MouseY,
Region.Bounds)) {
std::cout << "Mouse in region: " <<
Region.Name << "\n";
}
}
}
}
GameWindow.Update();
}
SDL_Quit();
return 0;
}
Mouse in region: Center
Mouse in region: Center
Mouse in region: Top Right
Mouse in region: Top Left
This manual approach gives you more control but requires you to manage the focus state yourself rather than relying on SDL's built-in focus events.
Answers to questions are automatically generated and may not have been reviewed.
Learn how to track and respond to mouse focus events in SDL2, including handling multiple windows and customizing focus-related click behavior.