Managing Mouse Focus with SDL2

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?

Abstract art representing computer programming

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:

  • Not all platforms support window shaping
  • Performance might be impacted with complex shapes
  • Some window managers might ignore the shape
  • The shape affects both mouse input and window appearance

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.

This Question is from the Lesson:

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.

Answers to questions are automatically generated and may not have been reviewed.

This Question is from the Lesson:

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.

sdl2-promo.jpg
Part of the course:

Game Dev with SDL2

Learn C++ and SDL development by creating hands on, practical projects inspired by classic retro games

Free, unlimited access

This course includes:

  • 67 Lessons
  • 100+ Code Samples
  • 91% Positive Reviews
  • Regularly Updated
  • Help and FAQ
Free, Unlimited Access

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

Screenshot from Warhammer: Total War
Screenshot from Tomb Raider
Screenshot from Jedi: Fallen Order
Contact|Privacy Policy|Terms of Use
Copyright © 2024 - All Rights Reserved