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


53

是否有任何当我插上或缩小外部监视器到我的笔记本电脑的DisplayPort的所触发的事件?ACPID和UDEV完全不响应。

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

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


4
可以使用udev完成。您的内核版本是什么?您是否正在使用KMS(内核模式设置)?
安迪

感谢您的回答。我不确定KMS,但是正如我在问题中所说,udev不发送任何事件。(udevadm监视器-属性完全不起作用)
janoliver 2011年

@Andy:上一次出现此问题时,似乎大多数系统都需要轮询。如果您找到了触发udev事件的方法,可以回答这个问题吗?
吉尔(Gilles)'所以

1
我终于在加载i915作为内核模块时运行了它。
janoliver 2011年

3
您可以使用xrandr或分散来检测是否已插入外部监视器。github.com/wertarbyte/autorandr可以向您展示如何使用它们。但是xrandr / disper可能不支持您的视频卡。
number5

Answers:


13

注意: 这已在装有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}允许使用布尔值参数:如果存在某些内容,答案将被反转:( 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

警告: Bash脚本比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.5和之间合理设置2

编辑#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为您提供信息,但您必须轮询状态。

我已经扫描了所有通过/proc&进行搜索的日志(内核,守护程序,X等)/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大约需要0.140到0.200秒钟,而插头上没有任何变化,而在刚插入或拔出某些东西之前,则最多需要0.700秒钟注意:这似乎不是资源消耗者)。

编辑#1

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

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

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

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

  • 在这种配置下,使用i915驱动程序xrandr -q只能运行运行来了解是否已插入监视器。

但是要小心,因为似乎没有其他方法。举例来说,xrandr似乎分享这个信息,所以我的GNOME桌面将切换xinerama自动... 当我跑xrandr

一些文档


4

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


使用nVidia 9800 GT和专有的驱动程序,当我连接HDMI监视器时,udevadm监视器什么也不显示。您正在使用什么硬件/驱动程序?
弗兰克斯特2014年

可惜的是,这对我来说并不可靠。有时在插入显示器时会收到这些事件消息,有时则不会。
Tobias

3

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

#!/ bin / bash

SCREEN_LEFT = DP2
SCREEN_RIGHT = eDP1
START_DELAY = 5

renice +19 $$> / dev / null

睡眠$ START_DELAY

OLD_DUAL =“ dummy”

而[1]; 做
    DUAL = $(cat / sys / class / drm / card0-DP-2 / status)

    如果[“ $ OLD_DUAL”!=“” $ DUAL“]; 然后
        如果[“ $ DUAL” ==“ connected”];然后
            回显“双显示器设置”
            xrandr-输出$ SCREEN_LEFT-自动-正常旋转--pos 0x0-输出$ SCREEN_RIGHT-自动-正常旋转-下面$ SCREEN_LEFT
        其他
            回声“单显示器设置”
            xrandr-汽车
        科幻

        OLD_DUAL =“ $ DUAL”
    科幻

    inotifywait -q -e关闭/ sys / class / drm / card0-DP-2 / status> / dev / null
做完了

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


我不会以为您可以使用inotify,/proc而且inotifywait -q -e close /sys/class/drm/card0-DP-2/status 在断开系统上的DP-2的连接之后确实
做不完

3

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


0

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

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


0

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

Linux杂志:

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

维基:

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

甚至还有一个Python库,并且ubuntu最近使用了称为“ zeitgeist ”的功能。


-6

以图形方式可以看到该显示器是否被识别Monitor,我知道您可以在Ubuntu(Ubuntu),Fedora和其他(或类似位置)上找到该显示器。

系统/首选项/监视器

您可以打开/关闭所需的任何显示器,或者同时使用两个显示器或独立显示器中的重复图像


2
他要求插入或拔下显示器时触发的事件
Michael Mrozek

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.