ฉันจะตรวจจับได้อย่างไรเมื่อเสียบปลั๊กหรือถอดปลั๊กจอภาพ


53

มีเหตุการณ์ใดบ้างที่เกิดขึ้นเมื่อฉันเสียบจอภาพภายนอกหรือเข้ากับ DisplayPort ของแล็ปท็อปของฉัน ACPID และ UDEV ไม่ตอบสนองเลย

ฉันใช้กราฟิกออนบอร์ดบนชิป Intel นี่คือการสนทนาที่คล้ายกันซึ่งมีอยู่แล้วสองสามปี

ฉันไม่ต้องการใช้หน่วยเลือกตั้ง แต่ฉันต้องมีการกำหนดค่าบางอย่างที่ตั้งค่าการตั้งค่าการแสดงผลโดยอัตโนมัติขึ้นอยู่กับว่ามีการเชื่อมต่อจอแสดงผลหรือไม่


4
มันสามารถทำได้ด้วย udev เคอร์เนลรุ่นของคุณคืออะไร? คุณใช้ KMS (การตั้งค่าโหมดเคอร์เนล) หรือไม่
Andy

ขอบคุณสำหรับคำตอบ. ฉันไม่แน่ใจเกี่ยวกับ KMS แต่อย่างที่ฉันพูดในคำถาม udev ไม่ส่งกิจกรรมใด ๆ ( udevadm มอนิเตอร์ - คุณสมบัติไม่ตอบสนองเลย)
janoliver

@Andy: ครั้งสุดท้ายที่มันเกิดขึ้นดูเหมือนว่าระบบส่วนใหญ่ต้องการการสำรวจ หากคุณพบวิธีที่จะเรียกใช้เหตุการณ์ udev คุณสามารถตอบคำถามนั้นได้หรือไม่?
Gilles 'ดังนั้น - หยุดความชั่วร้าย'

1
ในที่สุดฉันก็ได้มันรันการโหลด i915 เป็นโมดูลเคอร์เนล
janoliver

3
คุณสามารถใช้ xrandr หรือ disper เพื่อตรวจสอบว่าเสียบจอภาพภายนอกแล้วหรือไม่github.com/wertarbyte/autorandrสามารถแสดงวิธีใช้งานได้ แต่ xrandr / disper อาจไม่รองรับการ์ดแสดงผลของคุณ
หมายเลข

คำตอบ:


13

หมายเหตุ: สิ่งนี้ได้รับการทดสอบบนแล็ปท็อปที่มีการ์ดกราฟิกขับเคลื่อน i915


พื้นหลัง

หมายเหตุ:เมื่อเสียบปลั๊กหน้าจอใหม่ไม่มีเหตุการณ์ใดถูกส่งไปยังโฮสต์สิ่งนี้ยังคงเป็นจริงแม้หลังจากการแก้ไขครั้งล่าสุดของฉัน ดังนั้นวิธีเดียวคือใช้หน่วยเลือกตั้ง พยายามทำให้มีประสิทธิภาพเท่าที่จะเป็นไปได้ ...

แก้ไข # 3

ในที่สุดก็มีทางออกที่ดีกว่า (ผ่าน ACPI):

ยังไม่มีเหตุการณ์ใด ๆ แต่ดูเหมือนว่า ACPI จะมีประสิทธิภาพมากกว่าxrandrการสอบถาม (หมายเหตุ: ต้องมีโมดูลเคอร์เนล ACPI ที่โหลด แต่ไม่ต้องการสิทธิ์พิเศษ)

ทางออกสุดท้ายของฉัน (ใช้ทุบตี):

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จะให้ข้อมูลกับคุณ แต่คุณต้องสำรวจสถานะ

