0

I'm not sure exactly how to phrase what I'm trying to ask; in C++, using the stdio.h header instead of iostream, how would I make it so that if the escape key is pressed at any point, the program is terminated? Is there something I could add once at the top of the program, or would I have to add it to every loop/conditional individually? Below is my code (the sleep() function is just for a visual loading/calculating effect):

#include <stdio.h>
#include <math.h>
#include <windows.h>

void repeat();
void quadratic()
{
    double a, b, c;
    double ans[2];
    printf("-Arrange your equation in the form aX^2+bX+c \n-Enter the value of a: ");
    scanf("%lf", &a);
    printf("-Enter the value of b: ");
    scanf("%lf", &b);
    printf("-Enter the value of c: ");
    scanf("%lf", &c);
    double radical=((b*b)-(4*a*c));
    double root=sqrt(radical);
    double negB=(-1)*b;
    double denominator=2*a;
    if(denominator==0)
    {
        printf("Calculating");
        Sleep(100);
        printf(".");
        Sleep(100);
        printf(".");
        Sleep(100);
        printf(".");
        Sleep(100);
        printf("\nError: Denominator must be non-zero.\n \n \n");

    }
    else if(radical==0)
    {
        ans[0]=negB/denominator;
        printf("Both roots are equal: both values are X=%lf\n \n \n", ans[0]);

    }
    else if(radical<0)
    {
        printf("Calculating");
        Sleep(100);
        printf(".");
        Sleep(100);
        printf(".");
        Sleep(100);
        printf(".");
        Sleep(100);
        double r,i;
        radical*=-1;
        r=negB/(2*a);
        i=sqrt(radical)/(2*a);
        printf("\nBoth roots are imaginary numbers.\n");
        printf("Non-real answer(s): X=%lf+%lfi X=%lf-%lfi\n \n \n",r,i,r,i);

    }
    else
    {
    ans[0]=(negB+root)/denominator;
    ans[1]=(negB-root)/denominator;
    printf("Calculating");
        Sleep(100);
        printf(".");
        Sleep(100);
        printf(".");
        Sleep(100);
        printf(".");
        Sleep(100);
        printf("\nX=%lf, X=%lf\n \n", ans[0], ans[1]);
    }
    repeat();

}
void repeat()
{
    quadratic();
}
int main(void)
{   
    quadratic();
    return 0;
}
Mat Jones
  • 936
  • 1
  • 10
  • 27
  • 3
    Wouldn't it be better to use `Ctrl+C` instead of `esc`? – ForceBru Feb 24 '15 at 18:38
  • Check the value returned by `scanf` and exit if it's less than expected. – Austin Mullins Feb 24 '15 at 18:40
  • @AustinMullins: `scanf` will pause for input. – musiphil Feb 24 '15 at 18:50
  • @musiphil Good point, but if the user wants to quit, they could just hit enter with no input, right? – Austin Mullins Feb 24 '15 at 18:53
  • possible duplicate of [Capturing a keystroke in C++](http://stackoverflow.com/questions/4219506/capturing-a-keystroke-in-c) – musiphil Feb 24 '15 at 18:53
  • 2
    Have you looked at ***[GetAsyncKeyState()](https://msdn.microsoft.com/en-us/library/windows/desktop/ms646293%28v=vs.85%29.aspx)*** ? – ryyker Feb 24 '15 at 18:55
  • @AustinMullins: Yes. But I'm guessing what the OP wanted is probably letting the program continue without interruption unless Esc is pressed. – musiphil Feb 24 '15 at 18:55
  • FYI, the whole `repeat` function here could be replaced with a recursive call to `quadratic`, or better yet, throw the whole thing in a `while(1) or for(;;)` loop. If your compiler is incapable of converting tail recursion to a loop, this will blow up the call stack eventually. – Brian McFarland Feb 24 '15 at 18:58
  • GetAsyncKeyState() does exactly that. Run it in a while loop, or in a separate thread, and use it in conjunction with a `switch()`, to handle many different key/response response scenarios. ***[one simple example here](http://stackoverflow.com/a/23064255/645128)*** – ryyker Feb 24 '15 at 18:58
  • How would I get GetAsyncKeyState() to run continuously without interrupting the rest of my code? – Mat Jones Feb 24 '15 at 20:50
  • _How would I get GetAsyncKeyState() to run continuously..._? See edits to my answer below. – ryyker Feb 24 '15 at 23:48

2 Answers2

0

Is there something I could add once at the top of the program, or would I have to add it to every loop/conditional individually?

I think you can add something once, and use it to catch key stroke events easily throughout your program.

Following is a code snippet showing a function I have used to handle key stroke events in a console application. It uses GetAsyncKeyState(). Included is a section that shows how to capture a CTRL key, and how you can do something once you see it. (the snippet shown shows how I capture a <ctrl><shift><h> key sequence to display a help menu for using this particular routine.

Note: In the description, delay_x(float delay) is simply a custom, non-blocking sleep, or delay function that includes a call to the following snippet. It is called from within the main program loop while(1){...} . Exiting the program is provided in one of the keystroke combinations: <CTRL><SHIFT><K>

Code snippet:

/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
//
//  SetAppState() is called continuously from within delay_x()
//  to capture keystroke combinations as they occur asynchronously
//  with this application, Keystroke combinations are listed below
//
//  Note: GetAsyncKeyState() can maintian information regarding the 
//        state of a key instantaineously by use the MSB, 
//        and recently by using the LSB.  
//        
//        For this application
//        only instantaineous information will be kept, minimizing
//        conflicts with other keyboard shortcut definitions 
//        defined by other applications that may be running
//        simultaineously.
//  
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////

void SetAppState(void)
{
    short state=0;
    short state1=0;

    state = GetAsyncKeyState(VK_CONTROL);
    if (0x80000000 & state) //check instantaineous state of key
    {
        state = GetAsyncKeyState(VK_SHIFT); 
        if (0x80000000 & state) //check instantaineous state of key
        {
            state = GetAsyncKeyState('h'); 
            state1 = GetAsyncKeyState('H'); 
            if ((0x80000000 & state) || 
                (0x80000000 & state1))
            {    sprintf(gTempBuf, "Usage - keystrokes to access and control the PaAutoStartSlot application:\n\n"
                                   "<CTRL><SHIFT> H   (H)elp -    \n"
                                   "<CTRL><SHIFT> V  o(V)erride - \n"
                                   "<CTRL><SHIFT> S   (S)tatus -  \n"
                                   "<CTRL><SHIFT> K   (K)ill -    \n"
                                   "<CTRL><SHIFT> N   (N)o -      \n"
                                   "<CTRL><SHIFT> I   (I)Inside - \n"
                                   "<CTRL><SHIFT> O   (O)Outside- \n"
                                   "\nSee log file at this location for runtime errors: \n\n%s", LOGFILE); 
                 MessagePopup("Usage Menu",gTempBuf);
            }

///// ... more code ...
End of snippet  

Edit - Answer to questions in comments how to call GetAsyncKeyState()

There are many ways you could call GetAsyncKeyState() at the same time other stuff is going on. Threads are a good way. You can also do it all in line using a while()/switch(){} combination. Here is a very simple example of how you could do this (in pseudo code)

int gRunning = 1;
int state = 1; 

int main(void)
{

    //create variables, initialize stuff
    while(gRunning)//this is your main program loop
    {
        delay_x(1.0);//check for keystrokes
        switch(state)  {
            case 1:
                //do some stuff here  
                //and experiment with values passed to delay_x(n)
                delay_x(10000);//check for keystrokes
                state++;
                break;
            case 2:
                //do some different stuff here
                delay_x(10000);//check for keystrokes
                state++;
                break;
            ... Add as many cases as you need for your program.
            case n://last case, set execution flow to top
                //do some more different stuff here
                delay_x(10000);//check for keystrokes
                state = 1;//loop back to top
                break;
         }
     }
    return 0;
}
void delay_x (float delay)
{   
    static clock_t time1;   
    static clock_t time2;   clock();    

    time1 = clock();    
    time2 = clock();    

    while ((time2 - time1) < delay) 
    {       
        time2 = clock();        
        SetAppState(); //see partial definition in my original answer above.
    }       
}

Note: Using this method, you can have as many, or as few, cases as you need, the important thing is to keep a steady flow of calls to GetAsyncKeyState(). This does that via the call to delay_x().

Note2: Here is the segment (added to above definition) that will cause your program to exit:

    state = GetAsyncKeyState('k'); 
    state1 = GetAsyncKeyState('K'); 
    if ((0x80000000 & state) || 
        (0x80000000 & state1))
    {    
        printf("Kill Program"); 
        gRunning = FALSE;
    }
ryyker
  • 22,849
  • 3
  • 43
  • 87
  • So do I just put a code like this at the top of my code? Also I'm a bit confused about how to properly use the syntax/what the parameters are of the function? – Mat Jones Feb 24 '15 at 20:39
  • Google "GetAsyncKeyState MSDN", or click on the link I left above in the comment section of your question. – ryyker Feb 24 '15 at 20:49
  • _So do I just put a code like this at the top of my code?_ Yes. You define a function containing similar syntax to what I have provided for an _example_, ***But for your own purposes***, and ***call it*** from a within a loop running perhaps from your `main()` function. – ryyker Feb 24 '15 at 20:53
0

The terminal used in stdio is likely to be line buffered (cooked). If it is, checking for the escape key through scanf will not work.

SEE THESE URLS:

Capture characters from standard input without waiting for enter to be pressed

scanf not reading input

CURSES or NCURSES will detect the escape key (ASCII character 27), depending on the terminal type.

This code can be used in WINDOWS to check for the ESCAPE key.

    #include <conio.h> 
    #include <ctype.h>

    int ch;

    _cputs( "Type 'Y' when finished typing keys: " );
    do
    {
      ch = _getch();
      ch = toupper( ch );

          if (ch != 27) {
           _cputs( "CHARACTER: " );
           _putch( ch );
           _putch( '\r' );    // Carriage return
           _putch( '\n' );    // Line feed
      }

    } while( ch != 27 );
Community
  • 1
  • 1
A B
  • 4,068
  • 1
  • 20
  • 23