Clearing a field buffer in ncurses - c++

I've built a generic wrapper for the curses form object to use with a large
simulation project that I'm working on.
Basically, I instantiate an generic_form object, add some fields and their
descriptions to it, and then give it focus and get user input with a fill_form() routine.
Because each generic_form object can be used more than once, that is, that fill_form() may be called more than once per instantiation, I need to clear the field buffers at the beginning of the fill_form() routine. Currently, I'm using this at the beginning of the routine:
//clear the field buffers in case there's junk in them
for (std::vector<FIELD*>::iterator clear_iter = fields.begin();
clear_iter != fields.end(); clear_iter++)
{
if (*clear_iter != nullptr)
{
set_field_buffer(*clear_iter, 0, " ");
}
}
However, it throws a floating point exception at the set_field_buffer line on the second call to the fill_form() routine. Moreover, the set_field_buffer line doesn't seem to actually be doing anything, at least not clearing the buffer, because without calling free_field at the end of the routine, and instead in the object destructor, the fields buffers remain the same on each subsequent call.
Here's the entirety of the (ugly, in-development) fill_form() routine for brevity:
void generic_form::fill_form()
{
//fields.push_back(NULL);
if (fields.size() == 1)
{
fields.push_back(NULL);
form = new_form(static_cast<FIELD**>(fields.data()));
fields.erase((fields.end() - 1));
assert(fields.size() == 1);
}
else
{
form = new_form(static_cast<FIELD**>(fields.data()));
}
WINDOW* form_win = derwin(screen, fields.size() + 1, largest_desc + 6, ypos,
xpos);
set_form_win(form, form_win);
set_form_sub(form, form_win);
//clear the field buffers in case there's junk in them
for (std::vector<FIELD*>::iterator clear_iter = fields.begin();
clear_iter != fields.end(); clear_iter++)
{
if (*clear_iter != nullptr)
{
set_field_buffer(*clear_iter, 0, " ");
}
}
post_form(form);
for (int x = 0; x < descriptions.size(); x++)
{
mvwprintw(form_win, x, 0, descriptions.at(x).c_str());
}
wmove(form_win, 0, largest_desc + 1);
touchwin(screen);
wrefresh(form_win);
/* Loop through to get user requests */
int ch;
while((ch = getch()) != '\n')//KEY_F(1))
{ switch(ch)
{
case KEY_DOWN:
/* Go to next field */
form_driver(form, REQ_NEXT_FIELD);
/* Go to the end of the present buffer */
/* Leaves nicely at the last character */
form_driver(form, REQ_END_LINE);
break;
case KEY_UP:
/* Go to previous field */
form_driver(form, REQ_PREV_FIELD);
form_driver(form, REQ_END_LINE);
break;
case KEY_LEFT:
form_driver(form, REQ_PREV_CHAR);
break;
case KEY_RIGHT:
form_driver(form, REQ_NEXT_CHAR);
break;
// Delete the char before cursor
case KEY_BACKSPACE:
case 127:
form_driver(form, REQ_DEL_PREV);
break;
// Delete the char under the cursor
case KEY_DC:
form_driver(form, REQ_DEL_CHAR);
break;
default:
/* If this is a normal character, it gets */
/* Printed */
form_driver(form, ch);
break;
}
}
form_driver(form, REQ_VALIDATION);
for (int x = 0; x < fields.size() && first_run; x++)
{
//store the int_inputs from the forms
if ((fields.at(x) != nullptr) && (field_type(fields.at(x)) ==
TYPE_INTEGER))
{
int_inputs.push_back(std::atoi(field_buffer((fields.at(x)), 0)));
}
if ((fields.at(x) != nullptr) && (field_type(fields.at(x)) ==
TYPE_ALPHA))
{
str_inputs.push_back(field_buffer((fields.at(x)), 0));
}
}
first_run = false;
/* Un post form and free the memory */
unpost_form(form);
free_form(form);
for (int x = 0; x < fields.size(); x++)
{
free_field(fields.at(x));
}
delwin(form_win);
}
Long story short/TLDR:
How to I clear or reset a field buffer in ncurses, without deleting and re-adding it?

