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.
Related
I have the following code:
for (int i = 0; i < 1;) {
if (GetKeyState(VK_SHIFT) & 0x8000)
{
cout << "op";
}
}
This prints out op if the Shift key is held down, actually it spams the output if you hold down the key.
This is what I want instead:
The program prints out something ONCE when you press/hold down a key instead of spamming it, and the only way to print it again is to let go of the key and press it again. No matter how long you hold down the key, the program will only execute the following code ONCE, unless you press it again.
How do I make my code do this?
You could simply set a bool to true when you've detected a "key down" event and then only set it back to false once you detect a "key up" event. That way you can know if the key was already down and only report that it was pressed if it was not already in that state.
Im trying to get my movement of a ball to just move in a fluid like motion. How can I have it that when I press the up key, down key, left key, or right key, it doesnt move up one unit, stop, then keep moving. Also, how can i have it move in two directions at the same time wthout stopping another direction when letting off a key?
Thanks
if(GetAsyncKeyState(VK_UP))
{
if(g_nGameState == SETTINGUPSHOT_GAMESTATE || g_nGameState == INITIAL_GAMESTATE)
{
g_cObjectWorld.AdjustCueBallY(MOVEDELTA);
g_cObjectWorld.ResetImpulseVector();
}
}
if(GetAsyncKeyState(VK_DOWN))
{
if(g_nGameState == SETTINGUPSHOT_GAMESTATE || g_nGameState == INITIAL_GAMESTATE)
{
g_cObjectWorld.AdjustCueBallY(-MOVEDELTA);
g_cObjectWorld.ResetImpulseVector();
}
}
if(GetAsyncKeyState(VK_LEFT))
{
if(g_nGameState == SETTINGUPSHOT_GAMESTATE || g_nGameState == INITIAL_GAMESTATE)
{
g_cObjectWorld.AdjustCueBallX(-MOVEDELTA);
g_cObjectWorld.ResetImpulseVector();
}
}
if(GetAsyncKeyState(VK_RIGHT))
{
if(g_nGameState == SETTINGUPSHOT_GAMESTATE || g_nGameState == INITIAL_GAMESTATE)
{
g_cObjectWorld.AdjustCueBallX(MOVEDELTA);
g_cObjectWorld.ResetImpulseVector();
}
}
You can do something like this:
Use SetTimer to create a timer on your window event loop 10ms interval should be good for what you want. The reason it has to be on the window thread is that GetAsyncKeyState will not give you the desired results when called from a different thread.
We use a timer since the call to GetAsyncKeyState should be on a different message then the key processing events so the key is still in the queue.
Within the timer function you can do something like this
int deltaX = 0, deltaY = 0;
unsigned int downDown = GetAsyncKeyState(VK_DOWN);
unsigned int upDown = GetAsyncKeyState(VK_UP);
unsigned int leftDown = GetAsyncKeyState(VK_LEFT);
unsigned int rightDown = GetAsyncKeyState(VK_RIGHT);
if(downDown & 0x00008000)deltaY -= MOVEDELTA;
if(upDown & 0x00008000)deltaY += MOVEDELTA;
if(leftDown & 0x00008000)deltaX -= MOVEDELTA;
if(rightDown & 0x00008000)deltaX += MOVEDELTA;
g_cObjectWorld.AdjustCueBallX(deltaX);
g_cObjectWorld.AdjustCueBallY(deltaY);
g_cObjectWorld.ResetImpulseVector();
In this way you can also make sure that the movement stops on keyup (deltaX == 0 && deltaY == 0)
I'm not sure what are the semantics of AdjustCueBall(X|Y) but if you make sure they stop moving in that direction when they get 0 it should work just fine.
Also you should notice that your keyboard must support multiple key press in the hardware for you to be able to move diagonally using two keys - If it does the solution above will work if it doesn't you will still be able to move in either one of the four fundamental directions.
One design is to use the keyboard only for changing directions.
Let the ball continue in its present direction until a keypress is received that would change its direction. This reduces the load on the processor from continuously being interrupted by keypresses.
As for going in non-orthogonal directions, use more keys. Look at a "keypad". Some keys are diagonal from the '5' keys. Use those.
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.
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 have the following function that is used as the glutKeyboardFunc function parameter:
void handleKeypress(unsigned char key, //The key that was pressed
int x, int y) { //The current mouse coordinates
switch (key) {
case 27: //Escape key
exit(0); //Exit the program
}
if (key == 'a')
{
moveCircleLeft(0);
}
if (key == 'w')
{
moveCircleUp(0);
}
if (key == 's')
{
moveCircleDown(0);
}
if (key == 'd')
{
moveCircleRight(0);
}
}
Now I will show you moveCircleLeft as an example of how the moveCircle functions are written:
void moveCircleLeft(int x)
{
characterX = characterX - 0.1;
glutPostRedisplay();
x++;
if (x < 10)
{
glutTimerFunc(10, moveCircleLeft, x);
}
}
The other moveCircle functions work similar and the only differences between the four functions is whether its plus of minus 0.1 or if it is characterY as opposed to characterX.
Now, here is the problem:
All the directions are moving in the right direction but, there is a delay/pause in movement of the character when I try to press keys. So, if I press just the d key (moveCircleRight) it moves right a little, stops a for a small amount of time, then moves across the screen in that direction at a constant speed with no pauses. Then if I change to a different key it pause for a little bit before changing directions then moves at a constant speed in that direction.
Any suggestion around this would be appreciated!
Create a boolean variable for each key (preferably an array). Then use KeyDown/KeyUp instead of KeyPress (i believe in GLUT its something like KeyboardUpFunc and KeyboardFunc, but cant remember now). On KeyDown, set the appropriate variable to true, on KeyUp, set it to false. Now you probably have an Idle function or something like that. Call there your "move" functions based on the boolean variables. There should be no pauses now. Beware though that you might need to keep track of the time elapsed between frames and scale the distance moved appropriately.