New way to run your puppets

I wish to make a keyboard user interface such that if the user presses 1 you get one action and if they press 1-1 or 1-3-4 you would get other actions. Has anyone ever done this before? Any ideas about how best to pull it off?

In my case I hope to use the number key pad for this.

It would seem to me that you would get the key down and key up or key press and then start a timer. If the timer times out then you have just the one number but if they press again before that times out then you have more than one number as your entered command. I am really unsure about how best to do this with panda3d.

Thanks for any ideas or code that references that you know of about pulling this off.


In the manual seems to be useful functions (accept, acceptOnce, repeat,…) to make such keystroke processing. I have not needed that functions much in my code and don’t know of snippets for that either (maybe this threadhelps a bit), although I think what you explain is pretty feasible.

Thanks for the links. They look good!

I have been working on this a bit and have found that I need to change the design just a little bit. I want it to work so that if a button is press for longer than a certain time then it sends the event for that set of keys. Not sure if it should place it over and over or just give a key down and key up for the group of key presses.

So for example they would press 1-5-2 and hold the 2 down. This would cause and event called 152 down to be sent and then when the 2 was released then you would get 152 up.

Does this make good sense?


I am all for ideas and improvements!!!
Some of the comments are out of date but the rest of it work.
Thanks to those that helped with this.

Updated for better use with slow typers
For this code: © 2008 Douglas E Knapp
IF you use this code, site me and tell me. If you make a profit, give me a fair share. If you improve it, tell me about the improvements. Share it with others.

import direct.directbase.DirectStart
from direct.showbase import DirectObject
from pandac.PandaModules import *
from direct.task.Timer import Timer

class ReadNumPad(DirectObject.DirectObject):
    def __init__(self, holdTime = .4, tweenWait = .5, holdUpTime = .5):
        self.holdTime = holdTime # If this time is exceded with a key in the down possition then send the string as DOWN
        self.tweenWate = tweenWait # if this time is not exceded with a key in the up possition then add to the string.
        self.holdUpTime = holdUpTime # if this time is exceded then start a new string
        self.buttonString = ''
        self.buttonDown = False # a button is pressed already
        self.startString = True # time to make a new string

        self.currenKey = ''
        #keyboard buttons
        self._buttons =['0','1','2','3','4','5','6','7','8','9']

        self._buttonTimes = dict([(x, 0) for x in self._buttons])

        for key in self._buttons:
            base.accept('time-'+key, self._downBut, [key])
            base.accept('time-'+key+'-up', self._upBut,[key])

        base.accept('123', self.helloTest)
        self.t = Timer('end')

    def _downBut(self, key, time):
        self._buttonTimes[key] = time
        if not self.buttonDown : # Only one button pressed.
            self.t.startCallback(self.holdTime, self.stringDown) # Start the DownTimer. to see if we are to send a string down message
            if self.startString : # new string
                self.buttonDown = True
                self.startString = False
                self.buttonString = key
            else :
                # of a new string or we are within tweentime :
                self.buttonString += key
                self.buttonDown = True
        # If DownTimer runs out then string down is sent and repeat timer is started.

    def _upBut(self, key, time):
        held_time = time - self._buttonTimes[key]
        print 'up', held_time, key
        if held_time < self.tweenWate :
            self.t.startCallback(self.holdUpTime, self.stringUp) # must wait to see if this is end of adding, long pause
        else :
        # If the DownTimers has not run out then add this key to the string and stop the timer.
        # If the down timer has run out then this is a string key up event.

    def stringAdd(self):
        self.startString = False
        self.buttonDown = False

    def stringUp(self):
        messenger.send(self.buttonString + '-up')
        self.buttonDown = False
        self.startString = True
        print '--StringUp', self.buttonString

    def stringDown(self):
        print '--StringDown', self.buttonString
        self.buttonDown = True
        self.startString = True

        # what happens if 2 keys are down? But they never are together on the keypad.

    def helloTest(self):
        print 'helloTest'

# if you can't seem to get the keypad to work with your typing, change these numbers.
h = ReadNumPad(.4, .6, .6)


Hmm, I’m not very familiar with events, maybe you can do it that way if you work it, nevertheless if you have difficulties with that I think it could also be done with alternative approaches like a queue of keys or with a finite state machine.

Edit: Wow almost simultaneous posts, happy for you to get it working

Events are an ideal way to do it. The code only runs if someone types a number. When they type a set of numbers in generates a new event named by that group of numbers. You can see in this code the place where it calls helloTest if you type 123 and hold the 3 down. In normal language events are just interrupts.