Q: read-event: How to cancel a mouse event once read?

As to a generic keyboard keystroke, read-event reads the event without executing the command that the key is bound to. E.g., calling read-event and pressing SPC will not cause Emacs to execute self-insert-command.

As to mouse-1, read-event reads the event and executes the command that the key is bound to.

The following example creates a simple mouse-1 infinity loop to demonstrate the concept. The function signal does not break the infinity loop. It is not a recursive-edit situation, so top-level is inapplicable. The function discard-input has no effect here. Setting the following variables to nil have no effect here: unread-command-events, last-command-event and last-input-event. Through trial and error and sheer luck, I found that read-key-sequence-vector will serve to gobble up the event to achieve the desired outcome. Perhaps there is a proper way to handle this issue that does not involve calling read-key-sequence-vector.

(global-set-key [mouse-1] 'mouse-1--func)

(defun mouse-1--func (event)
  (interactive "e")
  (let ((event (read-event "Please press mouse-1 again.")))
    ;; (read-key-sequence-vector nil)
    (message "mouse-1--func:  %s" event)))
  • Not sure I understand. When I try your code in emacs -Q, what I see in *Messages* seems to indicate that mouse-1 events are not mentioned - I see only down-mouse-1 events printed there.
    – Drew
    Apr 2, 2022 at 15:52
  • @Drew -- thank you for having a look a this particular thread. Your observation is correct. The goal is to prevent mouse-1--func from running after (read-event) returns something like (down-mouse-1 (#<window 3 on *scratch*> 445 (317 . 283) 9803230 nil 445 (44 . 11) nil (23 . 129) (7 . 14))). I was unable to find any abort-like mechanism, so I had to resort to using read-key-sequence-vector to create the desired result of aborting / preventing mouse-1--func from running again. E.g., break the infinity loop with the mouse key, but do not run the function attached to it.
    – lawlist
    Apr 2, 2022 at 17:51

1 Answer 1


Whenever you click on the mouse, two events are generated. In this case down-mouse-1 and mouse-1.

Your code consumes down-mouse-1, but leaves the second in the queue.

If you consume both, the problem goes away.

For example:

(defun mouse-1--func (event)
  (interactive "e")
  (let ((event (read-event "Please press mouse-1 again.")))
    ;; (read-key-sequence-vector nil)
    (message "mouse-1--func:  %s" event)
    (when (eq (car-safe event) 'down-mouse-1)
      (let ((event2 (read-event "And a second")))
        (message "Second event: %s" event2)))))

Of course, you will need to generalize and add safeguards (e.g. what happens if the second event doesn't match the first).

Your Answer

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

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