CancelingInEmacs

Canceling an Action

You can use ‘C-g’ to cancel any action you have started. For some actions, you may need to repeat this. (If even this doesn’t clear things up entirely, then try `C-]’ or ‘M-x top-level’; that should do the trick.)

Example 1: You start to enter a command, with ‘M-x some-command’. Before you enter it (with the RET key), you use ‘C-g’ to cancel what you started.

Example 2: You enter command ‘M-x some-command’ and it starts to execute. It seems to take a while, and you’re not sure what it’s doing. You use ‘C-g’ to cancel the command execution.

Mapping ESC to Cancel

Many OperatingSystems and applications map the ‘ESC’ key to Cancel, so CustomizingEmacs this way can increase EmacsNewbie comfort.

But ‘ESC’ is mapped as another MetaKey by default, so this could cause trouble if you are already having MetaKeyProblems.

Here is some pseudo-code:

(if (Alt-works-as-meta?) ;; don't map if console has broken Alt key 
      (progn
        (global-set-key [escape] 'keyboard-quit) ;; all platforms?
        (setq w32-quit-key 27) ;; needed in MicroSCOft cages?
    ))

Why not call the ‘keyboard-escape-quit’ function? it’s even more do-what-i-want oriented. – SylvainGarden

Great, keyboard-escape-quit seems to work! Don’t forget to make escape cancel an isearch as well:

; Map escape to cancel (like C-g)...
(define-key isearch-mode-map [escape] 'isearch-abort)   ;; isearch
(define-key isearch-mode-map "\e" 'isearch-abort)   ;; \e seems to work better for terminals
(global-set-key [escape] 'keyboard-escape-quit)         ;; everywhere else

This kind of works in the terminal

This comes close-ish to making escape behave like ‘C-g’ in console emacs. I didn’t test it in GUI emacs, but the above solutions seem to work for GUI emacs.

There’s no perfect solution that includes allowing pressing escape to mean meta. So, in this code, escape behaves like meta if you type another key shortly after (within .2 seconds of) typing escape. If you type escape and then do nothing for .2 seconds, it fires off a ‘C-g’.

; normal-escape.el

(setq normal-escape-enabled t)   ; Makes sure we enable escape checking at the very beginning

; 1. define function for when esc is pressed
(defun normal-escape () (interactive)

  (let ((event (read-event nil nil 0.15)))

    (if (not event)

      ; No event soon after, so just escape out...

      (progn
        (setq normal-escape-enabled t)   ; Makes sure we re-enable escape checking

        ; Maybe this should conditionally do keyboard-escape-quit when in the minibuffer?
        (keyboard-quit))

      ; Recent event happened right after, so just put it back in effect...

      (setq unread-command-events (cons event unread-command-events))
      (setq unread-command-events (cons 27 unread-command-events))
      (setq normal-escape-enabled nil)   ; Disable intercepting esc for a moment, so it'll go through as normal
    )))

; 2. Check before each command
(defun normal-escape-pre-command-handler () (interactive)
  (setq normal-escape-enabled t))
(add-hook 'pre-command-hook 'normal-escape-pre-command-handler)

; 3. Define map
(setq normal-escape-map
  '((normal-escape-enabled keymap
    (27 . normal-escape))))

; 4. Add to end of emulation-mode-map-alists
(add-to-ordered-list 'emulation-mode-map-alists 'normal-escape-map 300)

(provide 'normal-escape)

One drawback, though, is that it messes up ‘C-h C-k’, making it think the key you typed was only escape. Does anyone know of a better way of putting the escape and the subsequent key back into effect than the following? Maybe a way that makes it not treat the escape separately?

      (setq unread-command-events (cons event unread-command-events))   ; Puts subsequent key back into effect
      (setq unread-command-events (cons 27 unread-command-events))   ; Puts escape back into effect

CategoryCommands CategoryHelp