Привязка ключа расширения оболочки Gnome

Каков самый простой способ (глобально) привязать комбинацию клавиш (например, <Super>+A) к функции в расширении оболочки gnome?

Проверив пару расширений, я наткнулся на следующий код:

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

Я понимаю, что комбинация клавиш задается параметром схемы и что можно создать XML-файл с описанием комбинации. Есть ли более простой способ сделать это?


person user1655742    schedule 07.09.2012    source источник
comment
Я пытаюсь найти решение именно этой проблемы, но документации не хватает или, по крайней мере, ее трудно найти. Я не понимаю, почему этот вопрос не по теме. Это прямой вопрос, касающийся четко определенной проблемы, связанной с программным API. Пожалуйста, откройте заново. Stackoverflow — это место, где можно задать этот вопрос. Фрагмент в вопросе явно должен использоваться в апплете. Он не предназначен для ручной настройки gnome, есть и другие способы сделать это. Этому вопросу не место в суперпользователе.   -  person Pico    schedule 10.07.2013
comment
согласованный. какое отношение кодирование имеет к суперпользователю?! К сожалению, это лучший результат для тех, кто ищет, как использовать нажатия клавиш в расширении оболочки gnome.   -  person gcb    schedule 15.02.2015


Ответы (3)


Ниже приведена копия моего ответа здесь Я только тестировал это в гноме 3.22

TL;DR

Вот класс:

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
            })
        }

    },

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

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

И вот как вы его используете:

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

Вам понадобится импорт:

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

Объяснение

Возможно, я ужасно ошибаюсь, но это то, что я понял за последние пару дней.

В первую очередь именно Mutter отвечает за прослушивание горячих клавиш. Mutter — это фреймворк для создания оконных менеджеров, а не сам оконный менеджер. В Gnome Shell есть класс, написанный на JS и называемый «Диспетчер окон» — это настоящий оконный менеджер, который внутри использует Mutter для выполнения всех низкоуровневых операций. У Mutter есть объект MetaDisplay. Это объект, который вы используете для запроса прослушивания горячей клавиши. Но! Но Mutter потребует от оконного менеджера разрешения на использование этой горячей клавиши. Так что же происходит, когда нажимается горячая клавиша? - MetaDisplay генерирует событие 'filter-keybinding'. - Менеджер окон в Gnome Shell проверяет, разрешено ли обрабатывать эту горячую клавишу. - Диспетчер окон возвращает соответствующее значение в MetaDisplay - Если ему разрешено обрабатывать эту горячую клавишу, MetaDisplay генерирует событие 'accelerator-actived' - Ваше расширение должно прослушивать это событие и определять по идентификатору действия, какая горячая клавиша активирована.

person p2t2p    schedule 26.02.2017

То же, что и у @p2t2p, но переработано с использованием класса ES5. Это также использует мой класс регистратора, но вы можете заменить его на log().

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

const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();

const Logger = Me.imports.logger.Logger;

var KeyboardShortcuts = class KeyboardShortcuts {
  constructor(settings) {
    this._grabbers = {};

    this.logger = new Logger('kt kbshortcuts', settings);

    global.display.connect('accelerator-activated', (display, action, deviceId, timestamp) => {
      this.logger.debug("Accelerator Activated: [display=%s, action=%s, deviceId=%s, timestamp=%s]",
        display, action, deviceId, timestamp)
      this._onAccelerator(action)
    });
  }

  listenFor(accelerator, callback) {
    this.logger.debug('Trying to listen for hot key [accelerator=%s]', accelerator);
    let action = global.display.grab_accelerator(accelerator, 0);

    if (action == Meta.KeyBindingAction.NONE) {
      this.logger.error('Unable to grab accelerator [%s]', accelerator);
      return;
    }

    this.logger.debug('Grabbed accelerator [action={}]', action);
    let name = Meta.external_binding_name_for_action(action);
    this.logger.debug('Received binding name for action [name=%s, action=%s]',
        name, action)

    this.logger.debug('Requesting WM to allow binding [name=%s]', name)
    Main.wm.allowKeybinding(name, Shell.ActionMode.ALL)

    this._grabbers[action]={
      name: name,
      accelerator: accelerator,
      callback: callback
    };
  }

  _onAccelerator(action) {
    let grabber = this._grabbers[action];

    if (grabber) {
      grabber.callback();
    } else {
      this.logger.debug('No listeners [action=%s]', action);
    }
  }
}

и использовать его как,

      this.accel = new KeyboardShortcuts(this.settings);
      this.accel.listenFor("<ctrl><super>T", () => {
        this.logger.debug("Toggling show endtime");
        this._timers.settings.show_endtime = !this._timers.settings.show_endtime;
      });
person Steeve McCauley    schedule 07.03.2021

Вопрос старый, но я только что реализовал это для Gnome Shell 40. Итак, вот как я это сделал.

Ключ определяется в вашем обычном файле схемы, который вы используете для настроек расширения. Так это выглядит так:

<?xml version="1.0" encoding="UTF-8"?>
<schemalist>
    <schema id="org.gnome.shell.extensions.mycoolstuff" path="/org/gnome/shell/extensions/mycoolstuff/">
        <key name="cool-hotkey" type="as">
            <default><![CDATA[['<Ctrl><Super>T']]]></default>
            <summary>Hotkey to open the cool stuff.</summary>
        </key>
        
        ... other config options

    </schema>
</schemalist>

Тип ключа — массив строк, поэтому вы можете настроить несколько комбинаций клавиш для действия.

В вашем коде вы используете это так:

const Main = imports.ui.main;
const ExtensionUtils = imports.misc.extensionUtils;

...

let my_settings = ExtensionUtils.getSettings("org.gnome.shell.extensions.mycoolstuff");

Main.wm.addKeybinding("cool-hotkey", my_settings,
    Meta.KeyBindingFlags.IGNORE_AUTOREPEAT,
    Shell.ActionMode.NORMAL | Shell.ActionMode.OVERVIEW
    this._hotkeyActionMethod.bind(this));

Я бы рекомендовал удалить привязку клавиш, когда расширение отключено. Не знаю, что произойдет, если вы этого не сделаете.

Main.wm.removeKeybinding("cool-hotkey");

Кстати: изменения в настройках (через редактор dconf, gsettings или ваши настройки расширений) активны немедленно.

person Ralf    schedule 16.06.2021