현재 어떤 모니터에 초점이 맞춰져 있는지 쿼리하는 간단한 방법

현재 어떤 모니터에 초점이 맞춰져 있는지 쿼리하는 간단한 방법

현재 포커스된 모니터를 쿼리할 수 있는 도구가 있는지 궁금합니다.

현재 사용하고 있는 모니터의 배경화면을 변경하는 스크립트를 원합니다(xwallpaper 사용). 내가 이해한 바로는 모니터 번호나 모니터 이름(예: HDMI1, eDP1)이 내 목표를 달성하는 데 도움이 될 것입니다.

최종적으로 현재 모니터에 선택된 배경화면은 다음 구조의 이름을 사용하여 복사됩니다 wall-HDMI1.png.wall-eDP1.png

부분적인 해결책이 있습니다.허용되는 대답은 마우스 위치를 사용하여 현재 모니터를 추측하는 것을 제안합니다.사용 xdotool. 이것은 기껏해야 까다로운 것 같습니다. 특히 다양한 레이아웃을 사용하여 여러 모니터에 연결할 수 있는 노트북의 경우 더욱 그렇습니다.

답변1

현재 기본 모니터가 무엇인지 궁금하다면 쉽습니다.

$ xrandr | grep primary
DP-2 connected primary 2560x1440+0+0 (normal left inverted right x axis y axis) 597mm x 336mm

또는

$ xrandr | awk '/ primary / {print $1}'
DP-2

현재 마우스 포인터가 어느 모니터에 켜져 있는지 알고 싶다면 좀 더 어렵습니다. 먼저 마우스 포인터의 위치를 ​​알아낸 다음(예를 들어 를 사용하여 xdotool) 마우스의 X, Y 좌표를 각 화면의 시작 및 끝 X, Y 좌표와 비교해야 합니다(예를 들어 를 사용 xrandr). .

다음 Perl 스크립트는 이를 수행하기 위해 xrandr및 를 사용합니다 xdotool.

#!/usr/bin/perl

use strict;

my %M;    # hash to hold keys from 'xdotool getmouselocation --shell'
my $pipe; # file handle for the pipes we're going to open

# get the current cursor location into $M{X} and $M{Y}
open($pipe, "-|", qw(xdotool getmouselocation --shell)) ||
    die "couldn't open pipe from xdotool: $!\n";

while(<$pipe>) {
  chomp;
  my($key, $val) = split /=/;
  $M{$key} = $val;
};
close($pipe);

# compare mouse location to monitor co-ordinates
open($pipe, "-|", "xrandr") ||
    die "couldn't open pipe from xrandr: $!\n";

while(<$pipe>) {
  my ($display, $width, $height, $x_offset, $y_offset);

  next unless m/ connected /;
  my @F = split;
  $display = $F[0];

  # co-ordinates are on fourth field (F[3]) on the primary display
  # or on third field (F[2]) on non-primary displays. Perl arrays
  # start from zero, not one (same as in bash). 
  if ($F[2] eq "primary") {
    ($width, $height, $x_offset, $y_offset) = split /[x+]/, $F[3];
  } else {
    ($width, $height, $x_offset, $y_offset) = split /[x+]/, $F[2];
  };

  if ($M{X} >= $x_offset && $M{X} <= $width + $x_offset && 
      $M{Y} >= $y_offset && $M{Y} <= $height + $y_offset) {
    print "$display\n";
    last;
  };
};
close($pipe);

예를 들어 로 저장하고 를 ./get-focused-monitor.pl사용하여 실행 가능하게 만든 chmod +x get-focused-monitor.pl다음 실행합니다. 현재 마우스 포인터가 어느 모니터 위에 있는지 알려줍니다.

$ ./get-focused-monitor.pl 
DP-2

이를 실행하면 watch -n 0.1 ./get-focused-monitor.pl한 모니터에서 다른 모니터로 마우스를 이동할 때 모니터 이름이 변경되는 것을 확인하게 될 것입니다. 수십 초 동안 이 짓을 했는데도 제 설렘은 변함이 없었습니다. 거의 너무 많습니다.


그런데 현재 두 개의 1440p 모니터가 연결되어 있습니다. 가로 모드의 27인치 모니터("DP-2", 기본 모니터)와 세로 모드로 전환된 24인치 모니터("DP-0"). 내 시스템에서 구문 분석된 이 스크립트의 출력은 xrandr다음과 같습니다.

$ xrandr | grep \\bconnected
DP-0 connected 1440x2560+2560+0 left (normal left inverted right x axis y axis) 527mm x 296mm
DP-2 connected primary 2560x1440+0+0 (normal left inverted right x axis y axis) 597mm x 336mm

split /[x+]/세 번째 또는 네 번째 필드를 너비, 높이, x 오프셋, y 오프셋 등 4개의 정수 배열로 분할하려면 스크립트에서 x또는 구분 기호로 사용하세요 . Perl 함수의 작동 방식에 대한 정보는 참고자료를 +참조하세요 .perldoc -f splitsplit()


