web-dev-qa-db-fra.com

Bloquer les raccourcis clavier d'Unity lorsqu'une certaine application est active

Les grands IDE JetBrains (IDEA et autres) attribuent pratiquement tous les raccourcis clavier imaginables à certaines fonctions. Bien que légèrement accablant par moments, il permet également une utilisation efficace.

Mon problème est que Unity assigne également certains de ces raccourcis, qui sont prioritaires. Un exemple particulièrement agaçant est CTRL + ALT + L. La question a été explorée auparavant ici .

Cependant, aucune des approches n'est satisfaisante.

  1. La désactivation globale des raccourcis système nuit à ma productivité globale avec le système.
  2. Passer à un autre clavier en IDEA me rendra confus lorsque je développe sur différentes plates-formes (et que je dois choisir différentes mappages).

Existe-t-il un moyen de désactiver les raccourcis système uniquement lorsqu'une application donnée est active, c'est-à-dire en cours d'exécution et active?

Je serais prêt à exécuter un script chaque fois que je lance l'application.

5
Raphael

Comment désactiver automatiquement plusieurs raccourcis (spécifiques) si (et aussi longtemps que) la fenêtre d'une application spécifique est active

Le script ci-dessous désactivera des raccourcis clavier spécifiques lorsque la fenêtre d'une application arbitraire est active.

Bien que vous ayez mentionné "", je serais prêt à exécuter un script chaque fois que je lance l'application. ", il n'y a aucune raison de supprimer le script par la suite. , il est extrêmement faible en jus.

Le scénario

#!/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

Comment utiliser

  1. Le script a besoin de xdotool:

    Sudo apt-get install xdotool
    
  2. Copiez le script dans un fichier vide, enregistrez-le sous le nom disable_shortcuts.py

  3. Dans la tête du script, remplacez dans la ligne:

    app = "gedit"
    

    "gedit" par votre application, ce qui signifie: le nom du processus propriétaire de la fenêtre.

  4. Test-exécuter le script par la commande:

    python3 /path/to/disable_shortcuts.py
    
  5. Si tout fonctionne correctement, ajoutez-le à Applications de démarrage: Dash> Applications de démarrage> Ajouter. Ajoutez la commande:

    /bin/bash -c "sleep 15 && python3 /path/to/disable_shortcuts.py"
    

Ajouter plus de raccourcis à désactiver

A titre d'exemple, j'ai ajouté le raccourci que vous avez mentionné: CTRL + ALT + L. Les raccourcis sont définis dans la base de données dconf et peuvent être définis ou désactivés à l'aide de gsettings.

Dans le script, ces entrées gsettings sont définies dans la fonction: setkeys()

def setkeys(val):
    # --- add the keys to be disabled below
    keys = [
        ["org.gnome.settings-daemon.plugins.media-keys", "screensaver"]
        ]
    # ---

Un exemple pour ajouter (désactiver) le raccourci de déconnexion:

  1. Ouvrez une fenêtre de terminal, exécutez la commande dconf watch /
  2. Ouvrir les paramètres système> "Clavier"> "Raccourcis"> "Système"
  3. Re-définir le raccourci à lui-même. Dans le terminal, vous pouvez voir la touche gsettings qui appartient au raccourci:

    enter image description here

  4. Nous devons maintenant ajouter la clé trouvée (sous une apparence légèrement différente):

    ["org.gnome.settings-daemon.plugins.media-keys", "logout"]
    

    ... à la liste "clés" de notre fonction:

    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"],
            ]
    

Maintenant les deux CTRL + ALT + L et CTRL + ALT + Delete sont désactivés si votre application est devant.

Explication

Comme mentionné, les raccourcis, comme ceux que vous avez mentionnés, sont définis dans la base de données dconf. Dans l'exemple CTRL + ALT + L, la clé pour définir ou éditer le schortcut est:

org.gnome.settings-daemon.plugins.media-keys screensaver

Pour désactiver la clé, la commande est la suivante:

gsettings set org.gnome.settings-daemon.plugins.media-keys screensaver ""

Pour réinitialiser la clé à sa valeur par défaut:

gsettings reset org.gnome.settings-daemon.plugins.media-keys screensaver

