SDL (And Others) Virtual Key Input - c++

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!

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.

How to disable key repeat in SDL2 text input

I would like to take over how keys repeat in my program, which means disabling how SDL2 does it automatically.
It's possible to ignore SDL_KEYDOWN repeat events since the Event union member key has a repeat boolean you can filter with (this question explores that solution: How to disable key repeat in SDL2?). But SDL_TEXTINPUT events do not have the same info available in them, and so it's impossible to filter out characters that have repeated.
Is there any way to outright disable key repeating?
It seems there is currently no simple way to do this, and because I need this as well I made a ticket: https://bugzilla.libsdl.org/show_bug.cgi?id=4598
If you have another additional use case why you want this, feel free to add a comment on the bug ticket so the developers get an idea what sort of uses this is important for. (Mine is providing an emergency disable option for people with keys-getting-stuck bluetooth keyboards on android who want to still be able to type texts without major accidents)
Well in SDL lib might be a solution, but you can also add some simple c++ code to resolve your problem. For example if you don't want to play with SDL_KEYUP you can just do something like this:
//before loop
int keypress_control = 0;
//much Code, loop etc.
//
swich(event.type)
case SDL_KEYDOWN :
/*if or switch again as you want */if (keypress_control ==
2)
{
/*Code here*/
keypress_control = 0;
}
else
{
keypress_control = 0;
}
}
//after switch but Still in program loop
Keypress_control++;
//
//

How to read key from keyboard in c++?

How to read key from keyboard in c++ ?
i used _getch() but this is not working always.
i heard about win32 keyboard api. i am targeting to windows so window specific technique is fine. can anyone give me simple example how to read key and check for arrow and function key.
i read article
How to simultaneous read keys on keyboard?
but this is not working in may case. here is my attempt inspired from above linked reference
char temp;
BYTE keys[256];
while(true)
{
temp = _getch();
if(GetKeyboardState(keys))
{
if(keys[VK_UP]&0xF0)
{
// Move Up : Case failing when i pressed up key
}
else if(keys[VK_DOWN]&0xF0 || keys[VK_RETURN]&0xF0)
{
// Move Down : Case failing when i pressed down or enter
}
else if(keys[VK_TAB]&0xF0)
{
// Move Next : Case failing when i pressed tab
}
else
{
// Print charecter which read using _getch()
cout<<temp;
}
}
}
i read MSDN article but do not understand what they are doing. i am doing such program first time so please make your example clear and illustrative so i can easly get it. thanks
I don't have a Windows machine at hand to test this out, but I am thinking that the fact that you are using temp = _getch(); before GetKeyboardState(keys) is eating your characters.
there are many library in C++ which handle this type of problem, if you are the choice, I advise you to use QKeySequence and other classes to let useful keyboard management.
If you want to see example, refer you to chromium project, here is an example used to test code of "keyboard driver".
you can either search many example with "filetype" syntax in google search engine (example : filetype:cc GetKeyboardState)...
you need to set correctly the layout before use GetKeyboardState...
Hope this help you.
Regards,
/Mohamed

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.

Qt LEFT CTRL Key Code

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){...