tags:

views:

226

answers:

2

I have a elisp script for Emacs that I want to do some clean up in if a user hits Ctrl-G. I use 'read-event' to catch all events, but this does not catch the Ctrl-G. When Ctrl-G is hit, it just stops execution.

In XEmacs, when you call next-command-event it will give you all events including when a user hits Ctrl-G. There must be some equivalent in Emacs.

+9  A: 

You can use with-local-quit to determine if C-g was pressed:

Edited solution to swallow quit as suggested by efunneko.

(defun my-c-g-test ()
  "test catching control-g"
  (interactive)
  (let ((inhibit-quit t))
    (unless (with-local-quit
              (y-or-n-p "arg you gonna type C-g?")
              t)
      (progn
        (message "you hit C-g")
        (setq quit-flag nil)))))

Note: with-local-quit returns the value of the last expression, or nil if C-g is pressed, so be sure to return something non-nil when no C-g is pressed. I found the elisp documentation on quitting useful. A related area is nonlocal exits, and specifically unwind-protect, which applies to more than just quit.

Trey Jackson
This solves part of the problem, but it does not swallow the control-g - just lets you know that it happened. If you want to prevent the control-g from escaping the block, use the 'inhibit-quit' and 'quit-flag' variables.
efunneko
A: 

condition-case and unwind-protect are helpful here. condition-case lets you "catch" "exceptions", of which quit is one:

(condition-case
    (while t) ; never terminates
  (quit (message "C-g was pressed")))

You can also catch other errors, like "error".

unwind-protect is like finally; it will execute "body forms" and then "unwind forms". However, the "unwind forms" are executed regardless of whether the "body forms" ran successfully:

(unwind-protect
    (while t)
  (message "Done with infinite loop"))

You want unwind-protect in your case.

jrockway