Hammerspoon

github.com

267 points by tosh 13 hours ago


abhikul0 - 7 minutes ago

Coming from windows to macos, I(i think i used perplexity :P) created a spoon for switching between open windows with 4 finger swipe[0]. Swiping left/right switches between windows, swiping down minimizes all visible windows, swiping up restores them(one by one). Created this repo to backup my config with an llm documenting it.

It uses a swipe gesture detection spoon I found after searching for something similar[1].

[0] https://github.com/abhikul0/hammerspoonConfig

[1] https://github.com/mogenson/Swipe.spoon

cmsj - 8 hours ago

Hammerspoon maintainer here - I'm enjoying reading all the comments, and hoping that everyone isn't going to be annoyed that I'm mostly working on a v2 atm, which switches from Lua to JavaScript :D

incanus77 - 12 hours ago

Hammerspoon is the glue that holds my Mac together. For a starter list of things to do with this app, a partial list of the things that I'm using it for:

  - Dumping all open Safari tabs to an Obsidian doc
  - Adding 'hyper' (Ctrl-Opt-Cmd) keybinds to pop a new window for:
    - Safari
    - Finder
    - Terminal / Ghostty
    - VS Code
    - Notes
    - Editing Hammerspoon/AeroSpace/Sketchybar config
    - Reloading Hammerspoon config
    - Reloading Sketchybar
    - Quitting all Dock apps except Finder
    - Screen lock
    - System sleep
    - Opening front Finder folder in VS Code
    - Opening front Safari URL on Archive.today
    - Showing front Safari window tab count
    - Showing front app bundle ID
    - Posting notification about current Music track
    - Controlling my Logi Litra light (various color temps/brightnesses)
    - Starting/stopping a client work timer
  - Tying it to AeroSpace for:
    - Pushing a window to another monitor
    - Performing a two-up window layout
    - Swapping those two windows
    - Closing all other workspace windows
    - Gathering all windows to first workspace
  - Ensuring some background apps stay running if they crash
  - Prompting to unmount disk images if trashed
  - Binding into Skim to jump to specific sections of spec PDFs using terse Markdown URLs
smasher164 - 14 minutes ago

One of the reasons I left macos was that automation via Automator and Applescript was inconsistent and unsupported in many contexts. Well that and the locking down of app distribution and sandboxing. However, the positive reception to Hammerspoon is making me consider trying it again.

iLemming - 10 hours ago

Shameless plug/proud self-promotion - https://github.com/agzam/spacehammer "Spacemacs|Doom inspired Hammerspoon modal toolkit"

I can't even work on Mac without it. It let's you do stuff like "alt+spc a b" (apps -> browser) or "alt+spc m j/k" (media -> vol up/down), or edit just about any text of any app in your editor (Emacs atm) - with all the tools you have there - spellchecking, thesaurus, translation, LLMs, etc.

