Getting non-ascii character events

I would like to be able to bind non-american character keys in my game. There are many issues with this. First, Panda doesn’t fire an event for keys like “Ñ” in a spanish keyboard. This is easy to fix by adding the code (241) to panda but it’s just a hack, for example, what about other layouts or keyboards with arbitrary keys, such us this monstrosity. I would like to be able to tell Panda to capture a key, like most games do in their key bindings screen. Then I would store the keycode and use that for future comparisons. I would just need a method for Panda to send me arbitrary keycode events and another method for getting the next keycode. Are these things possible? If not, I’ll implement them. Any suggestions, warnings, etc. would be appreciated.

But even if we fix that there’s another problem that I don’t know how to fix. The composed character sequences, such as ´ ^ `, that in non-american keyboards let you do characters like á ë ô or ~. At the low level panda isn’t receiving separate events for “^” and “o”, rather, the first event doesn’t happen and then a keycode is received corresponding to the “ô” character. By lowlevel I mean mouseAndKeyboard::do_transmit_data, where a MouseButton is received from the window. While this is convenient for a PGEntry input, for example, it’s inconvenient for the game itself because I would like to be able to bind the ´ key. Most of the games I’ve played let me do that, so this is a big problem with the panda input system.

If those things are impossible or hard to fix in panda, is it possible to use something else for input, like OIS? (Specifically I would like to use OIS for keyboard and still use panda for mouse, reason being that I prefer a windows api controlled mouse, like panda does, rather than directinput, cause directinput interpolates the raw values and it adds some delay)

(All this happens in Windows, btw, I don’t know about other platforms.)

Edit: After thinking about it, directinput for keyboard (as OIS does) has a lot of drawbacks too, so I’m very interested in fixing this in panda: 1) getting and listening for arbitrary keycodes 2) Separated concepts for character presses (“ô”) and key presses ("^", “o”)

For the record, it works fine for me on Linux.

Note that Panda makes a distinction between a “button” event, which refers to a physical button on the keyboard and doesn’t support composed characters, and a “keystroke” event, which refers to a high-level character that was typed and supports all forms of composed characters, and the full range of Unicode.

If you’re not seeing the international characters, you’re probably listening for “button” events instead of “keystroke” events.

David

Yeah, but I’m not getting a button event either, in Windows. (Pro-rsoft says it woks in Linux.) For example, I put a cout here:

cout << "[BUTTON] " << be._button << " " << be._keycode << " " << be._type << endl;
_button_events->add_event(be);

That’s in mouseAndKeyboard.cxx

Everytime I press a key, I get that cout, i.e: a button event is added, except for the keys “`” and “´”. Notice that these are primary glyphs on a spanish layout, i.e: they are the main character on the keys where you have “[” and “’” (single quote).

When those keys are pressed, no button event is generated. Instead, a button event will be generated when I press the next key, because it tries to compose a character such as á or é. Note also that it’s normal for games to get this right. It’s a problem of a character behavior when you expect key press behavior.

Also, you didn’t address my first concern. Is there a way to listen for arbitrary keycodes? Such as “Ñ”, which currently isn’t in Panda? And I would prefer to be able to map arbitrary keycodes rather than just adding Ñ to panda, as I said. When I’m programming to the windows api I can capture unknown keycodes, so I’m able support any keyboard layout. I would like to be able to do the same…

Hmm, it is true that Panda’s button-event system is only designed to report one of the standard known button names, and that we have never added explicit support for the primary keys that are unique to international keyboards. I think probably the right thing to do is to add those buttons to WinGraphicsWindow::lookup_key(), either explicitly in the switch statement, or implicitly via MapVirtualKey and some extension to KeyboardButton::ascii_key() (but extending this to unicode_key() will take some reengineering of KeyboardButton).

Another question is whether these keypress events even come through Window’s WM_KEYDOWN system at all. If not, then supporting them will require reworking this part of the event loop.

I think this applies to supporting Ñ, as well. There is a value in extending Panda to be able report any arbitrary, as-yet-unforeseen keycodes; but there aren’t that many keyboard buttons in the world, really; and if we only add explicit support for all of the existing known buttons, it will still make your generic-keycode application possible.

David

Ok, it’s reasonable. The thing is that in order to make my key binding-grabbing app it would be nice if there was a generic event like:

framework.define_key ( “raw”, “raw key input”, &key, NULL );

Then I could manage all the key events myself, plus it will support new keycodes automatically. Relaying on premapped keys on the other hand, I will have to add like 105 hooks! And it won’t support new keycodes. You say it’s easy to support all keycodes, and I agree, as far as standard layouts go, but there are new keycodes all the time, gaming keyboards with a dozen of extra keys, special multimedia functions, etc. I think there’s a reason that many API’s just send you a keycode, it gives you a lot of flexibility and it’s a clean and small solution.

Still I understand your point, and btw, I’ll try to add the Ñ, while I’m at it, but how to add it? We shouldn’t just add an “ñ” event to the table, because in other layouts, the same keycode will correspond to other glyph, so how do I do that?

Of course, if there was a “raw” even as I described above it wouldn’t be a problem, cause you would just listen for 241. Would you incorporate something like that?

Ah, Panda does support a generic event mode. It’s just not enabled by default. You can enable it with code like this:

NodePath btnp = get_window()->get_mouse().get_child(0);
ButtonThrower *bt = DCAST(ButtonThrower, btnp.node());
bt->set_button_down_event("generic_button");

(It’s a little unfortunate that the WindowFramework design doesn’t provide a direct handle to the ButtonThrower’s NodePath, and you have to assume it’s the child of the mouse. I’ve just added the missing interface to fix this.)

When you receive the event, you can get the first EventParameter, which will be the string that is associated with the button name.

Since Panda uses strings instead of keycodes, we can safely add support for ñ and any other keyboard-specific keys to the KeyboardButton table.

David

Ah this is very useful indeed.

I could extend this generic event to send unknown key presses as an int that is the keycode, instead of a string. Or maybe as a string containing an hex number, if you prefer? Like, “0xF1” to tell them apart from normal number key presses. Maybe in decimal with a prefix like “UNKNOWN_241”? It seems pretty easy to implement and it wouldn’t break compatibility with anything, would you incorporate this patch?

Seems pretty reasonable, and I’d be happy to incorporate that patch. You’d probably implement it at the KeyboardButton level by calling ButtonHandle::register_button() on the fly with the string you construct.

David

So I was adding support for this when I noticed a bigger problem. My app receives no keyboard input unless the mouse pointer is inside the client area of the window, much like some old unix window managers in sloppy mode. (except that would include the window titlebar and border) Is this normal? Any workaround?

Edit: and yeah, I’m in windows.

Why, so it does. How odd that we’d never noticed that behavior before. That is indeed unintended behavior; there must be some code somewhere that’s checking for has_mouse() or something before throwing a button event.

Unfortunately, the data path there is a bit convoluted, so it’ll take a little unwinding to track it to its source.

David

Here’s something that I found that will reduce the problem quite a bit. “Character events” work with the pointer outside the client area. For example, you can write on a PGEntry. Key events, however, won’t be triggered.

EDIT: And another thing, even though you can write, you can’t use the arrow keys to move the cursor in the PGEntry or backspace to delete stuff when the pointer is outside.

This is fixed now.