SDL2 Mouse implementation

In this tutorial we are going to see how to implement a full functional mouse using SDL2. The SDL mouse header gives us a lot of possibilities, from detect the position outside the created window to manage the movement of the mouse. I’m going to center this tutorial in the basics to make a videogame with free mouse.Like in the previous tutorial we are going to implement it in a way we try to avoid other systems to provide information. Unfortunately in this case we need the SDL event system to provide us information about the wheel.

In this case is not necessary to preallocate any memory since we can get the information about all the buttons of the mouse in a Uint32 bitmask variable using a bitwise macro provided by SDL that we will explain further in this tutorial.

In this case the header looks like this:

#ifndef __INPUTMOUSE_H__
#define __INPUTMOUSE_H__
#pragma once
///////////////////////////////

class InputMouse
{
public:
	///--- Constructor/Destructor
	InputMouse(void);
	~InputMouse(void);

	///--- Object control
	bool Initialize(void);
	void Update(void);
	void Release(void);

	///--- To receive SDL_MouseWheelEvent
	void ReceiveEvent(const SDL_Event& oEvent);

	///--- Mouse position fucntions
	void GetMousePosition(int& iCoordX, int& iCoordY) const;
	void GetMouseDiff(int& iDiffX, int& iDiffY) const;

	///--- Mouse button states
	bool IsButtonTrigered(const Uint32 uButton) const;
	bool IsButtonPressed(const Uint32 uButton) const;
	bool IsButtonReleased(const Uint32 uButton) const;

	///--- Wheel state
	int GetWheelX(void) const;
	int GetWheelY(void) const;
private:
	/// Information about the state of the mouse
	int m_iCurrentCoordX;
	int m_iCurrentCoordY;
	Uint32 m_uCurrentMouseState;

	int m_iPreviousCoordX;
	int m_iPreviousCoordY;
	Uint32 m_uPreviousMouseState;

	///information about the state of thw wheel
	Sint32 m_iWheelX;
	Sint32 m_iWheelY;
};

///////////////////////////////
#endif   //__INPUTMOUSE_H__

Let start by the initialize function. In this case we are going to initialize the previous state to 0 and get the information form the current state from SDL. In this way we avoid having false states during the first frame.

bool InputMouse::Initialize(void)
{
	///--- Last frame information to 0
	m_iPreviousCoordX=0;
	m_iPreviousCoordY=0;
	m_uPreviousMouseState=0;

	///--- Get the current state of the mouse
	m_uCurrentMouseState=SDL_GetMouseState(&m_iCurrentCoordX, &m_iCurrentCoordY);
	
	///--- initialize the wheel to 0 to avoid problems
	m_iWheelX=0;
	m_iWheelY=0;
	return true;
}

For the Update function we are going to assign the current state information to the previous one and get it again from SDL in this way we will be able to compare it and check the trigger, pressed and released states. Also we are going to reset the information of the wheel to set it back to 0.

void InputMouse::Update(void)
{
	///--- Store the current information to the previous 
	m_iPreviousCoordX=m_iCurrentCoordX;
	m_iPreviousCoordY=m_iCurrentCoordY;
	m_uPreviousMouseState=m_uCurrentMouseState;

	///--- Update the current state of the mouse
	m_uCurrentMouseState=SDL_GetMouseState(&m_iCurrentCoordX, &m_iCurrentCoordY);

	///--- Set the wheel back to 0
	m_iWheelX=0;
	m_iWheelY=0;
}

For this implementation we can’t avoid use the SDL event system to get the mouse wheel state. Once the event is received we only have to check if is the correct one and store the info.

void InputMouse::ReceiveEvent(const SDL_Event& oEvent)
{
	switch(oEvent.type)
	{
		case SDL_MOUSEWHEEL:
		{
			m_iWheelX=oEvent.wheel.x;
			m_iWheelY=oEvent.wheel.y;
			
			break;
		}
	}
}

Once of the most used information from the mouse is usually the mouse position. We are currently getting the information form the current window but as you can see in the link provided at the beginning of the tutorial SDL provides a lot of useful functions to get the position from outside the windows and other windows.

void InputMouse::GetMousePosition(int& iCoordX, int& iCoordY) const
{
	iCoordX=m_iCurrentCoordX;
	iCoordY=m_iCurrentCoordY;
}

void InputMouse::GetMouseDiff(int& iDiffX, int& iDiffY) const
{
	iDiffX=m_iCurrentCoordX-m_iPreviousCoordX;
	iDiffY=m_iCurrentCoordY-m_iPreviousCoordY;
}

Now we are going to check the different  states of the buttons. SDL_mouse.h headers gives us a bunch of macros to be able to bitwise the bitmask that stores the mouse button states:

/**
 *  Used as a mask when testing buttons in buttonstate.
 *   - Button 1:  Left mouse button
 *   - Button 2:  Middle mouse button
 *   - Button 3:  Right mouse button
 */
#define SDL_BUTTON(X)       (1 << ((X)-1))
#define SDL_BUTTON_LEFT     1
#define SDL_BUTTON_MIDDLE   2
#define SDL_BUTTON_RIGHT    3
#define SDL_BUTTON_X1       4
#define SDL_BUTTON_X2       5
#define SDL_BUTTON_LMASK    SDL_BUTTON(SDL_BUTTON_LEFT)
#define SDL_BUTTON_MMASK    SDL_BUTTON(SDL_BUTTON_MIDDLE)
#define SDL_BUTTON_RMASK    SDL_BUTTON(SDL_BUTTON_RIGHT)
#define SDL_BUTTON_X1MASK   SDL_BUTTON(SDL_BUTTON_X1)
#define SDL_BUTTON_X2MASK   SDL_BUTTON(SDL_BUTTON_X2)

We are going to use the SDL_BUTTON macro and the button defines instead of the masks, but it is really easy to change it if you want substituting the SDL_BUTTON macro for the mask macro during the checks.

Lets start with the trigger function. This function will tell us if the specified button was just pressed this frame. For that we have to check if the current status is not 0 and the previous one was 0.

bool InputMouse::IsButtonTrigered(const Uint32 uButton) const
{
	return ((SDL_BUTTON(uButton) & m_uCurrentMouseState)!=0)&&((SDL_BUTTON(uButton) & m_uPreviousMouseState)==0);
}

For the pressed state we only have to check if the current state for the button is different than 0.

bool InputMouse::IsButtonPressed(const Uint32 uButton) const
{
	return (SDL_BUTTON(uButton) & m_uCurrentMouseState)!=0;
}

For the release state we have to check the opposite of the trigger. This is that the current state is 0 and the previous one is not 0.

bool InputMouse::IsButtonReleased(const Uint32 uButton) const
{
	return ((SDL_BUTTON(uButton) & m_uCurrentMouseState)==0)&&((SDL_BUTTON(uButton) & m_uPreviousMouseState)!=0);
}

And the last two functions are the wheels ones that we only have to return the current state value.

int InputMouse::GetWheelX(void) const
{
	return m_iWheelX;
}

int InputMouse::GetWheelY(void) const
{
	return m_iWheelY;
}

Feel free to use this code without any restriction and share this page if you think this may be useful for other developers.

Leave a Reply

Your email address will not be published. Required fields are marked *