Как избежать застревания мыши на нескольких мониторах разных размеров
У меня есть два монитора. Один - 1920x1080 (левый экран), а другой - 1440x900 (правый экран).
Прямо сейчас я настроил его так, чтобы верх обоих мониторов был выровнен. Таким образом, когда моя мышь находится в самой верхней части левого экрана и я перемещаю мышь вправо, она плавно перемещается в правый экран. Однако, если моя мышь находится на нижних 180 пикселях левого экрана, и я перемещаю мышь вправо, она не будет перемещаться на правый экран, поэтому мне нужно переместить мышь вверх, прежде чем переместить ее вправо, потому что правый экран меньше левого экрана.
Моя желаемая функциональность: если я в нижней части левого экрана и перемещаю мышь вправо, она должна появиться в нижней части правого экрана.
4 ответа
Я столкнулся с той же проблемой, и, как уже отмечали другие, Ubuntu видит, что ваши мониторы выглядят примерно так (возможно, порядок наоборот):
+----------++----------------+
| || |
| || |
+----------+| |
| |
+----------------+
В этом примере, когда ваша мышь находится на правом мониторе внизу, а мышь перемещается прямо влево, вы попадаете в мертвую зону, где вы не можете пересекать экраны. Я изменил файл bash, который публикует кассета, чтобы она была пропорциональной высоте мыши при пересечении, поэтому если вы пересекаете мышь на 3/4 вверх от левого монитора, мышь появляется на 3/4 вверх на правом мониторе.
Чтобы запустить скрипт, который я запустил, следуйте инструкциям ниже:
1) Убедитесь, что ваши мониторы установлены правильно, с изображением в сценарии (ОДИН ИЗ ВЫШЕ РАЗЛИЧНЫХ) в настройках дисплеев Ubuntu
2) Создайте текстовый файл с именем "mousejumper.sh" или что-нибудь, заканчивающееся на.sh
3) Щелкните правой кнопкой мыши по файлу и измените свойства, чтобы сделать его исполняемым
4) Скопируйте и вставьте скрипт в файл
#! /bin/bash
# Cursor relocation script by Cass May <[email protected]>
# LEFTX and RIGHTX are the screen boundaries, which triggers cursor relocation
# LEFTMONHEIGHT and LEFTMONHEIGHT are the heights in pixels of the left and right monitor
# minus 1, because computers start counting at 0... so 1920 pixels heigh becomes 1919
LEFTX="1919"
LEFTMONHEIGHT="1080"
RIGHTX="1920"
RIGHTMONHEIGHT="2159"
# Size in pixels to jump over the screens with when you hit the boundary (ex: if 5, jumps from x = 1919 to x=1924)
BUFFER="5"
# In Ubuntu Displays settings window the two monitors must be setup to look like this:
# +----------------+
# | |
# +----------+| |
# | || |
# | || |
# +----------++----------------+
#
# If the monitor setup is in a different order (ex: larger screen on left side)
# or there are more than two monitors, then the script will need to be modified
# Tip: Set "Sticky Edges" to On in the Displays settings window because
# the script checks coordinates every 0.### seconds, and sticky edges
# keeps your mouse there longer
while true; do # keep loop going to run all the time, do a slight pause for performance
# grab cursor position, and extract x and y position
CURSORPOSITION="$(xdotool getmouselocation)"
XPOS="$(grep -o '[0-9]\+' <<< "$CURSORPOSITION" | awk 'NR==1{print $1}')"
YPOS="$(grep -o '[0-9]\+' <<< "$CURSORPOSITION" | awk 'NR==2{print $1}')"
#echo "Mouse position is: ($XPOS, $YPOS)"
# if XPOS is 1920 then on right 4k monitor
if [ $XPOS = $RIGHTX ]
then
#echo "Starting jump function"
# find % height then convert
# Input is 0-2159, Output is 1080-2159
NEWYPOS=$(echo "(($LEFTMONHEIGHT+$YPOS/$RIGHTMONHEIGHT*$LEFTMONHEIGHT))" | bc -l)
#echo "YPOS with floats is: $NEWYPOS"
NEWYPOS=$(echo "$NEWYPOS" | bc -l | xargs printf "%1.0f")
NEWXPOS=$(($RIGHTX-$BUFFER))
# Move Mouse to other screen with a few pixel buffer on the screen edge
#echo "Mouse jumped from right to left from: ($XPOS, $YPOS) to ($NEWXPOS, $NEWYPOS)"
xdotool mousemove "$NEWXPOS" "$NEWYPOS"
# if XPOS is 1919 then on left 1080 monitor
elif [ $XPOS = $LEFTX ]
then
#echo "Starting jump function"
# find % height then convert
# Input is 0-2159, Output is 1080-2159
NEWYPOS=$(echo "((($YPOS-$LEFTMONHEIGHT)/$LEFTMONHEIGHT*$RIGHTMONHEIGHT))" | bc -l)
#echo "YPOS with floats is: $NEWYPOS"
NEWYPOS=$(echo "$NEWYPOS" | bc -l | xargs printf "%1.0f")
NEWXPOS=$(($LEFTX+$BUFFER))
# Move Mouse to other screen with a few pixel buffer on the screen edge
#echo "Mouse jumped from left to right from: ($XPOS, $YPOS) to ($NEWXPOS, $NEWYPOS)"
xdotool mousemove "$NEWXPOS" "$NEWYPOS"
fi
sleep 0.05
done
5) Измените эти значения в скрипте, чтобы они соответствовали спецификациям вашего монитора.
LEFTX="1919"
LEFTMONHEIGHT="1080"
RIGHTX="1920"
RIGHTMONHEIGHT="2159"
Мои мониторы были 1920x1080 слева и 3840x2160 справа.
Если вам нужна помощь в поиске значений ваших мониторов, используйте этот маленький скрипт bash и наведите курсор мыши:
#! /bin/bash
while true; do # keep loop going to run all the time, do a slight pause for performance
# grab cursor position, and extract x and y position
CURSORPOSITION="$(xdotool getmouselocation)"
XPOS="$(grep -o '[0-9]\+' <<< "$CURSORPOSITION" | awk 'NR==1{print $1}')"
YPOS="$(grep -o '[0-9]\+' <<< "$CURSORPOSITION" | awk 'NR==2{print $1}')"
echo "Mouse position is: ($XPOS, $YPOS)"
sleep 0.1
done
6) Запустите его в терминале с помощью./mousejumper.sh
Я не хочу, чтобы это работало постоянно, поэтому система не запустится при запуске. У меня есть небольшая утилита, которую я написал для включения и выключения таких скриптов вручную.
Я выбил что-то, что работает на моей машине. Мне не удалось протестировать его с несколькими мониторами, но я думаю, что настройки будут работать для вас. Это требует, чтобы вы установили xdotool.
Если это работает, поместите его в свой.rclocal, как описано здесь, и он запустится при запуске.
#! /bin/bash
# Cursor relocation script by Cass May <[email protected]>
# definitions of "hot zone", which triggers cursor relocation
XZONE="1919"
YZONE="900"
#target for cursor relocation
XTARGET="1920"
YTARGET="899"
while true; do
# grab cursor position, and extract x and y position
CURSORPOSITION="$(xdotool getmouselocation)"
XPOS="$(grep -o '[0-9]\+' <<< "$CURSORPOSITION" | awk 'NR==1{print $1}')"
YPOS="$(grep -o '[0-9]\+' <<< "$CURSORPOSITION" | awk 'NR==2{print $1}')"
# perform tests. If you wish to reconfigure this behaviour, and do
# not know where to start, look up bash numerical comparison operators.
if [[ "$XPOS" -eq "$XZONE" ]] && [[ "$YPOS" -ge "$YZONE" ]]
then
xdotool mousemove "$XTARGET" "$YTARGET"
fi
sleep 0.1
done
Причина, по которой это происходит, заключается в том, что ваш левый монитор имеет высоту 1080 пикселей, в то время как правый экран имеет высоту 900. Поскольку эти два элемента выровнены вверху, ваша мышь будет двигаться плавно, если вы двигаетесь вправо к налево и наоборот.
Но это не будет работать для нижнего края, так как нижняя часть левого экрана имеет высоту на 180 пикселей больше, чем правый экран. Согласно этому вопросу, это известная ошибка в системе X Window
Показанное решение может работать для вас, если вы используете оборудование и драйверы NVIDIA, но в противном случае вы можете застрять. У меня нет этой проблемы под управлением Windows 7 с двумя мониторами с различным разрешением.
Я написал этот скрипт Python, вдохновленный ответами @cubash и @cassm. Это должно быть менее ресурсоемким, чем использование bash и запуск нескольких новых процессов xdotool на каждой итерации цикла.
Этот сценарий опрашивает положение мыши при заданном FPS и переводит указатель на другой экран, когда он «ударяется» о край.
Это позволяет телепортировать мышь в заданное место, если она застревает в определенной координате x или y. Однако он не позволит плавно интерполировать координаты, отображая 0..1080p в 0..3840, потому что на половине края экрана курсор будет переходить из области одного монитора в другой без останавливаясь на краю, и скрипт не успеет определить его позицию (поскольку он работает по опросу).
Вы можете расширить его, чтобы записать предыдущее местоположение курсора и «масштабировать» координаты, когда предыдущее и текущее местоположения находятся на разных мониторах (например, курсор находился в точке
Другая альтернатива: поместить большое количество пустого пространства между мониторами, например
+------+
| |
+----+ | 4K |
| HD | [1000px of space] | |
+----+ +------+
Другая альтернатива: «ударять» почти везде, заставляя экраны касаться всего одним пикселем.
+------+
| |
| 4K |
| |
+----++------+
| HD |
+----+
Кажется, что если экраны соприкасаются хотя бы на один пиксель, мышь будет натыкаться на края (что дает скрипту время опросить ее местоположение и телепортировать ее), но если экраны не соприкасаются, то мышь разрешено идти в «неопределенность», которая не привязана ни к одному экрану. Вероятно, есть способ объявить «мертвые зоны» для мыши и предотвратить ее попадание в те, которые позволили бы курсору постоянно натыкаться на край и позволять скрипту обнаруживать его.
#!/usr/bin/env python3
from Xlib import display
from time import sleep
from os import system
# Optional: set the coordinates of the monitors here, I have a 1680x1050 monitor centered on top of a 1920x1080 monitor:
system('xrandr --output DP-1 --pos 120x0 --auto --output eDP-1 --pos 0x1050')
fps=50.0
delay=1.0/fps
d=display.Display()
while True:
sleep(delay)
data = d.screen().root.query_pointer()._data
x = data["root_x"]
y = data["root_y"]
# Change conditions and coordinates here, I teleport the two segments on the top left and top right of my 1920x1080 screen to the bottom left and bottom right corners of the 1680x1050 screen:
if y == 1050 and (x < 120 or x >= 1800):
if x < 120:
d.screen().root.warp_pointer(120,1049)
else:
d.screen().root.warp_pointer(1799,1049)