Closed psifertex closed 3 years ago
Most likely a race condition as you suspect... the solution is put in a delay or loop to detect when the menu is actually populated, but to make things responsive, it's probably best to put the loop into a coroutine so it can yield every few milliseconds and keep Hammerspoon or the OS from seeming unresponsive... I should probably update the example at some point with something like this:
-- How long to wait for menu to appear before assuming a problem
local menuTimeout = 5
function doMenuItem(app, item)
local axlist = getItemListFromDock()
for i,v in ipairs(axlist) do
if v.AXSubrole == "AXApplicationDockItem" and v.AXTitle == app then
local waitForMenu -- predeclare so it can be referred to within assignment
waitForMenu = coroutine.wrap(function()
v:doAXShowMenu()
local startTime = os.time()
local doLoop = true
while doLoop do
-- this allows HS to do other things while waiting for menu to appear
coroutine.applicationYield()
doLoop = (#v == 0) and ((os.time() - startTime) < menuTimeout)
end
-- this makes coroutine an upvalue so it won't be collected
waitForMenu = nil
if #v == 0 then
error("doMenuItem timeout -- Dock may need restarting")
else
for i2,v2 in ipairs(v[1]) do
if v2.AXTitle == item then
v2:doAXPress()
return
end
end
v:doAXShowMenu() -- close menu so we can error
error("doMenuItem " .. tostring(item) .. " not found in " .. tostring(app) .. " menu list")
end
end)()
return
end
end
error(tostring(app) .. " not found in Dock application list")
end
Here we put the code to find the item in the menu into a coroutine so it can loop while waiting for the accessibility items for the menu to be created but yield each iteration so everything else remains unblocked. (If you're already familiar with Lua coroutines, coroutine.applicationYield
is our own addition that takes care of adding a timer to resume automatically so you don't have to do so yourself).
Thanks! That's very helpful, works great.
I'm trying to adapt https://github.com/asmagill/hs._asm.axuielement/blob/master/examples/dockStuff.lua to be able to "love" music in apple music with a global hotkey. I'm dropping the following into my
init.lua
because I'm a slob. 😉The
Music
dock is successfully opened, but the "Love" item isn't clicked. Error is:Line 139 corresponds with the
for i2, v2 in
line.I managed to get the code to work while doing some debugging by adding some logging lines just after
doAXShowMenu()
so I'm betting this is just a race-condition, but I don't know what the right fix would be?