In wxWidgets, I'm capturing the wxKeyDown event, which gives me a wxKeyEvent. I need to get the name of the key that was pressed (e.g. "F1", "Del", "Home", "A") to display to the user, however the closest I have found is wxKeyEvent::GetUnicodeKey():
void OnKeyDown(wxKeyEvent &event)
{
wxMessageBox(wxString::Format("Key pressed: %c", event.GetUnicodeKey()));
}
The only other solution I have found is to use a switch statement with keys that do not have a Unicode representation (e.g. Del). Is there any other way to retrieve the name of the key that was pressed?
There is no built-in function to get the name of the key, but you can see how to do it for most (and maybe even all the) special keys in the keyboard sample.
EDIT: Actually there is one function I didn't think of: wxAcceleratorEntry::ToString(). It is rather roundabout but you probably could use wxAcceleratorEntry(0 /* no modifiers */, keycode).ToString() to return a reasonably user-friendly description of the key.
Related
So inside the player controller there is a nice function called WasInputKeyJustPressed, you give it a key and it outputs a bool. I was curious if there was a similar function for Action Keys. For example, if I had an action mapping called MyActionKey which was tied to the Space bar. Is there a function like WasActionKeyJustPressed that essentially does the same thing as the original? If not how can I detect that with my player controller in a similar manner to WasInputKeyJustPressed?
I am not interested with the InputAction MyActionKey for this case it does not work for me. I am really looking for a function that will just output whether or not that particular Action Key is pressed in a bool form.
If this is a custom function that needs to be written then it would be nice if say I could pass in the name of the Action Key. I'd prefer if the solution was in C++.
I was able to find a sort of work around. Essentially, you can grab the input settings and then from there grab your axis mappings or your action mappings. They are both very similar. From there I looped through each of the mappings and grabbed the key it was referencing and called the WasInputKeyJustPressed function. An example below:
TArray<FInputAxisKeyMapping> axisMapping;
UInputSettings::GetInputSettings()->GetAxisMappingByName(axisName, axisMapping);
for(auto axis : axisMapping)
{
if (playerController->WasInputKeyJustPressed(axis.Key))
{
return true;
}
}
return false;
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.
What is the way to handle non-latin keys pressed with Qt?
For example, for 'W' key pressed QKeyEvent::key() returns 87, but for 'Ц' - the same key in the russian layout - it returns 1062.
So I can't use constants like Qt::Key_W for checking which key has been pressed: they won't work if a user switches the layout.
Thank you
The meaning of a key depends on the currently selected layout. What you observe is correct. If you pressed that key in any other application, you wouldn't get a W, but a Ц (C).
A given key means Qt::Key_W only if it's in a layout that produces the Roman W.
If you intend to refer to physical keys, you can try using QKeyEvent::nativeScanCode() and/or QKeyEvent::nativeVirtualKey(). These values are platform-dependent, of course.
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!
I'm in a situation whereby I am trying to read in a JSON config file which dictates what key commands map to given actions. For example:
...
{
"Action": "Quit",
"Combo" : "CTRL+Q"
},
...
Constructing a QKeySequence from the combo tag is trivial but I need to monitor QKeyEvents in order to trigger actions. Please note I have to monitor QKeyEvents because they are used for other purposes in the application as well. i.e. it would not be acceptable to only monitor key commands for QKeySequences (if that is even possible).
Short of writing a custom parser to construct a QKeyEvent object for each "Combo" tag, is there anyway of comparing a QkeyEvent to a QKeySequence? For example:
QKeyEvent KeyCommandsHandler::toKeyEvent(QKeySequence sequence) {
//somehow convert to QKeyEvent
}
In general, you cannot compare QKeyEvent and QKeySequence objects. QKeyEvent represents the event of a single key press or release, whereas a QKeySequence can contain a sequence of up to four keys, each with optional modifier information.
You can, however, compare the objects if you are sure that your key sequences will always contain just one key:
bool isEquiv(const QKeyEvent& event, const QKeySequence& seq)
{
if (seq.count() != 1)
return false;
return seq[0] == (event.key() | event.modifiers());
}
You can even write a conversion function for QKeyEvent to QKeySequence:
QKeySequence toKeySequence(const QKeyEvent& event)
{
return QKeySequence(event.key() | event.modifiers());
}
Note that it does not make sense to convert a QKeySequence to a QKeyEvent, though, since you have to choose a specific event type such as QEvent::KeyPress or QEvent::KeyRelease.
A simple solution (written in python):
key = QKeySequence(event.modifiers()|event.key()).toString()
Will give you the entire sequence in string form, such as "Ctrl+Q".
The benefits are (at least in python) that you can find in a dict of shortcuts, while a QKeySequence would not have been hashable.
Beware that this expects you use the correct typecase and spacing. "ctrl +Q" will not match. To avoid all issues, you can do the following when first reading the shortcuts:
shortcut = shortcut.lower().remove(' ')
and match/find using
key = QKeySequence(event.modifiers()|event.key()).toString().lower()
or better yet:
shortcut = QKeySequence(shortcut).toString()
and match directly.
A Qt4.7 note with code for converting KeyEvent to KeySequence. (But the code is flawed because it casts an int for the keycode from QKeyEvent.key() to a string. Better to use QKeyEvent.text() ?)
Also, the code in Ferdinand's answer:
QKeySequence(event.key() | event.modifiers())
is not type safe (mixes int and QKeyboardModifiers) and if converted to Python fails in PyQt, but not in PySide?
Also, "QKeyEvent represents the event of a single key press or release" doesn't really explain it. A QKeyEvent can tell you what combination of keys were down, just not the order in which they were pressed. When the user presses keys in sequence, your app might get a sequence of QKeyEvents (depending on whether your app is using default versus overridden handlers for QKeyEvent.) The later QKeyEvents will show you all the keys that were down at the time of the event. They might no longer be down. It is rather complicated.