Como desabilitar automaticamente vários atalhos (específicos) se (e enquanto) a janela de um aplicativo específico estiver ativa
O script abaixo desabilitará atalhos de chave específicos quando a janela de um aplicativo arbitrário estiver ativa.
Embora você tenha mencionado "" eu estaria disposto a executar um script toda vez que eu lançasse o aplicativo. ", não há razão para matar o script depois, é extremamente baixo em suco.
O script
#!/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
Como usar
-
O script precisa de
xdotool
:sudo apt-get install xdotool
-
Copie o script em um arquivo vazio, salve-o como
disable_shortcuts.py
-
Na cabeça do script, substitua na linha:
app = "gedit"
"gedit" pelo seu aplicativo, ou seja: o nome do processo que possui a janela.
-
Teste o script com o comando:
python3 /path/to/disable_shortcuts.py
-
Se tudo funcionar bem, adicione-o aos aplicativos de inicialização: Dash & gt; Aplicativos de inicialização & gt; Adicionar. Adicione o comando:
/bin/bash -c "sleep 15 && python3 /path/to/disable_shortcuts.py"
Adicionando mais atalhos a serem desativados
Como exemplo, adicionei o atalho que você mencionou: CTRL + ALT + L . Os atalhos são definidos no banco de dados dconf
e podem ser definidos ou desativados usando gsettings
.
No script, essas gsettings
entradas são definidas na função: setkeys()
def setkeys(val):
# --- add the keys to be disabled below
keys = [
["org.gnome.settings-daemon.plugins.media-keys", "screensaver"]
]
# ---
Um exemplo para adicionar (desabilitar) o atalho de logout:
- Abra uma janela de terminal, execute o comando
dconf watch /
- Abra as configurações do sistema & gt; "Teclado" & gt; "Atalhos" & gt; "Sistema"
-
Redefina o atalho para si mesmo. No terminal, você pode ver a chave
gsettings
que pertence ao atalho: -
Agora temos que adicionar a chave encontrada (em uma aparência ligeiramente diferente):
["org.gnome.settings-daemon.plugins.media-keys", "logout"]
... para a lista de "chaves" em nossa função:
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"], ]
Agora ambos CTRL + ALT + L e CTRL + ALT + Excluir serão desativados se seu aplicativo estiver na frente.
Explicação
Como mencionado, os atalhos, como os que você mencionou, são definidos no banco de dados dconf
. No exemplo CTRL + ALT + L , a chave para definir ou editar o schortcut é:
org.gnome.settings-daemon.plugins.media-keys screensaver
Para desativar a chave, o comando é:
gsettings set org.gnome.settings-daemon.plugins.media-keys screensaver ""
Para redefinir a chave para o valor padrão:
gsettings reset org.gnome.settings-daemon.plugins.media-keys screensaver
O script parece uma vez por segundo se:
- seu aplicativo é executado em todos
- se assim for, parece que alguma de suas janelas está ativa
-
novamente (somente) se assim for, desativa os atalhos, listados em
# --- add the keys to be disabled below keys = [ ["org.gnome.settings-daemon.plugins.media-keys", "screensaver"], ["org.gnome.settings-daemon.plugins.media-keys", "logout"], ]
... aguardando a próxima mudança no estado.
Se a janela ativa não for mais um dos seus aplicativos, as chaves mencionadas na lista serão redefinidas para o padrão.
Nota
Como mencionado anteriormente, o fardo adicional para o processador do script é nulo. Você poderia muito bem executá-lo na inicialização, conforme explicado em "Como usar".
Afetando vários aplicativos
Como discutido nos comentários, no caso específico do OP, é útil aplicar atalhos de desativação em um grupo de aplicativos, todos residindo em um diretório.
Abaixo de uma versão para aplicar isso em todas as aplicações das quais a saída de
pgrep -f
incluirá um diretório específico. No meu exemplo, defino o diretório /opt
, portanto, se a janela ativa for uma das aplicações em /opt
, os atalhos do conjunto serão desativados.
trazer uma janela de uma das aplicações em / opt to front desativará o atalho de logout
reativar o atalho se outra janela receber foco
O script
#!/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
Como usar
-
Como o primeiro script,
xdotool
precisa ser instalado:sudo apt-get install xdotool
-
Copie o script em um arquivo vazio, salve-o como
disable_shortcuts.py
-
Na cabeça do script, substitua na linha:
appdir = "/opt"
"/ opt" pelo diretório de seus aplicativos.
-
Teste o script com o comando:
python3 /path/to/disable_shortcuts.py
-
Se tudo funcionar bem, adicione-o aos aplicativos de inicialização: Dash & gt; Aplicativos de inicialização & gt; Adicionar. Adicione o comando:
/bin/bash -c "sleep 15 && python3 /path/to/disable_shortcuts.py"
A adição de outros atalhos à lista funciona de forma semelhante à versão 1 do script.
Funciona em todos os aplicativos?
Na sua resposta, você menciona:
xprop não revela PIDs para todas as janelas. Exemplo de falha: cronômetro.
O Windows com pid 0 (como janelas tkinter, incluindo Idle), não tem identificação de janela na saída de xprop -id
.O Idle
não tem nenhum atalho conflitante, embora na minha experiência. Se você encontrar algum aplicativo com pid 0 que exija desabilitar atalhos específicos, por favor mencione.
Nesse caso, uma possível fuga seria converter a saída de
xdotool getactivewindow
para hexadecimal, o formato wmctrl
usa e, em seguida, procura o pid
correspondente na saída de
wmctrl -lp
Embora isso parecesse a coisa mais óbvia para começar, eu não usei no script para manter o script o mais leve possível.