From 40b36fa401a7655d3bd56333d48eda457d7e6507 Mon Sep 17 00:00:00 2001 From: Enyium <123484196+Enyium@users.noreply.github.com> Date: Sun, 4 May 2025 00:16:26 +0200 Subject: [PATCH 1/4] Added "window reopen" phrase. Implemented it for Firefox. Co-authored-by: Nicholas Riley --- apps/firefox/firefox_mac.py | 4 ++++ apps/firefox/firefox_win_linux.py | 3 +++ core/windows_and_tabs/window_management.talon | 1 + core/windows_and_tabs/windows_and_tabs.py | 9 ++++++++- 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/apps/firefox/firefox_mac.py b/apps/firefox/firefox_mac.py index d8418c8f1d..742ff4f4c6 100644 --- a/apps/firefox/firefox_mac.py +++ b/apps/firefox/firefox_mac.py @@ -17,6 +17,10 @@ def firefox_bookmarks_sidebar(): def firefox_history_sidebar(): actions.key("cmd-shift-h") + def window_reopen(): + # Note that as of Firefox 138.0.1, this command does not appear in any Firefox’s menus and only works if there is already an existing Firefox window open. + actions.key("cmd-shift-n") + @ctx.action_class("browser") class BrowserActions: diff --git a/apps/firefox/firefox_win_linux.py b/apps/firefox/firefox_win_linux.py index f93eebf44d..228bbf24d1 100644 --- a/apps/firefox/firefox_win_linux.py +++ b/apps/firefox/firefox_win_linux.py @@ -18,6 +18,9 @@ def firefox_bookmarks_sidebar(): def firefox_history_sidebar(): actions.key("ctrl-h") + def window_reopen(): + actions.key("ctrl-shift-n") + @ctx.action_class("browser") class BrowserActions: diff --git a/core/windows_and_tabs/window_management.talon b/core/windows_and_tabs/window_management.talon index 9179d3dcbe..5265618073 100644 --- a/core/windows_and_tabs/window_management.talon +++ b/core/windows_and_tabs/window_management.talon @@ -1,4 +1,5 @@ window (new | open): app.window_open() +window reopen: user.window_reopen() window next: app.window_next() window last: app.window_previous() window close: app.window_close() diff --git a/core/windows_and_tabs/windows_and_tabs.py b/core/windows_and_tabs/windows_and_tabs.py index a496fce22a..cdd37c127f 100644 --- a/core/windows_and_tabs/windows_and_tabs.py +++ b/core/windows_and_tabs/windows_and_tabs.py @@ -1,5 +1,6 @@ -from talon import Context, actions, ui +from talon import Context, Module, actions, ui +mod = Module() ctx = Context() @@ -12,6 +13,12 @@ def window_next(): cycle_windows(ui.active_app(), 1) +@mod.action_class +class Actions: + def window_reopen(): + """Reopen the last-closed window""" + + def cycle_windows(app: ui.App, diff: int): """Cycle windows backwards or forwards for the given application""" active = app.active_window From fbb529028e7e817a90642e06453ee3e5f356a4d5 Mon Sep 17 00:00:00 2001 From: Enyium <123484196+Enyium@users.noreply.github.com> Date: Sun, 11 May 2025 14:49:41 +0200 Subject: [PATCH 2/4] Added phrases "window maximize/restore" for Windows and Linux. - Implemented them only for Windows. - Also similarly improved the implementations for `app.window_close()` and `app.window_hide()`. On Windows, this is useful to not depend on the window's system menu anymore in the majority of cases. --- .../window_management_win_linux.talon | 5 +++ core/windows_and_tabs/windows_and_tabs.py | 6 +++ .../windows_and_tabs_linux.py | 15 +++++-- core/windows_and_tabs/windows_and_tabs_mac.py | 12 ++++-- core/windows_and_tabs/windows_and_tabs_win.py | 39 +++++++++++++++++-- 5 files changed, 68 insertions(+), 9 deletions(-) create mode 100644 core/windows_and_tabs/window_management_win_linux.talon diff --git a/core/windows_and_tabs/window_management_win_linux.talon b/core/windows_and_tabs/window_management_win_linux.talon new file mode 100644 index 0000000000..c5ff9561f3 --- /dev/null +++ b/core/windows_and_tabs/window_management_win_linux.talon @@ -0,0 +1,5 @@ +os: windows +os: linux +- +window (max | maximize): user.window_maximize() +window restore: user.window_restore() diff --git a/core/windows_and_tabs/windows_and_tabs.py b/core/windows_and_tabs/windows_and_tabs.py index cdd37c127f..3a1965c6a2 100644 --- a/core/windows_and_tabs/windows_and_tabs.py +++ b/core/windows_and_tabs/windows_and_tabs.py @@ -15,9 +15,15 @@ def window_next(): @mod.action_class class Actions: + def window_maximize(): + """Maximize the current window""" + def window_reopen(): """Reopen the last-closed window""" + def window_restore(): + """Restore (unmaximize) the current window""" + def cycle_windows(app: ui.App, diff: int): """Cycle windows backwards or forwards for the given application""" diff --git a/core/windows_and_tabs/windows_and_tabs_linux.py b/core/windows_and_tabs/windows_and_tabs_linux.py index 78b10c1fff..f1512c3e94 100644 --- a/core/windows_and_tabs/windows_and_tabs_linux.py +++ b/core/windows_and_tabs/windows_and_tabs_linux.py @@ -1,6 +1,6 @@ # defines the default app actions for linux -from talon import Context, actions +from talon import Context, actions, ui ctx = Context() ctx.matches = r""" @@ -8,6 +8,7 @@ """ +# TODO: Some keyboard shortcuts were obviously just copied from the Windows implementation. Correct what doesn't work. @ctx.action_class("app") class AppActions: def tab_close(): @@ -26,10 +27,18 @@ def tab_reopen(): actions.key("ctrl-shift-t") def window_close(): - actions.key("alt-f4") + if window := ui.active_window(): + # TODO: Does this work on Linux? + window.close() + else: + actions.key("alt-f4") def window_hide(): - actions.key("alt-space n") + if window := ui.active_window(): + # TODO: Does this work on Linux? + window.minimized = True + else: + actions.key("alt-space n") def window_hide_others(): actions.key("win-d alt-tab") diff --git a/core/windows_and_tabs/windows_and_tabs_mac.py b/core/windows_and_tabs/windows_and_tabs_mac.py index 3fac8ab4cc..4bed1f3c7d 100644 --- a/core/windows_and_tabs/windows_and_tabs_mac.py +++ b/core/windows_and_tabs/windows_and_tabs_mac.py @@ -1,4 +1,4 @@ -from talon import Context, actions +from talon import Context, actions, ui ctx = Context() ctx.matches = r""" @@ -27,10 +27,16 @@ def tab_reopen(): actions.key("cmd-shift-t") def window_close(): - actions.key("cmd-w") + if window := ui.active_window(): + window.close() + else: + actions.key("cmd-w") def window_hide(): - actions.key("cmd-m") + if window := ui.active_window(): + window.minimized = True + else: + actions.key("cmd-m") def window_hide_others(): actions.key("cmd-alt-h") diff --git a/core/windows_and_tabs/windows_and_tabs_win.py b/core/windows_and_tabs/windows_and_tabs_win.py index 2070ac2d58..b5d66399b2 100644 --- a/core/windows_and_tabs/windows_and_tabs_win.py +++ b/core/windows_and_tabs/windows_and_tabs_win.py @@ -1,12 +1,14 @@ # defines the default app actions for windows -from talon import Context, actions +from talon import Context, actions, ui ctx = Context() ctx.matches = r""" os: windows """ +SYSTEM_MENU_SHORTCUT_MULTISTEP_DELAY = "50ms" + @ctx.action_class("app") class AppActions: @@ -26,10 +28,21 @@ def tab_reopen(): actions.key("ctrl-shift-t") def window_close(): - actions.key("alt-f4") + if window := ui.active_window(): + window.close() + else: + actions.key("alt-f4") def window_hide(): - actions.key("alt-space n") + if window := ui.active_window(): + window.minimized = True + else: + actions.key("alt-space") + actions.sleep(SYSTEM_MENU_SHORTCUT_MULTISTEP_DELAY) + # TODO: This and the other OS-language-dependent mnemonics in this file should be made to depend on a new Windows-only dictionary `OS_LANG_SYSTEM_MENU_MNEMONICS` that's defined per OS language. The current OS language decides what variant will be effective. + actions.key("n") # Depends on English OS language. + + # Note that 2x Win+Down not only minimizes the window, but also restores it before that. It would be contrary to user expectations if a window that was previously maximized is in restored state after unminimizing it again. The shortcut also unexpectedly arranges the window differently, if it's in an arranged state like covering an upper quarter or half of the work area. def window_hide_others(): actions.key("win-d alt-tab") @@ -42,3 +55,23 @@ def window_open(): class UserActions: def switcher_focus_last(): actions.key("alt-tab") + + def window_maximize(): + if window := ui.active_window(): + window.maximized = True + else: + actions.key("alt-space") + actions.sleep(SYSTEM_MENU_SHORTCUT_MULTISTEP_DELAY) + actions.key("x") # Depends on English OS language. + + # Note that Win+Up arranges the window differently instead of maximizing, if it's in an arranged state like covering a lower quarter or half of the work area. This would be contrary to user expectations. + + def window_restore(): + if window := ui.active_window(): + window.maximized = False + else: + actions.key("alt-space") + actions.sleep(SYSTEM_MENU_SHORTCUT_MULTISTEP_DELAY) + actions.key("r") # Depends on English OS language. + + # Note that Win+Down on a restored window minimizes it instead of restoring it. This can happen with apps that previously saved the maximized window placement, and then applied it to the window's restored state, e.g., when restarting the app. Besides *possible* tiny differences in the appearance of the window border, the only hint that the window isn't in maximized state, even though it covers the whole work area, will be the title bar's restore button symbol that's only slightly different to the maximize symbol. It would be contrary to user expectations if the respective voice command minimized a window that the user intended to restore. (The shortcut also arranges the window differently or minimizes it instead of being a no-op, if it's in any arranged state.) From 69bf1feddd6d005cfc296be8cd9716b29ab28b48 Mon Sep 17 00:00:00 2001 From: Enyium <123484196+Enyium@users.noreply.github.com> Date: Sun, 4 May 2025 22:52:50 +0200 Subject: [PATCH 3/4] Differentiated between minimizing windows and hiding apps. This is done by adding "app hide" phrases for Mac, and correcting terminology from "window hide" to "window minimize". --- core/windows_and_tabs/window_management.talon | 5 ++++- .../windows_and_tabs/window_management_mac.talon | 4 ++++ core/windows_and_tabs/windows_and_tabs_mac.py | 16 +++++++++++++++- core/windows_and_tabs/windows_and_tabs_win.py | 3 --- 4 files changed, 23 insertions(+), 5 deletions(-) create mode 100644 core/windows_and_tabs/window_management_mac.talon diff --git a/core/windows_and_tabs/window_management.talon b/core/windows_and_tabs/window_management.talon index 5265618073..c6e358d1ab 100644 --- a/core/windows_and_tabs/window_management.talon +++ b/core/windows_and_tabs/window_management.talon @@ -3,7 +3,7 @@ window reopen: user.window_reopen() window next: app.window_next() window last: app.window_previous() window close: app.window_close() -window hide: app.window_hide() +window (min | minimize): app.window_hide() app (preferences | prefs | settings): app.preferences() focus : user.switcher_focus(running_applications) # following only works on windows. Can't figure out how to make it work for mac. No idea what the equivalent for linux would be. @@ -22,3 +22,6 @@ snap : snap [screen] : user.move_app_to_screen(running_applications, number) + +# DEPRECATED +window hide: user.deprecate_command("2025-05-11", "window hide", "window minimize/app hide") diff --git a/core/windows_and_tabs/window_management_mac.talon b/core/windows_and_tabs/window_management_mac.talon new file mode 100644 index 0000000000..82d8fa3658 --- /dev/null +++ b/core/windows_and_tabs/window_management_mac.talon @@ -0,0 +1,4 @@ +os: mac +- +app hide: user.app_hide() +app hide others: user.app_hide_others() diff --git a/core/windows_and_tabs/windows_and_tabs_mac.py b/core/windows_and_tabs/windows_and_tabs_mac.py index 4bed1f3c7d..2a96ee5643 100644 --- a/core/windows_and_tabs/windows_and_tabs_mac.py +++ b/core/windows_and_tabs/windows_and_tabs_mac.py @@ -1,11 +1,24 @@ -from talon import Context, actions, ui +from talon import Context, Module, actions, ui +from talon.mac import applescript +mod = Module() ctx = Context() ctx.matches = r""" os: mac """ +@mod.action_class +class Actions: + def app_hide(): + """Hide the current app""" + ui.active_app().element.AXHidden = True + + def app_hide_others(): + """Hide all other apps""" + actions.key("cmd-alt-h") + + @ctx.action_class("app") class AppActions: def preferences(): @@ -39,6 +52,7 @@ def window_hide(): actions.key("cmd-m") def window_hide_others(): + # TODO: Currently hides all apps, like `actions.user.app_hide_others()` already does. Correct this to hide windows instead, if useful, or remove it. actions.key("cmd-alt-h") def window_open(): diff --git a/core/windows_and_tabs/windows_and_tabs_win.py b/core/windows_and_tabs/windows_and_tabs_win.py index b5d66399b2..5d3af58b70 100644 --- a/core/windows_and_tabs/windows_and_tabs_win.py +++ b/core/windows_and_tabs/windows_and_tabs_win.py @@ -44,9 +44,6 @@ def window_hide(): # Note that 2x Win+Down not only minimizes the window, but also restores it before that. It would be contrary to user expectations if a window that was previously maximized is in restored state after unminimizing it again. The shortcut also unexpectedly arranges the window differently, if it's in an arranged state like covering an upper quarter or half of the work area. - def window_hide_others(): - actions.key("win-d alt-tab") - def window_open(): actions.key("ctrl-n") From f862b6da6ca5d12335c53498b70f52dafa3b5d9c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 11 May 2025 13:43:55 +0000 Subject: [PATCH 4/4] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- core/windows_and_tabs/window_management.talon | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/windows_and_tabs/window_management.talon b/core/windows_and_tabs/window_management.talon index c6e358d1ab..3e56e5e990 100644 --- a/core/windows_and_tabs/window_management.talon +++ b/core/windows_and_tabs/window_management.talon @@ -24,4 +24,5 @@ snap [screen] : user.move_app_to_screen(running_applications, number) # DEPRECATED -window hide: user.deprecate_command("2025-05-11", "window hide", "window minimize/app hide") +window hide: + user.deprecate_command("2025-05-11", "window hide", "window minimize/app hide")