Vinculação de chave de extensão de shell Gnome


11

Qual é a maneira mais simples de vincular (globalmente) uma combinação de teclas (por exemplo <Super>+A) a uma função em uma extensão de shell do gnome?

Inspecionando algumas extensões, encontrei o seguinte código:

global.display.add_keybinding('random-name',
                              new Gio.Settings({schema: 'org.gnome.shell.keybindings'}),
                              Meta.KeyBindingFlags.NONE,
                              function() { /* ... some code */ });

Entendo que a combinação de teclas é especificada pelo parâmetro schema e que é possível criar um arquivo XML descrevendo a combinação. Existe uma maneira mais simples de fazer isso?


Se você estiver criando uma extensão de shell do GNOME, provavelmente obterá melhores respostas em http://stackoverflow.com/ . Sinalize a atenção do moderador e eles deverão migrar sua pergunta.
NobleUplift

Respostas:


5

TL; DR

Aqui está uma classe:

KeyManager: new Lang.Class({
    Name: 'MyKeyManager',

    _init: function() {
        this.grabbers = new Map()

        global.display.connect(
            'accelerator-activated',
            Lang.bind(this, function(display, action, deviceId, timestamp){
                log('Accelerator Activated: [display={}, action={}, deviceId={}, timestamp={}]',
                    display, action, deviceId, timestamp)
                this._onAccelerator(action)
            }))
    },

    listenFor: function(accelerator, callback){
        log('Trying to listen for hot key [accelerator={}]', accelerator)
        let action = global.display.grab_accelerator(accelerator)

        if(action == Meta.KeyBindingAction.NONE) {
            log('Unable to grab accelerator [binding={}]', accelerator)
        } else {
            log('Grabbed accelerator [action={}]', action)
            let name = Meta.external_binding_name_for_action(action)
            log('Received binding name for action [name={}, action={}]',
                name, action)

            log('Requesting WM to allow binding [name={}]', name)
            Main.wm.allowKeybinding(name, Shell.ActionMode.ALL)

            this.grabbers.set(action, {
                name: name,
                accelerator: accelerator,
                callback: callback,
                action: action
            })
        }

    },

    _onAccelerator: function(action) {
        let grabber = this.grabbers.get(action)

        if(grabber) {
            this.grabbers.get(action).callback()
        } else {
            log('No listeners [action={}]', action)
        }
    }
})

E é assim que você o usa:

let keyManager = new KeyManager()
keyManager.listenFor("<ctrl><shift>a", function(){
    log("Hot keys are working!!!")
})

Você precisará de importações:

const Lang = imports.lang
const Meta = imports.gi.Meta
const Shell = imports.gi.Shell
const Main = imports.ui.main

Para parar de ouvir:

for (let it of keyManager.grabbers) {
    global.display.ungrab_accelerator(it[1].action)
    Main.wm.allowKeybinding(it[1].name, Shell.ActionMode.NONE)
}

Explicação

Eu posso estar terrivelmente errado, mas é o que eu descobri nos últimos dias.

Antes de tudo, Mutter é responsável por ouvir as teclas de atalho. O Mutter é uma estrutura para a criação de gerenciadores de janelas, não é um gerenciador de janelas em si. O Gnome Shell possui uma classe escrita em JS e chamada "Gerenciador de Janelas" - este é o Gerenciador de Janelas real que usa o Mutter internamente para fazer todas as coisas de baixo nível. Mutter tem um objeto MetaDisplay. Esse é o objeto que você usa para solicitar a escuta de uma tecla de atalho. Mas! Mas o Mutter exigirá que o Gerenciador de Janelas aprove o uso dessa tecla de atalho. Então, o que acontece quando a tecla de atalho é pressionada? - MetaDisplay gera o evento 'filter-keybinding'. - O Gerenciador de Janelas no Shell do Gnome verifica se esta tecla de acesso rápido pode ser processada. - O Window Manager retorna o valor apropriado para MetaDisplay - Se for permitido processar essa tecla de acesso, o MetaDisplay gera o evento 'ativado por acelerador'


Eu testei este código apenas no Gnome 3.22
p2t2p

Esta é uma resposta fantástica, muito obrigado por compartilhar isso.
andy.holmes

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.