Le script recherche une fois par seconde si:

  • votre application fonctionne du tout
  • si oui, il regarde si l'une de ses fenêtres est active
  • encore (seulement) si oui, il désactive les raccourcis, listés dans

    # --- add the keys to be disabled below
    keys = [
        ["org.gnome.settings-daemon.plugins.media-keys", "screensaver"],
         ["org.gnome.settings-daemon.plugins.media-keys", "logout"],
       ]
    

    ... en attente du prochain changement d'état.

Si la fenêtre active ne fait plus partie de votre application, les clés mentionnées dans la liste sont réinitialisées.

Remarque

Comme mentionné précédemment, la charge supplémentaire imposée au processeur du script est le nihil. Vous pouvez très bien l'exécuter au démarrage, comme expliqué dans "Comment utiliser".


Affectant plusieurs applications

Comme indiqué dans les commentaires, dans le cas spécifique d'OP, il est utile d'appliquer des raccourcis désactivants sur un groupe d'applications, qui résident tous dans un seul répertoire.

Ci-dessous une version à appliquer sur toutes les applications dont la sortie de

pgrep -f 

comprendra un répertoire spécifique. Dans mon exemple, j'ai défini le répertoire /opt. Ainsi, si la fenêtre active est l'une des applications de /opt, les raccourcis définis seront désactivés.


si vous ouvrez une fenêtre de l'une des applications dans/opt avant, le raccourci de déconnexion sera désactivé.

enter image description here

réactiver le raccourci si une autre fenêtre devient active

enter image description here


Le scénario

#!/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

Comment utiliser

  1. Comme le premier script, xdotool doit être installé:

    Sudo apt-get install xdotool
    
  2. Copiez le script dans un fichier vide, enregistrez-le sous le nom disable_shortcuts.py

  3. Dans la tête du script, remplacez dans la ligne:

    appdir = "/opt"
    

    "/ opt" par le répertoire de vos applications.

  4. Test-exécuter le script par la commande:

    python3 /path/to/disable_shortcuts.py
    
  5. Si tout fonctionne correctement, ajoutez-le à Applications de démarrage: Dash> Applications de démarrage> Ajouter. Ajoutez la commande:

    /bin/bash -c "sleep 15 && python3 /path/to/disable_shortcuts.py"
    

L'ajout d'autres raccourcis à la liste fonctionne exactement de la même manière que la version 1 du script.

Cela fonctionne-t-il sur toutes les applications?

Dans votre réponse, vous mentionnez:

xprop ne révèle pas les PID pour toutes les fenêtres. Exemple manquant: chronomètre.

Les fenêtres avec pid (comme tkinter windows, y compris Idle), n'ont pas d'identifiant de fenêtre dans la sortie de xprop -id. Idle ne possède pas de raccourcis contradictoires, mais dans mon expérience. Si vous rencontrez une application avec le pid 0 qui nécessiterait la désactivation de raccourcis spécifiques, veuillez l'indiquer.

Dans ce cas, une issue possible serait de convertir la sortie de

xdotool getactivewindow

au format hexadécimal, le format wmctrl utilise, puis recherche le pid correspondant dans la sortie de

wmctrl -lp

Bien que cela paraisse la chose la plus évidente au début, je ne l’ai pas utilisé dans le script pour le garder aussi léger que possible.

10
Jacob Vlijm

Basé sur (une ancienne version de) la réponse de Jacob Vlijm j'ai écrit cette version qui résout ces problèmes supplémentaires:

  1. Honors changements effectués par l'utilisateur pendant l'exécution du script.
  2. Ne réinitialise pas les valeurs définies par l'utilisateur aux valeurs par défaut.
  3. Stocke une sauvegarde des paramètres au cas où le script se ferme alors que les raccourcis sont désactivés.
  4. Gère les raccourcis gsettings et dconf. (Cela peut avoir été un non-problème.)

Problèmes ouverts:


#!/usr/bin/env python3
import subprocess
import time
import os

# Path pattern to block
apppattern = "myprocess"

# Write a backup that can restore the settings at the
# start of the script.
# Leave empty to not write a backup.
backupfile = "~/.keymap_backup"