You can plug it to your favorite WM (I'm currently using Yabai) and do tons of other interesting things. Because it's all written in Fennel, one can develop things in a tight feedback loop with a connected REPL - e.g., I can ask Claude to inspect things in the running Slack app or Firefox and make interesting automations - all without ever leaving my editor.

zdw - 11 hours ago

I fake a tiling window manager on Mac with Hammerspoon, resizing to fit in specific corners/sizes:

     -- resize based on ratios
    function ratioResize(xr, yr, wr, hr)
      return function ()
        local win = hs.window.focusedWindow()
        win:moveToUnit({x=xr,y=yr,w=wr,h=hr})
      end
    end

    -- 4 corners, different sizes
    hs.hotkey.bind({"cmd", "ctrl"}, "w", ratioResize(0,     0, 2/5, 2/3))
    hs.hotkey.bind({"cmd", "ctrl"}, "e", ratioResize(2/5,   0, 3/5, 2/3))
    hs.hotkey.bind({"cmd", "ctrl"}, "s", ratioResize(0,   2/3, 2/5, 1/3))
    hs.hotkey.bind({"cmd", "ctrl"}, "d", ratioResize(2/5, 2/3, 3/5, 1/3))
And to throw windows to other monitors:

    -- send to next screen
    hs.hotkey.bind({"cmd", "ctrl"}, ";", function()
      local win = hs.window.focusedWindow()
      local screen = win:screen()
      local next_screen = screen:next()

      win:moveToScreen(next_screen)
    end)
pjm331 - 13 hours ago

here is my entire config

    hs.hotkey.bind({"ctrl"}, "D", function()
      hs.grid.show()
    end)
i've tried all of the other fancy window managers and for me nothing has ever beat the ease of use of just

(1) ctrl-d to see the grid, (2) type the letter where you want the top left corner of your window to be, (3) type the letter where you want the bottom right corner to be

window resized

dbalatero - 9 hours ago

Some stuff I've made in Hammerspoon you can use:

- Vim mode everywhere in macOS: https://github.com/dbalatero/VimMode.spoon

- Modifier keys + click/drag to resize or move windows: https://github.com/dbalatero/SkyRocket.spoon

- Show an overlay helper of all your keybinds when you hold modifier keys down: https://github.com/dbalatero/HyperKey.spoon

And my huge pile of random scripts/configs: https://github.com/dbalatero/nixpkgs/tree/main/home/modules/...

juancn - 11 hours ago

I use it to hide Zoom's screen sharing controls so they don't come back when pressing Esc:

    -- Hide Zoom's "share" windows so it doesn't come back on ESC keypress
    local zoomWindow = nil
    local originalFrame = nil
    
    hs.hotkey.bind({"cmd", "ctrl", "alt"}, "H", function()
      print("> trying to hide zoom")
      if not zoomWindow then
        print(">  looking for window")
        zoomWindow = hs.window.find("zoom share statusbar window")
      end
    
      if zoomWindow then
        print(">  found window")
        if originalFrame then
          print(">    restoring")
          zoomWindow:setFrame(originalFrame)
          originalFrame = nil
          zoomWindow = nil
        else
          print(">    hiding")
          originalFrame = zoomWindow:frame()
          local screen = zoomWindow:screen()
          local frame = zoomWindow:frame()
          frame.x = screen:frame().w + 99000
          frame.y = screen:frame().h + 99000
          zoomWindow:setFrame(frame)
        end
      else
        print(">  window not found")
      end
    end)
alexfortin - 11 hours ago

I use it to enable/disable the wifi when I disconnec/connect the macbook to a specific usb hub with ethernet connection:

  local usbWatcher = hs.usb.watcher.new(function(device)
    if device.productName == "EMEET SmartCam C960" then
      if device.eventType == "added" then
        hs.execute("networksetup -setairportpower en0 off")
        hs.notify.new({title="Wi-Fi", informativeText="Disabled (USB device connected)"}):send()
      elseif device.eventType == "removed" then
        hs.execute("networksetup -setairportpower en0 on")
        hs.notify.new({title="Wi-Fi", informativeText="Re-enabled (USB device removed)"}):send()
      end
    end
  end)
  usbWatcher:start()
tcoff91 - an hour ago

I really like the Label feature. I use it to put labels on the screen in my different aerospace workspaces so I can keep track of which project I’m working on. With agents working in parallel this is really useful.

fudged71 - 5 hours ago

I recently set up Hammerspoon to surveil my own computer usage actions (active tab/window, typing state, scrolling) to have a next-action predictor. It shows the predicted next action at the top of the screen but I was thinking of using it to improve voice command accuracy.

theshrike79 - 11 hours ago

I tried to find a proper window control tool for macOS for a while, tested Rectangle and Magnet and dunno how many.

Then I just figured out that I have Hammerspoon, it can control windows -> recreate one exactly how I like it. Been using it for a year now and it's 99% perfect. Some specific applications (coughFirefoxcough) sometimes get into a weird state that doesn't work, but I can live with that.

It can also pop all windows to a specific layout with a single shortcut by combining the active wifi + monitor setup to detect if I'm at home, at work, or working at home.

msephton - 4 hours ago

I use it to: - implement a keyboard based window manager - arrange/quit/launch some things based on whether my MBP is docked or not - resize and reposition certain windows that don't remember their own size and position - certain other hotkeys - probably stuff I forgot and rely on!

I'll be sad when it moves from Lua to JavaScript, but I guess that's better than moving to Tcl.

golem14 - 13 hours ago

Has anyone worked on making a config replicating aerospace?

Hammerspoon seems like a superset and it’s probably better to just have one, instead of two tools warring about who gets the keypresses?

overflowy - 11 hours ago

I use this to remap app keys:

    local appHotkeys = {}

    local function remapAppHotkey(appName, fromMods, fromKey, toMods, toKey, delay)
        if not appHotkeys[appName] then
            appHotkeys[appName] = {}
        end
        local hotkey = hs.hotkey.new(fromMods, fromKey, function()
            hs.eventtap.keyStroke(toMods, toKey, delay or 0)
        end)
        table.insert(appHotkeys[appName], hotkey)
    end
    
    local appWatcher = hs.application.watcher.new(function(appName, eventType)
        local hotkeys = appHotkeys[appName]
        if not hotkeys then return end
        for _, hotkey in ipairs(hotkeys) do
            if eventType == hs.application.watcher.activated then
                hotkey:enable()
            elseif eventType == hs.application.watcher.deactivated then
                hotkey:disable()
            end
        end
    end)
    
    appWatcher:start()

    -- Remap app hotkeys
    remapAppHotkey("Finder", { "cmd" }, "q", { "cmd" }, "w", 0.5)
    ... etc ...
kcrwfrd_ - 9 hours ago

I despair at not being able to easily send a window to another space with a keyboard shortcut on macOS.

Yabai supports this perfectly (especially combined with instant, animation-free space switching) but it requires disabling system integrity protection--which is a non-starter on a work computer.

Aerospace solves it with their own spaces implementation.

I was able to put together a hammerspoon script that does the job decently enough for my purposes: https://gist.github.com/kcrwfrd/6f3dcaec0e08e0e77b2884588a34...

mwagstaff - 12 hours ago

Can't live without Hammerspoon on Mac.

Can't live without AutoHotkey on Windows.

Thanks to everyone who contributed to both!

jjmiv - 12 hours ago

is there a particular reason this was shared?

otherwise I'm slowly working on a Spoon that figures out if there is an active meeting in Zoom, Teams, Huddle, Google Meet and will allow for muting, video enable/disable and screen sharing etc

saagarjha - 7 hours ago

Hammerspoon is one of the first apps I install on my Mac. Not having it makes it more or less broken to me.

trjordan - 12 hours ago

I utterly love Hammerspoon.

It's fun to combine with qmk [0], which gives you a bunch more options for hotkeys on your keyboard via layers. I've ended up with a layer where half the keyboard is Hammerspoon shortcuts directly to apps (e.g. go to Slack, to Chrome, etc.) and half of it is in-app shortcuts (like putting cmd-number on the home row, for directly addressing chrome tabs).

Between this and one of the tiling window manager-adjacent tools (I use Sizeup), I can do all my OS-level navigation directly. "Oh I want to go to Slack and go to this DM" is a few keystrokes away, and not dependent on what else I was doing.

[0] https://qmk.fm/

weitzj - 12 hours ago

I love hammerspoon. That's it :D

It's lua, so you can get creative with https://fennel-lang.org/

dbalatero - 9 hours ago

I have an unreleased pile of tutorial projects with Hammerspoon. I think not all chapters are finished, so I need to clean up and finish it at some point soon: https://learnhammerspoon.com

nxobject - 6 hours ago

Thank you so much for doing what Apple's neglected to do for many years! The way they let AppleScript/JXA rot was criminal.

ifh-hn - 10 hours ago

It's this like Mac equivalent to autohotkey on windows?

john-tells-all - 12 hours ago

I'd love to have a global "toggle Teams mute" button.

jmcguckin - 11 hours ago

I use it to give me focus-follows-mouse and to have a large circle surrounding the mouse when i move it, to aid finding it.

regus - 10 hours ago

How does this compare to AppleScript?

selectnull - 11 hours ago

Love hammerspoon. I use it to map double CMD to swap between the terminal and the browser.

swiftcoder - 11 hours ago

I always confuse "hammerspoon" and "rowhammer"

rco8786 - 6 hours ago

Love Hammerspoon

gedy - 10 hours ago

If you are on macOS but miss Paperwm or niri, etc this is a good compromise thanks to Hammerspoon: https://github.com/mogenson/PaperWM.spoon

ChrisArchitect - 10 hours ago

https://www.hammerspoon.org/

Some previous discussion:

2021 https://news.ycombinator.com/item?id=29533495

2019 https://news.ycombinator.com/item?id=21801178

hmokiguess - 11 hours ago

what's your favourite spoon?

hirvi74 - 12 hours ago

I have fond memories of this app. However, after many years, I have moved on. I am in the process of writing my own replacement for some of the various use cases that Hammerspoon once provided me. Though, Hammerspoon will always be a source of great inspiration.

rolymath - 12 hours ago

Is paperwm jittery for everyone?

cjbarber - 10 hours ago

See also:

KeyboardMaestro

Automator and AppleScript

Raycast

scm7k - 9 hours ago

[dead]