Keypress event in C++ - c++

I'm currently using GetAsyncKeyState() to detect Keydown events, but then the events will be repeated while you are holding down the key.
What would be an easy way to stop the event from repeating?
Example
If I hold down the key i on my keyboard for a while, I will get an output like this:
iiiiiiiiiiiiiiiiiiiiiiiii
Instead of this:
i
I want to force the user to press the key again to trigger the event.

Avoid using a keyboard related message like WM_KEYDOWN or WM_CHAR to detect a key, Windows repeats WM_KEYDOWN when the user holds it down. You simply need a your own bool flag that keeps track of the state of the key. Only change your game object state when you see a difference between the state as reported by GetAsyncKeyState() and this flag. Roughly:
bool movingLeft = false;
...
if ((GetAsyncKeyState(VK_LEFT) < 0) != movingLeft) {
movingLeft = !movingLeft;
gameObject->setVelocity(movingLeft ? -10 : 0);
}

Use KeyPress events (or KeyUp).
Btw according to MSDN SHORT WINAPI GetAsyncKeyState(__in int vKey);
Determines whether a key is up or down
at the time the function is called,
and whether the key was pressed after
a previous call to GetAsyncKeyState.
It doesn't say anything about detecting a keydown event.

Related

How to avoid handling both the key-event and char-event

To handle text input I've set up a char-event callback with glfwSetCharCallback, and to handle non-text keypresses (arrow keys & hotkeys) I've set up a key-event callback with glfwSetKeyCallback.
What happens in this situation is that for a key press of a character key, I get two calls, one in the key-event callback, and then one in the char-event callback. This can cause unwanted effects - for example let's suppose the user configured the key "a" to enter "Append Mode" of a text editor - after it enters the mode it will also enter the character "a".. Is there a good way to handle this?
So far I've relied on both events arriving together before glfwPollEvents returns, and have merged them. But I get reports that this scheme doesn't work well on some Ubuntu systems..
I've been having trouble with this one as well. After some rudimentary debugging I found that if you press, hold then release a 'typable' key (meaning a key which may fire both the glfwKeyCallback and glfwCharCallback), the output is as follows:
KeyCallback - pressed
CharCallback - typed
KeyCallback - repeated
CharCallback - typed
(3. and 4. repeat until key is released)
KeyCallback - released
With this, and judging from the fact that there is a 0ms delay between the two events firing, they're probably fired sequentially. The solution I came up with (is rather janky), and involves creating some sort of KeyEvent structure:
(examples are in C++)
enum KeyEventType
{
Pressed,
Repeated,
Released
}
struct KeyEvent
{
KeyEventType Type;
int Key;
unsigned char Codepoint;
bool IsTyped;
}
and store it along with an index variable, such as
[main/input class]
std::vector<KeyEvent> m_KeyEvents;
size_t m_LastKeyEventIndex;
in the main file.
Then, when the glfwKeyCallback fires, push a new KeyEvent into the vector:
[glfwKeyCallback]
KeyEventType type = (action == GLFW_PRESS ? KeyEventType::Pressed : (action == GLFW_REPEAT ? KeyEventType::Repeated : KeyEventType::Released));
KeyEvent event = KeyEvent(type, key);
m_KeyEvents.push_back(event);
m_LastKeyEventIndex = m_KeyEvents.size() - 1;
and if the glfwCharCallback fires, we know from the debugging that it should be (immediately) after the corresponding keyCallback event, so you can modify the last added entry in the vector to add the codepoint and mark it as a 'typed' event, after-the-fact. This also gives the added benefit of tying the actual key that was pressed to the generated codepoint, which could come in useful.
[glfwCharCallback]
m_KeyEvents.at(m_LastKeyEventIndex).Codepoint = codepoint;
m_KeyEvents.at(m_LastKeyEventIndex).IsTyped = true;
Finally, in the main loop when you go to call glfwPollEvents(), process all those pending KeyEvents and then clear the vector and reset the index.
I haven't fully tested this yet, but some very rudimentary debugging shows this as a promising solution, resulting in the following*:
*I'm using a custom Key enum in place of the int Key. You could probably use glfwGetKeyName() to get the printable key name, however this resulted in exceptions for me when pressing some keys.

Keyboard class implementation in windows application

