Hammerspoon – a great tool to automate your Mac

Honestly, Hammerspoon is an awesome tool to automate your macOS computer. It can react to system events, keyboard shortcuts and much more. Just have a look at its API and the Getting Started Guide. It is made for people that are not afraid to use an editor and code in the sweet programming language Lua. If you can code, it is more then sufficient to take a look at Learn Lua in Y Minutes to get a good grasp of Lua.

I could successfully replace 5 tools (CaffeineMoomKeyboard Maestro and Browserism) with a single script, that works much better and is way slimmer then these tools.


Caffeine has been a nice tool for disabling the sleep mode of my computer during a presentation or meeting. Sadly, it isn’t maintained anymore. A valid alternative is Amphetamine, but it has way to much options for me. I just need on and off. This can be accomplished with just 15 lines of Lua code in Hammerspoon. The code is taken straight from the Getting Started Guide. I just added the images from this reddit post.

-- Caffeine Replacement - Keep display awake when caffeine is active.
local caffeine = hs.menubar.new()
function setCaffeineDisplay(state)
    if state then
        caffeine:setIcon(os.getenv("HOME") .. "/.hammerspoon/caffeine/active.png")
        caffeine:setIcon(os.getenv("HOME") .. "/.hammerspoon/caffeine/inactive.png")
function caffeineClicked()
if caffeine then

Here you can download the images I use.

Moom & Keyboard Maestro

Well, macOS provides this fullscreen split view mode, but from my point of view it is useless crap. As much as I love split view on my iPad, I hate the implementation in macOS.

I have been working with some handy shortcuts for years now.

  • CTRL + ALT + Left — Move the current window to the left edge of the screen and resize it to half of the current screen size
  • CTRL + ALT + Right — Just the same in the other direction.
  • CTRL + ALT + Up — Resize the current window to “normal” fullscreen.
  • CTRL + ALT + Down — Resize the current window to 2/3 of the current screen width and the full screen height. Afterwards center it on the screen.

So far I have been using Moom or Keyboard Maestro for this setup. Moom is nice, but I don’t like the UI and it has some issues when moving and resizing windows at the same time. Keyboard Maestro has the worst user interface I know. I never got accustomed to it. Plain code works much better for me. So, I was pretty happy to find some good advice and examples in the Getting Started Guide again.

-- Window Movement
-- CTRL + ALT + Left - Move current window to the left half of the screen.
-- CTRL + ALT + Right - Move current window to the right half of the screen.
-- CTRL + ALT + Up - Go "fullscreen".
-- CTRL + ALT + Down - Center window, covering 2/3 of screen size.
function move_window(direction)
    return function()
        local win      = hs.window.focusedWindow()
        local app      = win:application()
        local app_name = app:name()
        local f        = win:frame()
        local screen   = win:screen()
        local max      = screen:frame()
        if direction == "left" then
            if app_name == "Tweetbot" then
                f.x = max.x
                f.x = max.x
                f.w = max.w / 2
        elseif direction == "right" then
            if app_name == "Tweetbot" then
                f.x = max.x + (max.w - f.w)
                f.x = max.x + (max.w / 2)
                f.w = max.w / 2
        elseif direction == "up" then
            f.x = max.x
            f.w = max.w
        elseif direction == "down" then
            f.x = max.x + (max.w / 6)
            f.w = max.w * 2 / 3
            hs.alert.show("move_window(): Freaky parameter received " .. direction)
        f.y = max.y
        f.h = max.h
        win:setFrame(f, 0)
local hyper = {"ctrl", "alt"}
hs.hotkey.bind(hyper, "Left", move_window("left"))
hs.hotkey.bind(hyper, "Right", move_window("right"))
hs.hotkey.bind(hyper, "Up", move_window("up"))
hs.hotkey.bind(hyper, "Down", move_window("down"))


Browserism is a nice tool to switch the default browser on macOS. But obviously I want to replace it with Hammerspoon, too.

This task was a bit trickier then the others. I wasted a lot of time to find out, how to switch the default browser using AppleScript. Apparently, this is not possible. You have to create an executable with Objective C or Swift to do it. But Hammerspoon can be set as the default browser, too. After I found out about that, the solution was pretty simple and with the hs.settings module you can even store the default browser setting between restarts.

-- Browser Menu
-- Step 1: Take care, that Hammerspoon is the default browser
if hs.urlevent.getDefaultHandler("http") ~= "org.hammerspoon.hammerspoon" then
-- Step 2: Setup the browser menu
local active_browser     = hs.settings.get("active_browser") or "com.apple.safari"
local browser_menu       = hs.menubar.new()
local available_browsers = {
    ["com.apple.safari"] = {
        name = "Safari",
        icon = os.getenv("HOME") .. "/.hammerspoon/browsermenu/safari.png"
    ["org.mozilla.firefox"] = {
        name = "Firefox",
        icon = os.getenv("HOME") .. "/.hammerspoon/browsermenu/firefox.png"
    ["com.google.chrome"] = {
        name = "Google Chrome",
        icon = os.getenv("HOME") .. "/.hammerspoon/browsermenu/chrome.png"
function init_browser_menu()
    local menu_items = {}
    for browser_id, browser_data in pairs(available_browsers) do
        local image = hs.image.imageFromPath(browser_data["icon"]):setSize({w=16, h=16})
        if browser_id == active_browser then
        table.insert(menu_items, {
            title   = browser_data["name"],
            image   = image,
            checked = browser_id == active_browser,
            fn      = function()
                active_browser = browser_id
                hs.settings.set("active_browser", browser_id)
-- Step 3: Register a handler for opening URLs
hs.urlevent.httpCallback = function(scheme, host, params, fullURL)
    hs.urlevent.openURLWithBundle(fullURL, active_browser)

Here you can download the icons I use. They were created using Font Awesome.


What’s next?

I think I will replace some more tools with a short snippet of Hammerspoon configuration.

  • Viscosity is simply the best OpenVPN client for macOS. Forget about Tunnelblick. But I think, I can replace it, too. I would prefer to edit my OpenVPN configs with an editor.
  • Hammerspoon can react to Wifi events. I would love to automatically connect to my private OpenVPN Server as soon as I connect to an untrusted Wifi network.

Image credit: Matthew Hurst. Shared under the Creative Commons Attribution-ShareAlike 2.0 Generic license.

Leave a Reply

Your email address will not be published. Required fields are marked *