Як я можу імітувати довільну ключову подію від Elisp?


26

Чи можна імітувати довільну ключову подію від elisp? Мені відомо, що я можу знайти прив'язку даного ключа, а потім викликати цю команду інтерактивно, але що робити, якщо ця ключова подія не пов'язана з командою?

Як один із прикладів , що робити, якщо я хотів би зобов’язати C-`себе поводитись так, як ESCключ у всіх контекстах ?


Схоже, key-bindingsце неправильний тег, якщо ви не намагаєтесь отримати псевдонім ключового прив'язки. Також, можливо, вам слід змінити свій приклад на щось інше, щоб він не заплутався.
b4hand

@ b4hand Я відкритий для пропозицій щодо кращих тегів. Тега немає key-events. Я повинен зробити його?
nispio

мені здається розумним, але події можуть бути кращими, оскільки це також може бути застосовно до подій миші.
b4hand

2
Я все ще плутаюсь щодо того, чи хочете ви імітувати ключову подію в elisp, чи ви конкретно хочете можливість зробити ключовий акт так, ніби це був інший ключ? Ласкаво key-translation-mapсприяти останньому, тому, якщо це все, що ви хочете, я б запропонував використовувати його, а не робити щось більш посібник.
філс

... і якщо ключовий переклад справді - це те, що ви хочете тут, я думаю, це вже інше питання, і вам слід задати це окремо; а потім переформулюйте свій приклад, щоб це питання було більш придатним до загальної проблеми "як я імітую ключову подію в Elisp?"
філс

Відповіді:


24

Ви можете подати до циклу команд довільні події (натискання клавіш, клацання миші тощо), наклавши їх на unread-command-events. Наприклад, наступне за допомогою циклу команд виконає перерву при наступному запуску:

(setq unread-command-events (listify-key-sequence "\C-g"))

Зауважте, що це лише подає події до циклу команд, тому це не зробить нічого цікавого, якщо ви будете циклічно запускати у власний код.

Інший підхід, про який ви, здається, усвідомлюєте, полягає в тому, щоб знайти функцію, до якої пов'язаний даний ключ, і виконати його самостійно:

(funcall (global-key-binding "\C-g"))

Це виконає команду негайно. Однак остерігайтеся, що деякі команди мають різну поведінку залежно від того, чи викликаються вони інтерактивно, наприклад аргументи за замовчуванням. Ви хочете компенсувати це за допомогою call-interactively:

(call-interactively (global-key-binding "\C-g"))

Я читав, unread-command-eventsале не зміг зрозуміти, як ним користуватися. Встановлення це не мало для мене ефекту. Чи є хороший приклад того, як він використовується?
nispio

Я бачив, як це використовується, коли просити користувача натиснути пробіл, щоб продовжити - якщо користувач натискає щось інше, він переходить на unread-command-events.
jch

@nispio: unread-command-eventsсаме те, що говорить його назва. Ви можете оглянути подію, а потім, залежно від того, що вона є, умовно натисніть її назад, u-c-eщоб потім нормально оброблятися. Є безліч прикладів його використання у вихідному коді Emacs - grepце ваш друг.
Дрю

1
Мені вдалося взятися unread-command-eventsна роботу. Штука, яку мені раніше не вистачало, була listify-key-sequenceфункцією. Я щойно використовував перероблений ключовий вектор.
nispio

1
Дякую за цю відповідь. Я хотів реалізувати неінтерактивні тести моєї системи завершення, тому я використав цю ідею, щоб реалізувати with-simulated-inputмакрос, який оцінює будь-який вираз із unread-command-eventsобмеженим до визначеної послідовності ключів: github.com/DarwinAwardWinner/ido-ubiquitous/blob/…
Райан Ч. Томпсон

8

Найпростіший спосіб, про який я знаю, - це просто використовувати execute-kbd-macro:

(defun foo () (interactive) (execute-kbd-macro (kbd "<escape>")))
(global-set-key (kbd "C-`") 'foo)

Оцінка вищезазначеного, а потім натискання C-` дає мені помилку apply: Wrong number of arguments: #[(ad--addoit-function ....
nispio

1
@nispio Не для мене. Ця помилка виглядає як порада.
Малабарба

@Malabarba Я думаю, ти маєш рацію. Після початку свіжої з emacs -Qцією помилкою немає. Я все ще отримую цю помилку, хоча:After 0 kbd macro iterations: foo: Lisp nesting exceeds `max-lisp-eval-depth'
nispio

Це власне те, що я шукав. З якоїсь дивної причини (ймовірно, деякі деталі взаємодії з evil) прямий виклик потрібної функції мав несподіваний ефект у моєму випадку ( evilmi-jump-items), і мені довелося скористатися(execute-kbd-macro (kbd "%"))
xji

4

З цієї відповіді ви можете використовувати глобальний ключ на зразок цього

(global-set-key (kbd "C-`") (kbd "<escape>"))

Яке трактуватиме C-`якescape

Здається, це має деякі проблеми, хоча якщо друга комбінація не виконує функцію. Тож якщо escapeвін використовується так Meta, він не працює належним чином. Але це, здається, працює для команд, прив'язаних до функцій.


@nispio: Насправді це працює, оскільки другий аргумент неявно перетворений на макрос клавіатури.
shosti

1
@shosti Оцінка вище і натиснувши C-` дає мені помилку: After 0 kbd macro iterations: command-execute: Lisp nesting exceeds `max-lisp-eval-depth'.
nispio

@nispio: Ви, мабуть, вже C-`зв'язані ESCяким-небудь іншим методом, тому він переходить у нескінченний цикл.
shosti

@shosti Ви мали рацію. Занадто багато eval-sexpвідбувається за один сеанс. :-) Але спробую знову з emacs -Qпричинами C-` просто нічого не робити.
nispio

Залежно від вашої системи (kbd "<escape>")та (kbd "ESC")може означати різні речі - ви пробували обидва?
shosti

2

Прочитавши пропозицію від jch для використання unread-command-events, я зміг зламати разом рішення, яке зробить деякі речі, які я шукаю.

(defun my-simulate-key-event (event &optional N)
  "Simulate an arbitrary keypress event.

This function sets the `unread-command-events' variable in order to simulate a
series of key events given by EVENT. Can also For negative N, simulate the
specified key EVENT directly.  For positive N, removes the last N elements from
the list of key events in `this-command-keys' and then appends EVENT.  For N nil,
treat as N=1."
  (let ((prefix (listify-key-sequence (this-command-keys)))
         (key (listify-key-sequence event))
         (n (prefix-numeric-value N)))
     (if (< n 0)
         (setq prefix key)
       (nbutlast prefix n)
       (nconc prefix key))
       (setq unread-command-events prefix)))

Існує ще низка кінок, які потрібно відпрацювати. А саме, я не отримую правильного результату, якщо викликаю цю функцію двічі поспіль у межах одного defun.


Бічна примітка:

Після перевірки пропозиції щодо використання філівkey-translation-map я зміг знайти, local-function-key-mapщо також дуже корисно для досягнення деяких моїх більш широких цілей.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.