Как автоматически отключить несколько (определенных) ярлыков, если (и пока) активно окно определенного приложения
Приведенный ниже скрипт отключит определенные сочетания клавиш, когда окно произвольного приложения активно.
Хотя вы упомянули: « Я бы хотел запускать сценарий каждый раз, когда запускаю приложение.» , Нет причин для того, чтобы впоследствии убивать сценарий, он очень мал.
Сценарий
#!/usr/bin/env python3
import subprocess
import time
import os
app = "gedit"
f = os.path.join(os.environ["HOME"], "keylist")
def run(cmd):
subprocess.Popen(cmd)
def get(cmd):
try:
return subprocess.check_output(cmd).decode("utf-8").strip()
except:
pass
def getactive():
return get(["xdotool", "getactivewindow"])
def setkeys(val):
# --- add the keys to be disabled below
keys = [
["org.gnome.settings-daemon.plugins.media-keys", "logout"],
["org.gnome.settings-daemon.plugins.media-keys", "screensaver"],
]
# ---
writelist = []
if not val:
try:
values = open(f).read().splitlines()
except FileNotFoundError:
values = []
for i, key in enumerate(keys):
try:
cmd = ["gsettings", "set"]+key+[values[i]]
except IndexError:
cmd = ["gsettings", "reset"]+key
run(cmd)
else:
for key in keys:
cmd = ["gsettings", "set"]+key+["['']"]
read = get(["gsettings", "get"]+key)
writelist.append(read)
run(cmd)
if writelist:
open(f, "wt").write("\n".join(writelist))
front1 = None
while True:
time.sleep(1)
pid = get(["pgrep", app])
if pid:
try:
active = get(["xdotool", "getactivewindow"])
relevant = get(["xdotool", "search", "--all", "--pid", pid]).splitlines()
front2 = active in relevant
except AttributeError:
front2 = front1
else:
front2 = False
if front2 != front1:
if front2:
setkeys(True)
else:
setkeys(False)
front1 = front2
Как пользоваться
Скрипт нуждается в xdotool
:
sudo apt-get install xdotool
Скопируйте скрипт в пустой файл, сохраните его как disable_shortcuts.py
В заголовке скрипта заменить в строке:
app = "gedit"
"gedit" вашим приложением, что означает: имя процесса, которому принадлежит окно.
Протестируйте скрипт с помощью команды:
python3 /path/to/disable_shortcuts.py
Если все работает нормально, добавьте его в Startup Applications: Dash> Startup Applications> Add. Добавьте команду:
/bin/bash -c "sleep 15 && python3 /path/to/disable_shortcuts.py"
Добавление нескольких ярлыков для отключения
В качестве примера я добавил ярлык, который вы упомянули: CTRL+ ALT+ L. Ярлыки устанавливаются в dconf
базе данных и могут быть установлены или отключены с помощью gsettings
.
В скрипте эти gsettings
записи задаются в функции:setkeys()
def setkeys(val):
# --- add the keys to be disabled below
keys = [
["org.gnome.settings-daemon.plugins.media-keys", "screensaver"]
]
# ---
Пример добавления (отключения) ярлыка выхода из системы:
- Откройте окно терминала, выполните команду
dconf watch /
- Откройте Системные настройки> «Клавиатура»> «Ярлыки»> «Система»
Переустановите ярлык на себя. В терминале вы можете увидеть gsettings
ключ, который принадлежит ярлыку:
Теперь мы должны добавить найденный ключ (в несколько ином виде):
["org.gnome.settings-daemon.plugins.media-keys", "logout"]
... к списку "ключей" в нашей функции:
def setkeys(val):
# --- add the keys to be disabled below
keys = [
["org.gnome.settings-daemon.plugins.media-keys", "screensaver"],
["org.gnome.settings-daemon.plugins.media-keys", "logout"],
]
Теперь CTRL+ ALT+ Lи CTRL+ ALT+ Deleteотключены, если ваше приложение находится впереди.
объяснение
Как уже упоминалось, ярлыки, как те, которые вы упоминаете, устанавливаются в dconf
базе данных. В примере CTRL+ ALT+ Lключ для установки или редактирования ярлыка:
org.gnome.settings-daemon.plugins.media-keys screensaver
Чтобы отключить ключ, команда:
gsettings set org.gnome.settings-daemon.plugins.media-keys screensaver ""
Чтобы сбросить ключ к его значению по умолчанию:
gsettings reset org.gnome.settings-daemon.plugins.media-keys screensaver
Сценарий выглядит один раз в секунду, если:
- ваше приложение работает вообще
- если это так, он смотрит, если какое-либо из его окон активно
снова (только), если это так, он отключает ярлыки, перечисленные в
# --- add the keys to be disabled below
keys = [
["org.gnome.settings-daemon.plugins.media-keys", "screensaver"],
["org.gnome.settings-daemon.plugins.media-keys", "logout"],
]
... в ожидании следующего изменения в состоянии.
Если активное окно больше не является вашим приложением, ключи, указанные в списке, сбрасываются на значения по умолчанию.
Запись
Как уже упоминалось ранее, дополнительная нагрузка на процессор сценария ничтожна. Вы можете очень хорошо запустить его при запуске, как описано в разделе «Как использовать».
Влияние на несколько приложений
Как обсуждалось в комментариях, в конкретном случае OP полезно применять ярлыки отключения для группы приложений, все они находятся в одном каталоге.
Ниже версия, чтобы применить это ко всем приложениям, выход которых
pgrep -f
будет включать в себя определенный каталог. В моем примере я установил /opt
каталог, поэтому, если активное окно является одним из приложений /opt
, установленные ярлыки будут отключены.
перенос окна одного из приложений в / opt на передний план отключит ярлык выхода из системы
повторное включение ярлыка, если другое окно получает фокус
Сценарий
#!/usr/bin/env python3
import subprocess
import time
import os
appdir = "/opt"
f = os.path.join(os.environ["HOME"], "keylist")
def run(cmd):
subprocess.call(cmd)
def get(cmd):
try:
return subprocess.check_output(cmd).decode("utf-8").strip()
except:
pass
def getactive():
return get(["xdotool", "getactivewindow"])
def setkeys(val):
# --- add the keys to be disabled below
keys = [
["org.gnome.settings-daemon.plugins.media-keys", "logout"],
["org.gnome.settings-daemon.plugins.media-keys", "screensaver"],
["org.gnome.desktop.wm.keybindings", "begin-move"],
]
# ---
writelist = []
if not val:
try:
values = open(f).read().splitlines()
except FileNotFoundError:
values = []
# for key in keys:
for i, key in enumerate(keys):
try:
cmd = ["gsettings", "set"]+key+[values[i]]
except IndexError:
cmd = ["gsettings", "reset"]+key
run(cmd)
else:
for key in keys:
cmd = ["gsettings", "set"]+key+["['']"]
read = get(["gsettings", "get"]+key)
writelist.append(read)
run(cmd)
if writelist:
open(f, "wt").write("\n".join(writelist))
front1 = None
while True:
time.sleep(1)
# check if any of the apps runs at all
checkpids = get(["pgrep", "-f", appdir])
# if so:
if checkpids:
checkpids = checkpids.splitlines()
active = getactive()
# get pid frontmost (doesn't work on pid 0)
match = [l for l in get(["xprop", "-id", active]).splitlines()\
if "_NET_WM_PID(CARDINAL)" in l]
if match:
# check if pid is of any of the relevant apps
pid = match[0].split("=")[1].strip()
front2 = True if pid in checkpids else False
else:
front2 = False
else:
front2 = False
if front2 != front1:
if front2:
setkeys(True)
else:
setkeys(False)
front1 = front2
Как пользоваться
Как и первый скрипт, xdotool
необходимо установить:
sudo apt-get install xdotool
Скопируйте скрипт в пустой файл, сохраните его как disable_shortcuts.py
В заголовке скрипта заменить в строке:
appdir = "/opt"
"/ opt" в каталоге, в котором находятся ваши приложения.
Протестируйте скрипт с помощью команды:
python3 /path/to/disable_shortcuts.py
Если все работает нормально, добавьте его в Startup Applications: Dash> Startup Applications> Add. Добавьте команду:
/bin/bash -c "sleep 15 && python3 /path/to/disable_shortcuts.py"
Добавление других ярлыков в список работает точно так же, как в версии 1 скрипта.
Это работает на всех приложениях?
В своем ответе вы упоминаете:
xprop не показывает PID для всех окон. Неудачный пример: секундомер.
Окна с pid 0 (например, окна tkinter, включая Idle) не имеют идентификатора окна в выводе xprop -id
. Idle
не имеет никаких конфликтующих сочетаний клавиш, хотя по моему опыту. Если вы запустили какое-либо приложение с pid 0, которое потребовало бы отключения определенных ярлыков, пожалуйста, укажите.
В этом случае возможным побегом будет преобразовать вывод
xdotool getactivewindow
в шестнадцатеричный формат wmctrl
использует формат , а затем ищет соответствующие pid
в выходных данных
wmctrl -lp
Хотя с самого начала это казалось наиболее очевидным, я не использовал его в сценарии, чтобы максимально облегчить его выполнение.