Kitty 终端热键下拉/覆盖热键(类似于 iTerm2 热键窗口)

问题描述 投票:0回答:2

TDLR

如何获得类似于 iTerm“下拉热键/覆盖”功能的功能以与 Kitty 终端(在 Mac 上)配合使用?


我在 Mac 上工作并使用了很长一段时间

iTerm2
并将“热键窗口”集成到我的工作流程中。自从我切换到
Kitty
以来,我一直在尝试获得相同的功能,但找不到适合我需求的东西。

注意事项/问题

据我所知,内置此功能的应用程序也是

iTerm
。此实现与本机
iTerm
实现有一个很大的区别。

iTerm
更像是一个“下拉菜单”,因为它充当叠加层。
BTT
实现将按字面意思显示和隐藏应用程序。这意味着每当您使用多个桌面并触发此快捷方式时,BTT都会将您移动到应用程序所在的桌面

Lunix 的类似解决方案是使用 tdrop。据我所知,MacOS 上没有等效的工具

我觉得这很烦人,很想知道是否有人知道如何做同样的事情,但是以“下拉”或“覆盖”的方式

我尝试过的

BetterTouch工具(BTT)

这是我使用 BTT 设置的方式。

AppleScript

这做了同样的事情,但不使用 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
macos terminal applescript iterm2 kitty
2个回答
2
投票

我感受到你的痛苦。

我通过使用 yabai、skhd、bash 和几个深夜取得了一些令我最满意的成果。

我可以尝试描述更多,购买我的带有几个错误启动的丑陋脚本如下:

#!/usr/bin/env bash
# Kitty Console command

# Ideal requirements:
# - If kitty is running:
#   - If there is no console window
#     - Create the console window, bring it to focus
#   - If there is a console window
#     - If it is not in focus or hidden, bring it to focus
#     - If it is in focus, hide the console window
# Bonus:
# - If kitty is not running:
#   - Launch kitty, create the console window, bring it to focus


# If a logfile is specified, it will write information there
logfile="${HOME}/.config/skhd/kitty_console.log"

function kclog {
    [[ -n "${logfile}" ]] && printf -- "$*\n" &>> "${logfile}"
}

kclog 'Launching Kitty Console Script.'
kclog "Which kitty = $(which kitty)"

function minimal_prototype {
    SOCKET='unix:/tmp/kitty-gui'
    kitty_cmd="kitty @ --to ${SOCKET}"

    # Save the below, this works well
    # 1) If kitty is not running, reports in log
    # 2) If kitty running and no Console window exists, creates one
    # 3) If kitty running and Console window exists, bring it to focus
    # Note that this requires the following in
    # ~/.config/kitty/macos-launch-services-cmd-line:
    # --override allow_remote_control=yes
    # --listen-on unix:/tmp/kitty-gui

    ${kitty_cmd} focus-window --match title:Console \
        || ${kitty_cmd} new-window --window-type os --title Console \
        || { \
            printf 'Kitty likely not running, launching \n' > "${logfile}";
            kitty --single-instance --directory "${HOME}" --override allow_remote_control=yes --listen-on "${SOCKET}"  --title Console; \
        }
}

function minimal_prototype_2 {
    SOCKET='unix:/tmp/kitty-gui'
    kitty_cmd="kitty @ --to ${SOCKET}"

    # Save the below, this works well
    # 1) If kitty is not running, reports in log and launches kitty normally,
    #    then launches console window
    # 2) If kitty running and no Console window exists, creates one
    # 3) If kitty running and Console window exists, bring it to focus
    # Note that this requires the following in
    # ~/.config/kitty/macos-launch-services-cmd-line:
    # --override allow_remote_control=yes
    # --listen-on unix:/tmp/kitty-gui

    ${kitty_cmd} focus-window --match title:Console \
        || ${kitty_cmd} new-window --window-type os --title Console \
        || { \
            printf 'Kitty likely not running, launching \n' > "${logfile}";
            /Applications/kitty.app/Contents/MacOS/kitty  --single-instance --directory "${HOME}" --override allow_remote_control=yes --listen-on "${SOCKET}" & \
            sleep 1; \
            ${kitty_cmd} new-window --window-type os --title Console; \
        }
}

function minimal_prototype_3 {
    SOCKET='unix:/tmp/kitty-console'
    kitty_cmd="kitty @ --to ${SOCKET}"
    # This version launches a separate kitty instance for console

    # Save the below, this works well
    # 1) If kitty is not running, reports in log and launches kitty normally,
    #    then launches console window
    # 2) If kitty running and no Console window exists, creates one
    # 3) If kitty running and Console window exists, bring it to focus
    # Note that this requires the following in
    # ~/.config/kitty/macos-launch-services-cmd-line:
    # --override allow_remote_control=yes
    # --listen-on unix:/tmp/kitty-gui

    ${kitty_cmd} focus-window --match title:Console \
        || ${kitty_cmd} new-window --window-type os --title Console \
        || { \
            printf 'Kitty likely not running, launching \n' > "${logfile}";
            kitty --directory "${HOME}" --override macos_hide_from_tasks=yes --override allow_remote_control=yes --listen-on "${SOCKET}" & \
            sleep 1; \
            ${kitty_cmd} new-window --window-type os --title Console; \
        }
    yabai -m rule --add app=kitty title=Console sticky=on
}


