from direct.showbase.DirectObject import DirectObject
class Controls(DirectObject):
"""Map hard-states to state controls and events to event controls.
To distinguish keyboard keys from dictionary keys "keyboard keys"
will be called "boardkeys" for short. Note that for our purposes
"mouse buttons" can be considered "boardkeys" as well because they
have also have an -up event after the button is released.
Control mapping has many advantages. State mappings can be queried when
needed without setting up additional listeners. Both State and
Event mappings can be changed at runtime. And both allow multiple events to
trigger a single control."""
def __init__(self,keybindings={},translation={},activate = True):
#controls is a dictionary of what control keys are currently pressed
#The keyOn/keyOff events update this, and the task queries it for input
self.controls = {}
#keybindings is a dictionary to map boardkeys to their controls.
self.stateBindings(keybindings,False)
#translation is a dictionary to map boardkey events to
#custom controls events
self.eventBindings(translation,False)
if activate:#bind controls by default
self.bindControls()
def stateBindings(self,keybindings,activate = True):
"""Setup state control dictionary.
keybindings must be a dictionary of the form:
{'control name1':['boardkey event name1',etc.],etc.} """
self.keybindings = keybindings.copy()
self.controls = {} #blank the self.conrols in preparation for re-bind
for k in self.keybindings.keys():
self.controls[k] = False
if activate:#re-bind the controls by default
self.bindControls()
def eventBindings(self,translation,activate = True):
"""Translate hard-event to event control.
translation must be a dictionary of the form:
{'control event name1':['boardkey event name1',etc.],etc.}"""
self.translation = translation.copy()
if activate:#re-bind the controls by default
self.bindControls()
def __translator(self,control,*params):
if params:
messenger.send(control,list(params))
else:
messenger.send(control)
def bindControls(self):
"""Map the controls to the boardkeys that activate them."""
self.ignoreAll()
for k,events in self.translation.items():
for v in events:
self.accept(v,self.__translator,[k,])
for control,boardkeys in self.keybindings.items():
for key in boardkeys:
self.acceptOnce(key,self.__keyOn,[control,])#no autorepeats
self.accept(key+'-up',self.__keyOff,[control,key])
def __keyOn(self,control):
self.controls[control] = True#set control to active
def __keyOff(self,control,event):
self.controls[control] = False#set control to off
self.acceptOnce(event,self.__keyOn,[control,])#listen once again
An example of how to use a controls module. You should be able to figure it out.
from controls import *
import direct.directbase.DirectStart
class World(DirectObject):
def __init__(self):
self.stateRight = {'up':['arrow_up','8',],
'down':['arrow_down','2',],'left':['arrow_left','4',],
'right':['arrow_right','6'],'fire':['space',],}
self.eventRight = {'print control states':['f1',],
'switch to left handed':['page_up','page_down']}
self.stateLeft = {'up':['w',],
'down':['s',],'left':['a',],
'right':['d'],'fire':['space',],}
self.eventLeft = {'print control states':['f12','enter'],
'switch to right handed':['2',]}
self.con = Controls(self.stateRight,self.eventRight)
self.accept('print control states',self.OnPrint)
self.accept('switch to left handed',self.OnLeft)
self.accept('switch to right handed',self.OnRight)
def OnPrint(self):
print self.con.controls
def OnLeft(self):
print 'left handed'
self.con.stateBindings(self.stateLeft,False)
self.con.eventBindings(self.eventLeft)
def OnRight(self):
print 'right handed'
self.con.eventBindings(self.eventRight,False)
self.con.stateBindings(self.stateRight)
World()
run()
Due to some changes in the way panda creates keyboard events as of 1.3.0, (As of 1.3.0 the keyboard auto-repeat sends a “-repeat” event instead of another key down event.) the script is taking some unnecessary extra steps. To fix it, change these two methods:
Omit the event parameter and the last line in __keyOff() :
def __keyOff(self,control,):
self.controls[control] = False#set control to off
Change the acceptOnce() in bindControls() to accept():
def bindControls(self):
"""Map the controls to the boardkeys that activate them."""
self.ignoreAll()
for k,events in self.translation.items():
for v in events:
self.accept(v,self.__translator,[k,])
for control,boardkeys in self.keybindings.items():
for key in boardkeys:
self.accept(key,self.__keyOn,[control,])
self.accept(key+'-up',self.__keyOff,[control,])
Note that both versions will still work in both versions of panda, but it is probably more efficient to use the correct version.