Handling mouse buttons

I’m trying to capture each mouse button independently but seems all them is triggered at same time. For example if I press the SDL_BUTTON_LEFT, all them are flagged, it happens in both events SDL_MOUSEBUTTONUP and SDL_MOUSEBUTTONDOWN, probably I’m doing something wrong. The code snippet to reproduce the “problem” is:

#include <SDL2/SDL.h>

int main(void) { 
    SDL_bool quit = SDL_FALSE;
    SDL_Init(SDL_INIT_VIDEO);
    SDL_Window *window = SDL_CreateWindow("Mouse events", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 800, 600, SDL_WINDOW_SHOWN);
    SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
    SDL_SetRenderDrawColor(renderer, 127, 127, 127, 255);
    SDL_RenderClear(renderer);
    SDL_Event event;

    int x = -1 , y = -1, rx = -1, ry = -1, wx = -1, wy = -1 , b[5] = {0};
    while(quit == SDL_FALSE) {
        while(SDL_PollEvent(&event) > 0 ) {
            switch(event.type) {
                case SDL_QUIT: quit = SDL_TRUE; break;
                case SDL_MOUSEWHEEL:
                    wx += event.wheel.x;
                    wy += event.wheel.y;
                    break;
                case SDL_MOUSEBUTTONUP:
                    if(SDL_BUTTON(SDL_BUTTON_LEFT))             b[0] = 0;
                    if(SDL_BUTTON(SDL_BUTTON_RIGHT))            b[1] = 0;
                    if(SDL_BUTTON(SDL_BUTTON_MIDDLE))           b[2] = 0;
                    if(SDL_BUTTON(SDL_BUTTON_X1))               b[3] = 0;
                    if(SDL_BUTTON(SDL_BUTTON_X2))               b[4] = 0;
                    break;
                case SDL_MOUSEBUTTONDOWN:
                    if(SDL_BUTTON(SDL_BUTTON_LEFT))             b[0] = 1;
                    if(SDL_BUTTON(SDL_BUTTON_RIGHT))            b[1] = 1;
                    if(SDL_BUTTON(SDL_BUTTON_MIDDLE))           b[2] = 1;
                    if(SDL_BUTTON(SDL_BUTTON_X1))               b[3] = 1;
                    if(SDL_BUTTON(SDL_BUTTON_X2))               b[4] = 1;
                    break;
                case SDL_MOUSEMOTION:
                    SDL_GetMouseState(&x, &y);        
                    SDL_GetRelativeMouseState(&rx, &ry);        
                    break;
            }
        }
        fprintf(stdout,
                "(x,y): (%4d,%4d): (rx,ry): (%2d,%2d) (wx, wy): (%4d,%4d) btn: %d%d%d%d%d\r",
                           x,  y,             rx, ry,             wx, wy,      b[0], b[1], b[2], b[3], b[4]);
        fflush(stdout);
        SDL_RenderClear(renderer);
        SDL_RenderPresent(renderer);
        SDL_Delay(20);
    }
    fprintf(stdout, "\n");
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_Quit();
    return 0;
}

The program output while idle is something like:

(x,y): ( 799, 34): (rx,ry): ( 0, 0) (wx, wy): ( -1, -1) btn: 00000

When I press, for example the left button I would expect

(x,y): ( 799, 34): (rx,ry): ( 0, 0) (wx, wy): ( -1, -1) btn: 10000

But instead I receive:

(x,y): ( 799, 34): (rx,ry): ( 0, 0) (wx, wy): ( -1, -1) btn: 11111

All other mouse events are being correctly handled.

Best regards,

if(SDL_BUTTON(SDL_BUTTON_RIGHT)) etc don’t do anything useful, it expands to if( (1 << ((SDL_BUTTON_RIGHT)-1)) ) => if( (1 << (3-1)) ) => if( (1 << 2) ) => if( 4 ), which is always true (same for the other SDL_BUTTONS).
What you want to check there is: if(event.button.button == SDL_BUTTON_LEFT) etc

The SDL_BUTTON(X) macro is only needed for the return value of SDL_Get*MouseState(), like:

Uint32 buttonState = SDL_GetMouseState(NULL, NULL);
if( buttonState & SDL_BUTTON(SDL_BUTTON_LEFT) )
    printf("left mouse button pressed\n");
if( buttonState & SDL_BUTTON(SDL_BUTTON_RIGHT) )
    printf("right mouse button pressed\n");

For SDL_MOUSEMOTION you shouldn’t use SDL_Get*MouseState() but event.motion.x (and .y, .xrel and .yrel)

https://wiki.libsdl.org/SDL_Event has more information on SDL events

1 Like

It’s working perfectly. Thanks.

I have read somewhere that event.button.button and event.motion.{x,y,xrel,yrel} should NOT be used, the functions should be used instead.

1 Like

I have read somewhere that event.button.button and event.motion.{x,y,xrel,yrel} should NOT be used, the functions should be used instead.

Maybe that made more sense in the context of the article/tutorial/whatever, but in general it’s wrong.

There’s nothing wrong with the events; of course you can use the functions if it makes more sense in your code for some reason - but in that case you most probably wouldn’t call them in the event-handling loop, and certainly not while handling an event containing that exact information anyway.