Merge pull request #1335 from sahilmakhijani/master

Refactored Event Handling Mechanism
This commit is contained in:
Grant Sanderson
2021-02-02 09:57:55 -08:00
committed by GitHub
7 changed files with 258 additions and 111 deletions

View File

@ -0,0 +1,6 @@
from manimlib.event_handler.event_dispatcher import EventDispatcher
# This is supposed to be a Singleton
# i.e., during runtime there should be only one object of Event Dispatcher
EVENT_DISPATCHER = EventDispatcher()

View File

@ -0,0 +1,92 @@
import numpy as np
from manimlib.event_handler.event_type import EventType
from manimlib.event_handler.event_listner import EventListner
class EventDispatcher(object):
def __init__(self):
self.event_listners = {
event_type: []
for event_type in EventType
}
self.mouse_point = np.array((0., 0., 0.))
self.mouse_drag_point = np.array((0., 0., 0.))
self.pressed_keys = set()
self.draggable_object_listners = []
def add_listner(self, event_listner):
assert(isinstance(event_listner, EventListner))
self.event_listners[event_listner.event_type].append(event_listner)
return self
def remove_listner(self, event_listner):
assert(isinstance(event_listner, EventListner))
try:
while event_listner in self.event_listners[event_listner.event_type]:
self.event_listners[event_listner.event_type].remove(event_listner)
except:
# raise ValueError("Handler is not handling this event, so cannot remove it.")
pass
return self
def dispatch(self, event_type, **event_data):
if event_type == EventType.MouseMotionEvent:
self.mouse_point = event_data["point"]
elif event_type == EventType.MouseDragEvent:
self.mouse_drag_point = event_data["point"]
elif event_type == EventType.KeyPressEvent:
self.pressed_keys.add(event_data["symbol"]) # Modifiers?
elif event_type == EventType.KeyReleaseEvent:
self.pressed_keys.difference_update({event_data["symbol"]}) # Modifiers?
elif event_type == EventType.MousePressEvent:
self.draggable_object_listners = [
listner
for listner in self.event_listners[EventType.MouseDragEvent]
if listner.mobject.is_point_touching(self.mouse_point)
]
elif event_type == EventType.MouseReleaseEvent:
self.draggable_object_listners = []
propagate_event = None
if event_type == EventType.MouseDragEvent:
for listner in self.draggable_object_listners:
assert(isinstance(listner, EventListner))
propagate_event = listner.callback(listner.mobject, event_data)
if propagate_event is not None and propagate_event is False:
return propagate_event
elif event_type.value.startswith('mouse'):
for listner in self.event_listners[event_type]:
if listner.mobject.is_point_touching(self.mouse_point):
propagate_event = listner.callback(
listner.mobject, event_data)
if propagate_event is not None and propagate_event is False:
return propagate_event
elif event_type.value.startswith('key'):
for listner in self.event_listners[event_type]:
propagate_event = listner.callback(listner.mobject, event_data)
if propagate_event is not None and propagate_event is False:
return propagate_event
return propagate_event
def get_listners_count(self):
return sum([len(value) for key, value in self.event_listners.items()])
def get_mouse_point(self):
return self.mouse_point
def get_mouse_drag_point(self):
return self.mouse_drag_point
def is_key_pressed(self, symbol):
return (symbol in self.pressed_keys)
__iadd__ = add_listner
__isub__ = remove_listner
__call__ = dispatch
__len__ = get_listners_count

View File

@ -0,0 +1,15 @@
class EventListner(object):
def __init__(self, mobject, event_type, event_callback):
self.mobject = mobject
self.event_type = event_type
self.callback = event_callback
def __eq__(self, o: object) -> bool:
return_val = False
try:
return_val = self.callback == o.callback \
and self.mobject == o.mobject \
and self.event_type == o.event_type
except:
pass
return return_val

View File

@ -0,0 +1,11 @@
from enum import Enum
class EventType(Enum):
MouseMotionEvent = 'mouse_motion_event'
MousePressEvent = 'mouse_press_event'
MouseReleaseEvent = 'mouse_release_event'
MouseDragEvent = 'mouse_drag_event'
MouseScrollEvent = 'mouse_scroll_event'
KeyPressEvent = 'key_press_event'
KeyReleaseEvent = 'key_release_event'

View File

