AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 677875
Accepted
Benjamin Chausse
Benjamin Chausse
Asked: 2021-11-17 18:42:15 +0800 CST2021-11-17 18:42:15 +0800 CST 2021-11-17 18:42:15 +0800 CST

查询当前关注哪个监视器的简单方法

  • 772

我想知道是否有一个工具可以查询当前关注的监视器。

我想要一个脚本来更改我当前使用的显示器上的墙纸(使用 xwallpaper)。据我了解,显示器编号或显示器名称(即 HDMI1、eDP1)都可能有助于实现我的目标。

最终,为当前监视器选择的壁纸将使用具有以下结构的名称复制:wall-HDMI1.png或wall-eDP1.png

有一个部分解决方案,其中接受的答案建议使用鼠标的位置猜测当前监视器xdotool。这似乎充其量是挑剔的。特别是在可以使用多种不同布局连接到多台显示器的笔记本电脑上。

multi-monitor x11
  • 1 1 个回答
  • 434 Views

1 个回答

  • Voted
  1. Best Answer
    cas
    2021-11-17T21:15:45+08:002021-11-17T21:15:45+08:00

    如果您想知道当前的主监视器是什么,这很简单:

    $ 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 脚本使用xrandrandxdotool来做到这一点。

    #!/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在脚本中,使用或作为分隔符将第三个或第四个字段拆分为一个由四个整数组成的数组+:宽度、高度、x 偏移量和 y 偏移量。perldoc -f split有关perlsplit()函数如何工作的信息,请参阅。


    PS:为什么是perl?因为 perl 更容易——在 shell 的 while-read 循环中解析文本很糟糕,并且在 shell 中进行计算至少也很糟糕,我不想处理通常的 shell 空白和引用和分词问题,或者数组的异常丑陋的 shell 语法。而且 shell 并不是唯一一种可以通过管道将数据传入或传出外部程序的语言。unix 和 linux 上常用的大多数语言都可以做到这一点。

    在 shell 中做这件事并不是特别困难,只是笨拙和笨拙。如果需要,请随意在 bash 中重新实现算法,重要的是方法,而不是语言。

    顺便说一句,在 shell 中执行此操作的最简单方法是运行类似的东西(xdotool getmouselocation --shell; xrandr) | awk '...'并让 awk 解析来自两个程序的不同类型的输入。或使用 perl 而不是 awk。另外值得注意的是,与 shell 和 perl 一样,awk 也可以运行外部程序并处理它们的输出。

    perl 中还有一些设置工作(显式打开管道),但那是样板文件。其余的代码比在 shell 中要容易得多。

    我可以使用反引号或qx()(参见perldoc -f qx)来像在 shell 中那样进行命令替换,而不是使用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;
      }
    }
    

    这将产生与第一个脚本完全相同的输出,但使用 perl 样式的命令替换而不是显式open()-ing 管道。它还使用正则表达式捕获组来提取数据,而不是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可以使用。根据您如何调用它,它可以返回一个标量值、一个数组或一个哈希值,这些值可以分配给变量或由其他函数使用。

    顺便说一句,foreach并且for是 perl 中的同义词。我写的任何地方foreach,你都可以用for. for/foreach可以用来迭代数组(列表),就像我在上面使用过的一样,它也可以像 C 风格的for ($i = 1; $i < 10; $i++)循环一样使用。

    可能有 perl 模块用于直接查询 X 以获取有关显示器和鼠标指针所需的信息,但我要花更长的时间才能找到它们并阅读它们的文档,而不仅仅是使用现有的xdotool工具xrandr。

    • 1

相关问题

  • 没有 x 会话的 gnome-keyring 用法

  • Arch Linux:在没有窗口管理器的情况下运行 VirtualBox (VM)

  • xrdb 冒号丢失错误

  • 在不改变分辨率的情况下让事情变得更大?[伴侣]

  • SSH X11 转发仅在使用受信任时有效

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    模块 i915 可能缺少固件 /lib/firmware/i915/*

    • 3 个回答
  • Marko Smith

    无法获取 jessie backports 存储库

    • 4 个回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    user12345 无法获取 jessie backports 存储库 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl 为什么大多数 systemd 示例都包含 WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve