I'm using Freeglut to design some basic games. However, I have been having some issues with keyboard input.
In some previous games I made, I had did something like this: (pseudocode)
class Key {
bool pressed;
void press() {pressed = true;}
void release() {pressed = false;}
bool isPressed() {return pressed;}
}
Key wkey, skey;
handleKeypress(unsigned char key, int xf, int yf) { //This is the function that glutKeyBoardFunc gets
switch(key) {
case 'w':
wkey.press();
case 's':
skey.press();
}
}
handleKeypress(unsigned char key, int xf, int yf) { //This is the function that glutKeyBoardUpFunc gets
switch(key) {
case 'w':
wkey.release();
case 's':
skey.release();
}
}
When I wanted to check whether or not a key was pressed, I checked wkey.isPressed(). However, this caused issues. For example, the Esc key was supposed to pause the game, and then pressing Esc from the pause screen was supposed to take the user to the main menu. However, pressing Esc directly took the user to the main menu because the user didn't release the escape key in that tick of the main loop.
To avoid this kind of issue, what is the best way to take (and use) keyboard input with Freeglut?
EDIT: By the way, this is C++
How about you save a previous key state and a current key state for each frame? This way you can test if the previous key state was KEY UP and the new key state is KEY DOWN. This indicates that the key has been pressed. You can adopt this for a "key pressed" function - just test to see if the previous key state was KEY DOWN and the new key state is also KEY DOWN. A "key up" function would test if the previous key state was KEY DOWN and the new key state is KEY UP.
Related
I'm trying to make my game do something when I press a key. I'm using GLFW to handle Windows API for me. I got stuck and confused when I used the mention callback function in title.
Referenced doc: https://www.glfw.org/docs/latest/input_guide.html#input_keyboard
I followed "Key input" resources (not "Text input"), but I get a kinda text input callback curve, like, when I keep pressed a key, I get pressed key event, then it stops for some time, and then I get repeated events. Shouldn't callbacks be constant in time (without that time gap)? This is my code:
void onKeyPress(GLFWwindow* window, int key, int scancode, int action, int mods)
{
if (key == GLFW_KEY_W && action != GLFW_RELEASE)
{
camera.pos += glm::vec3(0.0f, 0.0f, 1.0f);
updateCameraMatrices();
}
}
// ...
glfwSetKeyCallback(window, onKeyPress);
Nvm. It seems like my expectations were wrong. I should just listen for GLFW_PRESS and GLFW_RELEASE, store the key status, and use if(status) in my main loop.
There's no need to use event callbacks at all if you just want to know wether a key is pressed or not. Just use glfwGetKey(window,key) to get the current key status (this returns GLFW_PRESS or GLFW_RELEASE). See here for more details.
I have a QT Application on Windows which has a mode of using arrow keys, and also a mode which should totally ignore these arrow keys. That is, I want the arrow keys to not to trigger any event once the user checks a box.
I saw a post where eventFilter() was suggested, but I did not get how I could use it. Here is the checkbox event that listens the user, and gets triggered once the user checks it. In the else part I want the eventFilter() to work for arrow keys, but so far I could not get it running.
void MainWindow::on_checkBoxSmartCutMode_stateChanged(int arg1)
{
if (arg1 == 0)
{
// do as usual, arrow keys should work
}
else
{
eventFilter(); // if any arrow key is pressed, ignore the event
}
}
Any suggestions?
You can use keyEvent as your key filter by override keyPressEvent and test your checkbox state.
example:
void MainWindow::keyPressEvent(QKeyEvent *event)
{
// check your checkbox state
if (ui->poCheckBox->checkState() == Qt::Unchecked)
// do as usual, arrow keys should work
return;
switch(event->key())
{
case Qt::Key_Left:
case Qt::Key_Right: // add more cases as needed
event->ignore(); // if any arrow key is pressed, ignore the event
return;
}
// handle the event
}
So, I'm currently working on an options menu for my game, I have a button that when pressed it changes it's text to the next resolution in an array, so basically the user presses this button to change their resolution to the next string in the array.
My problem is getting the click event.
Right now, when the user presses the button, it returns true while the mouse is down, instead of when the mouse is pressed. I want to only return true in the mouse event when the mouse is pressed.
I've looked around, and everything I've found seems to be similar to what I've done or, as I said, returning true while the mouse is down, instead of the initial click.
My events are handled in a EventManager singleton, and here are the functions that I see as necessary:
My update function, this is where the event is polled, it is worth noting I'm using a private SDL_Event named "e".
void EventManager::update(){
while(SDL_PollEvent(&e)){
SDL_GetMouseState(&mouseX, &mouseY);
switch(e.type){
case SDL_QUIT:
running = false;
}
}
}
My mousePress function, where I want a mouse press returned.
int EventManager::mousePress(){
if(e.type == SDL_MOUSEBUTTONDOWN){
return e.button.button;
}
return 0;
}
Instead of using SDL_GetMouseState(), which gets you the actual state of the mouse (thats probably where its name comes from ;) ), use the event you are polling. SDL should give you a SDL_MouseButtonEvent which contains the informations you need and should only be queued once.
See https://wiki.libsdl.org/SDL_MouseButtonEvent
Edit to clarify what i mean:
You would use something like this:
void EventManager::update(){
SDL_Event e;
while(SDL_PollEvent(&e)){
switch(e.type){
case SDL_QUIT:
running = false;
break;
case SDL_MOUSEBUTTONDOWN:
//do whatever you want to do after a mouse button was pressed,
// e.g.:
mousePress(e.button);
break;
}
}
}
Inside your mousePress-Function you can then test, which of the mouse buttons has been pressed:
void EventManager::mousePress(SDL_MouseButtonEvent& b){
if(b.button == SDL_BUTTON_LEFT){
//handle a left-click
}
}
This works, because SDL_PollEvent will only return exactly once for every Event. If theres no new Event, it will return an empty Event. So 1 click = 1 times SDL_PollEvent() with e being of type SDL_MOUSEBUTTONDOWN afterwards and 1 times SDL_PollEvent() with e being of type SDL_MOUSEBUTTONUP afterwards. If you call SDL_PollEvent() in between or afterwards, it will return 0 and leave e as an Empty Event, not calling the switch at all. If you respond to MOUSEBUTTONDOWN or MOUSEBUTTONUP or both is up to you...
I've also declared the SDL_Event a local variable to update(). Why? The Idea behind an Event is, that theres an Event-Object whenever some event has occured. Then you react to the event and forget about it. So theres no need to have a global variable. If you want to prevent constant construction/destruction, you can also declare it to be static. But thats just some hint, not related to your original question.
I'm in the process of migrating a program from GLUT to SDL. In my current program pressing the a key results in a different response then pressing the A key. This was pretty straightforward to do in GLUT as it the keyboard function callback passed in the ASCII value of the key that was pressed.
void keyPressedFn(unsigned char key, int x, int y){
switch(key){
case 'a':
// do work for a
break;
case 'A':
// do work for A
break;
}
}
I'm struggling to replicate similar functionality in SDL as pressing the a key produces the same response regardless of if SHIFT or CAPS LOCK are pressed as well.
Is there a simple way of replicating the above function in SDL?
Edit: In the example above I only show how to handle one key, in practice however, I am going to have a list of about 15 keys that I want to respond to differently if the shift key is pressed as well.
Check the keyboard modifiers that are present when you get a keydown event. For example:
while(SDL_PollEvent(&event))
{
switch(event.type)
{
case SDL_KEYDOWN:
if(event.key.keysym.sym == SDLK_a)
{
if(event.key.keysym.mod & KMOD_SHIFT)
{
// Handle 'A'
}
else
{
// Handle 'a'
}
}
break;
...
}
}
SDL_keysym has mod field, which contains state of modifier keys at the time the event has been emitted. Bit-AND it with KMOD_SHIFT to check whether Shift has been active. See SDL wiki.
Why not just do this?
void keyPressedFn(unsigned char key, int x, int y){
switch(key){
case 'a':
case 'A':
// do work for A or a
break;
}
}
Do you have some other concerns that you cannot do as what I have suggested? If not I think this is as simple as it can get.
OS:: win xp sp3.
Qt:: 4.6
I have class Gameboard in which i have some rectangle.I defined keyPressEvent for that rectangle in order to move him around the screen.Key_A :: rectangle.moveToLeft & Key_D :: rectangle.moveToRight.Problem is that keys work with delay.
When i release one key and press another one it takes some time before that one begin to work.I checked Qt online documentation and now for that effect but dont now how to make those keys to work instantly without delay beetween them?
code snippet:
//in Gameboard class
ship = new QRect(x,y,w,h);
void Gameboard::keyPressEvent(QKeyEvent* event)
{
switch(event->key()) {
case Qt::Key_A :
{
x = x-10;
ship->moveTo(x,y);
break;
}
case Qt::Key_D :
{
x = x+10;
ship->moveTo(x,y);
break;
}
}
}
Put input cursor into any applicable text box and press the 'A' key. What you'll see is once you press the key, letter 'A' will be printed, then there will be a pause, and then first letter 'A' will be quickly followed by many others. That's the way keypress events work. And your program is receiving them exactly like this. First you receive one event when the key is actually pressed, and then after a delay you get a lot of automatically repeated events, in case user wants to enter one character many-many times.
It works perfectly for text input, but in games you usually need smooth movement. If that's the case, you need to move your ship not upon receiving the event, but regularly, for example, on timer event. And you will need to catch both keyPressEvent and keyRelease event and use them to remember what movement keys are currently pressed. So you could for example do this:
struct Ship {
bool is_moving_left, is_moving_right;
QPoint position;
int speed;
...
void timerEvent()
{
if (is_moving_left) position.setX (position.x() - speed);
if (is_moving_right) position.setX (position.x() + speed);
}
...
};
...
void Gameboard::keyPressEvent (OKeyEvent *_event)
{
switch(event->key()) {
case Qt::Key_A :
ship->is_moving_left = true;
break;
case Qt::Key_D :
ship->is_moving_right = true;
break;
}
}
...
void Gameboard::keyReleaseEvent (OKeyEvent *_event)
{
switch(event->key()) {
case Qt::Key_A :
ship->is_moving_left = false;
break;
case Qt::Key_D :
ship->is_moving_right = false;
break;
}
}
Then just make sure Ship::timerEvent() gets called on every timer event in the game.