showbase: make input device binding explicit, not automatic

This commit is contained in:
rdb 2018-09-16 20:22:40 +02:00
parent 8edc019307
commit 76365f3ed1

View File

@ -307,12 +307,7 @@ class ShowBase(DirectObject.DirectObject):
## This is the global input device manager, which keeps track of
## connected input devices.
self.devices = InputDeviceManager.getGlobalPtr()
# add existing devices to the data graph
for device in self.devices.devices:
self.connectDevice(device)
# Checks for device connection and disconnection
self.accept('connect-device', self.connectDevice)
self.accept('disconnect-device', self.disconnectDevice)
self.__inputDeviceNodes = {}
self.createStats()
@ -1681,76 +1676,56 @@ class ShowBase(DirectObject.DirectObject):
return self.mouseWatcherNode.getModifierButtons().isDown(
KeyboardButton.meta())
def connectDevice(self, device):
def attachInputDevice(self, device, prefix=None):
"""
This function will get called each time a new device got
connected and will add that new device to the data graph.
This function attaches an input device to the data graph, which will
cause the device to be polled and generate events. If a prefix is
given and not None, it is used to prefix events generated by this
device, separated by a hyphen.
Each device class will get a specific prefix for thrown events. Those
are currently as follow
gamepad
flight_stick
steering_wheel
dance_pad
mouse
keyboard
unclassified_device
In addition, the index of that device will appended to the prefix,
so for example if you hit the A button of the first connected gamepad
you will get an event like "gamepad0-action_a" the second gamepad will
then be catchable via "gamepad1-button_event" and so on.
Note, each device class will have a separate 0 based index, this way
you can have a gamepad0 as well as a steering_wheel0 and flight_stick0.
All newly created button throwers will be stored in
the deviceButtonThrowers lsit
If you call this, you should consider calling detachInputDevice when
you are done with the device or when it is disconnected.
"""
idn = self.dataRoot.attachNewNode(InputDeviceNode(device, device.getName()))
prefix = "unclassified_device"
if device.getDeviceClass() == InputDevice.DC_gamepad:
prefix = "gamepad"
elif device.getDeviceClass() == InputDevice.DC_flight_stick:
prefix = "flight_stick"
elif device.getDeviceClass() == InputDevice.DC_steering_wheel:
prefix = "steering_wheel"
elif device.getDeviceClass() == InputDevice.DC_dance_pad:
prefix = "dance_pad"
elif device.getDeviceClass() == InputDevice.DC_mouse:
prefix = "mouse"
elif device.getDeviceClass() == InputDevice.DC_keyboard:
prefix = "keyboard"
currentPrefixes = []
for np in self.dataRoot.findAllMatches("**/{}".format(prefix)):
bt = np.node()
currentPrefixes.append(bt.getPrefix())
# Protect against the same device being attached multiple times.
assert device not in self.__inputDeviceNodes
id = 0
# Find the next free ID for the newly connected device
while "{}{}-".format(prefix, id) in currentPrefixes:
id+=1
# Setup the button thrower for that device and register it's event prefix
bt = idn.attachNewNode(ButtonThrower(prefix))
assert self.notify.debug("Registered event prefix {}{}-".format(prefix, id))
bt.node().setPrefix("{}{}-".format(prefix, id))
# append the new button thrower to the list of device button throwers
idn = self.dataRoot.attachNewNode(InputDeviceNode(device, device.name))
# Setup the button thrower to generate events for the device.
bt = idn.attachNewNode(ButtonThrower(device.name))
if prefix is not None:
bt.node().setPrefix(prefix + '-')
assert self.notify.debug("Attached input device {0} with prefix {1}".format(device, prefix))
self.__inputDeviceNodes[device] = idn
self.deviceButtonThrowers.append(bt)
def disconnectDevice(self, device):
def detachInputDevice(self, device):
"""
This function will get called each time a new device got
connected. It is then used to clean up the given device from the
data graph.
This should be called after attaching an input device using
attachInputDevice and the device is disconnected or you no longer wish
to keep polling this device for events.
You do not strictly need to call this if you expect the device to be
reconnected (but be careful that you don't reattach it).
"""
self.notify.debug("Disconnect device {}".format(device.getName()))
idn = self.dataRoot.find("**/{}".format(device.getName()))
for bt in list(self.deviceButtonThrowers):
if bt.getName() == idn.getName():
if device not in self.__inputDeviceNodes:
assert device in self.__inputDeviceNodes
return
assert self.notify.debug("Detached device {0}".format(device.name))
# Remove the ButtonThrower from the deviceButtonThrowers list.
idn = self.__inputDeviceNodes[device]
for bt in self.deviceButtonThrowers:
if idn.isAncestorOf(bt):
self.deviceButtonThrowers.remove(bt)
break
idn.removeNode()
del self.__inputDeviceNodes[device]
def addAngularIntegrator(self):
if not self.physicsMgrAngular:
@ -1944,10 +1919,6 @@ class ShowBase(DirectObject.DirectObject):
# Check if there were newly connected devices.
self.devices.update()
# Poll all connected devices.
for device in self.devices.devices:
device.poll()
# traverse the data graph. This reads all the control
# inputs (from the mouse and keyboard, for instance) and also
# directly acts upon them (for instance, to move the avatar).
@ -3163,6 +3134,8 @@ class ShowBase(DirectObject.DirectObject):
setup_mouse = setupMouse
setup_mouse_cb = setupMouseCB
enable_software_mouse_pointer = enableSoftwareMousePointer
detach_input_device = detachInputDevice
attach_input_device = attachInputDevice
add_angular_integrator = addAngularIntegrator
enable_particles = enableParticles
disable_particles = disableParticles