Wait for keyboard event

ok i have this question

I need to wait for a keyboard event, any key… then i need to get the key the user pressed how can i do that? (the use of tasks would be apreciated)

example:

–Press a key to assign the forward action—
user presses w*

You have to get used to the idea of event-based programming. In Panda, as well as with most any graphical-based toolkit, you don’t write programs as a set of linear steps that involve waiting for the user in between each step. Instead, you write programs as a set of event handlers that respond to events generated by the user (or other sources).

In this case, take the code that you want to execute when the user presses the ‘w’ key. Put this code in its own method. Then call:

self.accept('w', self.myMethod)

The above is correct syntax when ‘self’ refers to a class that inherits from DirectObject. If you haven’t inherited from DirectObject, or you haven’t read that part of the manual yet, then you can use base instead, which is also a DirectObject:

base.accept('w', myFunction)

Though since here you want to respond to any key, and not just ‘w’, you need to tell Panda that you want to get a callback when any key is pressed:

base.buttonThrowers[0].node().setButtonDownEvent('button')
base.accept('button', myFunction)

And your myFunction will receive one parameter, which will be the button name pressed.

David

ty very much :slight_smile:

drwr:

afaik there is the “button” and the “button-up” event, also a “button-repeat” but the latest is delayed by the os-keyboard-repeat timeout.

wouldnt it make sense to add a “button-pressed” event, which fires every frame as long as a key is pressed, or would this generate a large burden onto the event system?

i know there are pretty easy ways store the button presses into a dict and read from that one, however i think this method would be more consistent.

Hmm, maybe. I can see how that might be convenient in certain cases.

David

Most other engines I have worked with supply either bit flags or events for the button_down, button_just_down, button_up, button_just_up events. Panda only handles “button” and “button_up”.

I find myself needing button_down a lot, so I am having to store a boolean, setting it to true on “button”, and setting it to false on “button_up” to simulate the button_down events. Then each update I check that boolean to see if the button is still being held.

recently i was thinking about what would be better for calling interaction functions, events, a dict of initialized actions or maybe even something else.

example: space is for shooting (all examples are very simplified btw. you shouldn’t write it exactly like that)
would you rather send an event ‘shoot’ at ‘space’,

base.accept("space", messenger.send, ["shoot"])
(...)
base.accept("shoot", shootingFunction)

store the request in a dict

def setKey(key, value):
    actions_dict[key] = value

base.accept("space", setKey, ["shoot", true])
base.accept("space-up", setKey, ["shoot", false])

def doActions(Task):
    if actions_dict[shoot]:
        shoot()

or just call the function?

base.accept("space", shootingFunction)
  • at the frist look the last method looks simpliest, but it’s also the least flexible.

  • the first one is better because events are shared along all your modules, so you won’t need to import anything, but only watch for the events whereever you want. dark side: it creates a mass of events in more complicated cases and may be hard to debug. overriding panda internal events also may complicate it.

  • the second example is used in the roaming ralph sample. it’s very easy to work with and it’s quite flexible as you can import the actions_dict and look it up anywhere.

my personal favor is a system of events, which you could even divide in sections (events can come with parameters), but the imho best solution would be to temporarily remap the panda internal key-event emitters to your desired actions, so that you don’t have a ‘space’ event but only a ‘shoot’ event. i think that would also decimate any performance problems with events (can they become a bottleneck? -i dunno). so… is there a method to do this or if not, what method would you choose and why?

edit: typo

my idea was to make it easier to create a permanent character controlling system. for example when i do a classical “wasd” movement, i have to remember the pressed keys into a dict:

# this should work, but i didnt check it
keymappings = {
  'a': Vec3(1,0,0),
  'd': Vec3(-1,0,0),
  'w': Vec3(0,1,0),
  's': Vec3(0,-1,0),
}

pressedKeys = dict()

def keypress(key, active):
  pressedKeys[key] = active

for key, action in keymappings.items():
  base.accept(key, [True])
  base.accept(key+"-up", [False])

def moveTask(task):
  for key, active in pressedKeys.items():
    if active:
      base.camera.setPos(base.camera, keymappings[key]*globalClock.getDt())
  return task.cont

if there would be a “pressed” event this would be simpler.

keymappings = {
  'a': Vec3(1,0,0),
  'd': Vec3(-1,0,0),
  'w': Vec3(0,1,0),
  's': Vec3(0,-1,0),
}

for key, moveVec in keymappings.items():
  base.accept(key, base.camera.setPos, [base.camera, moveVec/60.])

while the later isnt really a good example, because it’s not using the frameTime anymore, it would make it easier to write quick samples.

@Hypnos:
erm… this is actually the same as my 2nd method. the question is: is it really the best way? (and yeah, i know there is no ‘best’. call it ‘most effective’ or ‘preferable’ or whatever)