Search code examples
csdl

Mouse position set to (0,0) in SDL


My goal is to have a red square in the middle of a window and when I press it, it should give me my mouse position as long as I am holding the mouse button down. When I release the mouse button it should not give me the coordinates any longer. The problem is that in my code, it gives me the correct position, but then says the mouse position is (0, 0) maybe 300 times. Then it gives me the correct updated position again, and then 300 times (0,0). The output can look like this:

Mouse press detected!
Mouse position is (0, 0)
Mouse position is (0, 0)
Mouse position is (0, 0)
Mouse position is (0, 0)

...

Mouse position is (0, 0)
Mouse position is (0, 0)
Mouse position is (391, 207)
Mouse released!

This was with one click with the mouse button. Why is this? Here is my code:

#include <stdio.h>
#include <SDL.h>

#define WIDTH 760
#define HEIGHT 480


void moveRectangle(SDL_Event myEvent, SDL_Rect* pButton, SDL_Renderer* pRenderer) {

  if (myEvent.motion.x >= 330 && myEvent.motion.x <= 430 && myEvent.motion.y >= 190 && 
     myEvent.motion.y <= 290) {
     while (myEvent.type != SDL_MOUSEBUTTONUP) {
        SDL_PollEvent(&myEvent);
        printf("Mouse position is (%d, %d)\n", myEvent.motion.x, myEvent.motion.y);
     }
    printf("Mouse released!\n");
  }
} 

int main(int argc, char** args) {

   int running = 1;

   SDL_Window* window;
   SDL_Rect myButton;
   SDL_Renderer* myRenderer;
   SDL_Event event;

   myButton.x = 330;
   myButton.y = 190;
   myButton.w = 100;
   myButton.h = 100;

   SDL_Init(SDL_INIT_VIDEO);

   window = SDL_CreateWindow("Events", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 
   WIDTH, HEIGHT, 0);
   myRenderer = SDL_CreateRenderer(window, -1, 0);

   SDL_SetRenderDrawColor(myRenderer, 255, 0, 0, 0);
   SDL_RenderFillRect(myRenderer, &myButton);

   SDL_RenderPresent(myRenderer);

   while (running) {
      SDL_PollEvent(&event);
       switch (event.type) {
          case SDL_MOUSEBUTTONDOWN: printf("Mouse press detected!\n"); 
                moveRectangle(event, &myButton, myRenderer); break;
          case SDL_MOUSEBUTTONUP: printf("Mouse release detected!\n"); break;
          case SDL_MOUSEMOTION: printf("Mouse movement detected!\n"); break;
          case SDL_QUIT: printf("Exiting...\n"); running = 0;  break;
       }
    }

   SDL_DestroyRenderer(myRenderer);
   SDL_Quit();

   return 0;
}

Solution

  • When a mouse button is pressed inside the area you defined, the program goes into moveRectangle and stays there until a mouse button is released. There, you call SDL_PollEvent but you don't check what type of event you are getting back, so accessing myEvent.motion is potentially undefined behavior. Moreover, you do not check the return value of SDL_PollEvent, which tells you whether an event occured at all. Fix both of these issues and your code should work:

    void moveRectangle(SDL_Event myEvent, SDL_Rect* pButton, SDL_Renderer* pRenderer) {
        if (!(myEvent.motion.x >= 330 && myEvent.motion.x <= 430 && myEvent.motion.y >= 190 && myEvent.motion.y <= 290)) {
            return;
        }
    
        while (myEvent.type != SDL_MOUSEBUTTONUP) {
            if (SDL_PollEvent(&myEvent) && myEvent.type == SDL_MOUSEMOTION) {
                printf("Mouse position is (%d, %d)\n", myEvent.motion.x, myEvent.motion.y);
            }
        }
        printf("Mouse released!\n");
    } 
    

    However, having another event loop is not a particularly good idea. For example, you cannot correctly exit the program while in that function, because you no longer respond to SDL_QUIT events.

    Instead of entering a separate function to do whatever you need (reading the function's name, I assume you want to be able to drag a rectangle), I would just set a flag to indicate that the user has pressed a mouse button inside the rectangle and has not yet released it. Something like that:

    int draggingRectangle = 0;
    while (running) {
        if (SDL_PollEvent(&event)) {
            switch (event.type) {
            case SDL_MOUSEBUTTONDOWN:
                printf("Mouse press detected!\n"); 
                draggingRectangle = (
                    myEvent.motion.x >= 330 &&
                    myEvent.motion.x <= 430 &&
                    myEvent.motion.y >= 190 &&
                    myEvent.motion.y <= 290
                );
                break;
            case SDL_MOUSEBUTTONUP:
                printf("Mouse release detected!\n");
                draggingRectangle = 0;
                break;
            case SDL_MOUSEMOTION:
                printf("Mouse movement detected!\n");
                if (draggingRectangle) {
                    printf("Mouse position is (%d, %d)\n", myEvent.motion.x, myEvent.motion.y);
                }
                break;
            case SDL_QUIT:
                printf("Exiting...\n");
                running = 0;
                break;
            }
        }
    }