Keymapping: Identifying device-types

I think that I’ve made some progress in adapting my key-mapping class to use Panda’s extended input-device support. However, I’ve hit another stumbling block:

In order to determine which devices I should attach, I want to store the device-type associated with each key-mapped game-control. The problem is that of how to find that device-type when binding keys.

I’m using “ButtonThrower.setButtonDownEvent” and “ButtonThrower.setButtonUpEvent” to detect player inputs when binding a key. This works well enough–but its callback provides only a string key-name, as far as I’ve found. I see no way to provide any additional arguments (so that I might pass in the device-type), and it doesn’t seem to include the prefix given when calling “attachInputDevice” (so that I might parse the device-type out of the string). Thus I’m not sure of how to determine the device-type of the button that was pressed.

Any thoughts on how I might deal with this?

Why not just pass a different event button-down and button-up event name for devices of different types?

You could however consider whether you are benefiting from using ButtonThrower at all, since if you are building your own input framework you might as well fetch the button list from the InputDevice periodically to know which buttons have been pressed.

Hmm… That would mean setting up a separate event for every different device-type (save keyboard and mouse, which could be combined, I believe). Is there an easy way to iterate through the device-types? (So that the code would naturally pick up any that might be added later, or skip any that might be removed later.)

Ah, the iteration turns out to be easy. I think that I had the impression that “InputDevice.DeviceClass” was a normal class, and the various types thus ordinary class-variables. However, it looks like it’s an “enum”, and thus I can iterate over its members as though it were a list!

I’m not really building my own input-framework, I don’t think–it still fundamentally uses “DirectObject.accept” (and once I get to axial inputs, “InputDevice.findAxis”, I imagine). It’s not intended to replace the device-handling that Panda provides, but to provide a convenient means of handling the remapping of buttons, without game-code becoming a mess: from the game’s point of view, there are only game-controls; the key-mapper class handles the mapping from those game-controls to actual button-presses, etc.

In particular, ButtonThrower is only really used when binding a key, since it allows me to listen for any button-press. I suppose that I could use polling for this, but that’s a slightly more awkward approach than using an event, and (to a lesser degree) I fear that polling can occasionally lead to button-presses being missed if the timing is off. (If I’m understanding you correctly.)

Okay, I’m trying to set up individual events per device-type. As noted above, iterating over the device-types in order to construct event-names wasn’t a major problem,

However, I’m a little stuck trying to use those events on the various button-throwers: specifically, I don’t seem to be finding a way to either locate the button-thrower for a given device/device-class, or to determine the device/device-class associated with a button-thrower.

ButtonThrower doesn’t seem to expose a reference to a device or device-class; neither InputDevice nor InputDeviceSet seem to reference a ButtonThrower; and neither ShowBase nor InputDeviceManager seem to map one to the other, that I’ve found. Am I missing some means of doing this? :/

I’m not quite understanding the problem; couldn’t you just handle the attaching yourself by creating your own ButtonThrower whenever you want to listen for keybinds, setting its event name based on the device class, and storing it in whatever way you wish? If you wanted to, you could even create one ButtonThrower per device type and add it to multiple InputDeviceNodes at a time using add_child(), since the data graph is also a DAG, not a tree.

Ah, hmm–I wasn’t aware that it was feasible to create my own ButtonThrowers! I was looking at them as something opaquely provided by Panda. Thank you for pointing that out. :slight_smile:

Going back to my “should I attach them all?” thread, I see that what you suggested there gives me a line of investigation–I overlooked that perhaps because at the time I was concerned with whether I should (outside of key-binding) be attaching just anything, rather than with how ButtonThrowers are added.

Okay, so in that case, the new logic would likely look something like this, I think:

  • When binding keys, replicate the logic of “attachDevice”, but modified to my ends (likely with one ButtonThrower per device-type, as you suggest)
  • After binding:
    • Clean up after the above process, likely taking guidance from the logic behind “detachInputDevice”.
    • Iterate over the device-types used, and use traditional attaching to attach one device per type

All right, a follow-up question:

Would two InputDeviceNodes handling the same device come into conflict?

Right now that’s my best guess as to the source of a problem that I’m bumping into.

To explain: I’ve implemented more or less as I described above:

When I prompt the player for a key-binding, I create a set of ButtonThrowers for each device-type, a set of InputDeviceNodes for each available device (in both cases excluding mouse and keyboard), and then associate them via the “addChild” method.

As far as that goes, it works.

When I actually bind a specific key, I store the device being used for it, and attach that device using Panda’s “attachInputDevice” method.

And finally, once binding is finished, I clean up the ButtonThrowers and InputDeviceNodes that I created.

The problem is that it seems that those calls to “attachInputDevice” are somehow preventing my ButtonThrowers from producing events. As things stand, previously-bound gamepad buttons work, but attempting to bind a gamepad button doesn’t. If I comment out the call to “attachInputDevice”, the opposite is true.

I suppose that I could just keep my own InputDeviceNode, discarding only those that are unused after binding, and perhaps switch to having one ButtonThrower per device during binding (rather than one per device-type, as I do now). But that feels more awkward to manage, to me–it seems simpler to just keep binding and actual key-usage separate.

Yes, they would. You can have only one InputDeviceNode per device, but you can have multiple ButtonThrowers attached to it if you want.

Ah, I see! Thank you!

Hum… That is going to complicate things, I fear–but fair enough! At least now I know of that constraint!