diff --git a/src/textual/app.py b/src/textual/app.py index ed22f3c54..2ada12f61 100644 --- a/src/textual/app.py +++ b/src/textual/app.py @@ -196,7 +196,7 @@ class App(Generic[ReturnType], DOMNode): self._logger = Logger(self._log) - self._bindings.bind("ctrl+c", "quit", show=False, allow_forward=False) + self._bindings.bind("ctrl+c", "quit", show=False, universal=True) self._refresh_required = False self.design = DEFAULT_COLORS @@ -1282,11 +1282,12 @@ class App(Generic[ReturnType], DOMNode): namespace_bindings = [(node, node._bindings) for node in focused.ancestors] return namespace_bindings - async def check_bindings(self, key: str) -> bool: + async def check_bindings(self, key: str, universal: bool = False) -> bool: """Handle a key press. Args: key (str): A key + universal (bool): Check universal keys if True, otherwise non-universal keys. Returns: bool: True if the key was handled by a binding, otherwise False @@ -1294,7 +1295,7 @@ class App(Generic[ReturnType], DOMNode): for namespace, bindings in self._binding_chain: binding = bindings.keys.get(key) - if binding is not None: + if binding is not None and binding.universal == universal: await self.action(binding.action, default_namespace=namespace) return True return False @@ -1312,11 +1313,11 @@ class App(Generic[ReturnType], DOMNode): if isinstance(event, events.MouseEvent): # Record current mouse position on App self.mouse_position = Offset(event.x, event.y) - if isinstance(event, events.Key): - forward_target = self.focused or self.screen - await forward_target._forward_event(event) - else: await self.screen._forward_event(event) + elif isinstance(event, events.Key): + if not await self.check_bindings(event.key, universal=True): + forward_target = self.focused or self.screen + await forward_target._forward_event(event) elif isinstance(event, events.Paste): if self.focused is not None: diff --git a/src/textual/binding.py b/src/textual/binding.py index 498201c76..39984f517 100644 --- a/src/textual/binding.py +++ b/src/textual/binding.py @@ -34,7 +34,7 @@ class Binding: """Show the action in Footer, or False to hide.""" key_display: str | None = None """How the key should be shown in footer.""" - allow_forward: bool = True + universal: bool = False """Allow forwarding from app to focused widget.""" @@ -55,7 +55,7 @@ class Bindings: description=binding.description, show=binding.show, key_display=binding.key_display, - allow_forward=binding.allow_forward, + universal=binding.universal, ) yield new_binding else: @@ -103,7 +103,7 @@ class Bindings: description: str = "", show: bool = True, key_display: str | None = None, - allow_forward: bool = True, + universal: bool = False, ) -> None: all_keys = [key.strip() for key in keys.split(",")] for key in all_keys: @@ -113,7 +113,7 @@ class Bindings: description, show=show, key_display=key_display, - allow_forward=allow_forward, + universal=universal, ) def get_key(self, key: str) -> Binding: @@ -126,4 +126,4 @@ class Bindings: binding = self.keys.get(key, None) if binding is None: return True - return binding.allow_forward + return not binding.universal