I want to implement a Keyboard class like below;
class Keyboard
{
public:
Keyboard();
~Keyboard();
bool IsKeyDown(Key);
bool IsKeyUp(Key);
void SetPressedKey(int);
void SetReleasedKey(int);
private:
Key pressedKey;
Key releasedKey;
};
Key is an enum like below;
enum Key
{
A,
Enter,
Up,
Down
};
Here is the window callback function;
case WM_KEYDOWN:
kb.SetPressedKey(wParam);
break;
case WM_KEYUP:
kb.SetReleasedKey(wParam);
break;
First of all, my design can be completely wrong. If it's an acceptable design, there are some questions that I couldn't answer. Can value of the pressedKey be overwritten if user presses two buttons at the same time and how can I determine if user uses combinations like CTRL+C. The other question is I couldn't find a way to make a relationship between wParam's value and enum keys' indexes.
Most of the implementation of this class is unnecessary and should be removed. You are re-implementing functionality that the operating system already provides. If you want to know the state of a key, simply call GetKeyState.
You may choose to wrap up the low-level Win32 API GetKeyState with your class. But do not store the information as state in your class. When you need to know the state of a key, i.e. when implementing IsKeyDown() and IsKeyUp(), call GetKeyState.
Another good reason for this is that you cannot guarantee that all keyboard messages will arrive in your window. Somebody may press a key whilst a different window is active, and then switch to your program. At that point, your attempt to track state using keyboard messages will break down because you never got the key down message. However, GetKeyState will work.
That said, if you need to know the instantaneous state, outside of a window procedure, then you would use GetAsyncKeyState rather than GetKeyState. Only you fully understand the purpose of this class and so are in a position to make that decision.
Windows already keeps track of all this information. If you want to know if a key is currently pressed, GetKeyState. This queries the keyboard state tied to the current message. So for example it's accurate to use GetKeyState to know if CTRL was pressed inside a WM_KEYDOWN message.
There is also GetAsyncKeyState, if you want to query the keyboard state "right now", rather than the state when the current message was generated.
In terms of your design I personally would try to make it a bit better by having it as a set of Key object and have the keys maintain their own state. That way you can model multiple key presses. The example (incomplete and not tested!) shows the idea.
class Keyboard
{
public:
Keyboard();
~Keyboard();
bool isPressed(Key);
void pressKey(int); // or Key
void releaseKey(int);
private:
std::set<Key> keys;
};
class Keyboard
{
public:
// define your comparison operators to use std::set or else write a comparator.
Key(uint32 id);
~Key();
bool
void setPressed();
void setReleased();
bool isPressed() const;
private:
uint32 keyId;
bool pressed;
};
In order to relate the windows key values to Key objects you could build a factory to return the keyIds that you need. Your KeyIds could be an enum or just re-use the windows values. As long as they are unique and your application understands then then there is no point in being restrictive.

C++ WM_KEYDOWN different intervals

I am currently trying to get KeyBoard Input from the WM_KEYDOWN and WM_CHAR message for my own InputBox.
This is the code that I am using for basic input, which works fine for characters:
if(msg.message == WM_KEYDOWN)
{
keyHandled = false;
//handle other keys here, e.g. VK_LEFT
}
else if(msg.message == WM_CHAR && !keyHandled)
{
keyHandled = true;
gui->UpdateInput(msg.wParam);
}
If the key that is being pressed is also a key that triggers the WM_CHAR message, the interval is as in usual input boxes.
However, if it is a key like VK_LEFT, it keeps receiving the WM_KEYDOWN message without any delay.
Is there any way that I can receive all keys with the same interval or do I have to implement a timer that handles the delay between the messages? I have also had a look at the WM_KEYDOWN message on msdn, but I could not find anything related to the intervals.
Windows has its own delays for sending Keyboard events from Keyboard input and this isn't something you can simply change. As you know, holding down a key will result in a first message, a delay, and then a series of more messages with a quicker interval. You can get around this by requesting states rather than relying on the messages directly. This is called Unbuffered input and is state oriented. To store your states, you can do the following:
bool keys[256];
When you are checking windows events, you can update the key states accordingly like this:
//In your WinProc function most likely
if (msg.message == WM_KEYDOWN)
{
keys[msg.wParam] = true;
}
if (msg.message == WM_KEYUP)
{
keys[msg.wParam] = false;
}
Then whenever you'd like, you can request the state of a specific key through the following function:
bool getKeyPressed(char keycode)
{
return keys[keycode];
}
For example:
//This could be in some random update function and called
//whenever you need the information.
if (getKeyPressed(VK_UP))
{
//Do something here...
}
The above function can be used wherever you'd like, therefore the frequency at which you update is completely up to you at that point. As mentioned before, this is Unbuffered input and is State oriented, whereas Buffered Input is Event oriented.
I think that this internal delay can not be modified easily.
One approach could be writing your own general key handler that keeps track of the states of all keys. For example, a list containg the keycodes of all pressed keys. On WM_KEYDOWN you add the keycode to the list and on WM_KEYUP you remove it. Then create something like a timer that simply notifies you in the desired delay times and calls your key handling function for each element of the list.

Implement close function on keypress in c++ builder

How do I implement Close (or exit) function when the ESC key is pressed in a form application in C++ builder?
Also, note that the form will have a number of components; it can't be only an empty form.
I tried to use this code but it doesn't work every time I press ESC.
void __fastcall TForm1::FormKeyPress(TObject *Sender, System::WideChar &Key) {
if (Key == VK_ESCAPE) {
this->Close();
}}
The code above doesn't work because focus is not always on the form and, if you have more components like EditBox, you have to disable VK_ESCAPE on every event and reference the desired function (which is, of course, a weak solution).
Using the TForm::KeyPreview property and TForm::OnKeyPress event is the best approach, but an alternativve would be to put a hidden TButton on the form and set its Cancel property to true, then you can call Close() in its OnClick event.
Set the KeyPreview property of the Form to true. This way, keyboard events occur on the form, before the active control.

Can I force an Escape key "press" in C++?

I know that you can set actions to trigger if the user presses a set key, in my case Escape, with something like this:
transitions.push_back(new KeyTransition("GameMode", OIS::KC_ESCAPE));
What I want to know is if I can have the program "think" the Escape key has been pressed, even if it has not. For example, when the user clicks a button, the program simulates that the escape key has been pressed and triggers the event attached to it.
One way to do this would be instead of tying it to a specific key press event, you had a more generic method.
So have a method like Cancel() or GoBackOneScreen() etc, whatever it is that ESC is doing. Then you could have the ESC keypress call GoBackOneScreen() and when you needed to simulate the ESC key press, you could do it by just calling the GoBackOneScreen() method.
See this: How do I send key strokes to a window without having to activate it using Windows API?
Summary: You can't reliably.
//To force user to press escape key
#include<iostream.h>
#include<conio.h>
void main
{
cout<<"press escape to exit\n";
loop:
if(getch()==27);
else
{
if (getch()==27);
goto loop;
}
}