Hyper key configuration in Hammerspoon

January 26, 2025

The hyper key is a beloved productivity hack among computer geeks. It involves mapping a single key to toggle a combination of modifier keys, typically Ctrl + Option + Command + Shift, for use with custom keyboard shortcuts. I personally have several shortcuts for app switching (e.g., Hyper + T opens the terminal) and window management (e.g., Hyper + H and Hyper + L tile windows to the left and right sides of the screen, respectively).

For technically-minded users, Hammerspoon is a great tool for implementing hyper key shortcuts on macOS. It can interact with various system APIs through simple Lua scripts, allowing for powerful, keyboard-driven workflows (as well as other fun automations).

There are plenty of online resources that explain how to use Hammerspoon for this purpose; however, most rely on additional software, such as Karabiner-Elements or Hyperkey, to map the physical hyper key itself. I’ve found that Hammerspoon can handle this step entirely on its own with just a few lines of code:

-- ~/.hammerspoon/init.lua

-- Bit masks for remapped modifier key and hyper key modifiers
local flagMasks = hs.eventtap.event.rawFlagMasks
local originalKeyMask = flagMasks["deviceRightAlternate"] -- right option
local hyperKeyMask = flagMasks["control"] | flagMasks["option"] | flagMasks["command"] | flagMasks["shift"]

-- Create a global listener to monitor keyboard events
local events = { hs.eventtap.event.types.keyDown, hs.eventtap.event.types.keyUp }
KeyEventListener = hs.eventtap.new(events, function(event)
  -- Filter out irrelevant data from the event's modifier flags
  -- https://www.hammerspoon.org/docs/hs.eventtap.event.html#rawFlagMasks
  local flags = event:rawFlags() & 0xdffffeff

  -- Check if the keyboard event includes the desired modifier key to remap
  -- If so, update the event's modifier flags to use hyper key modifiers
  if flags & originalKeyMask ~= 0 then
    event:rawFlags(hyperKeyMask)
  end

  -- Propagate event to system
  return false
end):start()

In short, the code snippet above overrides keyboard events that contain the right option key to use the hyper key modifiers. We can now create hyper key shortcuts in Hammerspoon and other apps. For example, an app switcher could be set up as follows:

local hyper = { "cmd", "alt", "ctrl", "shift" }
local shortcuts = {
  f = "Finder",
  s = "Safari",
  t = "Terminal",
}

for key, app in pairs(shortcuts) do
  hs.hotkey.bind(hyper, key, function()
    hs.application.open(app)
  end)
end