read two keys values in C/C++ - c++

How can I add two numbers when Ctrl+A is pressed? I am currently using the following code:
int key1=getch();
int key2;
while(key1==65)
{
key2=getch();
if( key1==65 && key2==37) // set whatever number you wish here :-), 27 =Esc
{
printf("A + left key");
}
else
{
printf("other");
}
}
But its not a proper method like I wanted. Can you help me out.

To check if Crtl+A was pressed you can read input using getch() and compare obtained char to Crtl+A value which is equal to 1.
key = getch();
if(key == 1) {
// do sth
}
If you want to wait for Crtl+A and then add this two numbers, simply wrap it inside while with same condition.

Related

If statement within Case

The following code generates different characters based on choices taken by the user previously using a bool function. The user can choose whether or not to have some of the characters, such as "numbers" or "Uppercase characters".
The issue I'm having is that after I've implemented a switch/case system to fully randomize which character goes first, the choices aren't respected anymore.
Per example, the user can choose numbers off, yet sometimes numbers will still show up in the sequence. This does not occur with the switch taken off for randomization purposes (which keeps the sequence to Lowercase+Uppercase+Symbols+Numbers).
Should I be using if/else here, or is something else most likely wrong with the rest of the code?
int randomCharacter_cases;
for(int i=0; i<100; i++)
{
// If no appropriate option was selected, then the user will go back to selection:
if(StrongPass==0 && lowercase==0 && Uppercase==0 && numbers==0 && symbols==0)
{
// CODE
}
// This selects the order of each character:
randomCharacter_cases=rand()%4+1;
switch(randomCharacter_cases)
{
// Lowercase characters;
case 1:
{
if(StrongPass==1 || lowercase==1)
{
keeper.push_back((char)(rand()%(122-97+1)+97));
}
break;
}
// Uppercase characters;
case 2:
{
if(StrongPass==1 || Uppercase==1)
{
keeper.push_back((char)(rand()%(90-65+1)+65));
}
break;
}
// Symbols;
case 3:
{
if(StrongPass==1 || symbols==1)
{
keeper.push_back((char)(rand()%(64-33+1)+33));
}
break;
}
// Numbers;
case 4:
{
if(StrongPass==1 || numbers==1)
{
keeper.push_back((char)(rand()%(57-48+1)+48));
}
break;
}
}
}
EDIT: StrongPass, in this particular piece of code, is done in the case where the user doesn't wish to choose what characters he doesn't generate (for example, you may choose any of the four char. types, or you may simply say that you want an automatically generated password, which uses all four types of characters).
This is the function used to determine each individual usage:
bool yesno()
{
string inp;
cin>>inp;
if(!(inp=="Y" || inp=="y" || inp=="N" || inp=="n"))
{
cout<<"Y or N:";
yesno();
}
if(inp=="Y" || inp=="y")
return 1;
else
return 0;
}
EDIT: Usage example:
// Choices we take for each password option:
bool StrongPass,lowercase,Uppercase,symbols,numbers;
// Function for generating random numbers:
srand (time(NULL));
// Default strong options, for easy use:
cout<<"Would you like an automatic S.T.R.O.N.G. password?: ";
StrongPass=yesno();
// If you'd like a more advanced password:
if(StrongPass==0)
{
cout<<"Length of the password?: ";
cin>>length;
cout<<"Length of the password?: "<<length<<"\n";
cout<<"Include lowercase characters?: ";
lowercase=yesno();
cout<<"Include uppercase characters?: ";
Uppercase=yesno();
cout<<"Include symbols?: ";
symbols=yesno();
cout<<"Include numbers?: ";
numbers=yesno();
}
// The password itself is generated here:
int randomCharacter_cases;
for(int i=0; i<100; i++)
{
// This selects the order of each character:
randomCharacter_cases=rand()%4+1;
switch(randomCharacter_cases)
{
// Lowercase characters;
case 1:
{
if(StrongPass==1 || lowercase==1)
{
keeper.push_back((char)(rand()%(122-97+1)+97));
}
break;
}
// Uppercase characters;
case 2:
{
if(StrongPass==1 || Uppercase==1)
{
keeper.push_back((char)(rand()%(90-65+1)+65));
}
break;
}
// Symbols;
case 3:
{
if(StrongPass==1 || symbols==1)
{
keeper.push_back((char)(rand()%(64-33+1)+33));
}
break;
}
// Numbers;
case 4:
{
if(StrongPass==1 || numbers==1)
{
keeper.push_back((char)(rand()%(57-48+1)+48));
}
break;
}
}
}
Per example, the user can choose numbers off, yet sometimes numbers will still show up in the sequence.
Your symbols random generation includes numbers (48...57), so even if you switch numbers off symbols may produce numbers
To answer the question, "Should I be using if/else here" - Sure. It is perfectly acceptable to use a if/else statement within a switch case statement.
The reason you are getting numbers is because either StrongPass or numbers is equal to one. Since you haven't provided where/how/ you are assigning values to this, the best advice we can give you is as follows:
If you don't want numbers to appear, ensure that both StrongPass AND numbers is equal to 0.
[EDIT]
You're input selection function is broken. You have a recursive call that you are no longer catching the value of. Not sure how you are USING this function, though.
If the first call fails (user doesn't select valid input), the recursive call's return value IS NOT CAUGHT. The original function returns 0 no matter what. Even if the recursive call was a "successful" input.

Returning to main menu from another inner menu using c++

I thought of making a sort of Point Of Sales (POS) program. So, as you open the program, a menu (the main menu) would open-up which is a scrolling menu (you can move up & down to select an item in the menu with the arrow keys) and the items in it are like "Start business day", "Stats", "Inventory" blah blah.
Now, when you press "Start Business day"(using enter), you would get another menu which would ask for things like "Take order " ........"Return to the main menu". This is where I am finding the problem. When I press "Return to the main menu", I am not able to move back to the main menu.
MY ATTEMPT
#include<iostream>
#include<conio.h>
#include<string>
#include<windows.h>
using namespace std;
int chk=0;
int sbd(void) //the order menu (start business day -> ' press ENTER')
{
int pointer=0;
string order[4]={"TAKE ORDER","CHECK MENU","MEMO","RETURN TO MAIN MENU"};
while(true)
{
system("cls");
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),14);
cout<<"\t\t ZAIKA KATHI ROLLS\n";
cout<<"\t\t\tORDER MENU\n\n";
for(int i=0;i<=3;i++)
{
if( i==pointer)
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),11);
cout<<"-> "<<order[i]<<endl<<endl;
}
else
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),15);
cout<<" "<<order[i]<<endl<<endl;
}
}
while(true)
{
if(GetAsyncKeyState(VK_UP)!=0)
{
pointer-=1;
if(pointer==-1)
{
pointer=3;
}
break;
}
else if(GetAsyncKeyState(VK_DOWN)!=0)
{
pointer+=1;
if(pointer==4)
{
pointer=0;
}
break;
}
else if(GetAsyncKeyState(VK_RETURN)!=0)
{
switch(pointer)
{
case 3 : return 1;
}
}
}
Sleep(150);
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int main()
{
int pointer=0;
int flag=1;
string menu[6]={"START BUSINESS DAY","CONTINUE BUSINESS DAY","END BUSINESS DAY","INVENTORY MANAGEMENT","STATISTICS","SETTINGS"};
Mainmenu : while(true)
{
system("cls");
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),14);
int i=0;
cout<<"\t\t ZAIKA KATHI ROLLS\n";
cout<<"\t\t\tMAIN MENU\n\n";
for(i=0;i<=5;i++)
{
if(i==pointer)
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),11);
cout<<"-> "<<menu[i]<<endl<<endl;
}
else
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),15);
cout<<" "<<menu[i]<<endl<<endl;
}
}
while(true)
{
if(GetAsyncKeyState(VK_UP)!=0)
{
pointer-=1;
if(pointer==-1)
{
pointer=5;
}
break;
}
else if(GetAsyncKeyState(VK_DOWN)!=0)
{
pointer+=1;
/* if(flag==0 && pointer==1)
pointer=3;
if(flag==1 && pointer==0)
pointer=1;*/
if(pointer==6)
{
pointer=0;
}
break;
}
else if(GetAsyncKeyState(VK_RETURN)!=0)
{
switch(pointer)
{
case 0 :chk=sbd();
if(chk==1)
goto Mainmenu;
}
}
}
Sleep(150);
}
return 0;
}
The best idea that came to my mind was to make the "start business day" as a function and in that function as we press "Return to main menu",the function will return a value which the main fuction will detect and then by using the goto fuction the program control will transfer to the main menu.Apparently thats not working, so can anyone please help me out of this?
What's happening is that when you press enter on "Return to main menu" it is in fact going back to the main menu. If you debug and step through it you'll see this. The problem is that as soon as it steps out of the sub-menu loop it goes into the main menu loop, checks to see if "enter" was pressed, passes the condition and enters the sub-menu loop again.
The thing is that you're not using GetAsyncKeyState function properly in your code:
if (GetAsyncKeyState(VK_RETURN) != 0)
It checks whether the value is zero. But according to the docs this function returns a SHORT.
The most significant bit is 1 if the key is pressed down, and 0 if not.
The least significant bit is 1 if the key was pressed since last calling GetAsyncKeyState. I assume this is what you want. So to begin with change the two spots in your code:
if (GetAsyncKeyState(VK_RETURN) != 0)
to:
if (GetAsyncKeyState(VK_RETURN) & 0x01 != 0)
We only want to check the least significant bit to see if the key was pressed since last time that function was called. If you do this it should work.
You can also write it like this using the Windows macro:
if (LOBYTE(GetAsyncKeyState(VK_RETURN)) != 0)
I should also mention you should probably get around to doing it this same way for key up and key down.
I really like it though, nice work.
Edit: GetAsyncKeyState() returns a short integer. It's most likely two bytes. When the function returns with this value it sets certain bits or flags to tell you information. Like I said, the most significant bit (the highest) tells you whether the key is down or not, the lowest significant bit tells you if the key has been pressed since the last call to that function.
So the returned number in binary will look like this (MSB) is most significant and (LSB) is least significant:
10000000 00000001
^ MSB ^ LSB
If this were an unsigned integer its value would be 32769. You're not interested in whether the key is currently down, but more interested in whether the key has been pressed since the last call to the function. You're only interested in the bit on the right. The bitwise operator & AND will compare two bit patterns and if and only if BOTH bits are 1, it will set the resulting bit to one. This is used with a mask so you can pluck out certain values, so to speak.
10000000 00000001 // Original value
00000000 00000001 // The mask
00000000 00000001 // Result
The result is 1. Then you can check whether the value is 1, and if it is then the key was pressed since the last call. It's a very low level way of doing things, but that's kinda how Windows works and Windows actually helps out by providing that macro LOBYTE() which does the same thing. The alternative is the function could have returned class/struct with bool values for each thing instead.
SECOND EDIT (FURTHER EXPLANATION):
The least significant bit will only be 1 if the key was pressed down since the last call to GetAsyncKeyState. So if you press down the enter key and keep it pressed for 3 seconds, the LSB will be set only on the first call to GetAsyncKeyState. However the MSB will continue to return with the MSB set, because this indicates whether the key is down. The following quick program should illustrate this nicely I think.
A short in our case has 2(bytes) 16 bits, so we're going to use the right bitshift operator >> to get it. I'm going to convert the return type from SHORT to USHORT. This is because bitshifting is undefined for signed integers which are negative because right shifting can propagate the leftmost bit. For example:
// Right shifting 7 bits
UNSIGNED INT
1000 0000 >> 7 = 0000 0001
SIGNED INT
1000 0000 >> 7 = 1111 1111 // We may get this instead which is not what we want
Start a new project and paste this and run, try pressing the enter key:
#include <iostream>
#include <Windows.h>
using namespace std;
int main()
{
while (true)
{
int count = 0;
USHORT funcResult = 0;
while ((funcResult = GetAsyncKeyState(VK_RETURN)) != 0)
// If MSB or LSB is set then condition is true
{
count++;
cout << "Return pressed " << count << " times in one loop\n";
cout << "MSB = " << (funcResult >> 15) << '\n';
cout << "LSB = " << (funcResult & 1) << '\n';
}
// You will see that the MSB is always 1, because it tells us
// if the key is down.
// However the LSB is 1 only on the first run of the while loop
}
}
So this is why adding Sleep() also fixes the problem, because if you press down the enter key for 400 ms and let go, and make the thread sleep for 500 ms, next time it checks the key won't be down, and the MSB won't be set.

