-
-
Save kmplngj/9dc0a4f4128a75ce80ecdac7bd0de11b to your computer and use it in GitHub Desktop.
Hammerspoon script for ensuring Sidecar is active when iPad is plugged in (macOS 10.15; see comments for versions up to macOS 13)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
hs.loadSpoon('SpoonInstall') | |
spoon.SpoonInstall.use_syncinstall = true | |
Install = spoon.SpoonInstall | |
log = hs.logger.new('init', 5) | |
-- function debugUI(msg, table) | |
-- log:d(msg) | |
-- log:d(hs.inspect(table)) | |
-- end | |
function connectToSidecar(msg, results, count) | |
local item | |
sidecarItemFound = (count > 0) | |
if not sidecarItemFound then | |
return log:d("Can't get Sidecar connection menu item:", msg) | |
end | |
item = results[1] | |
if item.AXMenuItemMarkChar == nil then | |
-- log:d("Connecting to Sidecar...") | |
item:doAXPress() | |
else | |
-- log:d("Closing menu - already connected to Sidecar...") | |
item.AXParent:doAXCancel() | |
end | |
end | |
function stopConnectToSidecarItemSearchTimer() | |
if connectToSidecarItemSearchTimer then | |
connectToSidecarItemSearchTimer:stop() | |
connectToSidecarItemSearchTimer = nil | |
end | |
end | |
function displaysMenu(msg, results, count) | |
local menu, connectToSneezerItemSearch | |
if count == 0 then | |
return log:d("Can't get displays menu:", msg) | |
end | |
menu = results[1] | |
menu:doAXPress() | |
connectToSneezerItemSearch = hs.axuielement.searchCriteriaFunction({ | |
{attribute = 'AXRole', value = 'AXMenuItem'}, | |
{attribute = 'AXIdentifier', value = '_deviceSelected:'}, | |
{attribute = 'AXTitle', value = 'Sneezer'}}) | |
-- menu:elementSearch(debugUI, connectToSneezer, | |
-- {objectOnly = false, asTree = true, depth = 2}) | |
-- iPad may not appear immediately in the Displays menu | |
-- wait up to 3 seconds for it to appear | |
stopConnectToSidecarItemSearchTimer() | |
sidecarItemFound = false | |
connectToSidecarItemSearchTimer = hs.timer.doUntil( | |
function() | |
return sidecarItemFound | |
end, | |
function() | |
menu:elementSearch(connectToSidecar, connectToSneezerItemSearch, | |
{count = 1, depth = 2, noCallback = true}) | |
end, | |
0.5) | |
hs.timer.doAfter(3, stopConnectToSidecarItemSearchTimer) | |
end | |
function connectSidecar() | |
local suisApp, suisAX, displayMenuSearch | |
suisApp = hs.application.find('com.apple.systemuiserver') | |
suisAX = hs.axuielement.applicationElement(suisApp) | |
displayMenuSearch = hs.axuielement.searchCriteriaFunction({ | |
{attribute = 'AXRole', value = 'AXMenuBarItem'}, | |
{attribute = 'AXSubrole', value = 'AXMenuExtra'}, | |
{attribute = 'AXDescription', value = '^Displays', pattern = true} | |
}) | |
-- suisAX:elementSearch(debugUI, displayMenuSearch, | |
-- {objectOnly = false, asTree = true, depth = 2}) | |
suisAX:elementSearch(displaysMenu, displayMenuSearch, | |
{count = 1, depth = 2}) | |
end | |
-- what we actually get when the iPad connects: | |
-- connect, disconnect, connect | |
-- so, don't trigger twice within half a second | |
connectSidecarTimer = hs.timer.delayed.new(0.5, function() | |
connectSidecar() | |
end) | |
function iPadConnected(connected) | |
-- log:d("iPad connected?", connected) | |
if connected then | |
connectSidecarTimer:start() | |
else | |
connectSidecarTimer:stop() | |
end | |
end | |
Install:andUse( | |
"USBDeviceActions", | |
{ | |
config = { | |
devices = { | |
iPad = { fn = iPadConnected } | |
} | |
}, | |
start = true | |
} | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment