it-swarm.cn

如何检测显示器何时插入或拔出?

当我在笔记本电脑的DisplayPort中插入或拔出外接显示器时,是否会触发任何事件? ACPID和UDEV完全不响应。

我在英特尔芯片上使用板载图形。 这里 是已经有几年历史的类似讨论了。

我不想使用轮询,但是我需要一些配置来自动设置显示设置,具体取决于显示器是否已连接。

54
janoliver

注:已在装有i915驱动图形卡的笔记本电脑上进行了测试。


背景

注意:插入新屏幕时,没有事件发送到主机,即使在我上次编辑后,该事件也保持不变。因此,唯一的方法是使用轮询。试图使它们尽可能高效...

编辑#3

最后,有一个更好的解决方案(通过ACPI):

仍然没有事件,但是ACPI的查询效率比xrandr高。 (注意:此要求已加载ACPI内核模块,但不需要root特权)。

我的最终解决方案(使用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}允许boolean参数:如果某物存在,请回答会被反转:( 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轻,但并不重要,延迟小于.02秒,Bash脚本将转到资源消耗程序(top)的顶部!

尽管这需要0.001秒的时间:

$ time read -a </proc/stat crtStat

这需要约0.030秒:

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

好大!因此,根据您的需要,可以在0.52之间合理设置delay

编辑#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/monitorxrandr),图形卡的类型为scan,因此运行xrandr -q会为您提供信息,但是您必须轮询状态。

我已经扫描了所有日志(内核,守护程序,X等),它们搜索了/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,该工具将简单(正常)显示。但是,如果您之前插入或拔出了屏幕,有时您将运行此工具,并且您会看到桌面上出现resetrefresh(相同如果您运行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大约需要0.140秒至0.200秒,而插头上最多不会发生变化,直到0.700秒每当在(注:之前插入或拔出某物食者)。

编辑#1

为了确保我没有教给别人一些不正确的信息,我在网上和文档中进行了搜索,但是没有找到关于DBus and Screens的任何信息。

最后,我在两个不同的窗口dbus-monitor --system中运行(我也一直在使用选项)和我编写的小脚本:

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

...并多次插入电源,而不是拔下显示器电源。所以现在我可以说:

  • 在此配置中,使用i915驱动程序,除了运行xrandr -q来确定是否已插入监视器,没有其他方法是否。

但是要小心,因为似乎没有其他方法。例如,xrandr似乎共享此信息,因此当我运行xinerama时,我的GNOME桌面会自动切换到xrandr...

一些文档

14
F. Hauri

以下行出现在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接口时。因此,可能有一种方法可以解决这个问题。

4
sebastianwagner

我坚持使用 srandrd 。它监视X事件,并在显示器连接或断开连接时触发脚本。

3
scorpp

对于出于某种原因而不想采用热插拔路由的用户,仍然可以使用inotifywait不在脚本中进行轮询:

#!/ bin/bash 
 
 SCREEN_LEFT = DP2 
 SCREEN_RIGHT = eDP1 
 START_DELAY = 5 
 
 renice +19 $$>/dev/null 
 
 sleep $ START_DELAY 
 
 OLD_DUAL =“ dummy” 
 
 1]; do 
 DUAL = $(cat /sys/class/drm/card0-DP-2/status)

如果[“ $ OLD_DUAL”!=“ $ DUAL”];然后
如果[“ $ DUAL” ==“ connected”];然后
 echo'Dual monitor setup'
 xrandr-输出$ SCREEN_LEFT-自动-正常旋转--pos 0x0-输出$ SCREEN_RIGHT-自动-正常旋转-下面$ SCREEN_LEFT 
 else 
 echo'单显示器设置'
 xrandr --auto 
 fi 
 
 OLD_DUAL =“ $ DUAL” 
 fi 
 
 inotifywait -q -e close/sys/class/drm/card0-DP-2/status>/dev/null 
完成
 

最好从您的.xsessionrc中调用它,不要忘记结尾&。使用xrandr进行轮询在我的全新笔记本电脑上出现了严重的可用性问题(鼠标会定期停顿)。

3
Balzola

显然应该有东西! :)/sys文件系统告诉用户空间可用的硬件,因此用户空间工具(例如udev或mdev)可以使用代表当前可用硬件的设备节点动态填充“/dev”目录。 Linux提供了两个热插拔接口:/ sbin/hotplug和netlink。

以下文件中有一个小型C演示。 http://www.kernel.org/doc/pending/hotplug.txt

0
roncsak

今天,大多数情况下,Linux上的系统/应用程序软件都使用了一些ipc技术来相互通信。 D-Bus现在主要用于GNOME应用程序,可能会有所帮助。

Linux Journal:

D-BUS可以促进通过系统发送事件或信号,从而允许系统中的不同组件进行通信并最终实现更好的集成。例如,蓝牙恶魔可以发送您的音乐播放器可以拦截的来电信号,使音量静音直到通话结束。

维基:

D-Bus提供系统守护程序(用于“添加新硬件设备”或“打印机队列已更改”之类的事件)和每个用户登录会话守护程序(用于用户应用程序之间的一般进程间通信需求)。

甚至还有一个Python)库,而ubuntu最近使用了此功能,称为“ zeitgeist ”。

0
Amir Naghizadeh