내 터미널이 GUI에 포커스가 있는지 여부를 쉘 스크립트를 통해 어떻게 감지할 수 있습니까?

내 터미널이 GUI에 포커스가 있는지 여부를 쉘 스크립트를 통해 어떻게 감지할 수 있습니까?

문제/목표 설명

이상적으로는좋아요쉘 스크립트에서 창에 포커스가 있는지 감지하는 방법입니다. "좋은"이란 가장 적은 단계를 필요로 하며 가장 좋은 방법을 의미합니다.아니요제목에 따라 내 창을 찾으려면 열려 있는 모든 창을 맹목적으로 조사해야 합니다.

목적은 다양한 스크립트에서 알림을 제어하는 ​​것입니다. 따라서 저는 모든 스크립트에 대해 작동할 수 있는 일반적인 솔루션을 찾고 있습니다.

지금까지 내가 생각해낸 것은 다음과 같이 로터리적이고 진부합니다.

  1. 내 제목을 고유하거나 기계적으로 관련된 것으로 설정합니다(내 모델에서는 PTS 경로이거나 더 안정적인 UUID입니다). 이 제목이 무엇인가에 의해 덮어쓰여지지 않기를 간절히 바랍니다.

  2. 열려 있는 모든 창의 목록을 제목별로 가져옵니다.

  3. 목록을 반복하여 제목 요소와 일치시켜 내 창을 식별합니다. (다른 창에 동일한 제목 요소가 있으면 오류가 발생할 수 있습니다.)

  4. 창에 포커스가 있는지 확인합니다.

주목해야 할 점은 내가하다아니요이것을 구현하고 싶고 최후의 수단으로만 사용하고 싶습니다. 그래서 내가 여기서 요구하는 것은이건 아니지.

타협

이 해결책은 분명히 형편없기 때문에 더 좋은 방법이 있는지 궁금합니다. 나는 휴대성이 뛰어나고 우아하며 완벽한 것을 선호하지만 타협이 필요할 수도 있다는 것을 알고 있습니다. 통과더 나은 것내 말은 다음 중 하나를 의미합니다.

  1. 터미널 에뮬레이터 자체에서 스크립트가 현재 있는 창을 감지할 수 있도록 하는 환경 변수를 설정하는 등 특정 터미널 에뮬레이터에서만 작동하는 솔루션입니다.

  2. 제목 설정이 필요하지 않지만 대신 해당 창에 연결된 셸 스크립트에서 액세스하고 감지할 수 있는 창 상태에 다른 보이지 않는 마커를 사용하는 솔루션입니다.

  3. 상위 프로세스 래더를 재사용하여 상위 터미널 에뮬레이터 PID를 찾고 거기에서 작업합니다(프로세스 트리를 재사용하여 시작 스크립트의 상위 프로세스를 감지하는 솔루션은 스크립트가 로컬에서 실행 중인 경우에만 작동하므로 이 솔루션은 불완전한 솔루션입니다. 하지만 그래도 좋아)

상황

내가 선호하는 솔루션이 어떤 조건에서 실행되어야 하는지에 대한 질문을 받았고 대답은 다음과 같습니다.많을수록 좋다. 하지만 적어도 나는 유용한 것을 원합니다.

  1. 로컬로 실행되는 단일 탭 터미널 세션(기본 시나리오).

  2. tmux와 같은 터미널 멀티플렉서에서. (다른 터미널 멀티플렉서 간의 이식성이 선호되지만 실제로는 필수는 아닙니다.)

제가 정말 높이 평가하는 추가 기능(중요도 순)은 다음과 같습니다.

  1. Telnet 및 SSH를 통해 원격으로 연결하는 기능.

  2. 다중 탭 터미널 세션에서 열려 있는 탭을 구별하는 기능.


일반화하다

내가 하나를 원하는좋아요내 쉘 스크립트가 연결된 터미널 에뮬레이터 창을 찾아 포커스가 있는지 감지할 수 있는 방법입니다.

