So I'm making a game that runs on the console. I started with some functions to make drawing to the screen easier, and that worked fine. Then when I tried to add input (using the function GetAsyncKeyState), the program crashed as soon as I started the program. It said: "Text Game.exe has stopped working" Here's how I handled the code:
if(GetAsyncKeyState('A' && 0x8000)) {
x -= 1;
}
if(GetAsyncKeyState('D' && 0x8000)) {
x += 1;
}
if(GetAsyncKeyState('W' && 0x8000)) {
y += 1;
}
if(GetAsyncKeyState('S' && 0x8000)) {
y += 1;
}
If it helps, I got this method by reading this:
How to check if a Key is pressed
EDIT: So I ran it in debug mode, and it said it crashed when I ran a function I made called "refreshScreen();". I don't know why though. Here's the code:
void refreshScreen() {
system("CLS");
for ( int i = 0; i < screenHeight; i++ ) {
for ( int j = 0; j < screenWidth; j++ ) {
cout << screen[i][j];
}
cout << endl;
}
}
It's meant to clear the console, then print all of the contents of array "screen". "Screen", by the way, is the buffer that I write to.
If you are trying to use the GetAsyncKeyState as it's described in answers by the link you provided, you are doing it wrong.
Documentation says the following:
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.
So what is done in the answer by the link you provided:
if (GetAsyncKeyState('W') & 0x8000)
{ /*key is down*/ }
In the if statement there bitwise "and" operation is performed on return value of GetAsyncKeyState function and 0x8000 constant - which equals to 0x8000 the most significant bit is set or equals to 0 when it is not set.
What is your code doing:
if(GetAsyncKeyState('A' && 0x8000)) // ...
logical "and" operation between 'A' and 0x8000 constant - gives true which is casted to 1 and passed to GetAsyncKeyState as an argument.
[EDIT]: As it was mentioned in comments, 1 corresponds to left mouse button. So all if conditions will be true in case left mouse button is down and will be false otherwise. Probably, crash appears in different part of your program after unexpected change of x and y values. You should debug your program to localize the crash.
Related
So I wanted to write a program which prints out a pyramid made out of "O", whose height is given by user input.
#include <stdio.h>
int main()
{
int n, i, j, k;
scanf_s("%d", &n);
{
for (i = 1; i <= n; i++)
{
for (j = 1; j <= n - i; j++)
{
printf(" ");
}
for (k = 1; k <= 2 * i - 1; k = k + 1);
{
printf("O");
}
printf("\n");
}
return 0;
}
}
I'm a complete beginner, so if you have any advice, please do offer it. Anyways, I tried running it on a compiler on Android; seemed to work, printed out the pyramid.
Tried it on Microsoft Visual Studio. The command line opens, but after I put in the number and press "enter", the whole window just closes without giving me anything. How do I prevent this? Programs that don't need user input seem to run just fine.
For your described problem: Preventing console window from closing on Visual Studio C/C++ Console application
For your code, there seems to be a mistake, and currently your code will not produce a pyramid, but a slash of O. To solve this problem:
for (k = 1; k <= 2 * i - 1; k = k + 1); remove the ; from this line. Why this solved the problem?
When there is a ; after the loop, it means that the loop does nothing, and then the next three lines are:
{
printf("O");
}
Which means that there are only a single O prints out, instead of printing it in a loop.
Apart from the semicolon after the for (k = 1... loop, you have no bug in this code; if Visual Studio closes, the issue is with that program. (It could well just be closing because the program has finished execution, but I don't know that program).
Since you write that you are a complete beginner and you would appreciate advice, I'll offer some stylistic comments. But these are just comments on how I would do things differently if I were you, I am not saying that what you have is wrong.
Single-letter variable names: these will bite you. It is really easy to mix up i, j, and k since they are all kind of meaningless indexes. When your programs become more complex you will be happy to have meaningful variable names. Also, if you are trying to locate instances of a variable, searching for 'i' is a lot harder than searching for "spaces" or "spc"
Code block under scanf_s(): There is no reason to have this code inside a block--all that does is shift the internal code one tab right. Screenspace is precious.
You will likely find it more useful to iterate from 0 than from 1, as you will be using your iterator variable as an array index a whole lot. Getting into the habit of writing your loops as for (dex = 0 ; dex < max_val ; dex++) will serve you well. Note well that the comparison is "dex < max_val" and not "dex <= max_val"
The "k = k + 1" seems bad to me--people reading your code will need to stop and try to figure out why it's not just "k++" which what people are expecting and what you use in the other two loops. (And even for incrementing-by-more-than-one I'd expect something like "k += 2" not "k = k + 2")
Once console application returns from main method, the associated console window closes automatically. For Windows OS add a system("pause"); before your return 0; statement. For platform independent solution you can just show a prompt to user and wait for a key press before returning from main. Any character remaining in input buffer (enter from scanf in this case) must be cleared.
int main()
{
.........
.........
//clear input buffer
int d;
while ((d = getchar()) != '\n' && d != EOF) { }
printf("Press ENTER key to Continue\n");
getchar();
return 0;
}
You should include conio.h header file in your program and then simply place getch(); after your program's last cout statement.
I think that this would help the window from closing
it worked for me ;)
Put a cin command(C++) or a C equivalent at the very end just before return 0;, so it wont close. :>
Eg:
.
.
.
.
int control; cin>>control;
return 0;
}
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.
My game's main loop relies on a non-blocking read from getnstr. It checks whether the string to which it has read has non-zero length before proceeding with the rest of the loop (I couldn't find the convention for getting this behavior if one exists).
The problem is that it has the effect of forcing the input cursor down the bottom of the window, as if I had spammed Enter or something.
char command[5];
timeout(0);
while (getnstr(command, 4) && gameActive) {
if (strlen(command) == 0) { continue; }
...
}
Agreeing that it seems surprising, but SVr4 curses (which ncurses does match in this detail) always moves to the next row after completing the (attempt to) read characters.
You can see the corresponding code for (Open)Solaris at Illumos's Github in lines 191-207:
/*
* The following code is equivalent to waddch(win, '\n')
* except that it does not do a wclrtoeol.
*/
if (doecho) {
SP->fl_echoit = TRUE;
win->_curx = 0;
if (win->_cury + 1 > win->_bmarg)
(void) wscrl(win, 1);
else
win->_cury++;
win->_sync = savsync;
win->_immed = savimmed;
win->_leave = savleave;
(void) wrefresh(win);
}
that is, the "win->_cury++;" (or the scrolling operation).
So I decided that I wanted to write a little keylogger tonight, just to learn about getAsyncKeyState. I'm trying to get my log to write to a file but the file's contents either show up blank or throw a random memory address at me (0x28fef0 before). I've heard that getAsyncKeyState doesn't function well with Windows 7 x64, is it true?
This is pretty aggravating, I was hoping to actually be able to get this running tonight.
while(1)
{
Sleep(20);
for(DWORD_PTR key = 8; key <= 190; key++)
{
if (GetAsyncKeyState(key) == HC_ACTION)
checkKey(key);
}
}
Function definition
void checkKey(DWORD_PTR key)
{
ofstream out;
out.open("log.txt");
if (key==8)
out << "[del]";
if (key==13)
out << "n";
if (key==32)
out << " ";
if (key==VK_CAPITAL)
out << "[CAPS]";
if (key==VK_TAB)
out << "[TAB]";
if (key==VK_SHIFT)
out << "[SHIFT]";
if (key==VK_CONTROL)
out << "[CTRL]";
if (key==VK_PAUSE)
out << "[PAUSE]";
if (key==VK_ESCAPE)
out << "[ESC]";
if (key==VK_END)
out << "[END]";
if (key==VK_HOME)
out << "[HOME]";
if (key==VK_LEFT)
out << "[LEFT]";
if (key==VK_UP)
out << "[UP]";
if (key==VK_RIGHT)
out << "[RIGHT]";
if (key==VK_DOWN)
out << "[DOWN]";
if (key==VK_SNAPSHOT)
out << "[PRINT]";
if (key==VK_NUMLOCK)
out << "[NUM LOCK]";
if (key==190 || key==110)
out << ".";
if (key >=96 && key <= 105)
{
key -= 48;
out << &key; // had ampersand
}
if (key >=48 && key <= 59)
out << &key; // amp'd
if (key !=VK_LBUTTON || key !=VK_RBUTTON)
{
if (key >=65 && key <=90)
{
if (GetKeyState(VK_CAPITAL))
out << &key; // amp;d
else
{
key = key +32;
out << &key; // amp'd
}
}
}
}
I'm seriously stumped by this issue and any help would be greatly appreciated. Why would a function like this work differently on a 64 bit system? Considering it's the only box I've got I can't run it on a 32 bit to check whether or not it's an isolated issue. Because I'm assuming that it's related to getAsyncKeyState and not my code (which compiles and creates a blank log file) I only included those two code snippets.
Well, firstly you don't want to be using GetAsyncKeyState if you are writing a key logger; GetAsyncKeyState gets the state of the key at the immediate moment you call the function. You need to be listening in on the Windows messages, for things like WM_KEYDOWN, WM_KEYUP, or depending on the purpose of the logger WM_CHAR, WM_UNICHAR etc...
You're using the function incorrectly. Reading the documentation before requesting help is usually a good idea...
I'll just quote MSDN here:
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. However, you
should not rely on this last behavior; for more information, see the
Remarks.
That last part also means it's completely useless for a key logger.
PS: Consider using GetKeyNameText for translating virtual key codes into meaningful names.
For monitoring input, something like a keyboard hook is probably the way to go (look up SetWindowsHookEx with WH_KEYBOARD_LL on MSDN).
As noted elsewhere, you're not using GetAsyncKeyState correctly here.
As for why you're seeing an address appear:
out << &key; // amp'd
This is several places in your code: key is a DWORD_PTR, so &key is a pointer - this is likely where the addresses are coming from.
I'm fairly new to OpenGL, and I am writing a simple game in 2D, for fun. However, I ran into an issue I am having a hard time wrapping my head around.
It seems that whenever my keyboardUpFunc is called, that not only the key that has actually come up sent to the function, but every single key currently being pressed as well.
I'm using a simple key buffer to manage the keys, keyUp marks the key as up and is only called in this function. keyDown is called in my keyboardFunc. isDown returns a boolean value of whether or not the key is pressed. Take this code for example:
#include <iostream>
...
void keyboardUp(unsigned char key, int x, int y)
{
keys.keyUp(key);
if (keys.isDown('s') == false)
{
std::cout << "It's resetting s as well!" << std::endl;
}
// reset acceleration here, for each key
if ( (key == 'w') || (key == 's') )
{
yStep = 0.1;
}
if ( (key == 'a') || (key == 'd') )
{
xStep = 0.1;
}
std::cout << key << " is now up." << std::endl;
}
If you run this code, if you for example, hold S and D, then release the D key, you will note that S has been marked as up too, since this is the only location keyUp is being called.
Assuming my keyBuffer code is working correctly (and it is, but let me know if you want me to post it...), is there any way to get around this? Where if you were holding a key, and then pressed another key, the application would go back to what you were doing when you were just holding the original key? Instead of marking both as up? Or is this not feasible with GLUT?
Not very clear what is going wrong.. But where/how exactly are you calling this function ?? Directly in the Main Game loop, or are you checking certain conditions in an 'update' function. I ask because you need to check for input every run of the infinite loop, and if you are using a boolean to determine if a key is down, you should essentially reset it after its corresponding action has been performed. Anyway, just my 2 cents.
I changed my implementation of the keyboard buffer, and what I was describing above now works. The difference is that before I was using a vector to pile on the keys that were being pressed, whereas now, I am using a fixed-size array of boolean values.
Apparently, a vector implementation of a key buffer won't work properly with GLUT.