Hack of the day: stop accidental text scaling from brushing trackpad in GNU Emacs on macOS

By | March 2, 2022

I’ve been using GNU Emacs as my primary text editor and IDE for more than 30 years, so I’m not about to stop. You can’t teach an old dog new tricks and all that. When I started my current job and had to start using a Mac for work instead of my preferred Linux, GNU Emacs came over with me. That’s when I started running into this problem on a regular basis: when I am holding down the control key in Emacs and my palm brushes against my Mac’s trackpad, Emacs interprets that as a mouse-wheel scroll event and changes the viewing scale of the text in my current Emacs buffer. This is Incredibly Annoying.

I came up with the following fix. In my ~/.emacs file:

(when (eq system-type 'darwin)
  (defvar using-trackpad-timer nil)
  (defvar using-trackpad nil)

  (defun mouse-present-p ()
      (call-process "ioreg" nil (current-buffer) nil "-p" "IOUSB")
      (goto-char (point-min))
      (and (search-forward "USB Receiver" nil t) t)))

  (defun set-using-trackpad ()
    (setq using-trackpad (not (mouse-present-p))))

  (defun maybe-mouse-wheel-text-scale (event)
    (interactive (list last-input-event))
    (when (not using-trackpad)
      (mouse-wheel-text-scale event)))

  (when using-trackpad-timer
    (cancel-timer using-trackpad-timer))
  (setq using-trackpad-timer (run-at-time "0" 60 'set-using-trackpad))
  (global-set-key [(control wheel-up)] 'maybe-mouse-wheel-text-scale)
  (global-set-key [(control wheel-down)] 'maybe-mouse-wheel-text-scale))

(Incidentally, I am dismayed by the fact that SyntaxHighlighter Evolved does not support Lisp.)

At the most basic level, what this does is rebind the mouse-wheel text scale events to a function which only calls the real function when I’m using a mouse instead of the trackpad.

It determines whether I’m using a mouse by listing connected USB devices and looking for the “USB Receiver” for my wireless mouse. If you use this hack you may need to tweak that logic (in mouse-present-p) for your particular use case.

Calling an external process to list connected USB devices is a somewhat expensive process, so rather than doing it every time an event is received, I do it once every 60 seconds in a timed task which sets a global variable based on the result.

Perhaps this will be useful to someone else. Enjoy!

Print Friendly, PDF & Email

Leave a Reply

Your email address will not be published.