@@ -367,6 +367,12 @@ class MyApp(App[None]):
367367 self.app.dark = not self.app.dark # Toggle dark mode
368368 ```
369369 """
370+ app_focus = Reactive (True , compute = False )
371+ """Indicates if the app has focus.
372+
373+ When run in the terminal, the app always has focus. When run in the web, the app will
374+ get focus when the terminal widget has focus.
375+ """
370376
371377 def __init__ (
372378 self ,
@@ -2672,6 +2678,8 @@ async def on_event(self, event: events.Event) -> None:
26722678 await super ().on_event (event )
26732679
26742680 elif isinstance (event , events .InputEvent ) and not event .is_forwarded :
2681+ if not self .app_focus and isinstance (event , (events .Key , events .MouseDown )):
2682+ self .app_focus = True
26752683 if isinstance (event , events .MouseEvent ):
26762684 # Record current mouse position on App
26772685 self .mouse_position = Offset (event .x , event .y )
@@ -2819,6 +2827,16 @@ async def _on_resize(self, event: events.Resize) -> None:
28192827 for screen in self ._background_screens :
28202828 screen .post_message (event )
28212829
2830+ async def _on_app_focus (self , event : events .AppFocus ) -> None :
2831+ """App has focus."""
2832+ # Required by textual-web to manage focus in a web page.
2833+ self .app_focus = True
2834+
2835+ async def _on_app_blur (self , event : events .AppBlur ) -> None :
2836+ """App has lost focus."""
2837+ # Required by textual-web to manage focus in a web page.
2838+ self .app_focus = False
2839+
28222840 def _detach_from_dom (self , widgets : list [Widget ]) -> list [Widget ]:
28232841 """Detach a list of widgets from the DOM.
28242842
@@ -2976,6 +2994,15 @@ async def _prune_node(self, root: Widget) -> None:
29762994 await root ._close_messages (wait = True )
29772995 self ._unregister (root )
29782996
2997+ def _watch_app_focus (self , focus : bool ) -> None :
2998+ """Respond to changes in app focus."""
2999+ if focus :
3000+ focused = self .screen .focused
3001+ self .screen .set_focus (None )
3002+ self .screen .set_focus (focused )
3003+ else :
3004+ self .screen .set_focus (None )
3005+
29793006 async def action_check_bindings (self , key : str ) -> None :
29803007 """An [action](/guide/actions) to handle a key press using the binding system.
29813008
0 commit comments