You can clean field buffer using form_driver ()
Excerpt man form_driver
REQ_CLR_EOL
Clear to end of line from cursor.
REQ_CLR_EOF
Clear to end of field from cursor.
REQ_CLR_FIELD
Clear the entire field.
To elaborate this a bit more :-), I'm using code similar to following for clearing fields:
#include <stdio.h>
#include <stdlib.h>
#include <form.h>
enum f_name_l
{
f_name, f_surname, f_last
};
int main (void)
{
int ch = 0, i = 0;
FIELD *field[3], *save_field;
FORM *my_form;
initscr ();
start_color ();
noecho ();
raw ();
keypad (stdscr, TRUE);
refresh ();
field[f_name] = new_field (1, 10, 0, 25, 0, 0);
field[f_surname] = new_field (1, 10, 2, 25, 0, 0);
field[f_last] = NULL;
set_field_back (field[f_name], A_UNDERLINE);
set_field_back (field[f_surname], A_UNDERLINE);
my_form = new_form (field);
post_form (my_form);
// Form labels
mvprintw (0, 1, "Name: ");
mvprintw (2, 1, "Surname: ");
mvprintw (4, 1, "F5 to clear active field. F6 to clear form.");
pos_form_cursor (my_form);
refresh ();
// ^q to exit
while ((ch = getch ()) != 17)
{
switch (ch)
{
case KEY_UP:
form_driver (my_form, REQ_PREV_FIELD);
break;
case KEY_DOWN:
form_driver (my_form, REQ_NEXT_FIELD);
break;
case KEY_F(5):
form_driver (my_form, REQ_CLR_FIELD);
break;
case KEY_F(6):
save_field = current_field (my_form);
for (i = 0; i < f_last; i++)
{
set_current_field (my_form, field[i]);
form_driver (my_form, REQ_CLR_FIELD);
}
set_current_field (my_form, save_field);
break;
default:
form_driver (my_form, ch);
break;
}
form_driver (my_form, REQ_VALIDATION);
}
endwin ();
return EXIT_SUCCESS;
}
But seeing post from Thomas Dickey I start to feel like my life is a lie :-).

Related

key and mouse input

i have a question:
(i use winows, visual studio)
i making a program and i need to read keyboard and mouse input istantly so like getch() (because if i use cin i need to press fullstop new line evry time).
i have this:
char p;
while (running) {
if (_kbhit()) {
p = _getch();
switch (p) {
case 'w':
mx = -1;
map(player, mx, 0);
break;
case 'a':
my = -1;
map(player, 0, my);
break;
case 's':
mx = 1;
map(player, mx, 0);
break;
case 'd':
my = 1;
map(player, 0, my);
break;
case 27:
running = false;
break;
}
}
}
the problem is with _getch() i can't read mouse imput.
so how i can get this?

How to make a button that will go to the previous menu in ncurses

I am pretty new to c++ and ncurses, so sorry if my question is weird or obvious.
I managed to make a simple tui program that will do various tasks, my problem is that I have no back functionality or something that would loop the program.
I want to be able to go back to the main menu after accessing one of the submenus and I want to make the program repeat after it's done so I won't have to keep opening it over and over, so do you have any solutions that I can apply?
Thank you in advance
This is my code:
int main(int argc, char ** argv)
{
int i=0;
string input;
initscr();
noecho();
cbreak();
curs_set(0);
int yMax, xMax;
getmaxyx(stdscr, yMax, xMax);
WINDOW * menuwin = newwin (0, xMax, 0, 0);
leaveok(menuwin, true);
refresh();
wrefresh(menuwin);
keypad(menuwin, true);
string choices[4] = {"Youtube","Music","Anime","Games"};
int choice;
int highlight = 0;
int option = 0;
while(1)
{
for (i=0;i < 4; i++)
{
if(i == highlight)
wattron(menuwin, A_REVERSE);
mvwprintw(menuwin, i+1, 1, choices[i].c_str());
wattroff(menuwin, A_REVERSE);
}
choice = wgetch(menuwin);
switch(choice)
{
case KEY_UP:
highlight--;
if(highlight == -1)
highlight = 3;
break;
case KEY_DOWN:
highlight++;
if(highlight == 4)
highlight = 0;
break;
default:
break;
}
if(choice == 10)
{
break;
}
}
werase(menuwin);
switch(highlight)
{
case 0:
{
menu2();
break;
}
case 1:
{
menu3();
break;
}
case 2:
{
menu4();
break;
}
case 3:
{
menu2();
}
default:
break;
}
endwin();
return 0;
}

Input invisible c++ Maze Game

