SDL_Event parses changes in SDL_Rect dimensions but not text input

I’ve recently transitioned from using global variables to structs and I’ve come across an issue regarding text input. For some reason, event works for sprite movement but it doesn’t work for text input. Here are functions InputLoop() and RenderLoop():

void InputLoop(Graphics& Global, StructLoop& Loop)
{
  if(Loop.event.type == SDL_QUIT)
  {
    Loop.bQuit = true;
  }
  else if(Loop.event.type == SDL_KEYDOWN)
  {
    // Sprite movement
    switch(Loop.event.key.keysym.sym)
    {
      case SDLK_UP:
      Global.rcSprite.y -= 5;
      break;

      case SDLK_DOWN:
      Global.rcSprite.y += 5;
      break;

      case SDLK_LEFT:
      Global.rcSprite.x -= 5;
      break;

      case SDLK_RIGHT:
      Global.rcSprite.x += 5;
      break;
    }

    // Backspace handler
    if (Loop.event.key.keysym.sym == SDLK_BACKSPACE && Loop.InputText.length() > 0)
    {
      Loop.InputText.pop_back();
      if (Loop.InputText.length() == 0)
      {
        Loop.InputText = " ";
      }
    }

    // Creates new line of text
    else if (Loop.event.key.keysym.sym == SDLK_RETURN && Loop.InputText.length() != 0 && Loop.InputText != " ")
    {
      Global.Menu.NewBox(Loop.InputText);
      Loop.bRenderText = true;
      Loop.InputText = " ";
    }
  }
  else if (Loop.event.type == SDL_TEXTINPUT)
  {
    Loop.InputText += Loop.event.text.text;
  }
}

void RenderLoop(Graphics& Global, StructLoop& Loop)
{
  // Renders sprite movement
  if (Global.rcSprite.x < 0 || Global.rcSprite.y < 0 || Global.rcSprite.y > Global.rcGround.h || Global.rcSprite.x > Global.rcGround.w)
  {
    Global.rcSprite.x = 400;
    Global.rcSprite.y = 300;
  }

  // Sets background to black
  SDL_SetRenderDrawColor(Global.Renderer, 0x00, 0x00, 0x00, 0x00);
  SDL_RenderClear(Global.Renderer);

  // Renders background of sprite to black
  SDL_RenderFillRect(Global.Renderer, &Global.rcGround);
  SDL_BlitSurface(Global.CurrentSurface, NULL, Global.ScreenSurface, &Global.rcGround);

  // Renders background of text box to grey
  SDL_SetRenderDrawColor(Global.Renderer, 0x40, 0x40, 0x40, 0x40);
  SDL_RenderFillRect(Global.Renderer, &Global.rcTextOutputGrd);
  SDL_BlitSurface(Global.CurrentSurface, NULL, Global.ScreenSurface, &Global.rcTextOutputGrd);

  // Renders text input
  Global.TextInput.Render(Global.Renderer, Global.Font, Loop.InputText.c_str(), Global.TextColor);
  Global.rcTextInput = { 0, 880, Global.TextInput.GetWidth(), Global.TextInput.GetHeight() };
  SDL_RenderCopy(Global.Renderer, Global.TextInput.GetTexture(), NULL, &Global.rcTextInput);

  // Renders text output
  if (Loop.bRenderText)
  {
    Global.Menu.Update(Global.Renderer, Global.Font, Global.TextColor, Global.rcTextOutput);
  }
  SDL_RenderSetClipRect(Global.Renderer, NULL);

  // Renders text box background edges white
  SDL_SetRenderDrawColor(Global.Renderer, 0xFF, 0xFF, 0xFF, 0xFF);
  SDL_RenderDrawLine(Global.Renderer, 0, 600, 800, 600);
  SDL_RenderDrawLine(Global.Renderer, 0, 880, 800, 880);

  // Renders sprite
  SDL_RenderFillRect(Global.Renderer, &Global.rcSprite);
  SDL_BlitSurface(Global.CurrentSurface, NULL, Global.ScreenSurface, &Global.rcSprite);

  // Presents render
  SDL_RenderPresent(Global.Renderer);
}

