Finger event doesn't work

The following program is supposed to:

  1. Draw 2 rectangles on two sides of the screen.
  2. Move the left rect up and down according to the up and down finger movement in the left half of the touch device.
  3. Move the right rect up and down according to the up and down finger movement in the right half of the touch device.
#include <SDL2/SDL.h>

int main(int argc, char* argv[])
{
  SDL_Init(SDL_INIT_VIDEO);

  SDL_DisplayMode dm;
  SDL_GetCurrentDisplayMode(0, &dm);
  int w{dm.w}, h{dm.h};

  SDL_Window* window = SDL_CreateWindow("Movement", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, w, h, SDL_WINDOW_FULLSCREEN);

  SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);

  SDL_Rect rect1;
  rect1.x = w/8;
  rect1.y = h/2;
  rect1.w = 50;
  rect1.h = 50;

  SDL_Rect rect2{w/8*7, h/2, 50, 50};

  int middlescreenx = w/2;

  int initialTouchY1 = 0;
  int initialTouchY2 = 0;

  while (1)
  {
    SDL_Event event;
    while (SDL_PollEvent(&event))
    {
      switch (event.type)
      {
        case SDL_QUIT:
          SDL_DestroyRenderer(renderer);
          SDL_DestroyWindow(window);
          SDL_Quit();
          return 0;

        case SDL_FINGERDOWN:
          if (event.tfinger.x <= middlescreenx)
          {
            initialTouchY1 = event.tfinger.y;
          }
          else
          {
            initialTouchY2 = event.tfinger.y;
          }
          break;

        case SDL_FINGERMOTION:
          if (event.tfinger.fingerId == 0)   // First finger
          {
            int deltaY = event.tfinger.y - initialTouchY1;
            rect1.y += deltaY * 2;
            initialTouchY1 = event.tfinger.y;
          }
          else if (event.tfinger.fingerId == 1)   // Second finger
          {
            int deltaY = event.tfinger.y - initialTouchY2;
            rect2.y += deltaY * 2;
            initialTouchY2 = event.tfinger.y;
          }
          break;
      }
    }

    SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
    SDL_RenderClear(renderer);

    if (rect1.y < 0)
    {
      rect1.y = 0;
    }
    if (rect1.y + rect1.h > h)
    {
      rect1.y = h - rect1.h;
    }

    if (rect2.y < 0)
    {
      rect2.y = 0;
    }
    if (rect2.y + rect2.h > h)
    {
      rect2.y = h - rect2.h;
    }

    SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
    SDL_RenderFillRect(renderer, &rect1);
    SDL_RenderFillRect(renderer, &rect2);

    SDL_RenderPresent(renderer);
  }

  return 0;
}

But i don’t know what i’m doing wrong. This doesn’t work. This works fine if i implement this using the mousebutton events. But that way i cannot address two finger clicks at the same time. So, what’s wrong with the program?

event.tfinger.fingerId is not necessarily 0 or 1, so the value of event.tfinger.fingerId should be stored during SDL_FINGERDOWN so that it can be compared during SDL_FINGERMOTION.

@PiotrGrochowski I did this. Is it correct? Cause this still doesn’t work.

  std::vector<SDL_FingerID> fingers{};

  while (true)
  {
    SDL_Event event;
    while (SDL_PollEvent(&event))
    {
      switch (event.type)
      {
        case SDL_QUIT:
          SDL_DestroyRenderer(renderer);
          SDL_DestroyWindow(window);
          SDL_Quit();
          return 0;

        case SDL_FINGERDOWN:
          if (event.tfinger.x <= middlescreenx)
          {
            initialTouchY1 = event.tfinger.y;
            fingers.push_back(event.tfinger.fingerId);
          }
          else
          {
            initialTouchY2 = event.tfinger.y;
            fingers.push_back(event.tfinger.fingerId);
          }
          break;

        case SDL_FINGERMOTION:
          if (event.tfinger.fingerId == fingers[0])   // First finger
          {
            int deltaY = event.tfinger.y - initialTouchY1;
            rect1.y += deltaY * 2;
            initialTouchY1 = event.tfinger.y;
          }
          else if (event.tfinger.fingerId == fingers[1])   // Second finger
          {
            int deltaY = event.tfinger.y - initialTouchY2;
            rect2.y += deltaY * 2;
            initialTouchY2 = event.tfinger.y;
          }
          break;
      }
    }

The {} in std::vector declaration is C++11 and up syntax, not C++98 so that alone increases the minimum requirements of the program, at least for the build process, which can severely reduce the portability; removing it by std::vector<SDL_FingerID> fingers; already initializes empty vector. The correctness issue on the other hand is that the finger ids are pushed to vector but their array positions are not synchronized with initialTouchY1 and initialTouchY2, since push_back always pushes at the end, which is not necessarily in finger[0] and finger[1] but is beyond that after first two finger down events.

Who starts a new project using pre-C++11 nowadays? It has nothing to do with the OP’s problem anyway.

You haven’t told us what is not working. Does it move the rectangles incorrectly or not at all. Do you receive the SDL_FINGERDOWN and SDL_FINGERMOTION events at all? What are the fingerId of those events? Is it able to handle one finger but not two?

Unfortunately, I don’t have a touch device connected to my computer so I cannot test this myself.

1 Like

@Peter87 Exactly. Using modern C++ features was not the problem. Apparently, I was doing a very silly mistake. I was completely missing out the point that event.tfinger.y is a normalized value and it ranges from 0…1. So all I had to do was to multiply the screen height with event.tfinger.y and the screen width with event.tfinger.x. It successfully moved the rects.

But even then it was still problematic. Cause I demanded to move each rects individually depending on which half of the screen I was dragging my finger on. The fingerId approach assumes that the first finger that’s touching the window gets ID 0, the next finger gets 1…etc etc. This can be very problematic in my case. That’s why, in the FINGERMOTION block, i changed the conditions so that they check whether event.tfinger.x was in the left half of the screen or the right half.

And problem solved! Everything works as expected.