Reputation: 9
I am trying to make a simple console calculator. It works as intended, however, I would like to make a way to exit the program by pressing a button and without the program waiting for the loop to end. I tried putting !(GetAsyncKeyState(VK_RSHIFT))
inside the while loop condition and I've also tried putting !(GetAsyncKeyState(VK_RSHIFT))
inside an if statement in the loop, the result is the same.
#include <iostream>
#include <Windows.h>
using namespace std;
int main() {
cout << "Press RSHIFT for the program to close!\n";
while (!(GetAsyncKeyState(VK_RSHIFT))) {
long double num1, num2;
char mathOp;
cin >> num1 >> mathOp >> num2;
switch (mathOp) {
case('+'):
cout << num1 + num2 << endl;
break;
case('-'):
cout << num1 - num2 << endl;
break;
case('*'):
cout << num1 * num2 << endl;
break;
case('/'):
cout << num1 / num2 << endl;
break;
default:
cout << "ERROR: Operator doesn't match available operators (+ - * /)!\n";
}
}
return 0;
}
Upvotes: 0
Views: 279
Reputation: 24736
The function call
GetAsyncKeyState(VK_RSHIFT)
will report the state of the SHIFT key at the time the function is called. However, this does not seem to be what you want.
What you seem to want is to make the blocking function call
cin >> num1 >> mathOp >> num2;
to immediately abort when the user presses the SHIFT key, so that you can quit the program.
This is not possible when using std::cin
of the C++ standard library.
However, instead of using std::cin
, what you can do is call the platform-specific function ReadConsoleInput
in order to wait for keyboard events. If the user presses the SHIFT key, then you can stop the program. If the user presses a different key, then you can add that character to your input buffer, and when the user presses the ENTER key, you can then process that input buffer.
That way, your program will be immediately notified when the user presses the SHIFT key, and you won't have to resort to unreliable workarounds such as calling the Sleep
function.
However, this solution requires you to handle input on a low level, which requires your program to do some additional work which would normally be done automatically, such as echoing the input to the screen and providing special treatment for the BACKSPACE and ENTER keys.
I have written such a program below:
#include <Windows.h>
#include <iostream>
#include <string>
#include <sstream>
void process_input( const std::string &line )
{
std::stringstream ss( line );
long double num1, num2;
char mathOp;
ss >> num1 >> mathOp >> num2;
if ( !ss )
{
std::cout << "Error parsing input line \"" << line << "\"\n" << std::flush;
return;
}
switch (mathOp)
{
case('+'):
std::cout << num1 + num2 << '\n';
break;
case('-'):
std::cout << num1 - num2 << '\n';
break;
case('*'):
std::cout << num1 * num2 << '\n';
break;
case('/'):
std::cout << num1 / num2 << '\n';
break;
default:
std::cout << "Unknown operator encountered in line \"" << line << "\"\n";
}
std::cout << std::flush;
}
int main( void )
{
HANDLE hStdIn = GetStdHandle( STD_INPUT_HANDLE );
INPUT_RECORD ir;
DWORD dwRead;
std::string line;
//get scan code of the right shift key
UINT uRShiftScanCode = MapVirtualKeyA( VK_RSHIFT, MAPVK_VK_TO_VSC );
for (;;)
{
if ( !ReadConsoleInputA( hStdIn, &ir, 1, &dwRead ) )
{
std::cout << "Error in ReadConsoleInput\n";
std::exit( EXIT_FAILURE );
}
if ( ir.EventType != KEY_EVENT || !ir.Event.KeyEvent.bKeyDown )
continue;
if ( ir.Event.KeyEvent.wVirtualScanCode == uRShiftScanCode )
{
std::cout << "\n\nRight shift press detected, exiting program!\n";
return 0;
}
switch ( ir.Event.KeyEvent.uChar.AsciiChar )
{
case 0: //keystroke does not translate to a valid character
break;
case '\r': //carriage return character
//echo input to output
std::cout << '\n' << std::flush;
process_input( line );
line.clear();
break;
case '\b': //backspace character
for ( WORD i = 0; i < ir.Event.KeyEvent.wRepeatCount; i++ )
{
//echo backspace to output
std::cout << "\b \b" << std::flush;
//remove last character from string
if ( !line.empty() )
{
line.pop_back();
}
}
break;
default:
for ( WORD i = 0; i < ir.Event.KeyEvent.wRepeatCount; i++ )
{
//echo input to output
std::cout << ir.Event.KeyEvent.uChar.AsciiChar << std::flush;
//add character to input buffer
line.push_back( ir.Event.KeyEvent.uChar.AsciiChar );
}
}
}
}
This program has the following behavior:
5+3
8
10*4
40
5-3
2
20/3
6.66667
Right shift press detected, exiting program!
As you can see, it reacted immediately and correctly when the user pressed the right SHIFT button.
Upvotes: 1