6

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.

  • 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 '15 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 '15 at 3:34
  • @lawlist, this is an example. I really want to bind arbitrary prefixes. – PythonNut Jan 5 '15 at 5:06
  • @lawlist Just out of curiosity, which command did you run to grep the Emacs source? – Håkon Hægland Jan 5 '15 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 '15 at 17:19
5

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)
  • 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 '15 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 '15 at 16:04
  • Thank you, that fixes my problem perfectly and elegantly. – PythonNut Jan 5 '15 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. – Matthew Fidler Feb 28 '16 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"))) – Philip Daniels Feb 12 '17 at 12:22
3

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

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, privacy policy and cookie policy

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