Handling Mouse Scrolling

Learn how to detect and handle mouse scroll wheel events in SDL2, including vertical and horizontal scrolling, as well as scroll wheel button events.
This lesson is 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
Abstract art representing computer programming
Ryan McCombe
Ryan McCombe
Updated

In this lesson, we cover how to detect and react to our user providing input through their mouse scroll wheel. Similar to other forms of input, when these interactions are detected, SDL pushes events into the event queue. Accordingly, we receive these events within our event loop, and can react to them as needed.

This lesson builds on our earlier work, where we have a Window class that initializes SDL and creates a window, and an application loop set up in our main function. We receive and handle mouse wheel events within the SDL_PollEvent loop, highlighted below:

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

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

  while(true) {
    while(SDL_PollEvent(&Event)) {
      // Detect and handle input events
      // ...
    }
    GameWindow.Update();
  }

  SDL_Quit();
  return 0;
}

Mouse Wheel Events

When an event is created by the user interacting with their mouse wheel, the SDL_Event object will have a type of SDL_MOUSEWHEEL:

while (SDL_PollEvent(&Event)) {
  if (Event.type == SDL_MOUSEWHEEL) {
    std::cout << "Mouse wheel input detected\n";
  }
}
Mouse wheel input detected
Mouse wheel input detected
Mouse wheel input detected

Within the wheel object, the y member variable is an integer that lets us know how far the wheel was scrolled. By default, positive values mean the user scrolled the wheel forward, while negative means they scrolled backward.

while (SDL_PollEvent(&Event)) {
  if (Event.type == SDL_MOUSEWHEEL) {
    std::cout << "Scroll amount: "
      << Event.wheel.y << '\n';
  }
}

Unlike button presses, mouse scrolling is not discreet. It typically takes some amount of time for the user to provide their full scroll input - that is, how far they want to move their wheel.

Even if they're performing a small scroll that may only take a fraction of a second, it is still likely to span multiple frames of our application. To handle this, a typical scroll from the user will result in several SDL_MOUSEWHEEL events, each with a relatively small y value.

The previous program output will be something like this:

Scroll amount: 1
Scroll amount: 2
Scroll amount: 1
Scroll amount: 1

This implementation helps us make scroll input feel responsive and smooth. As soon as the user starts their input, we get an event we can react to immediately even though the user may still be scrolling. The full extent of the scroll (5, in the previous example) is spread across multiple frames.

SDL_MouseWheelEvent

If we want to store or transfer an SDL_Event that has a type of SDL_MOUSEWHEEL, we can use the more descriptive SDL_MouseWheelEvent subtype. This type is slightly easier to use as it does not require us to access the intermediate wheel subobject to retrieve the information we care about:

// Event Loop
while (SDL_PollEvent(&Event)) {
  if (Event.type == SDL_MOUSEWHEEL) {
    HandleMouseWheel(Event)
  }
}
// Handler
void HandleMouseWheel(const SDL_MouseWheelEvent& E) {
  int ScrollAmount { Event.y };
  // ...
}

Scroll Wheel Button Events

On many mice, the scroll wheel is also a button that can be pressed. This interaction is handled like any other mouse button event, which we covered in the previous lesson:

The scroll mouse button is typically represented by the SDL_BUTTON_MIDDLE variable, so we can detect scroll button keydown and keyup events like this:

// Event loop
while (SDL_PollEvent(&Event)) {
  if (Event.type == SDL_MOUSEBUTTONDOWN ||
      Event.type == SDL_MOUSEBUTTONUP) {
    HandleMouseButton(Event.button);
  }
}
// Handler
void HandleMouseButton(SDL_MouseButtonEvent& E) {
  if (E.button == SDL_BUTTON_MIDDLE) {
    std::cout << "\nScroll button "
      << (E.type == SDL_MOUSEBUTTONDOWN
        ? "pressed" : "released");
  }
}
Scroll button pressed
Scroll button released

Horizontal Scrolling

Some mice allow the user to provide horizontal scroll input, typically by tilting their mouse wheel left or right.

These actions also generate SDL_MouseWheelEvent events. The amount of horizontal scrolling is represented by the x member variable, where negative values indicate scrolling left and positive values indicate scrolling right:

// Handler
void HandleMouseWheel(SDL_MouseWheelEvent& E) {
  int HorizontalScrollAmount{E.x};

  if (HorizontalScrollAmount != 0) {
    std::cout << "Horizontal scroll detected: "
      << HorizontalScrollAmount << '\n';
  }
}
Horizontal scroll detected: -1
Horizontal scroll detected: 1

Precise Scroll Distance

On some devices, it is possible to get more precise scroll information than the integers reported in the x and y fields of the SDL_MouseWheelEvent.

If we want to support those devices, we can access the preciseX and preciseY fields instead. These will be floating point numbers:

// Handler
void HandleMouseWheel(SDL_MouseWheelEvent& E) {
  std::cout << "preciseX: " << E.preciseX
    << ", preciseY: " << E.preciseY << '\n';
}
preciseX: 0, preciseY: 1.023
preciseX: 0, preciseY: 0.853
preciseX: 0, preciseY: 1.911

When precise scroll distance isn’t supported, the preciseX and preciseY values will fall back to match the regular x and y values, albeit in float form.

Flipped Scroll Direction

On some platforms, users can invert their scroll direction. SDL detects this, and reports whether the user has inverted their scrolling in the direction field of the SDL_MouseWheelEvent. This variable will be an integer that is equal to either SDL_MOUSEWHEEL_NORMAL or SDL_MOUSEWHEEL_FLIPPED:

// Handler
void HandleMouseWheel(SDL_MouseWheelEvent& E) {
  if (E.direction == SDL_MOUSEWHEEL_NORMAL) {
    std::cout << "Using normal direction\n";
  }

  if (E.direction == SDL_MOUSEWHEEL_FLIPPED) {
    std::cout << "Using flipped direction\n";
  }
}
Using normal direction

The x, y, preciseX, and preciseY values reported by SDL have already considered the user’s preferred direction so, in most cases, we can ignore this.

However, if we wanted to override the user’s individual preferences and ensure scrolling works the same for everyone, we can conditionally multiply the scroll values by -1 before using them:

// Handler
void HandleMouseWheel(SDL_MouseWheelEvent& E) {
  int ScrollAmount{E.direction ==
    SDL_MOUSEWHEEL_NORMAL ? E.y : E.y * -1};
}

Mouse Position

Sometimes, we need to understand where the cursor was when a scroll event occurred. These coordinates are available through the mouseX and mouseY variables of the SDL_MouseWheelEvent:

// Handler
void HandleMouseWheel(SDL_MouseWheelEvent& E) {
  std::cout << "\nScroll event happened at "
            << "x = " << E.mouseX
            << ", y = " << E.mouseY;
}
Scroll event happened at x = 446, y = 181

Similar to SDL_MouseMotionEvents, the x and y coordinates are relative to the left edge and top edge of our window by default. If needed, we can determine the distance from the right and bottom edges by subtracting them from our window’s width and height:

// Handler
void HandleMouseWheel(SDL_MouseWheelEvent& E) {
  int DistanceFromLeft{E.mouseX};
  int DistanceFromTop{E.mouseY};
  int DistanceFromRight{WindowWidth - E.mouseX};
  int DistanceFromBottom{WindowHeight - E.mouseY};
}

Summary

This lesson covered how to detect and handle mouse scroll wheel events in SDL2. Key points include:

  • Understanding the SDL_MouseWheelEvent structure and its member variables.
  • Handling vertical and horizontal scrolling.
  • Detecting and responding to scroll wheel button events.
  • Using precise scroll distances when supported.
  • Accounting for flipped scroll directions and mouse positions during scroll events.

Was this lesson useful?

Next 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.
Abstract art representing computer programming
Ryan McCombe
Ryan McCombe
Updated
Lesson Contents

Handling Mouse Scrolling

Learn how to detect and handle mouse scroll wheel events in SDL2, including vertical and horizontal scrolling, as well as scroll wheel button events.

sdl2-promo.jpg
This lesson is 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
Mouse Input
    48.
    Handling Mouse Scrolling

    Learn how to detect and handle mouse scroll wheel events in SDL2, including vertical and horizontal scrolling, as well as scroll wheel button events.


  • 53.GPUs and Rasterization
  • 54.SDL Renderers
sdl2-promo.jpg
This lesson is 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:

  • 55 Lessons
  • 100+ Code Samples
  • 91% Positive Reviews
  • Regularly Updated
  • Help and FAQ
Next 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.
Abstract art representing computer programming
Contact|Privacy Policy|Terms of Use
Copyright © 2024 - All Rights Reserved