Search code examples
macosterminalapplescriptiterm2kitty

Kitty Terminal Hotkey Drop-Down/Overlay Hotkey (similar to iTerm2 hotkey window)


TDLR

How to get something similar to the iTerm "dropdown hotkey/overlay" functionality to work with Kitty Terminal (on a Mac)?


I work on a Mac and used iTerm2 for a long time and integrated the "hotkey window" into my workflow. Since I've made the switch to Kitty I have been trying to get the same functionality but couldn't find something that suits my needs.

Caveat/Problems

The one app that has this built-in, that I know of, is also iTerm. There's one big difference with this implementation and the native iTerm implementation.

iTerm is more of a "drop-down", in that it functions as an overlay. The BTT implementation will literally show and hide the application. This means that whenever you are working with multiple desktops, and you trigger this shortcut, BTT will move you to the desktop where the application is.

A similar solution for Lunix is using tdrop. As far as I know there's no equivalent tool for MacOS

I find this quite annoying TBH and would love to know if anyone knows how to do the same thing, but in a "drop-down" or "overlay" fashion

What I've tried

BetterTouchTool (BTT)

This is the way I've set it up using BTT. BTT Config

AppleScript

This does sort of the same thing, but without the use of BTT.

set appName to "kitty"

tell application "System Events"
    if visible of application process appName is true then
        set visible of application process appName to false
    else
        set visible of application process appName to true
    end if
end tell

Solution

  • I just got the same concern and implemented with the help of Hammerspoon app.

    1. Firstly, we need tweak Kitty config in ~/.config/kitty/kitty.conf:
    # hide title and corners on Mac OS X
    hide_window_decorations titlebar-and-corners
    # make kitty app quit instead of empty window, which made the script hard to detect kitty status
    macos_quit_when_last_window_closed yes
    # this one is optional, this would save the script to move the terminal window to top if manually set
    remember_window_size  yes
    
    1. Secondly, copy below init.lua to ~/.hammerspoon:
    local spaces = require("hs.spaces") -- https://github.com/asmagill/hs._asm.spaces
    
    -- Switch kitty
    hs.hotkey.bind({'command'}, 'escape', function ()  -- hotkey config
      local BUNDLE_ID = 'net.kovidgoyal.kitty' -- more accurate to avoid mismatching on browser titles
    
      function getMainWindow(app)
        -- get main window from app
        local win = nil
        while win == nil do
          win = app:mainWindow()
        end
        return win
      end
    
      function moveWindow(kitty, space, mainScreen)
        -- move to main space
        local win = getMainWindow(kitty)
        if win:isFullScreen() then
          hs.eventtap.keyStroke('fn', 'f', 0, kitty)
        end
        winFrame = win:frame()
        scrFrame = mainScreen:fullFrame()
        winFrame.w = scrFrame.w
        winFrame.y = scrFrame.y
        winFrame.x = scrFrame.x
        win:setFrame(winFrame, 0)
        spaces.moveWindowToSpace(win, space)
        if win:isFullScreen() then
          hs.eventtap.keyStroke('fn', 'f', 0, kitty)
        end
        win:focus()
      end
    
      local kitty = hs.application.get(BUNDLE_ID)
      if kitty ~= nil and kitty:isFrontmost() then
        kitty:hide()
      else
        local space = spaces.activeSpaceOnScreen()
        local mainScreen = hs.screen.mainScreen()
        if kitty == nil and hs.application.launchOrFocusByBundleID(BUNDLE_ID) then
          local appWatcher = nil
          appWatcher = hs.application.watcher.new(function(name, event, app)
            if event == hs.application.watcher.launched and app:bundleID() == BUNDLE_ID then
              getMainWindow(app):move(hs.geometry({x=0,y=0,w=1,h=0.4}))
              app:hide()
              moveWindow(app, space, mainScreen)
              appWatcher:stop()
            end
          end)
          appWatcher:start()
        end
        if kitty ~= nil then
          moveWindow(kitty, space, mainScreen)
        end
      end
    end)
    

    Reload config in Hammerspoon, now you could invoke/launch Kitty with hotkey cmd+esc