How to input a multi-digit integer into an Arduino using a 4x4 keypad?

I am trying to make a combination lock using an Arduino, a keypad and a Servo but I have come across an obstacle.
I can't find a way to store a 4 digit value in a variable. since keypad.getKey only allows to store one digit.
After some browsing on the internet I came upon a solution for my problem on a forum but the answer didn't include a code sample, and I couldn't find anything else about in on the internet.
The answer said to either use a time limit for the user to input the number or a terminating character (which would be the better option according to them).
I would like to know more bout these terminating characters and how to implement them, or if anybody could suggest a better solution that would be much appreciated as well.
Thank you in advance,
To store 4 digit values, the easiest and naive way to do it is probably to use an array of size 4. Assuming keypad.getKey returns an int, you could do something like this: int input[4] = {0};.
You will need a cursor variable to know into which slot of the array you need to write when the next key is pressed so you can do some kind of loop like this:
int input[4] = {0};
for (unsigned cursor = 0; cursor < 4; ++cursor) {
input[cursor] = keypad.getKey();
}
If you want to use a terminating character (lets say your keyboard have 0-9 and A-F keys, we could say the F is the terminating key), the code changes for something like:
bool checkPassword() {
static const int expected[4] = {4,8,6,7}; // our password
int input[4] = {0};
// Get the next 4 key presses
for (unsigned cursor = 0; cursor < 4; ++cursor) {
int key = keypad.getKey();
// if F is pressed too early, then it fails
if (key == 15) {
return false;
}
// store the keypress value in our input array
input[cursor] = key;
}
// If the key pressed here isn't F (terminating key), it fails
if (keypad.getKey() != 15)
return false;
// Check if input equals expected
for (unsigned i = 0; i < 4; ++i) {
// If it doesn't, it fails
if (expected[i] != input[i]) {
return false;
}
}
// If we manage to get here the password is right :)
return true;
}
Now you can use the checkPassword function in your main function like this:
int main() {
while (true) {
if (checkPassword())
//unlock the thing
}
return 0;
}
NB: Using a timer sounds possible too (and can be combined with the terminating character option, they are not exclusive). The way to do this is to set a timer to the duration of your choice and when it ends you reset the cursor variable to 0.
(I never programmed on arduino and don't know about its keypad library but the logic is here, its up to you now)
In comment OP says a single number is wanted. The typical algorithm is that for each digit entered you multiply an accumulator by 10 and add the digit entered. This assumes that the key entry is ASCII, hence subtracting '0' from it to get a digit 0..9 instead of '0'..'9'.
#define MAXVAL 9999
int value = 0; // the number accumulator
int keyval; // the key press
int isnum; // set if a digit was entered
do {
keyval = getkey(); // input the key
isnum = (keyval >= '0' && keyval <= '9'); // is it a digit?
if(isnum) { // if so...
value = value * 10 + keyval - '0'; // accumulate the input number
}
} while(isnum && value <= MAXVAL); // until not a digit
If you have a backspace key, you simply divide the accumulator value by 10.

Am I using the getch() function from the ncurses library incorrectly?

I am writing a Pacman game in c++ using the ncurses library, but I am not able to move the Pacman properly. I have used getch() to move it it up, down, left and right, but it only moves right and does not move anywhere else when I press any other key.
This is a code snippet for moving up. I have written similar code with some conditions altered accordingly for moving left, right and down.
int ch = getch();
if (ch == KEY_RIGHT)
{
int i,row,column;
//getting position of cursor by getyx function
for (i=column; i<=last_column; i+=2)
{
//time interval of 1 sec
mvprintw(row,b,"<"); //print < in given (b,row) coordinates
//time interval of 1 sec
mvprintw(row,(b+1),"O"); //print "O" next to "<"
int h = getch(); //to give the option for pressing another key
if (h != KEY_RIGHT) //break current loop if another key is pressed
{
break;
}
}
}
if (condition)
{
//code to move left
}
Am I using getch() wrong, or is there something else I have to do?
Many of the "special" keys on a keyboard -- Up, Down, Left, Right, Home, End, Function keys, etc. actually return two scan codes from the keyboard controller back to the CPU. The "standard" keys all return one. So if you want to check for special keys, you'll need to call getch() twice.
For example up arrow is first 224, then 72.
261 is consistent with KEY_RIGHT (octal 0405 in curses.h). That tells us at least that keypad was used to allow getch to read special keys.
The fragment shown doesn't give clues to how it was incorporated into the rest of the program. However, the use of getch in a loop is likely a source of confusion, since on exiting the loop the value is discarded. If you expect to do something different (from KEY_RIGHT), you could use ungetch to save the (otherwise discarded) value within the loop, e.g.,
if (h != KEY_RIGHT) //break current loop if another key is pressed
{
ungetch(h); //added
break;
}
Doing that will allow the next call to getch to return the key which exits the loop.

Converting scancodes to ASCII

I'm implementing my own text editor in c++. It's going... ok. ;P
I need a way to turn a keycode (specifically Allegro, they call it scancodes) into an ASCII-char. I can do A-Z easy, and converting those to a-z is easy as well. What I do currently is use a function in Allegro that returns a name from a scancode (al_keycode_to_name), meaning if the key pressed is A-Z it returns "A" to "Z". That's easy peasy, but I can't simply read special characters like ",", ";" etc. That's where I'm having a hard time.
Is there a way to do this automatically? Maybe a library that does this? The real trick is taking different layouts into consideration.
Here's what I have so far, in case anyone's interested. The class InputState is basically a copy of the Allegro inputstate, with added functionality (keyDown, keyUp, keyPress for example):
void AllegroInput::TextInput(const InputState &inputState, int &currentCharacter, int &currentRow, std::string &textString)
{
static int keyTimer = 0;
static const int KEY_TIMER_LIMIT = 15;
for (int i = 0; i < 255; i++)
{
if (inputState.key[i].keyDown)
{
keyTimer++;
}
if (inputState.key[i].keyPress)
{
keyTimer = 0;
}
if ((inputState.key[i].keyPress) || ((inputState.key[i].keyDown) && (keyTimer >= KEY_TIMER_LIMIT)))
{
std::string ASCII = al_keycode_to_name(i);
if ((ASCII.c_str()[0] >= 32) && (ASCII.c_str()[0] <= 126) && (ASCII.length() == 1))
{
textString = textString.substr(0, currentCharacter) + ASCII + textString.substr(currentCharacter, textString.length());
currentCharacter++;
}
else
{
switch(i)
{
case ALLEGRO_KEY_DELETE:
if (currentCharacter >= 0)
{
textString.erase(currentCharacter, 1);
}
break;
case ALLEGRO_KEY_BACKSPACE:
if (currentCharacter > 0)
{
currentCharacter--;
textString.erase(currentCharacter, 1);
}
break;
case ALLEGRO_KEY_RIGHT:
if (currentCharacter < textString.length())
{
currentCharacter++;
}
break;
case ALLEGRO_KEY_LEFT:
if (currentCharacter > 0)
{
currentCharacter--;
}
break;
case ALLEGRO_KEY_SPACE:
if (currentCharacter > 0)
{
textString = textString.substr(0, currentCharacter) + " " + textString.substr(currentCharacter, textString.length());
currentCharacter++;
}
break;
}
}
}
}
}
You should be using the ALLEGRO_EVENT_KEY_CHAR event with the event.keyboard.unichar value to read text input. ALLEGRO_EVENT_KEY_DOWN and ALLEGRO_EVENT_KEY_UP correspond to physical keys being pressed. There is not a 1:1 correspondence between them and printable characters.
Say a dead key is being used to convert the two keys e' to é. You'd get two key down events for e and ' (and neither are useful for capturing the proper input), but one key char event with é. Or inversely, maybe somebody mapped F4 to a macro that unleashes an entire paragraph of text. In that case, you'd have multiple chars for a single key down.
Or a simple test: if you hold down a key for five seconds, you will get one ALLEGRO_EVENT_KEY_DOWN but multiple ALLEGRO_EVENT_KEY_CHAR as the OS' keyboard driver sends repeat events.
You can use ALLEGRO_USTR to easily store these unicode strings.
ALLEGRO_USTR *input = al_ustr_new("");
// in the event loop
al_ustr_append_chr(input, event.keyboard.unichar);
There's also ways to delete characters if backspace is pressed, etc. You can use the ustr data types with the font add-on directly via al_draw_ustr(font, color, x, y, flags, input), or you can use al_cstr(input) to get a read-only pointer to a UTF-8 string.