@ -26,42 +26,39 @@ class MotionMobject(Mobject):
super().__init__(**kwargs) super().__init__(**kwargs)
assert(isinstance(mobject, Mobject)) assert(isinstance(mobject, Mobject))
self.mobject = mobject self.mobject = mobject
self.mobject.listen_to_events = True self.mobject.add_mouse_drag_listner(self.mob_on_mouse_drag)
self.mobject.on_mouse_drag = self.mob_on_mouse_drag
# To avoid locking it as static mobject # To avoid locking it as static mobject
self.mobject.add_updater(lambda mob: None) self.mobject.add_updater(lambda mob: None)
self.add(mobject) self.add(mobject)
def mob_on_mouse_drag(self, point, d_point, buttons, modifiers): def mob_on_mouse_drag(self, mob, event_data):
self.mobject.move_to(point) mob.move_to(event_data["point"])
return False return False
class Button(Mobject): class Button(Mobject):
""" """
Pass any mobject and register an on_click method Pass any mobject and register an on_click method
The on_click method takes mobject as argument like updater
""" """
def __init__(self, mobject, on_click, **kwargs): def __init__(self, mobject, on_click, **kwargs):
super().__init__(**kwargs) super().__init__(**kwargs)
assert(isinstance(mobject, Mobject))
self.on_click = on_click self.on_click = on_click
self.mobject = mobject self.mobject = mobject
self.mobject.listen_to_events = True self.mobject.add_mouse_press_listner(self.mob_on_mouse_press)
self.mobject.on_mouse_press = self.mob_on_mouse_press
self.add(self.mobject) self.add(self.mobject)
def mob_on_mouse_press(self, point, button, mods): def mob_on_mouse_press(self, mob, event_data):
self.on_click() self.on_click(mob)
return False return False
# Controls # Controls
class ControlMobject(ValueTracker): class ControlMobject(ValueTracker):
CONFIG = {
"listen_to_events": True
}
def __init__(self, value, *mobjects, **kwargs): def __init__(self, value, *mobjects, **kwargs):
super().__init__(value=value, **kwargs) super().__init__(value=value, **kwargs)
self.add(*mobjects) self.add(*mobjects)
@ -100,6 +97,7 @@ class EnableDisableButton(ControlMobject):
digest_config(self, kwargs) digest_config(self, kwargs)
self.box = Rectangle(**self.rect_kwargs) self.box = Rectangle(**self.rect_kwargs)
super().__init__(value, self.box, **kwargs) super().__init__(value, self.box, **kwargs)
self.add_mouse_press_listner(self.on_mouse_press)
def assert_value(self, value): def assert_value(self, value):
assert(isinstance(value, bool)) assert(isinstance(value, bool))
@ -113,8 +111,8 @@ class EnableDisableButton(ControlMobject):
def toggle_value(self): def toggle_value(self):
super().set_value(not self.get_value()) super().set_value(not self.get_value())
def on_mouse_press(self, point, button, mods): def on_mouse_press(self, mob, event_data):
self.toggle_value() mob.toggle_value()
return False return False
@ -143,6 +141,7 @@ class Checkbox(ControlMobject):
self.box = Rectangle(**self.rect_kwargs) self.box = Rectangle(**self.rect_kwargs)
self.box_content = self.get_checkmark() if value else self.get_cross() self.box_content = self.get_checkmark() if value else self.get_cross()
super().__init__(value, self.box, self.box_content, **kwargs) super().__init__(value, self.box, self.box_content, **kwargs)
self.add_mouse_press_listner(self.on_mouse_press)
def assert_value(self, value): def assert_value(self, value):
assert(isinstance(value, bool)) assert(isinstance(value, bool))
@ -156,8 +155,8 @@ class Checkbox(ControlMobject):
else: else:
self.box_content.become(self.get_cross()) self.box_content.become(self.get_cross())
def on_mouse_press(self, point, button, mods): def on_mouse_press(self, mob, event_data):
self.toggle_value() mob.toggle_value()
return False return False
# Helper methods # Helper methods
@ -189,9 +188,6 @@ class Checkbox(ControlMobject):
class LinearNumberSlider(ControlMobject): class LinearNumberSlider(ControlMobject):
CONFIG = { CONFIG = {
# Since, only slider circle listnes to drag event
"listen_to_events": False,
"value_type": np.float64, "value_type": np.float64,
"min_value": -10.0, "min_value": -10.0,
"max_value": 10.0, "max_value": 10.0,
@ -221,8 +217,7 @@ class LinearNumberSlider(ControlMobject):
self.slider_axis.set_opacity(0.0) self.slider_axis.set_opacity(0.0)
self.slider.move_to(self.slider_axis) self.slider.move_to(self.slider_axis)
self.slider.listen_to_events = True self.slider.add_mouse_drag_listner(self.slider_on_mouse_drag)
self.slider.on_mouse_drag = self.slider_on_mouse_drag
super().__init__(value, self.bar, self.slider, self.slider_axis, ** kwargs) super().__init__(value, self.bar, self.slider, self.slider_axis, ** kwargs)
@ -233,8 +228,8 @@ class LinearNumberSlider(ControlMobject):
prop = (value - self.min_value) / (self.max_value - self.min_value) prop = (value - self.min_value) / (self.max_value - self.min_value)
self.slider.move_to(self.slider_axis.point_from_proportion(prop)) self.slider.move_to(self.slider_axis.point_from_proportion(prop))
def slider_on_mouse_drag(self, point, d_point, buttons, modifiers): def slider_on_mouse_drag(self, mob, event_data):
self.set_value(self.get_value_from_point(point)) self.set_value(self.get_value_from_point(event_data["point"]))
return False return False
# Helper Methods # Helper Methods
@ -372,12 +367,12 @@ class Textbox(ControlMobject):
digest_config(self, kwargs) digest_config(self, kwargs)
self.isActive = self.isInitiallyActive self.isActive = self.isInitiallyActive
self.box = Rectangle(**self.box_kwargs) self.box = Rectangle(**self.box_kwargs)
self.box.listen_to_events = True self.box.add_mouse_press_listner(self.box_on_mouse_press)
self.box.on_mouse_press = self.box_on_mouse_press
self.text = Text(value, **self.text_kwargs) self.text = Text(value, **self.text_kwargs)
super().__init__(value, self.box, self.text, **kwargs) super().__init__(value, self.box, self.text, **kwargs)
self.update_text(value) self.update_text(value)
self.active_anim(self.isActive) self.active_anim(self.isActive)
self.add_key_press_listner(self.on_key_press)
def set_value_anim(self, value): def set_value_anim(self, value):
self.update_text(value) self.update_text(value)
@ -400,15 +395,17 @@ class Textbox(ControlMobject):
else: else:
self.box.set_stroke(self.deactive_color) self.box.set_stroke(self.deactive_color)
def box_on_mouse_press(self, point, button, mods): def box_on_mouse_press(self, mob, event_data):
self.isActive = not self.isActive self.isActive = not self.isActive
self.active_anim(self.isActive) self.active_anim(self.isActive)
return False return False
def on_key_press(self, symbol, modifiers): def on_key_press(self, mob, event_data):
symbol = event_data["symbol"]
modifiers = event_data["modifiers"]
char = chr(symbol) char = chr(symbol)
if self.isActive: if mob.isActive:
old_value = self.get_value() old_value = mob.get_value()
new_value = old_value new_value = old_value
if char.isalnum(): if char.isalnum():
if (modifiers & PygletWindowKeys.MOD_SHIFT) or (modifiers & PygletWindowKeys.MOD_CAPSLOCK): if (modifiers & PygletWindowKeys.MOD_SHIFT) or (modifiers & PygletWindowKeys.MOD_CAPSLOCK):
@ -421,7 +418,7 @@ class Textbox(ControlMobject):
new_value = old_value + '\t' new_value = old_value + '\t'
elif symbol == PygletWindowKeys.BACKSPACE: elif symbol == PygletWindowKeys.BACKSPACE:
new_value = old_value[:-1] or '' new_value = old_value[:-1] or ''
self.set_value(new_value) mob.set_value(new_value)
return False return False
@ -452,8 +449,7 @@ class ControlPanel(Group):
self.panel = Rectangle(**self.panel_kwargs) self.panel = Rectangle(**self.panel_kwargs)
self.panel.to_corner(UP + LEFT, buff=0) self.panel.to_corner(UP + LEFT, buff=0)
self.panel.shift(self.panel.get_height() * UP) self.panel.shift(self.panel.get_height() * UP)
self.panel.listen_to_events = True self.panel.add_mouse_scroll_listner(self.panel_on_mouse_scroll)
self.panel.on_mouse_scroll = self.panel_on_mouse_scroll
self.panel_opener_rect = Rectangle(**self.opener_kwargs) self.panel_opener_rect = Rectangle(**self.opener_kwargs)
self.panel_info_text = Text(**self.opener_text_kwargs) self.panel_info_text = Text(**self.opener_text_kwargs)
@ -461,8 +457,7 @@ class ControlPanel(Group):
self.panel_opener = Group(self.panel_opener_rect, self.panel_info_text) self.panel_opener = Group(self.panel_opener_rect, self.panel_info_text)
self.panel_opener.next_to(self.panel, DOWN, aligned_edge=DOWN) self.panel_opener.next_to(self.panel, DOWN, aligned_edge=DOWN)
self.panel_opener.listen_to_events = True self.panel_opener.add_mouse_drag_listner(self.panel_opener_on_mouse_drag)
self.panel_opener.on_mouse_drag = self.panel_opener_on_mouse_drag
self.controls = Group(*controls) self.controls = Group(*controls)
self.controls.arrange(DOWN, center=False, aligned_edge=ORIGIN) self.controls.arrange(DOWN, center=False, aligned_edge=ORIGIN)
@ -515,12 +510,14 @@ class ControlPanel(Group):
self.move_panel_and_controls_to_panel_opener() self.move_panel_and_controls_to_panel_opener()
return self return self
def panel_opener_on_mouse_drag(self, point, d_point, buttons, modifiers): def panel_opener_on_mouse_drag(self, mob, event_data):
point = event_data["point"]
self.panel_opener.match_y(Dot(point)) self.panel_opener.match_y(Dot(point))
self.move_panel_and_controls_to_panel_opener() self.move_panel_and_controls_to_panel_opener()
return False return False
def panel_on_mouse_scroll(self, point, offset): def panel_on_mouse_scroll(self, mob, event_data):
offset = event_data["offset"]
factor = 10 * offset[1] factor = 10 * offset[1]
self.controls.set_y(self.controls.get_y() + factor) self.controls.set_y(self.controls.get_y() + factor)
return False return False

View File

@ -27,6 +27,9 @@ from manimlib.utils.space_ops import get_norm
from manimlib.utils.space_ops import rotation_matrix_transpose from manimlib.utils.space_ops import rotation_matrix_transpose
from manimlib.shader_wrapper import ShaderWrapper from manimlib.shader_wrapper import ShaderWrapper
from manimlib.shader_wrapper import get_colormap_code from manimlib.shader_wrapper import get_colormap_code
from manimlib.event_handler import EVENT_DISPATCHER
from manimlib.event_handler.event_listner import EventListner
from manimlib.event_handler.event_type import EventType
class Mobject(object): class Mobject(object):
@ -68,6 +71,7 @@ class Mobject(object):
self.init_data() self.init_data()
self.init_uniforms() self.init_uniforms()
self.init_updaters() self.init_updaters()
self.init_event_listners()
self.init_points() self.init_points()
self.init_colors() self.init_colors()
self.init_shader_data() self.init_shader_data()
@ -1440,35 +1444,81 @@ class Mobject(object):
Event handling follows the Event Bubbling model of DOM in javascript. Event handling follows the Event Bubbling model of DOM in javascript.
Return false to stop the event bubbling. Return false to stop the event bubbling.
To learn more visit https://www.quirksmode.org/js/events_order.html To learn more visit https://www.quirksmode.org/js/events_order.html
Event Callback Argument is a callable function taking two arguments:
1. Mobject
2. EventData
""" """
def on_mouse_motion(self, point, d_point): def init_event_listners(self):
# To be implemented in subclasses self.event_listners = []
pass
def on_mouse_drag(self, point, d_point, buttons, modifiers): def add_event_listner(self, event_type, event_callback):
# To be implemented in subclasses event_listner = EventListner(self, event_type, event_callback)
pass self.event_listners.append(event_listner)
EVENT_DISPATCHER.add_listner(event_listner)
return self
def on_mouse_press(self, point, button, mods): def remove_event_listner(self, event_type, event_callback):
# To be implemented in subclasses event_listner = EventListner(self, event_type, event_callback)
pass while event_listner in self.event_listners:
self.event_listners.remove(event_listner)
EVENT_DISPATCHER.remove_listner(event_listner)
return self
def on_mouse_release(self, point, button, mods): def clear_event_listners(self, recurse=True):
# To be implemented in subclasses self.event_listners = []
pass if recurse:
for submob in self.submobjects:
submob.clear_event_listners(recurse=recurse)
return self
def on_mouse_scroll(self, point, offset): def get_event_listners(self):
# To be implemented in subclasses return self.event_listners
pass
def on_key_release(self, symbol, modifiers): def get_family_event_listners(self):
# To be implemented in subclasses return list(it.chain(*[sm.get_event_listners() for sm in self.get_family()]))
pass
def on_key_press(self, symbol, modifiers): def get_has_event_listner(self):
# To be implemented in subclasses return any(
pass mob.get_event_listners()
for mob in self.get_family()
)
def add_mouse_motion_listner(self, callback):
self.add_event_listner(EventType.MouseMotionEvent, callback)
def remove_mouse_motion_listner(self, callback):
self.remove_event_listner(EventType.MouseMotionEvent, callback)
def add_mouse_press_listner(self, callback):
self.add_event_listner(EventType.MousePressEvent, callback)
def remove_mouse_press_listner(self, callback):
self.remove_event_listner(EventType.MousePressEvent, callback)
def add_mouse_release_listner(self, callback):
self.add_event_listner(EventType.MouseReleaseEvent, callback)
def remove_mouse_release_listner(self, callback):
self.remove_event_listner(EventType.MouseReleaseEvent, callback)
def add_mouse_drag_listner(self, callback):
self.add_event_listner(EventType.MouseDragEvent, callback)
def remove_mouse_drag_listner(self, callback):
self.remove_event_listner(EventType.MouseDragEvent, callback)
def add_mouse_scroll_listner(self, callback):
self.add_event_listner(EventType.MouseScrollEvent, callback)
def remove_mouse_scroll_listner(self, callback):
self.remove_event_listner(EventType.MouseScrollEvent, callback)
def add_key_press_listner(self, callback):
self.add_event_listner(EventType.KeyPressEvent, callback)
def remove_key_press_listner(self, callback):
self.remove_event_listner(EventType.KeyPressEvent, callback)
def add_key_release_listner(self, callback):
self.add_event_listner(EventType.KeyReleaseEvent, callback)
def remove_key_release_listner(self, callback):
self.remove_event_listner(EventType.KeyReleaseEvent, callback)
# Errors # Errors

View File

@ -19,6 +19,8 @@ from manimlib.scene.scene_file_writer import SceneFileWriter
from manimlib.utils.config_ops import digest_config from manimlib.utils.config_ops import digest_config
from manimlib.utils.family_ops import extract_mobject_family_members from manimlib.utils.family_ops import extract_mobject_family_members
from manimlib.utils.family_ops import restructure_list_to_exclude_certain_family_members from manimlib.utils.family_ops import restructure_list_to_exclude_certain_family_members
from manimlib.event_handler.event_type import EventType
from manimlib.event_handler import EVENT_DISPATCHER
from manimlib.window import Window from manimlib.window import Window
@ -58,9 +60,6 @@ class Scene(object):
self.mouse_point = Point() self.mouse_point = Point()
self.mouse_drag_point = Point() self.mouse_drag_point = Point()
self.mob_listners = []
self.mobjects_to_drag = []
# Much nicer to work with deterministic scenes # Much nicer to work with deterministic scenes
if self.random_seed is not None: if self.random_seed is not None:
random.seed(self.random_seed) random.seed(self.random_seed)
@ -208,9 +207,6 @@ class Scene(object):
""" """
self.remove(*new_mobjects) self.remove(*new_mobjects)
self.mobjects += new_mobjects self.mobjects += new_mobjects
for new_mob in new_mobjects:
for mob_listner in filter(lambda mob: mob.listen_to_events, reversed(new_mob.get_family())):
self.mob_listners.insert(0, mob_listner)
return self return self
def add_mobjects_among(self, values): def add_mobjects_among(self, values):
@ -238,9 +234,6 @@ class Scene(object):
def bring_to_back(self, *mobjects): def bring_to_back(self, *mobjects):
self.remove(*mobjects) self.remove(*mobjects)
self.mobjects = list(mobjects) + self.mobjects self.mobjects = list(mobjects) + self.mobjects
for new_mob in reversed(mobjects):
for mob_listner in filter(lambda mob: mob.listen_to_events, reversed(new_mob.get_family())):
self.mob_listners.append(mob_listner)
return self return self
def clear(self): def clear(self):
@ -522,20 +515,12 @@ class Scene(object):
self.mobjects = mobjects self.mobjects = mobjects
# Event handling # Event handling
def get_event_listeners_mobjects(self):
"""
This method returns all the mobjects that listen to events
in reversed order. So the top most mobject's event is called first.
This helps in event bubbling.
"""
return self.mob_listners
def on_mouse_motion(self, point, d_point): def on_mouse_motion(self, point, d_point):
self.mouse_point.move_to(point) self.mouse_point.move_to(point)
for mob_listener in self.get_event_listeners_mobjects(): event_data = {"point": point, "d_point": d_point}
if mob_listener.is_point_touching(point): propagate_event = EVENT_DISPATCHER.dispatch(EventType.MouseMotionEvent, **event_data)
propagate_event = mob_listener.on_mouse_motion(point, d_point)
if propagate_event is not None and propagate_event is False: if propagate_event is not None and propagate_event is False:
return return
@ -554,35 +539,26 @@ class Scene(object):
def on_mouse_drag(self, point, d_point, buttons, modifiers): def on_mouse_drag(self, point, d_point, buttons, modifiers):
self.mouse_drag_point.move_to(point) self.mouse_drag_point.move_to(point)
for mob_listener in self.mobjects_to_drag: event_data = {"point": point, "d_point": d_point, "buttons": buttons, "modifiers": modifiers}
propagate_event = mob_listener.on_mouse_drag(point, d_point, buttons, modifiers) propagate_event = EVENT_DISPATCHER.dispatch(EventType.MouseDragEvent, **event_data)
if propagate_event is not None and propagate_event is False: if propagate_event is not None and propagate_event is False:
return return
def on_mouse_press(self, point, button, mods): def on_mouse_press(self, point, button, mods):
for mob_listener in self.get_event_listeners_mobjects(): event_data = {"point": point, "button": button, "mods": mods}
if mob_listener.is_point_touching(point): propagate_event = EVENT_DISPATCHER.dispatch(EventType.MousePressEvent, **event_data)
self.mobjects_to_drag.append(mob_listener)
for mob_listener in self.get_event_listeners_mobjects():
if mob_listener.is_point_touching(point):
propagate_event = mob_listener.on_mouse_press(point, button, mods)
if propagate_event is not None and propagate_event is False: if propagate_event is not None and propagate_event is False:
return return
def on_mouse_release(self, point, button, mods): def on_mouse_release(self, point, button, mods):
self.mobjects_to_drag = [] event_data = {"point": point, "button": button, "mods": mods}
propagate_event = EVENT_DISPATCHER.dispatch(EventType.MouseReleaseEvent, **event_data)
for mob_listener in self.get_event_listeners_mobjects():
if mob_listener.is_point_touching(point):
propagate_event = mob_listener.on_mouse_release(point, button, mods)
if propagate_event is not None and propagate_event is False: if propagate_event is not None and propagate_event is False:
return return
def on_mouse_scroll(self, point, offset): def on_mouse_scroll(self, point, offset):
for mob_listener in self.get_event_listeners_mobjects(): event_data = {"point": point, "offset": offset}
if mob_listener.is_point_touching(point): propagate_event = EVENT_DISPATCHER.dispatch(EventType.MouseScrollEvent, **event_data)
propagate_event = mob_listener.on_mouse_scroll(point, offset)
if propagate_event is not None and propagate_event is False: if propagate_event is not None and propagate_event is False:
return return
@ -596,8 +572,8 @@ class Scene(object):
frame.shift(-20.0 * shift) frame.shift(-20.0 * shift)
def on_key_release(self, symbol, modifiers): def on_key_release(self, symbol, modifiers):
for mob_listener in self.get_event_listeners_mobjects(): event_data = {"symbol": symbol, "modifiers": modifiers}
propagate_event = mob_listener.on_key_release(symbol, modifiers) propagate_event = EVENT_DISPATCHER.dispatch(EventType.KeyReleaseEvent, **event_data)
if propagate_event is not None and propagate_event is False: if propagate_event is not None and propagate_event is False:
return return
@ -608,8 +584,8 @@ class Scene(object):
print(" Warning: The value of the pressed key is too large.") print(" Warning: The value of the pressed key is too large.")
return return
for mob_listener in self.get_event_listeners_mobjects(): event_data = {"symbol": symbol, "modifiers": modifiers}
propagate_event = mob_listener.on_key_press(symbol, modifiers) propagate_event = EVENT_DISPATCHER.dispatch(EventType.KeyPressEvent, **event_data)
if propagate_event is not None and propagate_event is False: if propagate_event is not None and propagate_event is False:
return return