I am using C++ and ncurses to get key input for a game. I have a moveable object that the arrow keys control. The behavior that I want is to be able to constantly move right with an arrow key and jump with the up keyy without interrupting the moving right. However, currently with ncurses, when RIGHT is being held and UP is pressed, it stops registering that RIGHT is being held, and you have to release and press RIGHT again.
How can I fix this?
I have seen this post, which is how I'm getting the multiple key input (see below), however I don't think this is the problem.
while (gameRunning) {
int ch;
vector<int> keys;
while ((ch == getch()) != ERR) {
keys.push_back(ch);
// keys vector now has all pressed keys,
// however if you are holding right and up is pressed,
// holding right is not recognized until you release and
// right is pressed again
}
// loop through keys vector here, do things with pressed keys
}
Related
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.
I am using Qt creator to make a simple drawing program in c++. I have a mouseevent, that should get the coordinates to the nearest point (dot) allready existing from the point where mouse was clicked, and put them to line starting point coordinates. Thats done. But now the event should wait for a second mouse click to get the nearest dot coordninates again and put them to end point of line. But instead it does not wait for the second input and puts the same first point for the line endpoint also.
How can I make mouseevent take two click inputs, not do everything right away? Is it even possible? Thank you in advance.
You cannot make one event require two clicks (excluding, of course, the double click event). You can, however, establish a state within your application, where the first click starts the state and the second completes it. Pseudo-code to manage this:
// in your constructor:
StartingClickPoint = INVALID; // indicate that we have not entered our special state
// in your mouse event handler:
if (StartingClickPoint == INVALID) {
// we're only now starting this state; we don't have enough information to complete it
StartingClickPoint = CurrentClickPoint;
return;
}
else {
// complete the state handling and arm for the next pair of clicks
EndingClickPoint = CurrentClickPoint;
DoSomethingWithTheClickPoints();
StartingClickPoint = INVALID; // reset for the next pair of clicks
}
Today I set up the input in my application for all the different keys. This works fine except for virtual keys, for example, caret or ampersand. Keys that normally need shift to be got at. Using SDL these virtual keys don't work. As in they do not register an event.
if (event.type == SDL_KEYDOWN) {
switch (event.key.keysym.sym) {
case SDLK_CARET:
Keys[KeyCodes::Caret] = KeyState::Down;
break;
case SDLK_UP:
Keys[KeyCodes::Up] = KeyState::Down;
break;
default:
break;
}
I am absolutely sure my system works with physical keys like Up. The program queries a keystate like so:
if (Keys[KeyCode] == KeyState::Down) {
lua_pushboolean(L, true);
} else {
lua_pushboolean(L, false);
}
KeyCode is passed in as an argument.
So why are virtual keys, or keys that need shift to get at not working using SDL's KeyDown event type? Is more code needed to get to them? Or am I being stupid?
SDL only reports real key events.
The good news is you can enable Unicode translation to get symbols like '^' or '#'.
First put this in your initialization code:
SDL_EnableUNICODE(1);
Now SDL_KEYDOWN events will have the accompanying character in the unicode member of SDL_keysym. This factors in shift, caps lock, etc., when translating the key press into a character. Keys like SDLK_UP will have unicode == 0.
This actually makes using keysym.unicode ideal for text input, especially when used with SDL_EnableKeyRepeat.
Here's an example: on my keyboard, I hold shift-6 to generate ^. The program recieves an SDL_KEYDOWN event with keysym.sym == SDLK_6, and keysym.unicode == '^'.
The one caveat is that only key press events will be translated, not release events. But this should not be a big problem, since you shouldn't use text characters for game controls anyway, only real keys. And if you're doing text input with key repeating, it only matters when keys are pressed, not released.
You might have to mix-and-match using keysym.sym and keysym.unicode to fit your exact needs.
Ok I do apologise for getting slightly frustrated but I have finally got some code to tell when some one has pressed on the Caret key for example. I do hope others find this useful information.
case SDLK_6:
if (event.key.keysym.mod == KMOD_LSHIFT || event.key.keysym.mod == KMOD_RSHIFT) {
Keys[KeyCodes::Caret] = KeyState::Down;
} else {
Keys[KeyCodes::n6] = KeyState::Down;
}
break;
Basically when checking normal keys that have a shift click special key then check the key modifier. I understand the unicode value now but this idea seems simpler for now.
Again thanks for all the help!
In Qt's QKeyEvent I can check whether Ctrl was pressed by checking if ev->key() is Qt::Key_Control. But how can I distinguish between the left and right Ctrl keys?
I also need the same thing for Alt and Shift keys.
There is no way to do this using pure Qt methods, as far as I know.
Depending on your platform, however, you might be able to distinguish between the keys using the QKeyEvent::nativeScanCode() method instead of QKeyEvent::key().
For example, on Windows you should be able to test which Ctrl key was pressed as follows:
if (event->nativeScanCode() == VK_LCONTROL) {
// left control pressed
} else if (event->nativeScanCode() == VK_RCONTROL) {
// right control pressed
}
According to the Qt Namespace Reference, the enum Qt::Key has a different value for Qt::Key_Alt and Qt::Key_AltGr.
However, enum Qt::KeyboardModifier and enum Qt::Modifier don't see the pair of keys as different modifiers.
(note: I would have posted this as a comment but I don't have enough rep. yet)
Left and Right keys are part of virtual key code -> use nativeVirtualKey() to compare with windows VK_* enums instead of nativescancode().
If VK_RCONTROLdoes not work, check your nativeScanCode value of ctrl-right:
std::cout<<keyEvent->nativeScanCode(); and use this value:
int control_right = 285;
if(key->nativeScanCode() == control_right){...
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.