# Add the keys to be disabled below.
shortcuts = {
    "org.gnome.settings-daemon.plugins.media-keys/key" : "gsettings",
    "/org/gnome/desktop/wm/keybindings/key" : "dconf",
}

#
# Helper functions
#

# Run a command on the Shell
def run(cmd):
    subprocess.Popen(cmd)

# Run a command on the Shell and return the
# stripped result
def get(cmd):
    try:
        return subprocess.check_output(cmd).decode("utf-8").strip()
    except:
        pass

# Get the PID of the currently active window
def getactive():
    xdoid = get(["xdotool", "getactivewindow"])
    pidline = [l for l in get(["xprop", "-id", xdoid]).splitlines()\
                 if "_NET_WM_PID(CARDINAL)" in l]
    if pidline:
        pid = pidline[0].split("=")[1].strip()
    else:
        # Something went wrong
        print("Warning: Could not obtain PID of current window")
        pid = ""

    return pid

def readkey(key):
    if shortcuts[key] == "gsettings":
        return get(["gsettings", "get"] + key.split("/"))
    Elif shortcuts[key] == "dconf":
        return get(["dconf", "read", key])

def writekey(key, val):
    if val == "": 
        val = "['']"
    if shortcuts[key] == "gsettings":        
        run(["gsettings", "set"] + key.split("/") + [val])
    Elif shortcuts[key] == "dconf":
        run(["dconf", "write", key, val])

def resetkey(key):
    if shortcuts[key] == "gsettings":
        run(["gsettings", "reset"] + key.split("/"))
    Elif shortcuts[key] == "dconf":
        run(["dconf", "reset", key])

# If val == True, disables all shortcuts.
# If val == False, resets all shortcuts.
def setkeys(flag):
    for key, val in shortcutmap.items():
        if flag == True:
            # Read current value again; user may change
            # settings, after all!
            shortcutmap[key] = readkey(key)
            writekey(key, "")            
        Elif flag == False:
            if val:
                writekey(key, val)
            else:
                resetkey(key)

#
# Main script
#

# Store current shortcuts in case they are non-default
# Note: if the default is set, dconf returns an empty string!
# Optionally, create a backup script to restore the value in case
# this script crashes at an inopportune time.
shortcutmap = {}
if backupfile:
    f = open(os.path.expanduser(backupfile),'w+') 
    f.write('#!/bin/sh\n')

for key, val in shortcuts.items():
    if shortcuts[key] == "gsettings":
        shortcutmap[key] = get(["gsettings", "get"] + key.split("/"))

        if backupfile:
            if shortcutmap[key]:
                f.write("gsettings set " + " ".join(key.split("/")) + " " + 
                shortcutmap[key] + "\n")
            else:
                f.write("gsettings reset " + " ".join(key.split("/")) + "\n")
    Elif shortcuts[key] == "dconf":
        shortcutmap[key] = get(["dconf", "read", key])

        if backupfile:
            if shortcutmap[key]:
                f.write("dconf write " + key + " " + shortcutmap[key] + "\n")
            else:
                f.write("dconf reset " + key + "\n")

if backupfile: f.close()

# Check every half second if the window changed form or to a 
# matching application.
front1 = None
while True:
    time.sleep(0.5)
    checkpids = get(["pgrep", "-f", apppattern])

    if checkpids:
        checkpids = checkpids.splitlines()
        activepid = getactive()
        #print(activepid)

        if activepid:
            front2 = True if activepid in checkpids else False
        else:
            front2 = False
    else:
        front2 = False

    if front2 != front1:
        #print("Matches: " + str(flag))
        if front2:
            setkeys(True)
        else:
            setkeys(False)
    front1 = front2

Notes:

  • Notez les différents formats de clé pour gsettings resp. dconf.
  • Les touches gsettings font dans dconf, mais les modifications apportées n'ont aucun effet. En règle générale, ajoutez les clés trouvées en utilisant méthode de Jacob en tant que gsettings et celles que vous avez dû rechercher manuellement dans dconf en tant que telles.
  • Exécutez le fichier de sauvegarde en tant que script au cas où les raccourcis seraient confondus, par exemple. par le script se terminant lorsque les raccourcis sont désactivés.
7
Raphael