I have created a class to allow user input of multiple variables, displaying each prompt ont the screen at once and allowing the user to 'tab' between each prompt and 'enter' to record all the input into variables. Here is the code :
Code:
File : ConsoleIOBox.h
#ifndef IOBOX_H_INCLUDED
#define IOBOX_H_INCLUDED
#include <string>
#include <windows.h>
#include <iostream>
#include <conio.h>
typedef enum { // System key codes
ENTER = 13, BACKSPACE = 8, TAB = 9,
CTRL_TAB = 404, ESC = 27, UP_ARROW = 328,
DOWN_ARROW = 336, LEFT_ARROW = 331, RIGHT_ARROW = 333,
PAGE_UP = 329, PAGE_DOWN = 337, F1 = 315,
F2 = 316, F3 = 317, F4 = 318,
F5 = 319, F6 = 320, F7 = 321,
F8 = 322, F9 = 323, F10 = 324,
F11 = 325, F12 = 326
} SYSTEMKEYCODES;
typedef struct {
short X, // X and
Y, // Y coords for the start position of the box
Z; // length (in characters) of the box
} BOXCOORDS;
class ConsoleInputBox {
public : // Functions
ConsoleInputBox() {};
~ConsoleInputBox() {};
void SetBox(const BOXCOORDS, const std::string, const char, const char);
std::string Display();
std::string Display(const std::string);
std::string Read();
wchar_t Get(SYSTEMKEYCODES);
private : // Functions
static int GetCode() {
int ch = getch();
if ( ch == 0 || ch == 224 ) ch = 256 + getch();
return ch;
}
void RemoveTrailingSpaces(std::string&);
private : // Variables
BOXCOORDS box_coords;
short current_x_pos;
char front_border,
rear_border;
std::string title;
};
// Set the Coords, Prompt message, and border characters for the box
void ConsoleInputBox::SetBox(const BOXCOORDS set_coords,
const std::string s,
const char front,
const char rear ) {
box_coords = set_coords;
title = s;
front_border = front;
rear_border = rear;
return;
}
// Display the box
std::string ConsoleInputBox::Display() {
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
COORD Position;
Position.X = ( (box_coords.X - 1) - title.length() );
Position.Y = box_coords.Y;
SetConsoleCursorPosition(hOut, Position);
std::string space(box_coords.Z, ' ');
std::string str = title + front_border + space + rear_border;
return str;
}
// Display the box with optional information already in the box
std::string ConsoleInputBox::Display(const std::string s) {
std::string s2 = s;
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
COORD Position;
Position.X = ( (box_coords.X - 1) - title.length() );
Position.Y = box_coords.Y;
SetConsoleCursorPosition(hOut, Position);
std::string space( (box_coords.Z - s.length() ), ' ');
if (s.length() > box_coords.Z)
s2 = s.substr(0, box_coords.Z);
std::string str = title + front_border + s2 + space + rear_border;
return str;
}
// Read the information from the box into a variable
std::string ConsoleInputBox::Read() {
char tempchar[box_coords.Z];
std::string tempstring;
COORD Position;
DWORD NumRead;
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
Position.X = box_coords.X; Position.Y = box_coords.Y;
ReadConsoleOutputCharacter(hOut, tempchar, box_coords.Z,
Position, &NumRead);
tempstring.assign(tempchar, 0, box_coords.Z);
std::string space(tempstring.size(), ' ');
if (tempstring == space)
tempstring.clear();
else
RemoveTrailingSpaces(tempstring);
return tempstring;
}
// Get user input into the box
wchar_t ConsoleInputBox::Get(SYSTEMKEYCODES syscodes) {
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
COORD Position;
Position.X = box_coords.X;
Position.Y = box_coords.Y;
SetConsoleCursorPosition(hOut, Position);
int current_x_pos = 0;
bool loop = true;
const int length = ( (box_coords.X + box_coords.Z) - 1);
char ch;
wchar_t wch;
while(loop) {
wch = GetCode();
if (wch >= 32 && wch <= 126) {
if (current_x_pos < box_coords.Z) {
ch = wch;
std::cout<<ch;
++current_x_pos;
}
} else switch (wch) {
case LEFT_ARROW :
if (current_x_pos > 0) {
current_x_pos--;
Position.X = (box_coords.X + current_x_pos);
SetConsoleCursorPosition(hOut, Position);
}
break;
case RIGHT_ARROW :
if (current_x_pos < box_coords.Z) {
current_x_pos++;
Position.X = (box_coords.X + current_x_pos);
SetConsoleCursorPosition(hOut, Position);
}
break;
case BACKSPACE :
if (current_x_pos > 0) {
std::cout<<"\b \b";
current_x_pos--;
}
break;
default :
loop = false;
break;
}
}
return wch;
}
// Remove the trailing spaces in the variable
void ConsoleInputBox::RemoveTrailingSpaces(std::string& str) {
std::string::size_type length = str.length();
std::string::iterator iter;
for (iter = (str.end() - 1); iter != str.begin(); --iter) {
if (*iter == ' ')
--length;
else
break;
}
str.assign(str, 0, length);
return;
}
#endif
and a small program to test it :
Code:
#include "iobox.h"
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main() {
// Create an instance of the ConsoleInputBox
ConsoleInputBox cBox;
// Create typedef's for the box coords and system key codes
BOXCOORDS BoxCoords;
SYSTEMKEYCODES SysCodes;
// Create a vector to hold the ConsoleInputBoxes and an iterator
// to access them
vector<ConsoleInputBox> Boxes;
vector<ConsoleInputBox>::iterator iter;
// Load vector with coords for the three ConsoleInputBoxes
BoxCoords.X = 15;
BoxCoords.Y = 0;
BoxCoords.Z = 15;
cBox.SetBox(BoxCoords, "First Name ", '[', ']');
Boxes.push_back(cBox);
BoxCoords.X = 15;
BoxCoords.Y = 1;
BoxCoords.Z = 15;
cBox.SetBox(BoxCoords, "Middle Name ", '[', ']');
Boxes.push_back(cBox);
BoxCoords.X = 15;
BoxCoords.Y = 2;
BoxCoords.Z = 20;
cBox.SetBox(BoxCoords, "Last Name ", '[', ']');
Boxes.push_back(cBox);
// Display the three ConsoleInputBoxes
for (iter = Boxes.begin(); iter != Boxes.end(); ++iter) {
cout<<iter->Display() <<endl;
}
// User enters information into the ConsoleInputBoxes here
// User can TAB between the boxes or ENTER to read the
// information typed in into variables and exit out
iter = Boxes.begin();
wchar_t option;
bool loop = true;
do {
option = iter->Get(SysCodes);
switch (option) {
case TAB :
++iter;
if (iter == Boxes.end() )
iter = Boxes.begin();
break;
case ENTER :
loop = false;
break;
}
} while (loop);
// Display what the user typed in, just to make sure it worked
iter = Boxes.begin();
string first = iter->Read();
++iter;
string middle = iter->Read();
++iter;
string last = iter->Read();
cout<<"\n\n\n\n\n" <<first <<" " <<middle <<" " <<last;
cin.get();
return 0;
}
I've been playing with this for a while now and I was wondering if there was any way I can improve on it (less code, better syntax, ect...)
The one thing I don't like is the use of <iostream> in the header. I have been looking for another way to do this and have toyed with the WriteConsole function but have not been able to make it work.
Thanks for any suggestions
Oh, and in case you were wondering about all the codes in the SYSTEMKEYCODES enum, thats so I can use this with any other program I create and to allow flexability in choosing what keys the user can hit to get different results. For instance, I might want to use 'enter' to tab around, 'F8' to save and 'F3' to exit out and not save......