ฉันได้สแกนบันทึกทั้งหมด (เคอร์เนล, daemon, 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ในขณะที่ไม่มีหน้าจอใหม่เพิ่งเสียบหรือถอดปลั๊กเครื่องมือจะปรากฏเพียง (ปกติ) แต่ถ้าคุณเสียบหรือถอดปลั๊กหน้าจอก่อนหน้านี้ในบางครั้งคุณจะเรียกใช้เครื่องมือนี้และคุณจะเห็นเดสก์ท็อปของคุณทำการรีเซ็ตหรือรีเฟรชประเภท (เหมือนเดิมถ้าคุณใช้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 และหน้าจอ

ในที่สุดฉันก็ทำงานในสองหน้าต่างที่แตกต่างกัน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 และไดรเวอร์ที่เป็นกรรมสิทธิ์, udevadm monitor ไม่แสดงอะไรเลยเมื่อฉันเชื่อมต่อจอภาพ HDMI คุณใช้ฮาร์ดแวร์ / ไดรเวอร์ใดอยู่
frankster

น่าเสียดายที่มันไม่ได้ทำงานที่น่าเชื่อถือสำหรับฉัน บางครั้งฉันได้รับข้อความเหตุการณ์เหล่านี้เมื่อฉันเสียบจอภาพและบางครั้งไม่
โทเบียส

3

สำหรับผู้ที่ไม่ต้องการใช้เส้นทาง hotplug ไม่ว่าด้วยเหตุผลใดก็ตามคุณยังไม่สามารถสำรวจความคิดเห็นภายในสคริปต์ด้วยการใช้ inotifywait:

#! / bin / ทุบตี

SCREEN_LEFT = DP2
SCREEN_RIGHT = eDP1
START_DELAY = 5

renice +19 $$> / dev / null

นอนหลับ $ START_DELAY

OLD_DUAL = "จำลอง"

ในขณะที่ [1]; ทำ
    DUAL = $ (cat / sys / class / drm / card0-DP-2 / สถานะ)

    ถ้า ["$ OLD_DUAL"! = "$ DUAL"]; แล้วก็
        หาก ["$ DUAL" == "เชื่อมต่อ"]; แล้วก็
            echo 'การตั้งค่าจอภาพสองจอ'
            xrandr - เอาท์พุท $ SCREEN_LEFT - อัตโนมัติ - หมุนปกติ - เลือก 0x0 - ส่งออก $ SCREEN_RIGHT - อัตโนมัติ - หมุนปกติ - ด้านล่าง $ SCREEN_LEFT
        อื่น
            echo 'ตั้งค่าจอภาพเดียว'
            xrandr - อัตโนมัติ
        Fi

        OLD_DUAL = "$ DUAL"
    Fi

    inotifywait -q -e close / 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 ในระบบของฉัน
nhed

3

ผมติดอยู่กับการใช้srandrd มันจะตรวจสอบเหตุการณ์ X และเรียกสคริปต์ของคุณเมื่อจอแสดงผลได้รับการเชื่อมต่อหรือตัดการเชื่อมต่อ


0

เห็นได้ชัดว่าควรมีบางสิ่ง! ระบบไฟล์ :) / sys แจ้งให้ผู้ใช้ทราบว่าฮาร์ดแวร์ใดพร้อมใช้งานดังนั้นเครื่องมือ userpace (เช่น udev หรือ mdev) สามารถเติมไดเรกทอรี "/ dev" แบบไดนามิกพร้อมโหนดอุปกรณ์ที่เป็นตัวแทนของฮาร์ดแวร์ที่มีอยู่ในปัจจุบัน Linux มีสองอินเตอร์เฟส hotplug: / sbin / hotplug และ netlink

มีการสาธิต C ขนาดเล็กในไฟล์ต่อไปนี้ http://www.kernel.org/doc/pending/hotplug.txt


0

ซอฟต์แวร์ระบบ / แอพพลิเคชั่นบน Linux ส่วนใหญ่ในปัจจุบันใช้เทคนิค ipc บางอย่างสำหรับการสื่อสารซึ่งกันและกัน ตอนนี้ D-Bus ส่วนใหญ่จะใช้กับแอปพลิเคชั่น GNOME และอาจช่วยได้

ลินุกซ์วารสาร:

D-BUS สามารถอำนวยความสะดวกในการส่งเหตุการณ์หรือสัญญาณผ่านระบบช่วยให้ส่วนประกอบต่าง ๆ ในระบบสื่อสารและในที่สุดเพื่อบูรณาการที่ดีขึ้น ตัวอย่างเช่นบลูทู ธ สามารถส่งสัญญาณเรียกเข้าที่เครื่องเล่นเพลงของคุณสามารถดักจับการปิดเสียงจนกว่าจะสิ้นสุดการโทร

วิกิพีเดีย:

D-Bus ระบุทั้ง daemon ของระบบ (สำหรับเหตุการณ์เช่น "อุปกรณ์ฮาร์ดแวร์ใหม่ที่เพิ่ม" หรือ "คิวเครื่องพิมพ์ที่เปลี่ยนแปลง") และ daemon ต่อผู้ใช้เข้าสู่ระบบเซสชัน (สำหรับการสื่อสารระหว่างกระบวนการทั่วไปที่ต้องการระหว่างผู้ใช้แอปพลิเคชัน)

มีแม้แต่ห้องสมุด Python สำหรับสิ่งนี้และ Ubuntu เพิ่งใช้ความสามารถนี้ซึ่งเรียกว่า " zeitgeist "


-6

กราฟิกคุณสามารถดูว่าจอภาพเป็นที่รู้จักMonitorหรือไม่ฉันรู้ว่าคุณสามารถค้นหาสิ่งนี้ได้บน Ubuntu, Fedora และอื่น ๆ ในตำแหน่งนี้ (หรือที่คล้ายกัน)

ระบบ / การตั้งค่า / การตรวจสอบ

และคุณสามารถเปิด / ปิดจอภาพใด ๆ ที่คุณต้องการหรือใช้ทั้งสองพร้อมกันด้วยภาพที่ซ้ำกันในจอภาพหรือจอภาพอิสระ


2
เขาถามถึงเหตุการณ์ที่เกิดขึ้นเมื่อจอภาพถูกเสียบ / ถอดปลั๊ก
Michael Mrozek

คุณดูที่นี่ไหม stackoverflow.com/questions/5469828/…
Satish
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.