#Having trouble with making a key that wont repeat when held, trying to use bitfields, using glfw

41 messages · Page 1 of 1 (latest)

runic oliveBOT
#

When your question is answered use !solved to mark the question as resolved.

Remember to ask specific questions, provide necessary details, and reduce your question to its simplest form. For tips on how to ask a good question use !howto ask.

hollow sonnet
#

hi. i'm making a camera class that will be handling inputs, (using glfw) and in my KeyCallback, I have an array of bools for each glfw key that I set to true or false to avoid the os's repeat rate for held keys. here is the code I have for testing:

static bool held = false;
if (!held)
{
    if (userActions.Keys[GLFW_KEY_SPACE].KeyState) // Check if Space is pressed
    {
        Logger::logger->Log("KeyDown");
        held = true; // Set KeyHeld to true
    }
}
else if (!(userActions.Keys[GLFW_KEY_SPACE].KeyState)) // Check if Space is not pressed IF KeyHeld is true
{
    Logger::logger->Log("KeyUp");
    held = false; // Set KeyHeld to false
}

here is the KeyCallback, just in case there's something I can improve about it:

static void KeyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
    {
        if (action == GLFW_PRESS) // Make it so holding down a key doesnt rely on the repeat rate
            userActions.Keys[key].KeyState = true; // Meaning it shouldnt press once, then wait, then finally hold
        if (action == GLFW_RELEASE)
            userActions.Keys[key].KeyState = false;
    }

i want to change it to this, where held and keystate are a struct bitfield that take up one bit each.
i have a useractions struct that is passed around with the keys, context for the previous and latter code blocks:

struct UserActions
    {
        KeyHandler Keys[348]{ 0, 0 };
        bool MouseButtons[8]{false};
        double MousePos[2]{0.0};
    } userActions;

here is that KeyHandler struct:

struct KeyHandler
    {
        bool KeyState : 1;
        bool KeyHeld : 1;
    };

here is the code that doesn't currently work as intended, where instead of only recieving a log when the key becomes up or down (which is also what happens with the initial code at the top of this message), it logs every frame with the key's state. here is the working (compiles, but not intended function) code:

#
if (!userActions.Keys[GLFW_KEY_SPACE].KeyHeld)
{
    if (userActions.Keys[GLFW_KEY_SPACE].KeyState)
    {
        Logger::logger->Log("KeyDown");
        userActions.Keys[GLFW_KEY_SPACE].KeyHeld = true;
    }
}
else if (!(userActions.Keys[GLFW_KEY_SPACE].KeyState))
{
    Logger::logger->Log("KeyUp");
    userActions.Keys[GLFW_KEY_SPACE].KeyHeld = false;
}

I can't figure out what's wrong with the code, because it looks about the same, can someone help?

runic oliveBOT
#

@hollow sonnet

Please Do Not Delete Posts!

Please don't delete forum posts. They can be helpful to refer to later and other members can learn from them. In the future you can use !solved to close a post and mark a post as solved.

hollow sonnet
#

sorry, reordering posts for better reading

hollow sonnet
#

still having no luck :/

hollow sonnet
#

Having trouble with making a key that wont repeat when held, trying to use bitfields, using glfw

sullen pulsar
#

kind of hard to understand whats actually going on in your code without the full context. Github link or better yet a minimal example would help

hollow sonnet
#

sure, hold on just gotta commit it rq

#

problem is in the camera struct

sullen pulsar
#

I reckon its this

https://github.com/fl2mex/hyper/blob/master/src/UserActions.h

Its a global thats defined in a header so

https://github.com/fl2mex/hyper/blob/master/src/Camera.h

Defines their own userActions global. And Application.cpp

https://github.com/fl2mex/hyper/blob/master/src/Application.cpp

Also gets their own global userActions

If they ever interacted with eachother youd probably get a multiple definition error and it would blow up nicely. So since each file has their own userActions the inputs wont be consistent across files.

You can verify that by printing the address of userActions in Application.cpp and Camera.h incase Im wrong about this

hollow sonnet
#

problem is trying to access userActions in a static method (KeyCallback) that is used by glfw, so I cant change the method parameters

#

*to make userActions not static

sullen pulsar
#

you can declare it

// UserAction.hpp

// ...

extern UserAction userAction;

and define it in its own C++ file so every TU refers to same userAction

// User Action.cpp
#include "UserAction.hpp"

UserAction userAction{};
hollow sonnet
#

ah, never used the extern keyword before

#

ill try it out

sullen pulsar
#

you could also make it inline but that doesnt scale very well

#

definitely not static tho that just makes it explicit that every cpp file gets their own userAction

