Reputation: 6399
I'd like to know how to use a key as both a prefix for other keys and a command itself.
I can sorta do this with key-chord.el
, by binding the key chords to the commands following the first key but it has several issues
Some packages such as easy-kill
and expand-region
support this functionality, but they have complex codebases, and my lisp skills aren't spectacular...
How would I manage to do this? I'd really like <menu>
to be bound to evil-ex
, but I'd like to also bind <menu>
as a prefix for all movements (like arrow-keys) that sets the mark like a chordless cua-selection-mode
.
Since evil-ex isn't followed by movements and no movement self inserts, this would be a perfect use-case. <menu>
is perfect because it's right next to the arrow keys and other motions keys (eg. end, home etc.) and it's unmodified.
Upvotes: 2
Views: 534
Reputation: 1273
It seems that you want something like smartrep which enables specifying a key as a common prefix for several commands. The only thing you'll be missing out-of-the-box is binding a command to the common prefix key, so you'll need to get your hands dirty with smartrep
internals a bit. The function you're after is
(smartrep-read-event-loop
'((KEY1 command)
(KEY2 command)
...))
Here's a piece of code that may get you started:
(defun my-command-with-prefix ()
(interactive)
(invoke-prefix-command)
(initialize-event-loop)
;; The form
;;
;; (condition-case ERR FORM (quit QUIT-HANDLER))
;;
;; is there to catch C-g key presses and make sure that
;; finalization code is run.
(condition-case e
(smartrep-read-event-loop
'(("a" . command1)
("b" . command2)
("c" . command3)))
(quit nil))
;; finalize loop
(finalize-event-loop))
The snippet above is essentially a distilled version of code found here.
Upvotes: 1
Reputation: 30708
If I understand what you want, I'd suggest that it is better to forget about timers and waiting a slight delay (i.e., to distinguish the intention of <menu>
as a command from its use as a prefix key).
The approach I recommend, and use quite a bit, is to define a prefix key (in your case, e.g., <menu>
), and then put the command that you were thinking of using for <menu>
on <menu> <menu>
. That's as quick as hitting <menu>
once and trying to rely on some tiny delay etc.
And it allows the command you think of as being on <menu>
(really it is on <menu> <menu>
) to be repeatable.
I typically make such a command repeatable, so that <menu> <menu> <menu>
repeats the command once, <menu> <menu> <menu> <menu>
repeats it twice, and so on. IOW, I tend to use this trick for commands that I really want to repeat easily, by just holding down a key.
Here's a simple example, from a suggestion I made more generally to [email protected]
back in 2009, HERE. In that mailing-list message, if you scroll down to #9 you will see the proposal to use such keys, #12 shows this same example, and #15 addresses your question directly. The thread title is "have cake will eat,eat cake will have - krazy key koncept kontroversy", and its subject is exactly the question you raised.
;; This function builds a repeatable version of its argument COMMAND.
(defun repeat-command (command)
"Repeat COMMAND."
(interactive)
(let ((repeat-previous-repeated-command command)
(last-repeatable-command 'repeat))
(repeat nil)))
Here is how you could then define `C-x', which is already a prefix
key, as also a repeatable key for an action command, in this case,
`backward-char':
(defun backward-char-repeat ()
"Like `backward-char', but repeatable even on a prefix key."
(interactive)
(repeat-command 'backward-char))
(define-key ctl-x-map "\C-x" 'backward-char-repeat)
Now just holding down `C-x' invokes `backward-char' repeatedly - once
you've gotten past the first `C-x' (the prefix).
As I say, I've long used this technique to be able to (a) have "repeating prefix keys" and (b) still have other keys defined on them.
Upvotes: 5