모니터가 연결되거나 연결 해제된 시기를 어떻게 감지합니까?

모니터가 연결되거나 연결 해제된 시기를 어떻게 감지합니까?

당신은 가지고 있습니까?어느외부 모니터를 노트북의 DisplayPort에 연결하거나 분리하면 이벤트가 트리거됩니까? ACPID와 UDEV는 전혀 반응하지 않습니다.

저는 인텔 칩에 내장 그래픽을 사용하고 있습니다.여기비슷한 논의가 수년간 진행되어 왔습니다.

폴링을 사용하고 싶지는 않지만 모니터 연결 여부에 따라 디스플레이 설정을 자동으로 설정하려면 몇 가지 구성이 필요합니다.

답변1

노트: 이는 i915 드라이버 그래픽 카드가 장착된 노트북에서 테스트되었습니다.


배경

노트:새 화면이 삽입되면 마지막 편집 후에도 이벤트가 호스트로 전송되지 않습니다. 따라서 유일한 방법은 폴링을 사용하는 것입니다. 최대한 효율적으로 만들려고 노력 중입니다.

편집 #3

마지막으로 ACPI를 통한 더 나은 솔루션이 있습니다.

아직 이벤트는 없지만 ACPI가 xrandr쿼리보다 더 효율적인 것 같습니다. (참고: 이필요ACPI 커널 모듈이 로드되지만 루트 권한은 필요하지 않습니다.

내 최종 솔루션(bash 사용):

isVgaConnected() {
    local crtState
    read -a < /proc/acpi/video/VID/CRT0/state crtState
    test $(( ( ${crtState[1]} >>4 ) ${1:+*-1+1} )) -ne 0
}

이제 테스트해 보세요.

$ if isVgaConnected; then echo yes; else echo no; fi 
yes

연결되었으므로 이제 플러그를 뽑습니다.

$ if isVgaConnected; then echo yes; else echo no; fi 
no

노트: ${1:+*-1+1}하나 허용부울 값인수: 만약뭔가 존재한다, 대답은 반전됩니다: ( crtState >> 4 ) * -1 + 1.

최종 스크립트:

#!/bin/bash

export crtProcEntry=/proc/acpi/video/VID/CRT0/state

isVgaConnected() {
    local crtState
    read -a < $crtProcEntry crtState
    test $(( ( ${crtState[1]} >>4 ) ${1:+*-1+1} )) -ne 0
}

delay=.1
unset switch
isVgaConnected || switch=not
while :;do
    while isVgaConnected $switch;do
        sleep $delay
      done
    if [ "$switch" ];then
        unset switch
        echo VGA IS connected
        # doing something while VGA is connected
      else
        switch=not
        echo VGA is NOT connected.
        # doing something else, maybe.
      fi
  done

경고하다: 더 가벼우 xrandr나 중요하지 않음다음보다 짧은 지연 시간0.02몇 초 후에 Bash 스크립트는 리소스 소비자 프로세스( top)의 맨 위로 이동합니다!

이 과정은 약 0.001초 정도 소요됩니다.

$ time read -a </proc/stat crtStat

이 작업에는 ~0.030초가 소요됩니다.

$ read -a < /proc/acpi/video/VID/CRT0/state crtState

이건 엄청나다! 따라서 필요에 따라 ~ 사이로 합리적으로 설정 delay하시면 됩니다 .0.52

편집 #2

마침내 이것을 사용하여 뭔가를 찾았습니다.

중요 면책조항:저글링 /proc/sys항목으로 인해 시스템이 손상될 수 있습니다! 따라서 프로덕션 시스템에서는 다음을 시도하지 마십시오.

mapfile watchFileList < <(
    find /sys /proc -type f 2>/dev/null |
    grep -i acpi\\\|i91 
)

prompt=("/" "|" '\' '-');

l=0
while :; do
  mapfile watchStat < <(
    grep -H . ${watchFileList[@]} 2>/dev/null
  )

  for ((i=0;i<=${#watchStat[@]};i++)); do
    [ "${watchStat[i]}" == "${oldStat[i]}" ] || echo ${watchStat[i]}
  done

  oldStat=("${watchStat[@]}")
  sleep .5
  printf "\r%s\r" ${prompt[l++]}
  [ $l -eq 4 ]&&l=0
done

...원치 않는 항목을 정리한 후:

for ((i=0;i<=${#watchFileList[@]};i++)); do
  [[ "${watchFileList[$i]}" =~ /sys/firmware/acpi/interrupts/sci ]] &&
      unset watchFileList[$i] && echo $i
done

나는 이것을 읽을 수 있었습니다:

/proc/acpi/video/VID/CRT0/state:state: 0x1d
/proc/acpi/video/VID/CRT0/state:state: 0x0d
/proc/acpi/video/VID/CRT0/state:state: 0x1d

연결할 때 모니터 케이블을 뽑았다가 다시 연결하세요.

원래 답변

구성을 쿼리할 때( system/preferences/monitor또는 실행 xrandr) 그래픽 카드는 다음을 수행합니다.스캐닝, 실행하면 xrandr -q정보가 제공되지만 상태를 폴링해야 합니다.

모든 /proc로그 (커널, 데몬,/sys

나는 또한 이것을 시도했습니다 :

export spc50="$(printf "%50s" "")"
watch -n1  '
    find /proc/acpi/video -type f |
        xargs grep -H . |
        sed "s/^\([^:]*):/\1'$spc50'}:/;
             s/^\(.\{50\}\) *:/\1 /"'

결국, System/Preferences/Monitor연결하거나 분리하지 않고 새 화면을 실행하면 (보통) 도구가 간단히 표시됩니다. 그러나 이전에 화면을 연결하거나 분리한 적이 있는 경우 때때로 이 도구를 실행하면 다음과 같은 메시지가 표시됩니다.초기화또는새로 고치다(실행하는 경우에도 마찬가지입니다 xrandr).

이는 런타임에서 상태를 주기적으로 폴링하여 도구에 필요한 xrandr(또는 동일한 방식으로 작동) 것을 확인하는 것 같습니다.

직접 시도해 볼 수 있습니다.

$ for ((i=10;i--;)); do xrandr -q | grep ' connected' | wc -l; sleep 1; done
1
1
1
2
2
2
1
1
1
1

10초 동안 연결된 화면(모니터) 수를 보여줍니다.

실행되는 동안 화면/모니터를 연결하거나 분리하고 무슨 일이 일어나는지 확인하세요. 따라서 작은 Bash 테스트 기능을 만들 수 있습니다.

isVgaConnected() {
    local xRandr=$(xrandr -q)
    [ "$xRandr" == "${xRandr#*VGA1 con}" ] || return 0
    return 1
}

그 용도는 다음과 같습니다:

$ if isVgaConnected; then echo yes; fi

하지만 조심하세요 xrandr. 약 1시간 정도 걸립니다.0.140초 ~ 0.200초플러그에는 아무것도 변경되지 않았지만 대부분0.700초이전에 무언가가 연결되거나 분리되었을 때마다(노트:자원을 잡아먹는 사람은 아닌 것 같습니다.)

편집 #1

제가 뭔가 잘못된 것을 가르치고 있지는 않은지 확인하기 위해 웹과 문서를 검색했지만 관련 내용을 찾지 못했습니다.DBus 및 화면.

dbus-monitor --system마지막으로, 제가 작성한 이 작은 스크립트를 사용하여 두 개의 서로 다른 창(옵션도 사용하고 있음) 에서 실행하고 있습니다 .

$ for ((i=1000;i--;)); do isVgaConnected && echo yes || echo no; sleep .5; done

...모니터 플러그를 뽑지 않고 여러 번 다시 연결했습니다. 이제 나는 이렇게 말할 수 있습니다:

  • 이 구성에서는i915 드라이버 사용xrandr -q, 모니터가 실행되는 것 외에는 연결되어 있는지 알 수 있는 방법이 없습니다 .

하지만 다른 방법은 없는 것 같으니 조심하세요. 예를 들어, xrandr이 정보는 공유되어 내 GNOME 데스크탑이 xinerama자동으로 전환됩니다...내가 달릴 때xrandr.

일부 문서

답변2

다음 줄이 나타납니다.udevadm monitor

KERNEL[46578.184280] change   /devices/pci0000:00/0000:00:02.0/drm/card0 (drm)
UDEV  [46578.195887] change   /devices/pci0000:00/0000:00:02.0/drm/card0 (drm)

모니터를 VGA 커넥터에 연결하는 경우. 따라서 이 문제를 해결할 수 있는 방법이 있을 수 있습니다.

답변3

어떤 이유로든 핫플러그 경로를 사용하고 싶지 않은 사람들을 위해 폴링 없이 스크립트에서 inotifywait를 계속 사용할 수 있습니다.

#!/bin/bash

SCREEN_LEFT=DP2
SCREEN_RIGHT=eDP1
START_DELAY=5

Rennis+19 $$ >/dev/null

수면$START_DELAY

OLD_DUAL="가상"

그리고 [1];
    DUAL=$(cat /sys/class/drm/card0-DP-2/상태)

    if [ "$OLD_DUAL" != "$DUAL" ];
        if [ "$DUAL" == "연결됨" ];
            echo '듀얼 모니터 설정'
            xrandr --output $SCREEN_LEFT --auto --rotation Normal --pos 0x0 --output $SCREEN_RIGHT --auto --rotation Normal --below $SCREEN_LEFT
        기타
            echo '단일 모니터 설정'
            xrandr--자동
        필리핀 제도

        OLD_DUAL=“$DUAL”
    필리핀 제도

    inotifywait -q -e 닫기 /sys/class/drm/card0-DP-2/status >/dev/null
완벽한

.xsessionrc에서 호출하는 것이 더 좋습니다. 후행 &를 잊지 마세요. xrandr을 사용한 폴링은 내 새 노트북에서 심각한 사용성 문제가 있습니다(마우스가 주기적으로 정지됨).

답변4

나는 bash, gawk, xrandr 및 xev를 사용하여 이 아주 멋진 스크립트를 작성했습니다. 시스템 장치를 건드리지 않고 그러한 장치에 대한 광범위한 지식이 필요하지 않고 연결된 모니터를 사용 xev하고 감지하는 데만 의존한다는 점에서 매우 깨끗합니다. randrawk 스크립트는 올바른 이벤트를 구문 분석하고 선택하는 데 사용됩니다.

노트: xev v1.2.4 이상이 필요합니다.

항상 다른 외부 모니터를 연결해 두는 노트북 사용자에게 권장됩니다.

#!/bin/bash

function monitor_xevents {
    local connected_monitors=()
    local monitor

    for monitor in $(xrandr --listactivemonitors | awk '/^\s+[0-9]+:/ {print $4}'); do
        connected_monitors+=("$monitor")
    done

    xev -root -event randr -1 | stdbuf --output=L gawk --sandbox \
        --source "BEGIN{$(printf -- 'monitors["%s"]=1\n' ${connected_monitors[@]})}" \
        --source 'BEGIN {
            pat=@/output (.[^,]*),.*connection RR_(\w+),/
            for (monitor in monitors)
                print monitor, "connected"
        }
        !/crtc None/ && match ($0, pat, s) {
            # Newly discovered monitor at runtime
            if (!(s[1] in monitors)) {
                monitors[s[1]] = 1
                print s[1], "connected"
                next
            }
            switch (s[2]) {
                case "Connected":
                    if (!monitors[s[1]])
                        monitors[s[1]] = 1
                    else next
                    break
                case "Disconnected":
                    if (monitors[s[1]])
                        monitors[s[1]] = 0
                    else next
                    break
            }
            print s[1], tolower(s[2])
        }'
}

while read output status; do
    printf "$output was $status\n"
done < <(monitor_xevents)

systemd로 실행할 수 있습니다사용자제공하다:

[Unit]
Description="Monitor hotplug notifier"

[Service]
ExecStart='/home/chigozirim/Dev/mon.sh'
Restart=on-failure
RestartSec=5s
RemainAfterExit=yes

[Install]
WantedBy=default.target

시작되면 먼저 연결된 모든 모니터를 알려준 다음, 계속 사용하면서 모니터가 연결되거나 연결이 끊긴 시기를 알려줍니다.

출력 예:

Jan 06 01:48:18 ArcoB mon.sh[495478]: eDP-1 was connected
Jan 06 01:48:18 ArcoB mon.sh[495478]: HDMI-1-0 was connected
Jan 06 18:51:13 ArcoB mon.sh[495478]: HDMI-1-0 was disconnected
Jan 06 20:29:19 ArcoB mon.sh[495478]: HDMI-1-0 was connected
Jan 07 12:47:23 ArcoB mon.sh[495478]: HDMI-1-0 was disconnected
...

제가 노트북을 사용하고 있기 때문에 eDP-1(내장형 디스플레이 포트 1)은 기본적으로 제 노트북이므로 절대 연결이 끊어지지 않습니다.

이를 확장하여 다른 스크립트 등을 호출할 수 있습니다. 이것은 위와 동등한 C/C++ 작성을 시작하고 싶지 않은 사람들을 위한 POC일 뿐입니다.

관련 정보