So I have most of my game finish up however, I want to save the score and name of the player to a text file and display it. So far the user input works and does save to a text file named score.txt however the input is invisible and you can't see what you are typing. Does anyone know why this is happening?
Main
int main()
{
DWORD mode; /* Preserved console mode */
INPUT_RECORD event; /* Input event */
BOOL EXITGAME = FALSE; /* Program termination flag */
unsigned int counter = 0; /* The number of times 'Esc' is pressed */
/* Get the console input handle */
HANDLE hstdin = GetStdHandle( STD_INPUT_HANDLE );
/* Preserve the original console mode */
GetConsoleMode( hstdin, &mode );
/* Set to no line-buffering, no echo, no special-key-processing */
SetConsoleMode( hstdin, 0 );
srand ( time(NULL) ); //initialize the random seed
// Variables
int health = 2;
// Declare variable positions
player.x=1;
player.y=1;
treasure.x = 20;
treasure.y = 5;
treasure.z= 0;
traps.x = 1;
traps.y = 7;
traps.z = 0;
lives.x = 1;
lives.y = 9;
ofstream file;
int score = 0;
string name;
string line;
/*
while(treasure.z < 2)
{
treasure.x = (rand() % 24);
treasure.y = (rand() % 16);
if(treasure.x == 0 && treasure.y == 0)
{
treasure.z++;
}
}
while(traps.z < 3)
{
traps.x = (rand() % 24);
traps.y = (rand() % 16);
if(traps.x == 0 && traps.y == 0)
{
traps.z++;
}
}
while(lives.z < 2)
{
lives.x = (rand() % 24);
lives.y = (rand() % 16);
}
*/
clrscr();
setcolor(15);
while (!EXITGAME)
{
if (WaitForSingleObject( hstdin, 0 ) == WAIT_OBJECT_0) /* if kbhit */
{
DWORD count; /* ignored */
/* Get the input event */
ReadConsoleInput( hstdin, &event, 1, &count );
/* Only respond to key release events */
if ((event.EventType == KEY_EVENT)
&& !event.Event.KeyEvent.bKeyDown)
clrscr();
putmenu();
gotoxy(6,20);
cout<<"Lives: " << health;
gotoxy(6,22);
cout<<"Score: " << score;
Sleep(50);
switch (event.Event.KeyEvent.wVirtualKeyCode)
{
case VK_ESCAPE:
clrscr();
putend();
EXITGAME = TRUE;
break;
case VK_LEFT:
// left key move player left
moveleft();
break;
case VK_RIGHT:
// right key move player right
moveright();
break;
case VK_UP:
// up key move player up
moveup();
break;
case VK_DOWN:
// down key move player down
movedown();
break;
case VK_A:
// left key move player left
moveleft();
break;
case VK_D:
// right key move player right
moveright();
break;
case VK_W:
// up key move player up
moveup();
break;
case VK_S:
// down key move player down
movedown();
break;
}//switch
puttreasure();
puttraps();
putlives();
putplayer();
if((player.x == lives.x) && (player.y == lives.y))
{
health++;
lives.x = 0;
lives.y = 0;
}
if((player.x == traps.x) && (player.y == traps.y))
{
health--;
traps.x = 0;
traps.y = 0;
}
if((player.x == treasure.x)&& (player.y == treasure.y))
{
score += 100;
EXITGAME = true;
}
else if(health == 0)
{
EXITGAME = true;
}
if(EXITGAME == true)
{
score = score + (health * 100);
}
}
}
if(EXITGAME == true)
{
// clear screen
clrscr();
}
setcolor(10);
cout << "Enter your name ";
cin >> name;
ofstream out("score.txt");
out << name;
out << "\n";
out << score;
out.close();
/* if(file.is_open())
{
while( getline (file, line))
cout << line << '\n';
}*/
gotoxy(1,23);cout<<" ";
SetConsoleMode( hstdin, mode );
return 0;
}
/* Set to no line-buffering, no echo, no special-key-processing */
You turned off echo - means that the user wont see what they type

Detecting collision with arrays in C++