추신: 왜 펄인가? Perl이 더 쉽기 때문에 쉘의 while-read 루프에서 텍스트를 구문 분석하는 것은 끔찍하고 쉘에서 계산을 수행하는 것은 적어도 그만큼 나쁩니다. 따라서 일반적인 쉘 공백, 인용 및 토큰화 문제를 다루고 싶지 않습니다. 또는 어레이에 대한 엄청나게 추악한 쉘 구문. 셸은 외부 프로그램과 데이터를 연결하는 유일한 언어가 아닙니다. UNIX와 Linux에서 일반적으로 사용되는 대부분의 언어가 이를 수행할 수 있습니다.

셸에서 이 작업을 수행하는 것은 특별히 어렵지 않고 단지 어색하고 어색할 뿐입니다. 원한다면 bash에서 알고리즘을 다시 구현해도 됩니다. 중요한 것은 언어가 아니라 방법입니다.

그건 그렇고, 셸에서 이 작업을 수행하는 가장 쉬운 방법은 이와 같은 것을 실행 (xdotool getmouselocation --shell; xrandr) | awk '...'하고 awk가 두 프로그램의 다양한 입력 유형을 구문 분석하도록 하는 것입니다. 아니면 awk 대신 perl을 사용하세요. Shell 및 Perl과 마찬가지로 awk도 외부 프로그램을 실행하고 해당 출력을 처리할 수 있다는 점도 주목할 가치가 있습니다.

Perl에는 설정 작업이 조금 더 있지만(명시적으로 파이프 열기) 이는 상용구 항목입니다. 나머지 코드는 셸보다 훨씬 쉽습니다.

백틱을 사용하여 수행할 수 있습니다. 또는 qx()(참조 perldoc -f qx)명령 대체셸에서와 마찬가지로 사용하는 대신 open()(참고자료 참조 perldoc -f open) 예를 들어:

#!/usr/bin/perl

foreach (qx(xdotool getmouselocation --shell)) {
  m/^([^=]+)=(.*)$/;
  $M{$1} = $2;
};

foreach (qx(xrandr)) {
  next unless m/connected/;
  ($d, $w, $h, $xo, $yo) = m/^([^\s]+) .* (\d+)x(\d+)\+(\d+)\+(\d+)/;

  if ($M{X} >= $xo && $M{X} <= $w + $xo &&
      $M{Y} >= $yo && $M{Y} <= $h + $yo) {
    print "$d\n";
    last;
  }
}

open()이는 첫 번째 스크립트와 정확히 동일한 출력을 생성하지만 명시적인 -ing 파이프 대신 Perl 스타일 명령 대체를 사용합니다 . 또한 정규식 캡처 그룹을 사용하여 split().

그런데 Perl에는 이라는 매우 유용한 기능이 있습니다 map. perfoc -f map자세한 내용은 참고자료를 참조하세요( perldoc -f grep비슷한 유용한 내장 기능도 참조하세요). 이는 매우 유용하고 다재다능한 도구입니다. 이 도구로 수행할 수 있는 가장 간단한 작업 중 하나는 첫 번째 foreach루프를 다음으로 바꾸는 것과 같은 작업을 수행하는 것입니다.

foreach (qx(xdotool getmouselocation --shell)) {
  map { $M{$1} = $2 } m/^([^=]+)=(.*)$/;
};

심지어:

map { $M{$1} = $2 } m/^([^=]+)=(.*)$/ foreach (qx(xdotool getmouselocation --shell));

두 버전 모두 기본적으로 동일합니다. map { CODE BLOCK } ARRAY- 배열은 이미 존재하는 변수이거나 익명 배열일 수 있으며 사용자에게 적합한 방식으로 즉석에서 생성됩니다.

목록(하나 이상의 일치 항목) 컨텍스트에서 호출되면 정규식은 배열을 반환합니다. 위의 예에서 정규식 일치 연산자( m/PATTERN/)는 루프의 각 요소에 적용되어 foreach배열의 요소를 차례로 반복합니다(이 예의 배열은 xdotool getmouselocation --shell배열 요소당 행이 하나씩 있는 의 출력입니다).

다른 방법도 map사용할 수 있습니다. 호출 방법에 따라 스칼라 값, 배열 또는 해시 값을 반환할 수 있으며, 이는 변수에 할당되거나 다른 함수에서 사용될 수 있습니다.

그건 그렇고, foreachand는 forPerl의 동의어이기도 합니다. 내가 작성한 모든 곳에서 /를 사용하여 위에서 사용한 것처럼 배열(목록)을 반복할 수 있으며 C foreach스타일 루프처럼 사용할 수도 있습니다.forforforeachfor ($i = 1; $i < 10; $i++)

xdotoolxrandr직접 쿼리를 위한 Perl 모듈이 있을 수 있습니다.

관련 정보