如何模拟Elisp的任意按键事件?


26

是否可以从elisp模拟任意键事件?我知道可以找到给定键的绑定,然后以交互方式调用该命令的方法,但是如果该键事件未绑定到命令怎么办?

一个例子,如果我想绑定C-`在所有上下文中ESC键表现相同,该怎么办?


key-bindings如果您不打算给键绑定加上别名,则似乎是错误的标签。另外,也许您应该将示例更改为其他示例,以免混淆。
b4hand 2014年

@ b4hand我愿意提出更好的标签建议。没有key-events标签。我应该做一个吗?
nispio 2014年

听起来对我来说很合理,但事件可能会更好,因为这也可能适用于鼠标事件。
b4hand 2014年

2
对于您是否要在elisp中模拟键事件还是我特别困惑,您是否特别希望能够像执行另一个键一样使键起作用?诸如key-translation-map方便后者之类的功能,因此,如果您只想这样做,我建议您使用它,而不要做更多的手动操作。
2014年

...如果您真的想在这里进行关键翻译,我认为这是一个不同的问题,您应该单独提出;然后将这个问题的示例重新措词更适合“我如何在elisp中模拟键事件?”这一更普遍的问题。
2014年

Answers:


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 2014年

我已经看到它在要求用户按空格键继续时使用-如果用户按了其他任何键,它将转到unread-command-events
2014年

@nispio:unread-command-events就是它的名字所说的。您可以检查一个事件,然后根据事件的性质,有条件地将其推回,u-c-e以便可以正常处理。在Emacs源代码中有很多使用它的示例- grep是您的朋友。
Drew 2014年

1
我能够unread-command-events上班了。我以前缺少的是listify-key-sequence功能。我刚刚使用了原始密钥向量。
nispio

1
感谢您的回答。我想实现我完成系统的非交互式测试,所以我用这个想法实施with-simulated-input,评估与任何表情宏观unread-command-events松懈绑定到一个指定的按键顺序:github.com/DarwinAwardWinner/ido-ubiquitous/blob/...
Ryan

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 2014年

1
@nispio不适合我。该错误看起来像一个建议。
马拉巴巴2014年

@Malabarba我认为你是对的。重新开始后,emacs -Q该错误不存在。我仍然收到此错误:After 0 kbd macro iterations: foo: Lisp nesting exceeds `max-lisp-eval-depth'
nispio 2014年

这实际上是我想要的。由于某些奇怪的原因(可能与有一些交互细节evil),在我的case(evilmi-jump-items)中直接调用所需函数产生了意想不到的效果,我不得不使用(execute-kbd-macro (kbd "%"))
xji 2015年

4

这个答案中,您可以像这样使用global-set-key

(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 2014年

@nispio:您可能已经通过其他方法C-绑定了` ESC,因此进入了无限循环。
shosti

@shosti你是对的。eval-sexp在一个会话中进行的太多。:-)但是再尝试emacs -Q使原因C-` 完全无效。
nispio 2014年

根据您的系统,(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


边注:

在检查了phils的使用建议后,key-translation-map我发现了local-function-key-map哪些对实现我的更广泛目标也很有帮助。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.