So I have a 2d map array printed out. I have 0's set as a space and 1 set as a wall. I have variables such as traps and health as well as the player. However, I am having trouble implementing a score as the two collide. I was wondering how I can detect when a player and life collide which would increment the health variable by 1. Right now it increments every time I move.
Thank you!
These are my variable functions
void putplayer()
{
setcolor(9);
gotoxy( player.x +mazex, player.y +mazey);
cout<<playersymbol;
setcolor(7);
}
void puttreasure()
{
setcolor(14);
gotoxy(treasure.x +mazex, treasure.y +mazey);
cout<<treasuresymbol;
setcolor(7);
}
void puttraps()
{
setcolor(14);
gotoxy( traps.x +mazex, traps.y +mazey);
cout<<trapssymbol;
setcolor(7);
}
void putlives()
{
setcolor(14);
gotoxy( lives.x +mazex, lives.y +mazey);
cout<<livessymbol;
setcolor(7);
}
void moveleft()
{
gotoxy(31,7);
cout<<"left key move player left \n\n";
if (maze[player.y][player.x-1]==0) player.x = player.x -1;
}
Then my Main, however some code I took out as it might not be relevant
int main()
{
DWORD mode; /* Preserved console mode */
INPUT_RECORD event; /* Input event */
BOOL EXITGAME = FALSE; /* Program termination flag */
// unsigned int counter = 0; /* The number of times 'Esc' is pressed */
/* Get the console input handle */
HANDLE hstdin = GetStdHandle( STD_INPUT_HANDLE );
/* Preserve the original console mode */
GetConsoleMode( hstdin, &mode );
/* Set to no line-buffering, no echo, no special-key-processing */
SetConsoleMode( hstdin, 0 );
srand ( time(NULL) ); //initialize the random seed
// Variables
int health = 0;
// Declare variable positions
player.x=1;
player.y=1;
treasure.x = 1;
treasure.y = 3;
traps.x = 1;
traps.y = 7;
lives.x = 1;
lives.y = 9;
clrscr();
setcolor(15);
while (!EXITGAME)
{
if (WaitForSingleObject( hstdin, 0 ) == WAIT_OBJECT_0) /* if kbhit */
{
DWORD count; /* ignored */
/* Get the input event */
ReadConsoleInput( hstdin, &event, 1, &count );
/* Only respond to key release events */
if ((event.EventType == KEY_EVENT)
&& !event.Event.KeyEvent.bKeyDown)
clrscr();
putmenu();
gotoxy(6,20);
cout<<"Lives: " << health;
Sleep(100);
switch (event.Event.KeyEvent.wVirtualKeyCode)
{
case VK_ESCAPE:
EXITGAME = TRUE;
break;
case VK_LEFT:
// left key move player left
moveleft();
break;
case VK_RIGHT:
// right key move player right
moveright();
break;
case VK_UP:
// up key move player up
moveup();
break;
case VK_DOWN:
// down key move player down
movedown();
break;
case VK_A:
// left key move player left
moveleft();
break;
case VK_D:
// right key move player right
moveright();
break;
case VK_W:
// up key move player up
moveup();
break;
case VK_S:
// down key move player down
movedown();
break;
}//switch
putplayer();
puttreasure();
puttraps();
putlives();
}
if(maze[player.x][player.y] = maze[lives.x][lives.y]){
health++;
}
else if(maze[player.x][player.y] = maze[traps.x][traps.y]){
health--;
}
}
gotoxy(1,23);cout<<" ";
SetConsoleMode( hstdin, mode );
return 0;
}
You have the code
if(maze[player.x][player.y] = maze[lives.x][lives.y])
which sets the maze[player.x][player.y] to the value at maze[lives.x][lives.y], and then evaluates it (it will evaluate to true if 1 (wall), false if 0 (space)). I think you meant to have something like
if((player.x == lives.x) && (player.y == lives.y))
which will (as far as I can tell) evaluate if the player and the lives are at the same location.

SDL 2 Space keydown not detected but Space keyup works fine

