keystate change checker ineffective

I put together this class based on another I found on the forum:

class kbdInput(DirectObject):
    def __init__(self, desiredInkeys):
        self.keysDown=[]
        self.keys=desiredInkeys
        self.keyChange=False
        taskMgr.add(self.checkGameKeys, 'check keys')
        
    def checkGameKeys(self,ok):
        self.keyChange=False
        
        def down(key):
            self.keysDown.append(key)
            self.keyChange=True
   
        def up(key):
            self.keyChange=True
            try: self.keysDown.remove(key)
            except: pass
            
        for key in self.keys:
            
            self.accept(key, down, [key])
            self.accept(('%s-up' % key), up, [key])

        return Task.cont

    def getPressed(self): return self.keysDown
    def checkKeyChange(self): return self.keyChange

getPressed works perfectly, and always gives me the current set of keys that are pressed. However, checkKeyChange detects a keystate change only about half the time. Can anyone tell me what is wrong with my implementation that makes it so buggy? Thanks!

depending on how often you are checking keyChange. It is reset to false every time a frame renders. If you don’t check it every frame, you can miss it. keyChange will only be true for 1 frame, then the event handler retriggers checkGameKeys, which sets it false again.

Verify that your check is happening every frame.

The check happens in a Task, so it must happen every frame, right?. How can I ensure the state change checker task happens before the keystate function above resets itself to False ? I read that all tasks are in one thread, so I guess the task completion order is ambiguous. I think this is why the state change checker only works sometimes. Is there a way to control this, or do I have to try another implementation?

If you are absolutely certain that you check it every frame, you can do this:

  1. remove self.keChange=False from the checkGameKeys function.

  2. change checkKeyChange to:


def checkKeyChange(self):
   if (self.keyChange):
      self.keyChange = False
      return True

   else:

      Return False

In real life, I write software that controls manufacturing equipment, and this type of interlock is used quite frequently to make sure that a handshake is not missed. The only caveat is that if checkKeyChange does not run as frequently as checkGameKeys, it could miss an update. On the other hand, if you use checkGameKeys to process any and all changes, even if there is more than one, then it doesn’t matter anyway.

Hope this helps!

YES!!! Thank you sooooo much! That is really smart! It works perfectly, and it’s a great way to go about it. I’ve never heard of handshakes before. I can implement that in a bunch of different functions. You’re the best, and here is the code, which is now a really great keychecker!:

class kbdInput(DirectObject):
    def __init__(self, desiredInkeys):
        self.keysDown=[]
        self.keys=desiredInkeys
        self.keyChange=False
        taskMgr.add(self.checkGameKeys, 'check keys')
        
    def checkGameKeys(self,ok):
        def down(key):
            self.keyChange=True
            self.keysDown.append(key)
            
        def up(key):
            self.keyChange=True
            try: self.keysDown.remove(key)
            except: pass
            
        for key in self.keys:
            self.accept(key, down, [key])
            self.accept(('%s-up' % key), up, [key])
        return Task.cont

    def getPressed(self): return self.keysDown
    #Tutunkommon
    def checkKeyChange(self): 
        if (self.keyChange):
            self.keyChange=False
            return True
        else:
            return False