10

suppose I want to bind a key to a partial key sequence (i.e. a key sequence that is a prefix of some other bound keybindings).

I've tried the obvious

(global-set-key (kbd "C-x C-x") (kbd "C-c"))

But that doesn't work for some reason.

5
  • Control+X has some nice built-in bindings to choose from: (1) ctl-x-map; (2) ctl-x-4-map; (3) ctl-x-5-map; and (4) ctl-x-r-map. Will any of those meet your needs? If not, you could define your own by grepping for those maps and copying the same method used to create them to create you own custom Control-X map. For example, grepping for ctl-x-4-map leads us to subr.el where there is (defvar ctl-x-4-map (make-sparse-keymap) . . .
    – lawlist
    Jan 5, 2015 at 3:27
  • Grepping the Emacs source code for ctl-x- will give you every example in Emacs of how to define keys using all of the maps mentioned in the previous comment. And by doing that, we see that I missed one: ctl-x-ctl-p-map
    – lawlist
    Jan 5, 2015 at 3:34
  • @lawlist, this is an example. I really want to bind arbitrary prefixes.
    – PythonNut
    Jan 5, 2015 at 5:06
  • @lawlist Just out of curiosity, which command did you run to grep the Emacs source? Jan 5, 2015 at 12:34
  • 1
    @Håkon Hægland: I use the folowing grep arguments in a custom function that I put together: i case insensitive;n print line number; I ignore binary files; E extended regular expressions; and, r recursive. I primarily use Emacs on OSX with all the *.el and src directory packaged into an *.app directory. After building Emacs, I temporarily change the time on my computer to an hour or so before the build. Then I use another tool to find and extract all of the *.el files from the *.gz compressed files into the same directories they are presently in.
    – lawlist
    Jan 5, 2015 at 17:19

3 Answers 3

8

If you want to no longer have the prefix key be a prefix key, and you want to instead bind it to a single command, you can do that - no problem: just bind it.

If you want to have the prefix key act as both a single command and as a prefix key then that is of course impossible - a key is bound to either a command or a keymap (or to a command that is a keymap).

But if you want to bind a different prefix key to the same keymap that is bound to some other prefix key, that is not a problem. What you tried to do suggests that this is maybe what you really want: to make the key sequence C-x C-x act as a prefix key the same way that C-c does.

To do that, you bind C-x C-x not to C-c but to the binding of C-c. (lookup-key global-map (kbd "C-c")) tells you that C-c is bound to command mode-specific-command-prefix (which is in fact a keymap). So if you bind C-x C-x to that then it will behave like C-c:

(global-set-key (kbd "C-x C-x") (lookup-key global-map (kbd "C-c")))

or just:

(global-set-key (kbd "C-x C-x") 'mode-specific-command-prefix)
7
  • I believe there may be an exception to the rule regarding a prefix key acting as both a single command and as a prefix key: stackoverflow.com/questions/20026083/… I've been using the example in the previous link for about a year now and am very happy with it.
    – lawlist
    Jan 5, 2015 at 7:12
  • No, that is not an exception at all. That is simply binding a key to a command (menu item, if you like) that dispatches the behavior conditionally.
    – Drew
    Jan 5, 2015 at 16:04
  • Thank you, that fixes my problem perfectly and elegantly.
    – PythonNut
    Jan 5, 2015 at 17:37
  • You can bind a key to both a keymap and an action, but only through hacks. Both cua mode and ergoemacs-mode do this for C-c and C-x. Feb 28, 2016 at 4:32
  • 1
    Nice. Just looking at Windows-ifying my keybindings and this allowed me to move help to F1 in one statement (global-set-key [f1] (lookup-key global-map (kbd "C-h"))) Feb 12, 2017 at 12:22
4

For completeness, here's an alternative to Drew's answer. It may or may not be completely equivalent.

(defun simulate-key-press (key)
  "Pretend that KEY was pressed.
KEY must be given in `kbd' notation."
  `(lambda () (interactive)
     (setq prefix-arg current-prefix-arg)
     (setq unread-command-events (listify-key-sequence (read-kbd-macro ,key)))))

(global-set-key (kbd "C-x C-x") (simulate-key-press "C-c"))
1
  • For what it's worth, and it took me a while to figure this out when I was getting started, but if you just do ,key instead of (read-kbd-macro ,key), then simulate-key-press is just consistent with all the global-set-key/define-key/etc functions, and you can do any of (simulate-key-press (kbd "C-c")), (simulate-key-press "\C-c"), or (simulate-key-press [?\C-c]).
    – mtraceur
    Apr 29 at 3:01
2

OPTION # 1:

(global-unset-key "\C-x\C-x")

(global-set-key (kbd "C-x C-x C-c") 'help-for-help)

OPTION # 2:

The following example is taken from: .../lisp/textmodes/page-ext.el and modified slightly:

(global-unset-key "\C-x\C-x")

(defvar ctl-x-ctl-x-map (make-sparse-keymap)
  "Keymap for subcommands of C-x C-x, which are for PythonNut.")

(define-key ctl-x-map "\C-x" 'ctl-x-ctl-x-prefix)
(fset 'ctl-x-ctl-x-prefix ctl-x-ctl-x-map)

(define-key ctl-x-ctl-x-map "\C-c" 'help-for-help)

Example creating C-z as a new global prefix key:

(global-unset-key "\C-z")

(defalias 'ctl-z-keymap (make-sparse-keymap))
(defvar ctl-z-map (symbol-function 'ctl-z-keymap)
  "Global keymap for characters following C-z.")
(define-key global-map "\C-z" 'ctl-z-keymap)

(define-key ctl-z-map "\C-c" 'help-for-help)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.