Creating SDL2 Buttons

Handling Right and Middle Mouse Clicks in SDL2

How would I handle right-clicks or middle-clicks on an SDL2 button?

Abstract art representing computer programming

In the lesson, our Rectangle::HandleEvent function specifically checks if the pressed button was the left mouse button:

// Rectangle.h (Lesson Version Snippet)
// ...
} else if (E.type == SDL_MOUSEBUTTONDOWN) {
  if (isPointerHovering &&
    E.button.button == SDL_BUTTON_LEFT // Check left 
  ) {
    OnLeftClick();
  }
}
// ...

The E.button.button field within the SDL_MouseButtonEvent structure (which is part of the SDL_Event union when E.type is SDL_MOUSEBUTTONDOWN or SDL_MOUSEBUTTONUP) tells you which button was pressed.

SDL provides constants for the common mouse buttons:

  • SDL_BUTTON_LEFT: The primary mouse button (usually the left one).
  • SDL_BUTTON_RIGHT: The secondary mouse button (usually the right one).
  • SDL_BUTTON_MIDDLE: The middle mouse button (often the scroll wheel click).
  • SDL_BUTTON_X1: Additional mouse button 1 (if present).
  • SDL_BUTTON_X2: Additional mouse button 2 (if present).

Handling Other Clicks

To handle right or middle clicks, you simply need to check for these other constants within your SDL_MOUSEBUTTONDOWN event handling logic.

A good approach is to mirror the OnLeftClick() pattern by adding corresponding virtual functions to the Rectangle base class for other clicks you want to support.

// Rectangle.h (Modified)
#pragma once
#include <SDL.h>

class Rectangle {
 public:
  // ... (Constructor, Render, etc.) ...

  virtual void OnMouseEnter() {}
  virtual void OnMouseExit() {}
  virtual void OnLeftClick() {}
  virtual void OnRightClick() {}  
  virtual void OnMiddleClick() {} 

  void HandleEvent(SDL_Event& E) {
    if (E.type == SDL_MOUSEMOTION) {
      // ... (mouse enter/exit logic) ...
       bool wasPointerHovering{isPointerHovering};
      isPointerHovering = isWithinRect(
        E.motion.x, E.motion.y
      );
      if (!wasPointerHovering && isPointerHovering) {
        OnMouseEnter();
      } else if (
        wasPointerHovering && !isPointerHovering
      ) {
        OnMouseExit();
      }
    } else if (
      E.type == SDL_WINDOWEVENT &&
      E.window.event == SDL_WINDOWEVENT_LEAVE
    ) {
      if (isPointerHovering) OnMouseExit();
      isPointerHovering = false;
    } else if (E.type == SDL_MOUSEBUTTONDOWN) {
      if (isPointerHovering) {
        if (E.button.button == SDL_BUTTON_LEFT) {
          OnLeftClick();
        } else if (E.button.button == SDL_BUTTON_RIGHT) {
          OnRightClick();
        } else if (E.button.button == SDL_BUTTON_MIDDLE) {
          OnMiddleClick();
        }
      }
    }
    // ... potentially handle SDL_MOUSEBUTTONUP too ...
  }

  // ... (Rest of the class: SetColor, members) ...
 private:
  SDL_Rect Rect;
  SDL_Color Color{255, 0, 0};
  SDL_Color HoverColor{0, 0, 255};
  bool isPointerHovering{false};
  bool isWithinRect(int x, int y) {
    if (x < Rect.x) return false;
    if (x > Rect.x + Rect.w) return false;
    if (y < Rect.y) return false;
    if (y > Rect.y + Rect.h) return false;
    return true;
  }
};

Implementing in Derived Classes

Now, a derived class like Button can choose to override these new methods to implement specific behaviors for right or middle clicks:

// Button.h
#pragma once
#include <SDL.h>
#include "Rectangle.h"
#include <iostream> // For std::cout

class UI;

class Button : public Rectangle {
 public:
  Button(UI& UIManager, const SDL_Rect& Rect)
  : UIManager{UIManager},
    Rectangle{Rect}
  {
    SetColor({255, 165, 0, 255});
  }

  // Override methods as needed
  void OnLeftClick() override {
    std::cout << "Left Click!\\n";
    // Push SDL_QUIT or other actions...
  }

  void OnRightClick() override { 
    std::cout << "Right Click! Changing color.\\n"; 
    SetColor({0, 255, 255, 255}); // Cyan 
  } 

  // Middle click not overridden, uses base
  // class (empty) implementation.

 private: 
  UI& UIManager;
 //private:  - Typo in original thought, should be private
};

By adding checks for SDL_BUTTON_RIGHT, SDL_BUTTON_MIDDLE, etc., in your base event handler and providing corresponding virtual functions, you can create components that respond differently to various mouse button interactions in a clean, extensible way.

Note: Handling mouse events, including button presses, releases, clicks, double-clicks, and mouse wheel scrolling, involves several nuances. We will explore event handling in much greater detail in a subsequent lesson.

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

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

This course includes:

  • 110 Lessons
  • 92% Positive Reviews
  • Regularly Updated
  • Help and FAQs
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 © 2025 - All Rights Reserved