Text Input in an Allegro Game
by Chris "23yrold3yrold" Barry


ADVERTISEMENT

A common request in the Allegro forums is for a way to process player text input. cin doesn't work. The Allegro GUI does, but is simplistic and limiting (*cough* and ugly *cough*). Back when I wrote an article on the standard C++ string class, I wrote a small C++ program that stored player input in a std::string. Since then, I made a simpler C version that uses a char array. The code is very short and simple to use, so modifying it for your purposes (to word wrap, for example, if you want that) is dirt easy. I get asked for it often, so I'm just submitting it for ease of finding.

Both the C and C++ version just take the input and print it onscreen. The C++ version lets you move the caret around, processes the Insert key to toggle replacing and inserting, and lets you both delete and backspace. None of that's really necessary; It's only there because the string class makes it so easy. The functionality can be added to the C version easily enough, I know. But I'm a lazy spoilt C++ coder, so all effort to that end is left as an exercise to the reader.

Here is the C version.

// edittext.c
#include <allegro.h>

#define BUFFERSIZE 128
#define WHITE makecol(255, 255, 255)

int main()
{
   BITMAP* buffer = NULL;
   char    edittext[BUFFERSIZE];
   int     caret  = 0;

   /* typical Allegro initialization */
   allegro_init();
   install_keyboard();
   set_gfx_mode(GFX_AUTODETECT, 320, 240, 0, 0);

   buffer = create_bitmap(320, 240);

   do
   {
      if(keypressed())
      {
         int  newkey   = readkey();
         char ASCII    = newkey & 0xff;
         char scancode = newkey >> 8;

         /* a character key was pressed; add it to the string */
         if(ASCII >= 32 && ASCII <= 126)
         {
				if(caret < BUFFERSIZE - 1)
				{
					edittext[caret] = ASCII;
					caret++;
					edittext[caret] = '\0';
				}
         }
         else if(scancode == KEY_BACKSPACE)
         {
            if (caret > 0) caret--;
            edittext[caret] = '\0';
         }
      }
      
      /* all drawing goes here */
      clear(buffer);
      textout(buffer, font, edittext, 0, 10, WHITE);
      vline(buffer, caret * 8, 8, 18, WHITE);
      blit(buffer, screen, 0, 0, 0, 0, 320, 240);

   }
   while(!key[KEY_ESC]);
   
   destroy_bitmap(buffer);

   return 0;
}
END_OF_MAIN()

The C++ version, as stated, is slightly more robust. This is essentially the code from my original article.

C++:

// edittext.cpp
#include <allegro.h>
#include <string>
using namespace std;

#define WHITE makecol(255, 255, 255)

int main()
{
   // typical Allegro initialization
   allegro_init();
   install_keyboard();
   set_gfx_mode(GFX_AUTODETECT, 320, 240, 0, 0);

   // all variables are here
   BITMAP* buffer = create_bitmap(320, 240); // initialize the double buffer
   string  edittext;                         // an empty string for editting
   string::iterator iter = edittext.begin(); // string iterator
   int     caret  = 0;                       // tracks the text caret
   bool    insert = true;                    // true if text should be inserted
   
   // the game loop
   do
   {
      while(keypressed())
      {
         int  newkey   = readkey();
         char ASCII    = newkey & 0xff;
         char scancode = newkey >> 8;

         // a character key was pressed; add it to the string
         if(ASCII >= 32 && ASCII <= 126)
         {
            // add the new char, inserting or replacing as need be
            if(insert || iter == edittext.end())
               iter = edittext.insert(iter, ASCII);
            else
               edittext.replace(caret, 1, 1, ASCII);

            // increment both the caret and the iterator
            caret++;
            iter++;
         }
         // some other, "special" key was pressed; handle it here
         else
            switch(scancode)
            {
               case KEY_DEL:
                  if(iter != edittext.end()) iter = edittext.erase(iter);
               break;

               case KEY_BACKSPACE:
                  if(iter != edittext.begin())
                  {
                     caret--;
                     iter--;
                     iter = edittext.erase(iter);
                  }
               break;
            
               case KEY_RIGHT:
                  if(iter != edittext.end())   caret++, iter++;
               break;
            
               case KEY_LEFT:
                  if(iter != edittext.begin()) caret--, iter--;
               break;
            
               case KEY_INSERT:
                  insert = !insert;
               break;

               default:

               break;
            }
      }
      
      // clear screen
      clear(buffer);

      // output the string to the screen
      textout(buffer, font, edittext.c_str(), 0, 10, WHITE);

      // output some stats using Allegro's printf functions
      textprintf(buffer, font,  0, 20, WHITE, "length:   %d", edittext.length());
      textprintf(buffer, font,  0, 30, WHITE, "capacity: %d", edittext.capacity());
      textprintf(buffer, font,  0, 40, WHITE, "empty?:   %d", edittext.empty());
      if(insert)
         textout(buffer, font, "Inserting", 0, 50, WHITE);
      else
         textout(buffer, font, "Replacing", 0, 50, WHITE);

      // draw the caret
      vline(buffer, caret * 8, 8, 18, WHITE);

      // blit to screen
      blit(buffer, screen, 0, 0, 0, 0, 320, 240);

   }while(!key[KEY_ESC]); // end of game loop
   
   // clean up
   destroy_bitmap(buffer);
   set_gfx_mode(GFX_TEXT, 0, 0, 0, 0);
   
   return 0;
}
END_OF_MAIN()

I hope that was helpful to you. Comments, questions, feedback, etc. can be posted in the forums or sent to crbarry@mts.net.

Discuss this article in the forums


Date this article was posted to GameDev.net: 8/14/2004
(Note that this date does not necessarily correspond to the date the article was written)

See Also:
General
Sweet Snippets

© 1999-2011 Gamedev.net. All rights reserved. Terms of Use Privacy Policy
Comments? Questions? Feedback? Click here!