diff --git a/src/cthulhu/scripts/web/script_utilities.py b/src/cthulhu/scripts/web/script_utilities.py index 749ae68..f9949df 100644 --- a/src/cthulhu/scripts/web/script_utilities.py +++ b/src/cthulhu/scripts/web/script_utilities.py @@ -276,6 +276,14 @@ class Utilities(script_utilities.Utilities): def sanityCheckActiveWindow(self): app = self._script.app + if app is None: + app = AXObject.get_application(cthulhu_state.activeWindow) \ + or AXObject.get_application(cthulhu_state.locusOfFocus) + if app is not None: + tokens = ["WEB: recovered script app for active window check:", app] + debug.printTokens(debug.LEVEL_INFO, tokens, True) + self._script.app = app + if AXObject.get_parent(cthulhu_state.activeWindow) == app: return True @@ -299,6 +307,14 @@ class Utilities(script_utilities.Utilities): setattr(self._script, attr, value) window = self.activeWindow(app) + if window is None: + tokens = [ + "WARNING: WEB could not confirm a replacement active window; preserving", + cthulhu_state.activeWindow, + ] + debug.printTokens(debug.LEVEL_INFO, tokens, True) + return cthulhu_state.activeWindow is not None + self._script.app = AXObject.get_application(window) tokens = ["WEB: updating script's app to", self._script.app] debug.printTokens(debug.LEVEL_INFO, tokens, True) diff --git a/tests/test_web_input_regressions.py b/tests/test_web_input_regressions.py index a20e9c6..287f0cc 100644 --- a/tests/test_web_input_regressions.py +++ b/tests/test_web_input_regressions.py @@ -100,6 +100,59 @@ class WebKeyGrabRegressionTests(unittest.TestCase): testScript.refreshKeyGrabs.assert_called_once_with() +class WebActiveWindowRegressionTests(unittest.TestCase): + def test_sanity_check_recovers_missing_script_app_from_active_window(self): + testScript = mock.Mock(app=None) + utilities = web_script_utilities.Utilities.__new__(web_script_utilities.Utilities) + utilities._script = testScript + activeWindow = object() + app = object() + + with ( + mock.patch.object(web_script_utilities.cthulhu_state, "activeWindow", activeWindow), + mock.patch.object(web_script_utilities.cthulhu_state, "locusOfFocus", None), + mock.patch.object( + web_script_utilities.AXObject, + "get_application", + side_effect=lambda obj: app if obj is activeWindow else None, + ), + mock.patch.object( + web_script_utilities.AXObject, + "get_parent", + side_effect=lambda obj: app if obj is activeWindow else None, + ), + mock.patch.object(web_script_utilities.cthulhu, "setActiveWindow") as setActiveWindow, + ): + result = web_script_utilities.Utilities.sanityCheckActiveWindow(utilities) + + self.assertTrue(result) + self.assertIs(testScript.app, app) + setActiveWindow.assert_not_called() + + def test_sanity_check_preserves_current_window_when_recovery_is_inconclusive(self): + oldApp = object() + testScript = mock.Mock(app=oldApp) + utilities = web_script_utilities.Utilities.__new__(web_script_utilities.Utilities) + utilities._script = testScript + activeWindow = object() + + with ( + mock.patch.object(web_script_utilities.cthulhu_state, "activeWindow", activeWindow), + mock.patch.object( + web_script_utilities.AXObject, + "get_parent", + return_value=object(), + ), + mock.patch.object(utilities, "activeWindow", return_value=None), + mock.patch.object(web_script_utilities.cthulhu, "setActiveWindow") as setActiveWindow, + ): + result = web_script_utilities.Utilities.sanityCheckActiveWindow(utilities) + + self.assertTrue(result) + self.assertIs(testScript.app, oldApp) + setActiveWindow.assert_not_called() + + class WebPresentationModeSpeechRegressionTests(unittest.TestCase): def _make_script(self, inFocusMode): testScript = web_script.Script.__new__(web_script.Script)