I’ve already added SDL_StartTextInput() and SDL_StopTextInput() by the way.


You can browse the entire source code here, but here’s the rest of the main source file:

Graphics.cpp:

#include <stdio.h>
#include <stdexcept>
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>

#include "TextMenu.h"
#include "TextBox.h"

// Screen dimensions, constants
#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 900
// 600 for ground, 280 for output, 20 for input

struct Graphics // Core SDL2 elements
{
  SDL_Window* Window; // The window we'll be rendering to
  SDL_Renderer* Renderer; // The renderer we'll be using
  SDL_Surface* ScreenSurface; // The surface contained by the window
  SDL_Surface* CurrentSurface; // Current displayed image
  TTF_Font* Font; // Font pointer.
  SDL_Color TextColor = { 255, 255, 255, 255 }; // Text color, white.
  TextMenu Menu; // Primary TextBox handler.
  TextBox TextInput; // Handles text input.
  SDL_Rect rcGround, rcSprite, rcTextInput, rcTextOutput, rcTextOutputGrd; // Various geometry.
} Global;

struct StructLoop
{
  bool bQuit = false;
  bool bRenderText = false;
  SDL_Event event;
  std::string InputText = " ";
} Loop;

void Init(Graphics& Global)
{
  if (SDL_Init(SDL_INIT_VIDEO) > 0)
  {
    throw(::std::runtime_error("SDL failed to initialise! ERROR: "));
  }
  Global.Window = SDL_CreateWindow("Caventure",
                              SDL_WINDOWPOS_UNDEFINED,
                              SDL_WINDOWPOS_UNDEFINED,
                              SCREEN_WIDTH,
                              SCREEN_HEIGHT,
                              SDL_WINDOW_SHOWN);
  if (Global.Window == NULL)
  {
    throw(::std::runtime_error("Window failed to initialise! ERROR: "));
  }
  Global.ScreenSurface = SDL_GetWindowSurface(Global.Window);
  if (Global.ScreenSurface == NULL)
  {
  throw(::std::runtime_error("Surface failed to initialise! ERROR: "));
  }
  Global.Renderer = SDL_CreateRenderer(Global.Window, -1, 0);
  if (Global.Renderer == NULL)
  {
    throw(::std::runtime_error("Renderer could not be initialised! ERROR: "));
  }
  if (TTF_Init() > 0)
  {
    throw(::std::runtime_error("TTF could not be initialised! ERROR: "));
  }
}

void LoadMedia(Graphics& Global)
{
  // Set geomtry dimensions, apart from rcTextInput.
  Global.rcGround = { 0, 0, 800, 600 };
  Global.rcSprite = { 400, 300, 4, 4 };
  Global.rcTextOutput = { 0, 600, 800, 280 };
  Global.rcTextOutputGrd = { 0, 600, 800, 280 };

  Global.Font = TTF_OpenFont("src/graphics/resources/notomono-regular.ttf", 14);
  if (Global.Font == NULL)
  {
    throw(::std::runtime_error("Font failed to load! ERROR: "));
  }

  SDL_SetTextInputRect(&Global.rcTextInput);
}

void InputLoop(Graphics& Global, StructLoop& Loop)
{
  if(Loop.event.type == SDL_QUIT)
  {
    Loop.bQuit = true;
  }
  else if(Loop.event.type == SDL_KEYDOWN)
  {
    // Sprite movement
    switch(Loop.event.key.keysym.sym)
    {
      case SDLK_UP:
      Global.rcSprite.y -= 5;
      break;

      case SDLK_DOWN:
      Global.rcSprite.y += 5;
      break;

      case SDLK_LEFT:
      Global.rcSprite.x -= 5;
      break;

      case SDLK_RIGHT:
      Global.rcSprite.x += 5;
      break;
    }

    // Backspace handler
    if (Loop.event.key.keysym.sym == SDLK_BACKSPACE && Loop.InputText.length() > 0)
    {
      Loop.InputText.pop_back();
      if (Loop.InputText.length() == 0)
      {
        Loop.InputText = " ";
      }
    }

    // Creates new line of text
    else if (Loop.event.key.keysym.sym == SDLK_RETURN && Loop.InputText.length() != 0 && Loop.InputText != " ")
    {
      Global.Menu.NewBox(Loop.InputText);
      Loop.bRenderText = true;
      Loop.InputText = " ";
    }
  }
  else if (Loop.event.type == SDL_TEXTINPUT)
  {
    Loop.InputText += Loop.event.text.text;
  }
}

