Alerts from hs.dialog do not get keyboard focus when launched from hs.hotkey
jdv85 opened this issue · comments
When using hs.dialog.blockAlert()
and hs.dialog.textPrompt()
from a hs.hotkey.bind()
callback, the alerts do not get keyboard focus. This means I have to reach for my mouse to enter text, which defeats the purpose of the hotkey.
Steps to reproduce
- Put this code in
init.lua
:
ctrlCmdOpt = { 'ctrl', 'cmd', 'alt' }
hs.hotkey.bind(ctrlCmdOpt, "a", function()
hs.dialog.blockAlert("Test alert", "alert ...", "Button 1", "Button 2")
end)
hs.hotkey.bind(ctrlCmdOpt, "t", function()
hs.dialog.textPrompt("Test prompt", "Enter something", "", "OK", "Cancel")
end)
- Restart Hammerspoon
- Disable "Show Dock icon" in the Hammerspoon preferences
- Make sure the Hammerspoon is not the frontmost app
- Use one of the hotkeys (ctrl + cmd + alt + a / t) to bring up a dialog
Expected result
The appearing dialog should have keyboard focus:
Actual result
The first time a dialog is launched after Hammerspoon starts, the dialog does not get keyboard focus:
With "Show Dock icon" enabled, the dialogs do get focus, but they don't appear above the currently active window.
I thought this might be fixed by simply adding [[alert window] makeKeyAndOrderFront:nil];
in textPrompt()
in libdialog.m
but it does not work. It reports the following exception from Cocoa:
[General] ERROR: Setting <NSTextField: 0x61800001b880> as the first responder for window <NSPanel: 0x614000076c40>, but it is in a different window ((null))! This would eventually crash when the view is freed. The first responder will be set to nil.
Another approach that did work for me is telling the NSApplication
instance to activate:
From b090a8b41a00c999e1d3361c7c341932e781965f Mon Sep 17 00:00:00 2001
From: Jonas Due Vesterheden <jonasduevesterheden@gmail.com>
Date: Mon, 23 May 2022 11:01:54 +0200
Subject: [PATCH] #3218 possible fix
---
extensions/dialog/libdialog.m | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/extensions/dialog/libdialog.m b/extensions/dialog/libdialog.m
index 5abac1be..f7e9a14a 100755
--- a/extensions/dialog/libdialog.m
+++ b/extensions/dialog/libdialog.m
@@ -749,8 +749,9 @@ static int textPrompt(lua_State *L) {
[alert setAccessoryView:input];
// Focus on text input:
- [[alert window] setInitialFirstResponder: input];
-
+ [[alert window] setInitialFirstResponder:input];
+ [NSApp activateIgnoringOtherApps:YES];
+
// Show alert:
NSInteger result = [alert runModal];
--
2.35.1
I am not sure if this would be an acceptable fix?
May be this is a workaround/solution:
local ctrlCmdOpt = { 'ctrl', 'cmd', 'alt' }
hs.hotkey.bind(ctrlCmdOpt, "t", function()
local lastApplication = hs.application.frontmostApplication()
hs.application.get("Hammerspoon"):activate()
hs.dialog.textPrompt("Test prompt", "Enter something", "", "OK", "Cancel")
if lastApplication then
lastApplication:activate()
end
end)
I use this sometimes for the inputs in Hammerspoon.
Here's a utility function for doing something for the above workaround (generalized for any application):
--- @param app string|table
--- @param fn function
--- @return any
function doWithActivated(app, fn)
local app_obj = app
if type(app) == "string" then
app_obj = hs.application.get(app)
end
local last_app = hs.application.frontmostApplication()
app_obj:activate()
local retval = {fn()}
if last_app then
last_app:activate()
end
return table.unpack(retval)
end
(yes, the type annotations should use generics, but they're broken in the lua-language-server in vscode)