나는 다음 메커니즘을 이해했습니다.어떻게열린 창을 반복하고 포커스가 있는지, 제목이 무엇인지 감지하는 방법을 반복합니다. 나는 xdotool그것을 알고 존재하며 xprop이 질문은 이러한 도구의 기본 메커니즘과 아무 관련이 없다는 것을 알고 있습니다(현재 솔루션의 본질적인 해킹성을 우회하는 숨겨진 흑마법 기능이 있는 경우는 제외).

하고 싶지 않은 이유는 너무 무섭기 때문이다. 동일한 작업을 수행할 수 있는 다른 솔루션이 있습니까?

답변1

하나 있다포커스 입력/포커스 출력모델. 할 수 있게 하다:

echo -ne '\e[?1004h'

장애가 있는:

echo -ne '\e[?1004l'

\e[I각 포커스 이벤트에서 입력 스트림으로부터 수신 (in) 또는 (out)됩니다.\e[O

이 모드를 활성화하면 GNOME 터미널(및 기타 VTE 기반 터미널)도 현재 상태를 보고합니다. 즉, 활성화한 후 즉시 비활성화하여 값을 한 번 쿼리할 수 있습니다.

시간 제한을 결합 read하거나 응답을 얻기 위해 읽을 문자 3개를 지정할 수 있습니다. 그러나 예를 들어 특정 문자를 미리 입력하는 경우 경쟁 조건이 발생할 수 있다는 점에 유의하세요.

답변2

if [ "$(xdotool getwindowfocus)" -eq "$WINDOWID" ]; then
   echo I have the focus
fi

screen/tmux가 다른 곳에서 실행되고 단순히 현재 창에 연결된 경우 screen/tmux 내에서는 아무런 효과가 없습니다.

답변3

macOS용 iTerm Python API를 사용하여 솔루션을 작성했습니다.여기Redis에 iTerm의 데이터를 저장하는 Python 데몬입니다.블리시pip install -U brish:) :

#!/usr/bin/env python3

import AppKit
bundle = "com.googlecode.iterm2"
if not AppKit.NSRunningApplication.runningApplicationsWithBundleIdentifier_(bundle):
    AppKit.NSWorkspace.sharedWorkspace().launchApplication_("iTerm")

import os
from brish import z, zp
os.environ["ITERM2_COOKIE"] = z("""osascript -e 'tell application "iTerm2" to request cookie' """).outrs

import asyncio
import iterm2

async def main(connection):
    app = await iterm2.async_get_app(connection)
    async with iterm2.FocusMonitor(connection) as monitor:
        while True:
            update = await monitor.async_get_next_update()
            window = app.current_terminal_window
            if (update.active_session_changed or update.selected_tab_changed or update.window_changed) and window.current_tab:
                if update.window_changed:
                    zp('redis-cli set iterm_focus {update.window_changed.event.name} 2>&1')
                zp('redis-cli set iterm_active_session {window.current_tab.active_session_id} 2>&1')


iterm2.run_forever(main)

그리고여기쉘 패키지는 다음과 같습니다.

function iterm-session-active() {
    redis-cli --raw get iterm_active_session
}

function iterm-session-my() {
    if [[ "$ITERM_SESSION_ID" =~ '[^:]*:(.*)' ]] ; then
        ec "$match[1]"
    else
        return 1
    fi
}

function iterm-session-is-active() {
    [[ "$(iterm-session-active)" == "$(iterm-session-my)" ]]
}

function iterm-focus-get() {
    redis-cli --raw get iterm_focus
}

function iterm-focus-is() {
    [[ "$(iterm-focus-get)" == TERMINAL_WINDOW_BECAME_KEY ]]
}

내 Git 저장소에 있는 최신 버전의 코드를 보려면 링크를 클릭하세요. 그러나 코드에서 불필요한 항목을 정리해야 합니다.

관련 정보