void RenderLoop(Graphics& Global, StructLoop& Loop)
{
  // Renders sprite movement
  if (Global.rcSprite.x < 0 || Global.rcSprite.y < 0 || Global.rcSprite.y > Global.rcGround.h || Global.rcSprite.x > Global.rcGround.w)
  {
    Global.rcSprite.x = 400;
    Global.rcSprite.y = 300;
  }

  // Sets background to black
  SDL_SetRenderDrawColor(Global.Renderer, 0x00, 0x00, 0x00, 0x00);
  SDL_RenderClear(Global.Renderer);

  // Renders background of sprite to black
  SDL_RenderFillRect(Global.Renderer, &Global.rcGround);
  SDL_BlitSurface(Global.CurrentSurface, NULL, Global.ScreenSurface, &Global.rcGround);

  // Renders background of text box to grey
  SDL_SetRenderDrawColor(Global.Renderer, 0x40, 0x40, 0x40, 0x40);
  SDL_RenderFillRect(Global.Renderer, &Global.rcTextOutputGrd);
  SDL_BlitSurface(Global.CurrentSurface, NULL, Global.ScreenSurface, &Global.rcTextOutputGrd);

  // Renders text input
  Global.TextInput.Render(Global.Renderer, Global.Font, Loop.InputText.c_str(), Global.TextColor);
  Global.rcTextInput = { 0, 880, Global.TextInput.GetWidth(), Global.TextInput.GetHeight() };
  SDL_RenderCopy(Global.Renderer, Global.TextInput.GetTexture(), NULL, &Global.rcTextInput);

  // Renders text output
  if (Loop.bRenderText)
  {
    Global.Menu.Update(Global.Renderer, Global.Font, Global.TextColor, Global.rcTextOutput);
  }
  SDL_RenderSetClipRect(Global.Renderer, NULL);

  // Renders text box background edges white
  SDL_SetRenderDrawColor(Global.Renderer, 0xFF, 0xFF, 0xFF, 0xFF);
  SDL_RenderDrawLine(Global.Renderer, 0, 600, 800, 600);
  SDL_RenderDrawLine(Global.Renderer, 0, 880, 800, 880);

  // Renders sprite
  SDL_RenderFillRect(Global.Renderer, &Global.rcSprite);
  SDL_BlitSurface(Global.CurrentSurface, NULL, Global.ScreenSurface, &Global.rcSprite);

  // Presents render
  SDL_RenderPresent(Global.Renderer);
}

void Quit(Graphics& Global)
{
  // Deallocate memory
	SDL_DestroyWindow(Global.Window);
	SDL_DestroyRenderer(Global.Renderer);
  TTF_CloseFont(Global.Font);
	Global.Window = NULL;
  Global.Renderer = NULL;
  Global.Font = NULL;

	// Quit SDL subsystems
  TTF_Quit();
	SDL_Quit();
}

int main()
{
  try
  {
    Init(Global);
    LoadMedia(Global);

    SDL_StartTextInput();

    while(!Loop.bQuit)
    {
      while(SDL_PollEvent(&Loop.event) != 0)
      {
      InputLoop(Global, Loop);
      RenderLoop(Global, Loop);
      }
    SDL_StopTextInput();
    }
  }
  catch (std::runtime_error const& msg)
	{
		printf("%s", msg.what());
		if (SDL_GetError() != NULL)
		{
			printf("%s", SDL_GetError());
		}
    else if (TTF_GetError() != NULL)
		{
			printf("%s", TTF_GetError());
		}
    else
    {
      printf("%s", "NULL");
    }
    Quit(Global);
		return EXIT_FAILURE;
	}
  Quit(Global);
  return EXIT_SUCCESS;
}