function simple_kitty_console {
    # This function implements a simple console window.
    SOCKET='unix:/tmp/kitty-gui'
    kitty_cmd="kitty @ --to ${SOCKET}"
    if ${kitty_cmd} focus-window --match title:Console; then
        kclog 'Focusing Console window'
    else
        kclog 'No Console window, create.'
        ${kitty_cmd} new-window --window-type os --title Console \
            && yabai -m rule --add \
                label=kitty-console \
                app=kitty \
                title=Console \
                sticky=on \
                grid=1:2:2:1:1:1 \
                manage=on
    fi
}

function hide_process {
    osascript -e "
        tell application \"System Events\"
            set visible of the first process whose unix id is ${1} to false
        end tell
    "
}

function show_process {
    osascript -e "
        tell application \"System Events\"
            set visible of the first process whose unix id is ${1} to true
        end tell
    "

}

function activate_process {
    # Assumes that variable `myProcessId` contains the PID of interest.
    osascript -e "
        tell application \"System Events\"
            set frontmost of the first process whose unix id is ${1} to true
        end tell
        "
}

function independent_kitty_console {
    # This function launches an independent kitty instance
    # This function implements a simple console window.
    SOCKET='unix:/tmp/kitty-console'
    kitty_cmd="kitty @ --to ${SOCKET}"
    # if ${kitty_cmd} focus-window --match title:Console; then
    if ${kitty_cmd} focus-window; then
        kclog 'Focusing Console window'
    else
        kclog 'No Console window, create.'
        launch_new_hidden_kitty
        # ${kitty_cmd} new-window --window-type os --title Console \
        #     && yabai -m rule --add \
        #         label=kitty-console \
        #         app=kitty \
        #         title=Console \
        #         sticky=on \
        #         grid=1:2:2:1:1:1 \
        #         manage=on
    fi
    :
}

function launch_new_kitty {
    SOCKET='unix:/tmp/kitty-console'
    { kitty --title Console --directory '/' --listen-on "${SOCKET}" & } 2>/dev/null
    kitty_pid=$!
    disown -r "${kitty_pid}"
    printf "${kitty_pid}\n"
}

function launch_new_hidden_kitty {
    # This works well to launch a hidden instance of Kitty and get the PID, but
    # it seems that kitty windows launched in this way do not respond the same
    # way to the Apple events the way 'non-hidden' Kitty windows do.
    SOCKET='unix:/tmp/kitty-console'
    { kitty --title Console --override macos_hide_from_tasks=yes --directory '/' --listen-on "${SOCKET}" & } 2>/dev/null
    kitty_pid=$!
    disown -r "${kitty_pid}"

    kclog "${kitty_pid}"
    # Attempt to rename the window on launch
    kitty @ --to "${SOCKET}" set-window-title -m recent:0 Console
}

function learnings {
    # Get the process ID of the bash instance inside kitty window
    kitty @ --to unix:/tmp/kitty-console ls | jq '.[].tabs[].windows[].pid'

    # From this, one can use
    ps -f $KITTY_BASH_PID

    # To get the main kitty PID
}

function kitty_console_post_fix {
    # This is work performed after I saw the following fix:
    # https://github.com/kovidgoyal/kitty/issues/5210
    # This function implements a simple console window.
    # This uses the "launch" command
    SOCKET='unix:/tmp/kitty-gui'
    kitty_cmd="kitty @ --to ${SOCKET}"
    if ${kitty_cmd} focus-window --match title:Console; then
        kclog 'Focusing Console window'
    else
        kclog 'No Console window, create.'
        ${kitty_cmd} launch --type=os-window --title=Console \
            && yabai -m rule --add \
                label=kitty-console \
                app=kitty \
                title=Console \
                sticky=on \
                grid=1:2:2:1:1:1 \
                manage=on
    fi


}

function independent_kitty_console_post_fix {
    kclog '\nRunning independent_kitty_console_post_fix'
    # This function launches an independent kitty instance
    # This function implements a simple console window.
    SOCKET='unix:/tmp/kitty-console'
    kitty_cmd="kitty @ --to ${SOCKET}"
    if ${kitty_cmd} focus-window --match title:Console; then
        kclog 'Focusing Console window'
    else
        launch_new_hidden_kitty
        # if ${kitty_cmd} launch --type=os-window --title=Console \
        #     --override macos_hide_from_tasks=yes; then
        #     kclog 'No Console window, create.'
        #     yabai -m rule --add \
        #         label=kitty-console \
        #         app=kitty \
        #         title=Console \
        #         sticky=on \
        #         grid=1:2:2:1:1:1 \
        #         manage=on
        # else
        #     kclog 'No Kitty instance, launching'
        #     { kitty --override macos_hide_from_tasks=yes --directory '/' --listen-on "${SOCKET}" & } 2>/dev/null
        #     kitty_pid=$!
        #     disown -r "${kitty_pid}"
        #     kclog "${kitty_pid}\n"
        # ${kitty_cmd} launch --type=os-window --title=Console \
        #     && yabai -m rule --add \
        #         label=kitty-console \
        #         app=kitty \
        #         title=Console \
        #         sticky=on \
        #         manage=on
        #         # grid=1:2:2:1:1:1 \
        # fi
    fi
}

# simple_kitty_console
# independent_kitty_console
# kitty_console_post_fix
# independent_kitty_console_post_fix


################################################################################
# Another try - 2022-09-12
################################################################################
# This tries to achieve my goal using a separate instance of kitty for the
# Console window. Codename: ibk (itty bitty kitty)

IBK_SOCKET='unix:/tmp/kitty-console'

function ibk_launch {
    # Launch a Console instance of Kitty
    # Note: I launch it using the root directory as an extra way of identifying
    # which instance is the Console instance.
    kitty \
        --title Console \
        --directory "${HOME}" \
        --override allow_remote_control=yes \
        --listen-on "${IBK_SOCKET}"
}

function ibk_launch_background {
    # Launch a Console instance of Kitty
    # Note: I launch it using the root directory as an extra way of identifying
    # which instance is the Console instance.
    { kitty \
        --title Console \
        --directory "${HOME}" \
        --override allow_remote_control=yes \
        --listen-on "${IBK_SOCKET}" &
    } &> /dev/null
    kitty_pid=$!
    disown -r "${kitty_pid}"
    # yabai -m rule --add \
    #     label=kitty-console \
    #     app=kitty \
    #     title=Console \
    #     sticky=on
    # echo -n "${kitty_pid}"
}

function ibk_get_pid {
    # Get the pid of the kitty process in order to hide it
    # local ppids
    # ppids=$(
    # Note: if kitty ls returns '[]', no windows exist
    _ppids="$( \
        kitty @ --to "${IBK_SOCKET}" ls \
            | jq '.[].tabs[].windows[].pid' \
            | xargs -I {} ps -o ppid= {} \
            | sort \
            | uniq
    )"
    num_ppids=$(echo "$_ppids" | wc -l)
    if [[ "${num_ppids// /}" == '1' && -n "${_ppids}" ]]; then
        echo -n "${_ppids}"
    else
        return 1
    fi
}

function ibk_hide {
    hide_process "$(ibk_get_pid)"
}

function ibk_show {
    show_process "$(ibk_get_pid)"
}

function ibk_focus {
    activate_process "$(ibk_get_pid)"
}

function ibk_is_hidden {
    # I'm not sure how to do this yet, but I'll need to check whether or not
    # the instance of kitty is hidden.
    :
}

function ibk_toggle {
    osascript -e "
        tell application \"System Events\"
            if frontmost of the first process whose unix id is ${1} then
                set visible of the first process whose unix id is ${1} to false
            else
                set frontmost of the first process whose unix id is ${1} to true
            end if
        end tell
        "
}


function ibk_kitty_console {
    # Todo: Add ability to hide if currently in focus with same function
    if ibk_pid=$(ibk_get_pid) &> /dev/null; then
        ibk_toggle "${ibk_pid}"
        # ibk_focus "${ibk_pid}"
    else
        # Either not running, or has no windows open
        if [[ '[]' == "$(kitty @ --to "${IBK_SOCKET}" ls)" ]]; then
            # Running, but has no windows open, create one
            kitty @ --to "${IBK_SOCKET}" launch --type=os-window
        else
            # Not running, launch
            ibk_launch_background
        fi
    fi
    ibk_ensure_yabai_managed
}

function ibk_ensure_yabai_managed {
    yabai -m rule --list | grep -q '"label":"kitty-console"' || \
        yabai -m rule --add \
            label=kitty-console \
            app=kitty \
            title=Console \
            sticky=on
}

ibk_kitty_console

我使用 shkd 通过 Ctrl-~ 来运行它:

ctrl - 0x32 : ~/.config/skhd/kitty_console

1
投票

我刚刚得到了同样的担忧,并在 Hammerspoon 应用程序的帮助下实现了。

  1. 首先,我们需要在
    ~/.config/kitty/kitty.conf
    中调整Kitty配置:
# 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. 其次,将下面的
    init.lua
    复制到
    ~/.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)

在 Hammerspoon 中重新加载配置,现在您可以使用热键调用/启动 Kitty

cmd
+
esc

© www.soinside.com 2019 - 2024. All rights reserved.