#

thats probably also why your program didnt blow up when you ended up defining multiple userActions in each file

hollow sonnet
#

i've done that now, (and changed my useractions to non-static) but when space is being held, it logs every second in comparison of what I want it to do, which is only log when the key is pressed down and back up, while maintaining the ability to (commented out at the top of the ProcessKeyboardInput function) have input be held down without having to wait for the os to send repeated inputs in

#

really all i'm trying to do is figure out why I can't change this:

static bool held = false;
 
if (!held)
{
    if (userActions.Keys[GLFW_KEY_SPACE].KeyState) // Check if Space is pressed
    {
        Logger::logger->Log("KeyDown");
        held = true;
    }
}
else if (!userActions.Keys[GLFW_KEY_SPACE].KeyState) // Check if Space is not pressed IF KeyHeld is true
{
    Logger::logger->Log("KeyUp");
    held = false;
}```
into this:
```cpp
if (!userActions.Keys[GLFW_KEY_SPACE].KeyHeld)
{
    if (userActions.Keys[GLFW_KEY_SPACE].KeyState)
    {
        Logger::logger->Log("KeyDown");
        userActions.Keys[GLFW_KEY_SPACE].KeyHeld = true;
    }
}
else if (!userActions.Keys[GLFW_KEY_SPACE].KeyState)
{
    Logger::logger->Log("KeyUp");
    userActions.Keys[GLFW_KEY_SPACE].KeyHeld = false;
}```
#

and with what you said before, my guess is something to do with static?

#

(again, inside my ProcessKeyboardInput function in camera.h)

#

i commited changing the static useractions to extern

sullen pulsar
#

Can you push those changes real quick?

hollow sonnet
#

oh shit didn't notice 😭

#

done

sullen pulsar
#

ahh you just declared it in Application.cpp.

You declare it in UserAction.hpp so every file knows that the global exists somewhere

extern UserAction userAction;

But you define it in a C++ file for example UserAction.cpp so userAction only actually exists once for your entire program

UserAction userAction{};
#

Whats also important to remember is that static means different things for functions/classes and namespace/global scope

Functions and Classes static implies that the variable exists only once. In functions you get nice guarantees about it being initialized and for classes you have to initialize it yourself in a C++ file or make it inline

Namespace/Global static means that the static variable/function is unique to that translation unit (basically everything that makes up the file you compile)

#

You could also look up Meyers Singletons if you want which is the most common way to design globals in C++

hollow sonnet
#

so i've made some changes that ive committed and pushed, including moving some camera functions to a seperate cpp file so I can put useractions in a cpp file, and also in the application.cpp file so glfw can access it, but i still get errors for redefinitions inside application.obj, alongside two unresolved external symbols inside application.obj and camera.obj

#

i'm still very confused 😭

#

i'm going to have to look at this tomorrow, it's 3am and i have uni in the morning, thank you for teaching me about externs, i hope that we can fix this later

#

have a good day/night

runic oliveBOT
#

@hollow sonnet Has your question been resolved? If so, type !solved :)

sullen pulsar
#

Okok

You probably should drop using anonymous structs. Can be done but its usually a bad idea. Just declare UserActions and then declare your global of that type instead of doing it in one go.

Heres how Id change UserActions.h

#pragma once

namespace hyper
{
    struct KeyH
    {
        bool KeyState : 1;
        bool KeyHeld : 1;
    };

    struct UserActions // Having an extra header is dumb but I need it in two places
    {
        KeyH Keys[348]{ 0, 0 }; // I need to figure out how to get all of this as pointers
        bool MouseButtons[8]{ false }; // so i'm not passing around ~0.4 KILOBYTES every time
        double MousePos[2]{ 0.0 };       // I move the mouse/press keys
    }; // Should declare this somewhere else more visible
  extern UserActions userActions; // Declare here this gets pasted into every file that includes UserActions.h so they are aware of the globel 
}

And instead of defining userActions in Application.cpp and Camera.cpp which is where the redefinition error comes from.

A global must be defined only once in a single C++ file

I suggested creating UserActions.cpp twice now because if the file is named after the class its easy to guess that the global is defined in there so you dont accidentally define it twice

You can define it there like you did in the other files

// UserActions.cpp
#include "UserActions.h"

hyper::UserActions userActions{}; // Define it only here and make sure this is the only place where this is ever defined

Dunno about the unresolved symbols. If you cant figure it out later you can always ask here again

hollow sonnet
#

it works! thank you so much

#

i just had to make a UserActions.cpp file and not redefine the userActions

#

i'll close this now, thank you so much again

#

!close