Resolving Option-Key Hotkey Issues in macOS Sequoia(15.0.1)
Background
The MacOS Sequoia(15.0.1) will let the Option+*
or Option+Shift+*
no longer work. I believe a lot of guys like me use this to custom hotkeys or shortcuts.
Apple’s official answer is that this was an intentional change for security purposes. We can see the discussion on Reddit. I don’t want to judge it here, just to provide a solution(or maybe a band-aid solution for someone or some situation.) to mitigate the issue.
Solution: Hammerspoon and retrigger hotkey
In the beginning, Thanks for danrnx’s reply, which enlightened me.
My solution is using the Hammerspoon, which is an alternative to the Keyboard Maestro to some extent.
Installation
Here is a step-by-step tutorial:
- Install the Hammerspoon from release or brew. You can reference it here.
- Write the lua(a programming language) for
~/.hammerspoon/init.lua
. You can reference the official guidance here. I’ll give some examples below.
Configuration
Remember to Reload Config after you change the ~/.hammerspoon/init.lua
.
Demo 1: Open or gain focus on an App
It works well if you just need to define a hotkey to open or focus on an app.
-- Define the hotkey for Option+C to gain an app's focus.
hs.hotkey.bind({"alt"}, "C", function()
local currentApp = hs.application.frontmostApplication()
if currentApp:name() == "Google Chrome" then
-- Don't alert if already gained the focus.
return
else
hs.alert.show("Chrome")
hs.application.launchOrFocus("Google Chrome")
end
end)
The following is an improved and more practical version of the above:
function getBundleID(appName)
local app = hs.application.find(appName)
if app then
return app:bundleID()
else
-- If the application is not running, get it through the application path
local appPath = hs.application.pathForBundleID(appName)
if appPath then
return hs.application.infoForBundlePath(appPath).CFBundleIdentifier
else
hs.alert.show("Application not found: " .. appName)
return nil
end
end
end
-- A generic function to bind hotkeys and handle application launches or focus
function bindAppHotkey(modifiers, key, appName)
local bundleID = getBundleID(appName)
if not bundleID then
return
end
hs.hotkey.bind(modifiers, key, function()
local currentApp = hs.application.frontmostApplication()
if currentApp:bundleID() == bundleID then
return
else
local appIcon = hs.image.imageFromAppBundle(bundleID)
-- Create a canvas to display the icon
local iconCanvas = hs.canvas.new{ x = 0, y = 0, h = 100, w = 100 }:appendElements({
type = "image",
image = appIcon,
imageAlignment = "center",
imageScaling = "scaleToFit"
})
-- Get the screen center position to display the canvas
local screenFrame = hs.screen.mainScreen():frame()
iconCanvas:frame({
x = screenFrame.w / 2 - 50,
y = screenFrame.h / 2 - 50,
h = 100,
w = 100
})
-- Show the icon and automatically delete it after 1 second
iconCanvas:show()
hs.timer.doAfter(1, function() iconCanvas:delete() end)
-- Launch or focus the application
hs.application.launchOrFocus(appName)
end
end)
end
-- Use the generic function to set hotkeys for different applications
bindAppHotkey({"alt"}, "C", "Google Chrome")
bindAppHotkey({"alt"}, "S", "Sublime Text")
bindAppHotkey({"alt"}, "space", "iTerm")
I’d like to show the app icon rather than the app name :)
Demo 2: Retrigger
Sometimes we’d like to use functions such as screenshots, OCR, or translation. They’re different from opening an app. So we can use a hotkey to trigger another hotkey.
hs.hotkey.bind({"alt"}, "A", function()
hs.eventtap.keyStroke({"alt", "cmd"}, "A")
end)
I define the screenshot hotkey as Option+Command+A
, and then bind the Option+A
in Hammerspoon. Now, I can take a screenshot by Option+A
.
References
Enjoy Reading This Article?
Here are some more articles you might like to read next: