Tutorial 11: Handling Mouse Input
Mouse::GetState()
Mouse input follows the same snapshot-polling pattern as keyboard input. Call Mouse::GetState() once at the start of Update():
#include "Microsoft/Xna/Framework/Input/Mouse.hpp"
using namespace Microsoft::Xna::Framework::Input;
void MyGame::Update(GameTime& gameTime) {
MouseState ms = Mouse::GetState();
// Use 'ms' to read position, buttons, and scroll wheel
}
MouseState is a lightweight value type. Keeping the previous frame's state alongside the current one lets you detect click events (press) and release events.
MouseState Struct
MouseState exposes the following properties:
| Property / Method | Type | Description |
|---|---|---|
getX() | intcs | Mouse X position in client (window) coordinates |
getY() | intcs | Mouse Y position in client coordinates |
getPosition() | Point | Position as a Point{X, Y} |
getLeftButton() | ButtonState | Left mouse button |
getRightButton() | ButtonState | Right mouse button |
getMiddleButton() | ButtonState | Middle mouse button (scroll wheel click) |
getXButton1() | ButtonState | Extra mouse button 1 (side button) |
getXButton2() | ButtonState | Extra mouse button 2 (side button) |
getScrollWheelValue() | intcs | Cumulative scroll wheel ticks (can be negative) |
Mouse Position (X and Y)
Mouse position is returned in window client coordinates: (0,0) is the top-left corner of the game window, with X increasing right and Y increasing down.
void MyGame::Update(GameTime& gameTime) {
MouseState ms = Mouse::GetState();
int mouseX = ms.getX();
int mouseY = ms.getY();
// As a Vector2 for math:
Vector2 mousePos(static_cast<float>(mouseX), static_cast<float>(mouseY));
// As a Point (integer):
Point mousePoint = ms.getPosition();
std::cout << "Mouse: " << mouseX << ", " << mouseY << "\n";
}
The position is in screen pixels, which is what you need when comparing against sprite rectangles. If your game uses a virtual resolution with a scaling matrix, you will need to transform the mouse position through the inverse of that matrix.
Button State
ButtonState is an enum with two values:
ButtonState::Pressed // button is currently held down
ButtonState::Released // button is not held
Hold detection (is the button currently down?)
MouseState ms = Mouse::GetState();
if (ms.getLeftButton() == ButtonState::Pressed) {
// Left button is held — drag or continuous fire
std::cout << "Left button held at " << ms.getX() << ", " << ms.getY() << "\n";
}
Click detection (single press event)
As with keyboard input, single-click events require comparing the current and previous state:
// Class members:
MouseState prevMs_;
// In Update():
MouseState ms = Mouse::GetState();
bool leftClicked = (ms.getLeftButton() == ButtonState::Pressed) &&
(prevMs_.getLeftButton() == ButtonState::Released);
bool rightClicked = (ms.getRightButton() == ButtonState::Pressed) &&
(prevMs_.getRightButton() == ButtonState::Released);
if (leftClicked) {
// Fire once on click
spawnProjectile(ms.getX(), ms.getY());
}
if (rightClicked) {
// Right-click action
openContextMenu(ms.getX(), ms.getY());
}
prevMs_ = ms; // save for next frame
Hit testing: did the user click a rectangle?
Rectangle buttonRect(200, 250, 200, 60); // x, y, w, h
bool clickedButton = leftClicked && buttonRect.Contains(ms.getPosition());
if (clickedButton) {
std::cout << "Button clicked!\n";
startGame();
}
Rectangle::Contains(Point) returns true if the point is inside the rectangle (inclusive). ms.getPosition() returns the mouse position as a Point.
ScrollWheelValue
getScrollWheelValue() returns a cumulative counter of scroll wheel ticks. It increases when you scroll up and decreases when you scroll down. To detect scroll events, compare the current and previous value:
// Class member:
int prevScrollValue_ = 0;
// In Update():
MouseState ms = Mouse::GetState();
int scrollDelta = ms.getScrollWheelValue() - prevScrollValue_;
if (scrollDelta > 0) {
// Scrolled up — zoom in
cameraZoom_ = std::min(cameraZoom_ + 0.1f, 3.0f);
} else if (scrollDelta < 0) {
// Scrolled down — zoom out
cameraZoom_ = std::max(cameraZoom_ - 0.1f, 0.5f);
}
prevScrollValue_ = ms.getScrollWheelValue();
One notch of the scroll wheel typically corresponds to 120 units (SDL convention). Divide by 120 to get "notches scrolled":
int notches = scrollDelta / 120; // positive = up, negative = down
Mouse::SetPosition()
Mouse::SetPosition(x, y) moves the OS cursor to a specific position within the game window. This is useful for FPS-style games where you want to lock the cursor to the screen centre:
// Lock the cursor to the window centre every frame
auto& vp = getGraphicsDeviceProperty().getViewport();
int centreX = vp.getWidth() / 2;
int centreY = vp.getHeight() / 2;
Mouse::SetPosition(centreX, centreY);
// Read the delta from this centre position
MouseState ms = Mouse::GetState();
// After SetPosition, GetState will return the new position immediately
// so store the delta before calling SetPosition
Typical FPS mouse-look pattern:
void MyGame::Update(GameTime& gameTime) {
auto& vp = getGraphicsDeviceProperty().getViewport();
int cx = vp.getWidth() / 2, cy = vp.getHeight() / 2;
MouseState ms = Mouse::GetState();
// Compute delta from centre
float dx = static_cast<float>(ms.getX() - cx);
float dy = static_cast<float>(ms.getY() - cy);
cameraYaw_ += dx * mouseSensitivity_;
cameraPitch_ += dy * mouseSensitivity_;
// Clamp pitch to prevent flipping
cameraPitch_ = std::clamp(cameraPitch_, -MathHelper::PiOver2 + 0.01f,
MathHelper::PiOver2 - 0.01f);
// Reset cursor to centre
Mouse::SetPosition(cx, cy);
}
Cursor Visibility
Hide or show the OS cursor:
// Hide the cursor (e.g., when showing a custom crosshair)
Mouse::setIsVisible(false);
// Show the cursor again (e.g., in menus)
Mouse::setIsVisible(true);
// Query current visibility
bool visible = Mouse::getIsVisible();
Common pattern: hide the cursor when entering gameplay and show it when the game is paused or in a menu.
Complete drag demo
class DragDemo final : public Game {
public:
DragDemo() : graphics_(this) {}
protected:
void LoadContent() override {
spriteBatch_ = std::make_unique<SpriteBatch>(getGraphicsDeviceProperty());
pixel_ = std::make_unique<Texture2D>(getGraphicsDeviceProperty(), 1, 1);
Color w = Color::White;
pixel_->SetData(&w, 1);
}
void Update(GameTime& gameTime) override {
MouseState ms = Mouse::GetState();
Point mousePos = ms.getPosition();
bool lbDown = ms.getLeftButton() == ButtonState::Pressed;
bool lbClick = lbDown && prevMs_.getLeftButton() == ButtonState::Released;
Rectangle boxRect(static_cast<int>(boxX_), static_cast<int>(boxY_), 80, 80);
// Start dragging on click inside the box
if (lbClick && boxRect.Contains(mousePos)) {
dragging_ = true;
dragOffsetX_ = static_cast<float>(mousePos.X) - boxX_;
dragOffsetY_ = static_cast<float>(mousePos.Y) - boxY_;
}
// Move box while dragging
if (dragging_ && lbDown) {
boxX_ = static_cast<float>(mousePos.X) - dragOffsetX_;
boxY_ = static_cast<float>(mousePos.Y) - dragOffsetY_;
}
// Stop dragging on release
if (!lbDown) dragging_ = false;
if (Keyboard::GetState().IsKeyDown(Keys::Escape)) Exit();
prevMs_ = ms;
}
void Draw(const GameTime&) override {
auto& device = getGraphicsDeviceProperty();
device.Clear(Color::CornflowerBlue);
spriteBatch_->Begin();
Color boxColor = dragging_ ? Color::Yellow : Color::Red;
spriteBatch_->Draw(*pixel_,
Rectangle(static_cast<int>(boxX_), static_cast<int>(boxY_), 80, 80),
boxColor);
spriteBatch_->End();
device.Present();
}
private:
GraphicsDeviceManager graphics_;
std::unique_ptr<SpriteBatch> spriteBatch_;
std::unique_ptr<Texture2D> pixel_;
MouseState prevMs_;
float boxX_ = 360.0f, boxY_ = 260.0f;
float dragOffsetX_ = 0, dragOffsetY_ = 0;
bool dragging_ = false;
};
Click the red box to drag it around. It turns yellow while dragging. In Tutorial 12 you will combine input, delta time, and texture drawing into a proper moving sprite demo.