Hey so I'm working on a project/2d game and I'm having some odd behavior from SDL which I'm sure is probably something I'm not understanding. The function ProcessKeys is called and works fine for all the key press downs except SDLK_SPACE and I cannot for the life of me figure out why.
What is even more bizarre is that the SDL_KEYUP switch of SDLK_SPACE works great. I tried using some debugging code to print out which key is being pressed and when you press space down nothing registers. Every other key on the keyboard registers in my debug statement at the top of the SDL_KEYDOWN case.
If anyone can see what is going on I would really appreciate it.
And if you need to see where its being called let me know.
SDLKeyboard::KeyState SDLKeyboard::ProcessKeys(SDL_Event * event)
{
switch(event->type)
{
/* Look for a keypress */
case SDL_KEYDOWN:
{
std::cout << "Key currently pressed" << event->key.keysym.sym << std::endl;
/* Check the SDLKey values and move change the coords */
switch(event->key.keysym.sym)
{
case SDLK_LEFT:
{ // rotate the ship left
c.setIsTurningLeft(true);
return this->keystate = LeftPressed;
// add code when user presses left
break;
}
case SDLK_RIGHT:
{
// rotate the ship right
c.setIsTurningRight(true);
return this->keystate = RightPressed;
// add code when user presses right
break;
}
case SDLK_UP:
{
// accleration
c.setIsAccelerating(true);
return this->keystate = UpPressed;
// add code when user presses up
break;
}
case SDLK_SPACE:
{
// shoot
c.setIsShooting(true);
std::cout << "keystate = " << this->keystate;
return this->keystate = SpacePressed;
// add code when user presses space
break;
}
default:
{
return this->keystate = NotPressed;
break;
}
}
break;
}
/* We must also use the SDL_KEYUP events to zero the x */
/* and y velocity variables. But we must also be */
/* careful not to zero the velocities when we shouldn't*/
case SDL_KEYUP:
{
std::cout << "Key currently pressed" << event->key.keysym.sym << std::endl;
switch(event->key.keysym.sym)
{
case SDLK_LEFT:
{ /* We check to make sure the ship is moving */
/* to the left. If it is then we zero the */
/* velocity. If the ship is moving to the */
/* right then the right key is still press */
/* so we don't touch the velocity */
c.setIsTurningLeft(false);
return this->keystate = LeftReleased;
// code to do things when left isn't pushed anymore but still moving left
break;
}
case SDLK_RIGHT:
{ // code to do things when right isn't pushed anymore but still moving right
c.setIsTurningRight(false);
return this->keystate = RightReleased;
break;
}
case SDLK_UP:
{ // code to do things when up isn't pushed anymore but still moving up
c.setIsAccelerating(false);
return this->keystate = UpReleased;
break;
}
case SDLK_SPACE:
{ // accleration
c.setIsShooting(false);
return this->keystate = SpaceReleased;
// add code when user presses up
break;
}
default:
break;
}
break;
}
default:
{
return this->keystate = NotPressed;
break;
}
}
}
EDIT:
Here is the example requested. The other thing that I've noticed is the latency in response isn't that great. Like if you press a key sometimes the console doesn't print the corresponding key. Probably has to do with the issue I'm having with the space as well.
void GUI::TakeInput(SDL_Event *e)
{
while (SDL_PollEvent(e))
OnEvent(e);
}
void SDLEvent::OnEvent(SDL_Event * event)
{
switch(event->type)
{
case SDL_KEYDOWN:
{
OnKeyDown(event->key.keysym.sym);
break;
}
case SDL_KEYUP:
{
OnKeyUp(event->key.keysym.sym);
break;
}
case SDL_MOUSEMOTION:
{
OnMouseMove(event->motion.x,event->motion.y);
break;
}
case SDL_MOUSEBUTTONDOWN:
{
OnMouseButtonDown(event->button.button, event->button.x,event->button.y);
break;
}
case SDL_MOUSEBUTTONUP:
{
OnMouseButtonUp(event->button.button, event->button.x,event->button.y);
break;
}
case SDL_QUIT: {
OnExit();
break;
}
case SDL_SYSWMEVENT: {
//Ignore
break;
}
case SDL_WINDOWEVENT_RESIZED: {
OnResize();
break;
}
case SDL_WINDOWEVENT_EXPOSED: {
OnExpose();
break;
}
default: {
OnUser(event->user.type,event->user.code,event->user.data1,event->user.data2);
break;
}
}
}
void GUI::Play()
{
Uint32 start_ticks = SDL_GetTicks();
TakeInput(this->setup->GetEvent());
this->keyboard->ProcessKeys(this->setup->GetEvent());
this->setup->RenderBegin();
this->ship->drawBackBuffer();
this->ship->renderSprite();
Uint32 end_ticks = SDL_GetTicks();
int sleep_delay = (1000 / 60) - (end_ticks-start_ticks);
if (sleep_delay > 0) {
SDL_Delay(sleep_delay);
}
}
If you are only writing event->key.keysym.sym on the console, you should know that the spacebar key produces an almost invisible character.
Try this instead:
std::cout << "<" << event->key.keysym.sym << ">"
So you can see whataver invisible character printed between angle brackets.