Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to emulate a specific key press in Emacs Lisp

Context: I want to make a minor mode where pressing f twice fast results in whatever the pressing of ( should do at that time. This doesn't always mean just insertion of (. For example, in buffers where paredit mode or autopair mode is enabled, pressing of ( usually results in insertion of (). In a paredit mode buffer, that sometimes results in wrapping the selected text: for example, if I select a b and press (, that should result in replacing the selection with (a b).

For detection of f being pressed twice, I just need to take the logic in the short code in http://www.emacswiki.org/emacs/electric-dot-and-dash.el

So the only missing piece is a Lisp code snippet that tells Emacs "Trigger pressing of ( now!"

The first thing that came to my mind was that the snippet should do

  1. find the command bound to the key (
  2. and then call call-interactively on that command.

but that breaks down if the auto pairing package (autopair or paredit or other similar package) binds ( to a command that has a logic that looks up what key was used to call the command, or if the package simply relies on post-self-insert-hook or post-command-hook instead of binding (.


update

I've looked up Key Chord documentation and it turns out what I am trying to do with answers to this question has a simpler solution:

(require 'key-chord)
(key-chord-mode 1)

(defvar my-easy-open-paren-mode-map
  (let ((map (make-sparse-keymap)))
    (key-chord-define map ",." (kbd "("))
    map))
(define-minor-mode my-easy-open-paren-mode
  "In this mode, pressing . and , together is another way of pressing the open paren.")

(defvar my-easy-semicolon-mode-map
  (let ((map (make-sparse-keymap)))
    (key-chord-define map ";;" (kbd "C-e ;"))
    map))
(define-minor-mode my-easy-semicolon-mode
  "In this mode, pressing semicolon twice fast is another way of pressing C-e and semicolon.")

(add-hook 'prog-mode-hook 'my-easy-open-paren-mode)

(add-hook 'c-mode-common-hook 'my-easy-semicolon-mode)

Triggering key press may still be useful in other contexts though.

like image 241
Jisang Yoo Avatar asked Sep 19 '13 21:09

Jisang Yoo


People also ask

How do I set key bindings in Emacs?

The manual way is to use C-h k KEY to describe what KEY is bound to; the other way is to describe a function, FUNCTION , with C-h f FUNCTION . Because Emacs is a self-documenting editor all functions, variables, keys, etc. known to Emacs are accessible through the describe-xxx commands. Type C-h C-h to see them all.

Is Emacs Lisp the same as Lisp?

Emacs Lisp is a dialect of the Lisp programming language used as a scripting language by Emacs (a text editor family most commonly associated with GNU Emacs and XEmacs). It is used for implementing most of the editing functionality built into Emacs, the remainder being written in C, as is the Lisp interpreter.

What does #' mean in Emacs Lisp?

function (aka #' ) is used to quote functions, whereas quote (aka ' ) is used to quote data.

How do I lisp in Emacs?

In a fresh Emacs window, type ESC-x lisp-interaction-mode . That will turn your buffer into a LISP terminal; pressing Ctrl+j will feed the s-expression that your cursor (called "point" in Emacs manuals' jargon) stands right behind to LISP, and will print the result.


2 Answers

You might appreciate the Key Chord library for binding functions to a double key-press. (I wouldn't recommend using f if you'll be writing in English, mind you; but YMMV.)

post-self-insert-hook would still run if the binding was self-insert-command. post-command-hook will run in any case, but if you're worried about it seeing an incorrect function and/or input event, you can manipulate those...

After looking up the binding, your function can set this-command to the function you're about to call-interactively, and last-command-event to the required key. e.g.:

(defun my-fake-paren ()
  (interactive)
  (let ((command (key-binding "(")))
    (setq last-command-event ?\()
    (setq this-command command)
    (call-interactively command)))
like image 68
phils Avatar answered Oct 26 '22 11:10

phils


I use Key Chord for this sort of thing, although the page you link appears to do the same thing. The trick is getting the call to call-interactively to work correctly. I wrapped it in a let that reset the variable last-command-event, such that call-interactively thinks it was a "(". This works for me in paredit and fundamental modes.

(require 'key-chord)
(key-chord-mode 1)

(defun my-paren-call ()
  (interactive)
  (let ((last-command-event ?\())
    (call-interactively (key-binding "("))))

(key-chord-define-global "ff" 'my-paren-call)
like image 43
Tyler Avatar answered Oct 26 '22 12:10

Tyler