I've seen this answered for other languages but not for C++. How would I get a program to wait for the user to press Enter or some key like that, but also to automatically continue after a set time period as long as a key hasn't been entered? I need basic code, I'm sort of a beginner. I know that cin.get(); or system("pause"); will wait for a key and sleep(x seconds); or Sleep(x milliseconds); (with the "windows.h" library) will pause a program, but how do I get both at once?
In windows you can use GetAsyncKeyState() to poll the current state of the keyboard. Then you can use Sleep() to sleep a certain number of milliseconds. Combine those two and you can make something like what you need:
int keyToWaitFor = VK_SPACE;
int count = 0;
int maxcount = 500;
for(int a = 0; a < maxcount; a++){
if (GetAsyncKeyState(keyToWaitFor)!=0){
break;
}
Sleep(5);
}
Since you apparently want to do this on Windows, it's fairly straightforward.
You start by opening a handle to the console, such as with GetStdHandle. Then when you want to do a read, you call WaitForSingleObject on that handle, specifying your timeout value. Check the return. If the return value is WAIT_OBJECT_0, it means you have some input, which you can read with (for example) ReadConsoleInput. If the return is WAIT_TIMEOUT, it means there's no input, so you can do whatever else it is you want to do.
With conio.h, You can wait for a keypress with kbhit() and getch() and make a wait for a 20 second timer with a
while loop, while( key==0 && (time_to_wait < secs) ).
#include <iostream>
#include <cstdio>
#include <ctime>
#include <conio.h>
#include <windows.h>
using namespace std;
int key=0;
bool quit=false;
void check_if_keypressed();
void gotoxy(int x, int y);
void clrscr();
int main()
{
clock_t start;
double time_to_wait;
double secs=10;
gotoxy(1, 2);
cout<<"Press any key to continue or wait 20 seconds: \n ";
start = clock();
while( key==0 && (time_to_wait < secs) )
{
check_if_keypressed();
time_to_wait = ( clock() - start ) / (double) CLOCKS_PER_SEC;
// proceed with whatever here
gotoxy(1, 23);
cout<<"countdown: "<< secs-time_to_wait <<" \n ";
}
// proceed with whatever here
// while( key!=27)
// {
// check_if_keypressed();
// do_other_stuff();
// }
return 0;
}
void check_if_keypressed()
{
if( kbhit() ) key=getch();
switch(key)
{
case 27:
quit=true;
break;
}
}
void gotoxy(int x, int y)
{
COORD coord;
coord.X = x; coord.Y = y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
return;
}
void clrscr()
{
COORD coordScreen = { 0, 0 };
DWORD cCharsWritten;
CONSOLE_SCREEN_BUFFER_INFO csbi;
DWORD dwConSize;
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleScreenBufferInfo(hConsole, &csbi);
dwConSize = csbi.dwSize.X * csbi.dwSize.Y;
FillConsoleOutputCharacter(hConsole, TEXT(' '), dwConSize, coordScreen, &cCharsWritten);
GetConsoleScreenBufferInfo(hConsole, &csbi);
FillConsoleOutputAttribute(hConsole, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten);
SetConsoleCursorPosition(hConsole, coordScreen);
return;
}
Related
This question already has an answer here:
C++ Hotkey to run function
(1 answer)
Closed 5 years ago.
I'm trying to code a little "virus" (just a fun joke program which messes around with the cursor and makes some beep sounds). However, I want to close this process with my F9 key.
Here's what I have so far:
void executeApp()
{
while (true)
{
if (GetAsyncKeyState(VK_F9) & 0x8000)
{
exit(0);
}
Sleep(200);
}
}
I made a thread that runs this function. However, when I run my entire code and press F9, the process still runs. Only when I press it 2-3 times, it comes up with an Error: "Debug Error! abort() has been called."
It would be nice if someone knows how I can kill my process via a hotkey.
Here is the whole code of the program:
#include <iostream>
#include <stdio.h>
#include <windows.h>
#include <conio.h>
#include <ctime>
#include <thread>
#include <random>
using namespace std;
//random number gen for while loops in cursor/beep functions.
random_device rd;
mt19937 eng(rd());
uniform_int_distribution<> distr(1, 100);
//variables used for this program.
int random, Dur, X, Y, Freq;
HWND mywindow, Steam, CMD, TaskMngr;
char Notepad[MAX_PATH] = "notepad.exe";
char Website[MAX_PATH] = "http:\\www.google.de";
//functions
void RandomCursor(), Beeper(), OpenStuff(), executeApp();
//threads
thread cursor(RandomCursor);
thread beeps(Beeper);
thread openstuff(OpenStuff);
thread appexecute(executeApp);
int main()
{
srand(time(0));
random = rand() % 3;
system("title 1337app");
cursor.join();
beeps.join();
appexecute.join();
return 0;
}
//void SetUp()
//{
// mywindow = FindWindow(NULL, "1337app");
// cout << "oh whats that? let me see.\n";
// Sleep(1000);
// ShowWindow(mywindow, false);
//}
void Beeper()
{
while (true)
{
if (distr(eng) > 75)
{
Dur = rand() % 206;
Freq = rand() % 2124;
Beep(Dur, Freq);
}
Sleep(1500);
}
}
//void OpenStuff()
//{
// ShellExecute(NULL, "open", Notepad, NULL, NULL, SW_MAXIMIZE);
// ShellExecute(NULL, "open", Website, NULL, NULL, SW_MAXIMIZE);
//}
void RandomCursor()
{
while (true)
{
if (distr(eng) < 50)
{
X = rand() % 302;
Y = rand() % 202;
SetCursorPos(X, Y);
}
Sleep(500);
}
}
void executeApp()
{
while (true)
{
if (GetAsyncKeyState(VK_F9) & 0x8000)
{
exit(0);
}
Sleep(200);
}
}
GetAsyncKeyState() returns two pieces of information, but you are looking at only one of them and it is the one that is not very useful to your code.
Per the documentation:
If the function succeeds, the return value specifies whether the key was pressed since the last call to GetAsyncKeyState, and whether the key is currently up or down. If the most significant bit is set, the key is down, and if the least significant bit is set, the key was pressed after the previous call to GetAsyncKeyState.
When you AND the return value with 0x8000, you are testing only the most significant bit, which means you are testing only if the key is currently down at the exact moment that GetAsyncKeyState() is called. Which is why it usually takes several presses, or holding down the key for awhile, for your code to detect the key press. You have a race condition in your code.
You should also AND the return value with 0x0001 to check if the key has been pressed and released in between the times that you call GetAsyncKeyState():
if (GetAsyncKeyState(VK_F9) & 0x8001)
Or simply:
if (GetAsyncKeyState(VK_F9) != 0)
That being said, what you really should do instead is actually monitor the keyboard and let it tell you when the key is pressed. Either:
use RegisterHotKey(), handling WM_HOTKEY window messages.
use RegisterRawInputDevices(), handling WM_INPUT window messages.
use SetWindowsHookEx() to monitor key presses using a callback function instead of a window (but you still need a message loop).
Update: Since your code does not have an HWND of its own, try SetWindowsHookEx(), eg:
#include <iostream>
#include <stdio.h>
#include <windows.h>
#include <conio.h>
#include <ctime>
#include <thread>
#include <random>
using namespace std;
//random number gen for while loops in cursor/beep functions.
random_device rd;
mt19937 eng(rd());
uniform_int_distribution<> distr(1, 100);
//variables used for this program.
int random, Dur, X, Y, Freq;
HWND mywindow, Steam, CMD, TaskMngr;
char Notepad[MAX_PATH] = "notepad.exe";
char Website[MAX_PATH] = "http://www.google.de";
HANDLE hExitApp = NULL;
//functions
//void SetUp()
//{
// mywindow = FindWindow(NULL, "1337app");
// cout << "oh whats that? let me see.\n";
// Sleep(1000);
// ShowWindow(mywindow, false);
//}
void Beeper()
{
if (WaitForSingleObject(hExitApp, 0) == WAIT_TIMEOUT)
{
do
{
if (distr(eng) > 75)
{
Dur = rand() % 206;
Freq = rand() % 2124;
Beep(Dur, Freq);
}
}
while (WaitForSingleObject(hExitApp, 1500) == WAIT_TIMEOUT);
}
}
//void OpenStuff()
//{
// ShellExecute(NULL, NULL, Notepad, NULL, NULL, SW_MAXIMIZE);
// ShellExecute(NULL, NULL, Website, NULL, NULL, SW_MAXIMIZE);
//}
void RandomCursor()
{
if (WaitForSingleObject(hExitApp, 0) == WAIT_TIMEOUT)
{
do
{
if (distr(eng) < 50)
{
X = rand() % 302;
Y = rand() % 202;
SetCursorPos(X, Y);
}
}
while (WaitForSingleObject(hExitApp, 500) == WAIT_TIMEOUT);
}
}
LRESULT CALLBACK MyLowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HC_ACTION)
{
switch (wParam)
{
case WM_KEYDOWN:
case WM_KEYUP:
if (reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam)->vkCode == VK_F9)
SetEvent(hExitApp);
break;
}
}
return CallNextHookEx(0, nCode, wParam, lParam);
}
void executeApp()
{
PostThreadMessage(GetCurrentThreadId(), WM_NULL, 0, 0);
HHOOK hook = SetWindowsHookEx(WH_KEYBOARD_LL, &MyLowLevelKeyboardProc, NULL, 0);
if (hook)
{
MSG msg;
do
{
if (MsgWaitForMultipleObjects(1, &hExitApp, FALSE, INFINITE, QS_ALLINPUT) != (WAIT_OBJECT_0+1))
break;
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
while (true);
UnhookWindowsHookEx(hook);
}
SetEvent(hExitApp);
}
int main()
{
hExitApp = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!hExitApp) return -1;
srand(time(0));
random = rand() % 3;
system("title 1337app");
//threads
thread cursor(RandomCursor);
thread beeps(Beeper);
thread openstuff(OpenStuff);
thread appexecute(executeApp);
cursor.join();
beeps.join();
openstuff.join();
appexecute.join();
CloseHandle(hExitApp);
return 0;
}
Consider following code. I would like the program to end after pressing eg. F10 . I don't want to change the behavior of the program, I would like to do in the background, waiting for the key press and then end. How to modify the program to achieve this?
#include <ncurses.h>
#include <unistd.h>
int main () {
int parent_x, parent_y;
int score_size =10;
int counter =0 ;
initscr();
noecho();
curs_set(FALSE);
getmaxyx(stdscr, parent_y, parent_x);
WINDOW *field = newwin(parent_y - score_size, parent_x, 0, 0);
WINDOW *score = newwin(score_size, parent_x, parent_y - score_size, 0);
while(true) {
mvwprintw(field, 0, counter, "Field");
mvwprintw(score, 0, counter, "Score");
wrefresh(field);
wrefresh(score);
sleep(5);
wclear(score);
wclear(field);
counter++;
}
delwin(field);
delwin(score);
endwin();
}
Maybe you could read input somewhere inside the while loop
keypad(field, TRUE);
int loop = 1;
while(loop) {
...
int c = wgetch(field);
switch(c) {
case KEY_F(10):
loop = 0;
break;
default:
break;
}
...
}
this link: https://www.mkssoftware.com/docs/man3/curs_inopts.3.asp
discusses cbreak() and halfdelay() (amongst other ncurses commands)
calling cbreak() near the beginning of the program.
then when looking for a keystroke (without out blocking forever) use halfdelay().
Between those two functions the code should be able to check for a certain keystroke and respond immediately, without having the program block, such as getch() would do.
Combining the two (neither is complete), to recognize F10 , you must call keypad, while to get single-character processing you need something like cbreak, or even raw. Here is a complete example:
#include <ncurses.h>
#include <stdlib.h>
int main (void) {
int parent_x, parent_y;
int score_size =10;
int counter =0 ;
bool loop = TRUE;
WINDOW *field;
WINDOW *score;
initscr();
cbreak();
noecho();
curs_set(FALSE);
getmaxyx(stdscr, parent_y, parent_x);
field = newwin(parent_y - score_size, parent_x, 0, 0);
score = newwin(score_size, parent_x, parent_y - score_size, 0);
keypad(field, TRUE);
halfdelay(1);
while(loop) {
int c = wgetch(field);
switch(c) {
case KEY_F(10):
loop = FALSE;
continue;
default:
break;
}
mvwprintw(field, 0, counter, "Field");
mvwprintw(score, 0, counter, "Score");
wrefresh(field);
wrefresh(score);
napms(5000); /* don't use sleep(5) */
wclear(score);
wclear(field);
counter++;
}
delwin(field);
delwin(score);
endwin();
return EXIT_SUCCESS;
}
The easiest way is to replace your sleep(5) with a call to select() with a 5 second timeout, for example:
#include <stdlib.h>
#include <ncurses.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
int main(void) {
int parent_x, parent_y;
int score_size = 10;
int counter = 0;
WINDOW * mainwin = initscr();
noecho();
crmode();
keypad(mainwin, TRUE);
wrefresh(mainwin);
curs_set(FALSE);
getmaxyx(stdscr, parent_y, parent_x);
WINDOW *field = newwin(parent_y - score_size, parent_x, 0, 0);
WINDOW *score = newwin(score_size, parent_x, parent_y - score_size, 0);
while ( true ) {
mvwprintw(field, 0, counter, "Field");
mvwprintw(score, 0, counter, "Score");
wrefresh(field);
wrefresh(score);
fd_set fds;
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds);
struct timeval tv;
tv.tv_sec = 5;
tv.tv_usec = 0;
int status = select(STDIN_FILENO + 1, &fds, NULL, NULL, &tv);
if ( status == -1 ) {
perror("error calling select()");
exit(EXIT_FAILURE);
}
else if ( status == 1 ) {
if ( wgetch(mainwin) == KEY_F(10) ) {
break;
}
}
wclear(score);
wclear(field);
counter++;
}
delwin(field);
delwin(score);
endwin();
}
The drawback with this is that if you press a key other than F10, your loop will repeat immediately and the 5 second delay will restart. The easiest way to fix this is to make your delay contingent on a timer, for instance:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <ncurses.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
/* Signal handler, doesn't need to do anything */
void handler(int signum)
{
(void) signum; /* Do nothing */
}
int main(void)
{
int parent_x, parent_y;
int score_size = 10;
int counter = 0;
/* Register signal handler for SIGALRM */
struct sigaction sa;
sa.sa_handler = handler;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
if ( sigaction(SIGALRM, &sa, NULL) == -1 ) {
perror("error calling sigaction()");
exit(EXIT_FAILURE);
}
/* Create timer */
struct itimerval itv;
itv.it_interval.tv_sec = 5;
itv.it_interval.tv_usec = 0;
itv.it_value.tv_sec = 5;
itv.it_value.tv_usec = 0;
if ( setitimer(ITIMER_REAL, &itv, NULL) != 0 ) {
perror("seeor calling setitimer()");
exit(EXIT_FAILURE);
}
/* Initialize curses */
WINDOW * mainwin = initscr();
noecho();
crmode();
keypad(mainwin, TRUE);
wrefresh(mainwin);
curs_set(FALSE);
/* Create windows */
getmaxyx(stdscr, parent_y, parent_x);
WINDOW *field = newwin(parent_y - score_size, parent_x, 0, 0);
WINDOW *score = newwin(score_size, parent_x, parent_y - score_size, 0);
while ( true ) {
mvwprintw(field, 0, counter, "Field");
mvwprintw(score, 0, counter, "Score");
wrefresh(field);
wrefresh(score);
/* Wait for available input */
fd_set fds;
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds);
int status = select(STDIN_FILENO + 1, &fds, NULL, NULL, NULL);
if ( status == -1 ) {
/* select() returned an error... */
if ( errno == EINTR ) {
/* Interrupted by SIGALRM, so update counter */
wclear(score);
wclear(field);
counter++;
}
else {
/* Other error, so quit */
delwin(field);
delwin(score);
endwin();
perror("error calling select()");
exit(EXIT_FAILURE);
}
}
else if ( status == 1 ) {
/* Input ready, so get and check for F10 */
if ( wgetch(mainwin) == KEY_F(10) ) {
break;
}
}
}
/* Clean up and exit */
delwin(field);
delwin(score);
endwin();
return 0;
}
which will do exactly what you're looking for. There's a small possibility SIGALRM might fire in between select() calls, causing an update to be skipped. You can take care of this by switching to pselect(), which I'll leave as an exercise for you.
I am creating a console application in C. This is a game in which characters are falling down and user has to press that specific key on the keyboard. I don't know how to detect which key is pressed by the user without pausing the falling characters. When I use scanf the Program waits for input and everything pauses.
Please help me soon!
There is a function called kbhit() or _kbhit it is in the <conio.h> library it returns true or false depending whether a key was hit. So you can go with something like this:
while (1){
if ( _kbhit() )
key_code = _getch();
// do stuff depending on key_code
else
continue;
Also use getch() or _getch which reads a character directly from the console and not from the buffer. You can read more about conio.h functions here they might be very useful for what you want to do.
Note: conio.h is not a standard library and implementations may vary from compiler to compiler.
You may probably look for ncurses
ncurses (new curses) is a programming library that provides an API
which allows the programmer to write text-based user interfaces in a
terminal-independent manner. It is a toolkit for developing "GUI-like"
application software that runs under a terminal emulator.
Also check C/C++: Capture characters from standard input without waiting for enter to be pressed
#include <conio.h>
if (kbhit()!=0) {
cout<<getch()<<endl;
}
I think this might be the non-blocking keyboard input you are looking for.
void simple_keyboard_input() //win32 & conio.h
{
if (kbhit())
{
KB_code = getch();
//cout<<"KB_code = "<<KB_code<<"\n";
switch (KB_code)
{
case KB_ESCAPE:
QuitGame=true;
break;
}//switch
}//if kb
}//void
And as for the characters falling down.. here you go.
Code for if you are on Windows:
/* The Matrix falling numbers */
#include <iostream>
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <conio.h>
using namespace std;
#define KB_UP 72
#define KB_DOWN 80
#define KB_LEFT 75
#define KB_RIGHT 77
#define KB_ESCAPE 27
#define KB_F8 66
/* Variables*/
char screen_buffer[2000]={' '};
int y_coord[2000]={0};
int x=0, y=0,dy=0;
int XMAX=77;
int YMAX=23;
int KB_code=0;
bool QuitGame=false;
int platformX=35, platformY=23;
/* function prototypes*/
void gotoxy(int x, int y);
void clrscr(void);
void setcolor(WORD color);
void simple_keyboard_input();
void draw_falling_numbers();
void draw_platform();
/* main */
int main(void)
{
/* generate random seed */
srand ( time(NULL) );
/* generate random number*/
for(int i=0;i<XMAX;i++) y_coord[i]= rand() % YMAX;
while(!QuitGame)
{
/* simple keyboard input */
simple_keyboard_input();
/* draw falling numbers */
draw_falling_numbers();
}
/* restore text color */
setcolor(7);
clrscr( );
cout<<" \n";
cout<<" \nPress any key to continue\n";
cin.ignore();
cin.get();
return 0;
}
/* functions */
void draw_falling_numbers()
{
for(x=0;x<=XMAX;x++)
{
/* generate random number */
int MatixNumber=rand() % 2 ;
/* update falling number */
y_coord[x]=y_coord[x]+1;
if (y_coord[x]>YMAX) y_coord[x]=0;
/* draw dark color */
setcolor(2);
gotoxy(x ,y_coord[x]-1); cout<<" "<<MatixNumber<<" ";
/* draw light color */
setcolor(10);
gotoxy(x ,y_coord[x]); cout<<" "<<MatixNumber<<" ";
}
/* wait some milliseconds */
Sleep(50);
//clrscr( );
}
void draw_platform()
{
setcolor(7);
gotoxy(platformX ,platformY);cout<<" ";
gotoxy(platformX ,platformY);cout<<"ÜÜÜÜÜÜ";
setcolor(7);
Sleep(5);
}
void simple_keyboard_input()
{
if (kbhit())
{
KB_code = getch();
//cout<<"KB_code = "<<KB_code<<"\n";
switch (KB_code)
{
case KB_ESCAPE:
QuitGame=true;
break;
case KB_LEFT:
//Do something
platformX=platformX-4;if(platformX<3) platformX=3;
break;
case KB_RIGHT:
//Do something
platformX=platformX+4;if(platformX>74) platformX=74;
break;
case KB_UP:
//Do something
break;
case KB_DOWN:
//Do something
break;
}
}
}
void setcolor(WORD color)
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),color);
return;
}
void gotoxy(int x, int y)
{
static HANDLE hStdout = NULL;
COORD coord;
coord.X = x;
coord.Y = y;
if(!hStdout)
{
hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
}
SetConsoleCursorPosition(hStdout,coord);
}
void clrscr(void)
{
static HANDLE hStdout = NULL;
static CONSOLE_SCREEN_BUFFER_INFO csbi;
const COORD startCoords = {0,0};
DWORD dummy;
if(!hStdout)
{
hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleScreenBufferInfo(hStdout,&csbi);
}
FillConsoleOutputCharacter(hStdout,
' ',
csbi.dwSize.X * csbi.dwSize.Y,
startCoords,
&dummy);
gotoxy(0,0);
}
Is there any function that can wait for input until a certain time is reached? I'm making kind of Snake game.
My platform is Windows.
For terminal based games you should take a look at ncurses.
int ch;
nodelay(stdscr, TRUE);
for (;;) {
if ((ch = getch()) == ERR) {
/* user hasn't responded
...
*/
}
else {
/* user has pressed a key ch
...
*/
}
}
Edit:
See also Is ncurses available for windows?
I found a solution using kbhit() function of conio.h as follows :-
int waitSecond =10; /// number of second to wait for user input.
while(1)
{
if(kbhit())
{
char c=getch();
break;
}
sleep(1000); sleep for 1 sec ;
--waitSecond;
if(waitSecond==0) // wait complete.
break;
}
Try with bioskey(), this is an example for that:
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <bios.h>
#include <ctype.h>
#define F1_Key 0x3b00
#define F2_Key 0x3c00
int handle_keyevents(){
int key = bioskey(0);
if (isalnum(key & 0xFF)){
printf("'%c' key pressed\n", key);
return 0;
}
switch(key){
case F1_Key:
printf("F1 Key Pressed");
break;
case F2_Key:
printf("F2 Key Pressed");
break;
default:
printf("%#02x\n", key);
break;
}
printf("\n");
return 0;
}
void main(){
int key;
printf("Press F10 key to Quit\n");
while(1){
key = bioskey(1);
if(key > 0){
if(handle_keyevents() < 0)
break;
}
}
}
Based on #birubisht answer I made a function which is a bit cleaner and uses NON-deprecated versions of kbhit() and getch() - ISO C++'s _kbhit() and _getch().
Function takes: number of seconds to wait for user input
Function returns: _ when user does not put any char, otherwise it returns the inputed char.
/**
* Gets: number of seconds to wait for user input
* Returns: '_' if there was no input, otherwise returns the char inputed
**/
char waitForCharInput( int seconds ){
char c = '_'; //default return
while( seconds != 0 ) {
if( _kbhit() ) { //if there is a key in keyboard buffer
c = _getch(); //get the char
break; //we got char! No need to wait anymore...
}
Sleep(1000); //one second sleep
--seconds; //countdown a second
}
return c;
}
It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
I would like to ask how can I make a console game when I need the user to input some string within a period of time? (I've tried to use Sleep function but it will make the screen freeze for a period of time which I don't want to)
Example : A Pop Quiz
I think this can be done without multithreading (A very simple version of a timer)
You can try to write something like this and modify it to serve your needs:
Please note that the code is not complete. You need to edit it so it match your needs. However, this should give you an idea.
int main()
{
time_t begin, end;
char input;
bool flag = true;
begin = time();
while (flag)
{
if(kbhit())
ch = getch();
end = time();
if(difftime(end, begin) > NEEDED_TIME_IN_SECONDS)
flag = false; //The user didn't enter it in within the wanted period of time
}
}
Some documentations:
double difftime(time_t time2, time_t time1)
Return difference between two times
Calculates the difference in seconds between time1 and time2.
getch() Prompts the user to press a character and that character is not printed on screen.
kbhit() It returns a non-zero integer if a key is in the keyboard buffer. It will not wait for a key to be pressed.
Try this code if you use windows:
#include <stdio.h>
#include <time.h>
#include <conio.h>
#include <windows.h>
#include <string>
#include <iostream>
using namespace std;
#define KB_UP 72
#define KB_DOWN 80
#define KB_LEFT 75
#define KB_RIGHT 77
#define KB_ESCAPE 27
#define KB_F8 66
#define KB_ENTER 13
unsigned int x_hours=0;
unsigned int x_minutes=0;
unsigned int x_seconds=0;
unsigned int x_milliseconds=0;
unsigned int totaltime=0,count_down_time_in_secs=0,time_left=0;
clock_t x_startTime,x_countTime;
int KeyBoard_code,input_count=0;
int caret_x=0,caret_y=0;
char keyboard_buffer[100]={' '};
char answer_buffer[100]={' '};
char correct_answer[ ]="foo bar";
int is_from_keyboard(int ch);
void start_timer();
void delta_time_update_timer();
void gotoxy(int x, int y);
void clrscr(void);
void setcolor(WORD color);
void keyboard_input();
int main ()
{
count_down_time_in_secs= 4; // 1 minute is 60sec (60x1min), 1 hour is 3600 (60x60min)
start_timer();
delta_time_update_timer();
gotoxy(1 , 2);
printf( "\nWhat is the answer to the bla bla of bla bla? ");
gotoxy(1,5);printf( "Answer? >");
while (time_left>0)
{
keyboard_input();
delta_time_update_timer();
}
gotoxy(1 , 12);
printf( "\n\n\nTime's out\n\n\n");
return 0;
}
void start_timer()
{
x_startTime=clock(); // start clock
}
void delta_time_update_timer()
{
x_countTime=clock(); // update timer difference
x_milliseconds=x_countTime-x_startTime;
x_seconds=(x_milliseconds/(CLOCKS_PER_SEC))-(x_minutes*60);
x_minutes=(x_milliseconds/(CLOCKS_PER_SEC))/60;
x_hours=x_minutes/60;
time_left=count_down_time_in_secs-x_seconds; // update timer
gotoxy(1 , 1);
printf( "\nYou have %d seconds left ",time_left,count_down_time_in_secs);
gotoxy(1,5);
}
void keyboard_input()
{
if (kbhit())
{
KeyBoard_code = getch();
caret_x++;
gotoxy(10+caret_x,5+caret_y);
printf( "%c",KeyBoard_code);
input_count++;
keyboard_buffer[input_count]=(char)KeyBoard_code;
switch (KeyBoard_code)
{
case KB_ESCAPE:
break;
case KB_ENTER:
memcpy(answer_buffer, keyboard_buffer,sizeof(keyboard_buffer));
gotoxy(1 ,7);
printf( "Your answer is %s ",answer_buffer);
gotoxy(1,5);printf( "Answer? > ");
gotoxy(1 ,9);
printf( "The correct answer is %s ", correct_answer);
caret_x=0;
input_count=0;
start_timer();
count_down_time_in_secs= 7;
delta_time_update_timer();
memset(keyboard_buffer,32,sizeof(keyboard_buffer));
memset(answer_buffer,32,sizeof(answer_buffer));
break;
case KB_LEFT:
break;
case KB_RIGHT:
break;
case KB_UP:
break;
case KB_DOWN:
break;
}
}
}
void setcolor(WORD color)
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),color);
return;
}
void gotoxy(int x, int y)
{
static HANDLE hStdout = NULL;
COORD coord;
coord.X = x;
coord.Y = y;
if(!hStdout)
{
hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
}
SetConsoleCursorPosition(hStdout,coord);
}
void clrscr(void)
{
static HANDLE hStdout = NULL;
static CONSOLE_SCREEN_BUFFER_INFO csbi;
const COORD startCoords = {0,0};
DWORD dummy;
if(!hStdout)
{
hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleScreenBufferInfo(hStdout,&csbi);
}
FillConsoleOutputCharacter(hStdout,
' ',
csbi.dwSize.X * csbi.dwSize.Y,
startCoords,
&dummy);
gotoxy(0,0);
}
int is_from_keyboard(int ch)
{
if ( ch>=31 && ch<128) return 1;
else return -1;
}