Today i was testing how key pressing might work in C++ and made simple loop for it,and found that getch() duplicate itself for some reason or idk what is going on honestly,just look at that:
#include <iostream>
#include <windows.h>
#include <conio.h>
#define VK_H 0x48
using namespace std;
int main()
{
int n=1;
int total=0;
bool theEnd=true;
while(theEnd)
{
cout<<total<<endl;
getch();
if(GetAsyncKeyState(VK_LEFT))
{
total -=n;
}else if(GetAsyncKeyState(VK_RIGHT))
{
total +=n;
}else if(GetAsyncKeyState(VK_LSHIFT) && GetAsyncKeyState(VK_F1))
{
total = 0;
} else if(GetAsyncKeyState(VK_ESCAPE))
{
break;
}
}
cout<<total<<endl;
}
Its pretty simple.Program starts with a loop,where endlessly outputs value of variable "total",and after pressing left/right buttons "total" decrements/increments by 1.
Its was worked fine and perfect when i was using system("pause"); Sleep(milliseconds); cin.get();(but this one assume pressing enter each time,so it is not proper one) ,all that output right value on the screen after each pressing on the buttons.But in case with getch(); it somehow appear to working like only one time per/two cycles of the loop.
So the result i've get is like this: i'm pressing button right - current loop working fine,but next one working like without getch(),incrementing and outputting one more time without my command...
I've siting and thinking couple hours,trying find any answers in google and here but nothing...
P.S.without using getch() or other things for purpose stoping loop till next pressing - it will add not +1 to total by single pressing(as i need),but hundreds(average pressing key will do 150-300 loops lol).
From MS documentation
Remarks
The _getch and_getwch functions read a single character from the
console without echoing the character. None of these functions can be
used to read CTRL+C. When reading a function key or an arrow key, each
function must be called twice; the first call returns 0 or 0xE0, and
the second call returns the actual key code.
When you press arrow keys, the input is 2 chars
Related
C++ how to move Text from off screen to inside the terminal (animation 20/50 millisec.) and then stop the animation. with ncurses.h ? pls with examples
with perhaps a loop that increases the X coordinate from (x = 0-number characters text-1) to (x = 2 or 1), for each Line of text containing the color.
let me explain: the previous sentence no longer moves (it remains stationary on X2 coordinates), the sentence of now makes the entry animation, as soon as the animation ends, it becomes the still sentence together with the other preceding sentences. moves the next one, and continues the loop until it is finished.
I didn't get the result I wanted: (this is the code)
#include <iostream>
#include <windows.h>
#include <ncurses.h>
using namespace std;
void tdnVoid(short colore)
{
HANDLE a = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(a, colore);
}
int main()
{
initscr();
int b = 0;
while (b != 256)
{
b++;
refresh();
move(0, 0);
tdnVoid(b);
cout << b << ". ■ ";
cout << "\n";
if (b % 16 == 0)
{
cout << "\n";
}
Sleep(100);
}
return 0;
}
☑️the result I wanted (GIF):
Gif Hello World example - GIF
❌the result I got: Gif C++ Program execution, pls help me solve it
NEW EDIT:
according to the documentation, you can use this:
mvprintw(y,x,"your string",); refresh(); but i use and try for like 2 hours, having errors;
pls if someone can help me, you will really help me!
this program may seem useless, but I am using it to learn C ++, once I have learned this, I can use the same function and complicate and do more interesting things. hope you understand me (there are those who created Nokia's Snake game with ncurses, there are those who 3D things that rotate in space) thank pls help me to understand :)
stackoverflow guys. i started stackoverflow bad. sorry for my wrong attitude
(that's why I didn't get an answer)
but luckily I managed to get the result I wanted! I can be of help for you! in the documentation it won't say, but through a while () loop I managed to do it!
int main()
{
initscr();
int x = -1;
while (x < 22)
{
x++;
refresh();
mvprintw(0, x, " C++ colori", 10);
Sleep(300);
}
//other my code
}
before putting refresh (); which is important to update, then mvprintw() which is like a cout << /*from <iostream> library*/ but with mv (mv is move()) ... which is what I wanted !! the first attribute is the Y which are the vertical, and the second attribute is the X that is to move in the same horizontal line.
all separated by commas, attention: I put the x as a variable and not as a number because I made it move through the while loop.
after put the string of characters, remember: put a space before if not you have a result like this
❌output: CCCCCCCCCCCCCC++ colori
with a space before, it appears to be invisible, so it works.
☑️output: C++ colori
after I put Sleep(/*milliseconds*/); remember to put the <windows.h> library
10 is the number of characters, I know you could have done better by automating it with char [] =" your string " and make the program count, but it was was a beta.
===========
remember: if you don't put endwin (); at the end of the loop what you saw in the GIF will happen. on all your next normal code. here my first Bug
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.
Had a new problem with the while function. As easy as it sounds, I still can't wrap my head around it.
Like my last program, this one closes unexpectedly after the correct and wrong messages.
I want this to loop after entering a number, so that the program won't stop.
Thanks for the help, if any.
#include <iostream>
using namespace std;
int main()
{
int X = 0; //setting the first variable
int num; //setting the second
while (X == 0) //this should happen whenever X is equal to 0
{
cout << "Type a number bigger than 3. "; //output
X++; //This should increase X, so that the next while function can happen
}
while (X == 1) //again, since I increased x by one, (0+1=1 obviously) this should happen
{
cin >> num; //standard input
if (num > 3) //if function: if num is bigger than three, then this should happen
{
cout << "Correct! Try again!" <<endl; //output
X--; //Here I'm decreasing x by one, since it was 1 before, now it becomes 0. This should make the "while (X == 0)" part happen again, so that another number bigger than three can be entered
}
if (num <= 3) //if function: if num is lesser than or equal to 3, this should happen
{
cout << "Wrong! Try again!" <<endl; //output
X--; //This is supposed to work like the "X--;" before, repeating the code from "while (X==0)"
}
}
}
now it becomes 0. This should make the "while (X == 0)" part happen again
Nope. While loops don't magically take effect at any point during execution of the program. You only enter a while loop when you've reached it from code above. Programs are executed top-to-bottom, generally.
You would need a loop around the entire program if you want to keep going round and round. Those whiles you have now should probably be ifs.
Merge the two while loops into one, while(true).
Put each previous while body into an if state with the clause from the old while in it.
while(true) {
if (X==0) {
// the X==0- case
} else if (X==1) {
// the X==1 case
}
}
in order to end your loop, do a break;.
You have to think of C++ programs as a sequence of instructions, like a recipe. while just means a loop: you check the condition. If true, you run the body. After running the body, you check only that condition again, and run the body if true. Whenever the condition is false at the start or end of the body of the while (the {} enclosed code after it), you end the loop and proceed to the next one.
The first loop runs, finishes, then the second loop runs in your code. Once the first loop exits, you do not go back into it just because the condition becomes true.
Understanding flow control is one of the "hard" steps of learning to program, so it is ok if you find this tricky.
There are many improvements you can do your code beyond getting it working -- there is, actually, little need for X at all. But baby steps! Once you get it working, you can ponder "how could I remove the variable X?".
Before making such fundamental changes to your program, you should get it working, and save a copy of it so you can "go back" to the last working version.
You want to wrap all that code in it's own while loop:
while (true /* or something */)
{
while (X == 0) //this should happen whenever X is equal to 0
{
// ...
}
At least put your second while loop inside the first one to get it working as intended. Otherwise your program has no reason to go back again.
Nevertheless it's not a good design.
I've made a program that allows me to read all the stand-alone function keys (that I thought to test, at least) on my keyboard. I have it designed so that I can refer to any single key input as a single value. It handles Return, F1-F12, delete, backspace, arrows etc
I just thought to test modifications of input. I already made sure shift works, but now I decided to test Ctrl and Alt.
Question 1
Why does Alt not modify any of the input key codes?
Question 2
Why can I not capture certain Ctrl + combinations?
Eg. Ctrl + s; Ctrl + 1-9;
Ctrl + 2 works, but I think it might be due to having my keyboard set as UK.
This is the code I am using.
Please note, I am not necessarily asking how to capture these key combinations (unless it is a simple modification or two). I only want to know why I am unable to.
#include <iostream>
#include <conio.h>
#include <cwchar>
union wide_char
{
short Result;
char C[2];
};
int main()
{
wchar_t R;
int N;
wide_char user_input;
//Loops forever, this is only a proof of concept program proving this is possible to incorporate into a larger program
while(true)
{
user_input.C[0] = 0;
user_input.C[1] = 0;
//Loop twice, or until code causes the loop to exit
//Two times are neccessary for function keys unfortunately
for(int i = 0; i < 2; ++i)
{
//While there isn't a key pressed, loop doing nothing
while(!kbhit()){}
//Grab the next key from the buffer
//Since the loop is done, there must be at least one
user_input.C[i] = getch();
switch(user_input.C[i])
{
case 0:
case -32:
//The key pressed is a Function key because it matches one of these two cases
//This means getch() must be called twice
//Break switch, run the for loop again ++i
break;
default:
//The character obtained from getch() is from a regular key
//Or this is the second char from getch() because the for loop is on run #2
//Either way we need a wide char (16 bits / 2 Bytes)
if(user_input.C[1] != 0)
//Function keys {Arrows, F1-12, Esc}
//We now combine the bits of both chars obtained
//They must be combined Second+First else the F1-12 will be duplicate
//This is because on F1-12 getch() returns 0 thus won't affect the combination
R = user_input.Result;
else
//Regular key press
R = user_input.C[0];
//Display our unique results from each key press
N = R;
std::cout << R << " R = N " << N << std::endl;
if( R == 'a' )
std::cout << "a = " << N << std::endl;
//Manually break for loop
i = 3;
break;
}
}
//We need to reset the array in this situation
//Else regular key presses will be affected by the last function key press
}
}
This is very specific to your environment. You're using conio which is specific to DOS / Windows.
Most of the Ctrl + alpha key values are bound to characters 1 - 26, and certain others are bound to other values under 31, to map to ASCII control characters. But some, like Ctrl + S have special meaning (Ctrl + S is XOFF in ASCII), and so might get 'eaten' by your environment.
Fundamentally, the issue you're facing is the fact that getch approximates an old-school serial terminal interface. They only expose keyboard events at a "least common denominator" level, as opposed to a lower level that would allow you to distinguish modifier keys, etc. and give you a better way to deal with special keys such as function keys.
(As you've noticed, function keys, have special multi-byte sequences. Again, this is due to emulating old-school serial terminals, where the keyboard might be at the other end of a remote link.)
To get a lower-level (and therefore more direct and flexible interface) you need to use a more platform-specific library, or a richer library such as SDL. Either would give you a lower level view of the inputs from the keyboard.
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.