I use pdf-tools in Emacs to view PDF documents. I would like to be able to select words (mark their region and then copy them to the kill-ring) in the PDF by double-clicking on them. Is there a function in pdf-tools or elsewhere I could use to obtain this functionality?

More specifically, I want to write a function (unless it already exists in some form)

(defun select-word-on-doubleclick (ev)
    "Set region to the word under the mouse pointer and copy it to the kill-ring"
    (interactive "@e")
    ...  ;; Set region to the word under the pointer
    (pdf-view-kill-ring-save)  ;; Save region to kill-ring

and bind it to <double-mouse-1>. I need help filling out the dots above.

In the pdf-tools package there is a function called

(pdf-info-gettext PAGE EDGES &optional SELECTION-STYLE FILE-OR-BUFFER)

which could be useful for this purpose. Based on the event ev, the position of the mouse pointer (when double-clicked) can be obtained. If somehow the edges of the word under the pointer could be determined from this position, the function above would do the trick. I greatly appreciate any hints on how to make this computation.

  • In what way is this emacs-related? – NickD Sep 2 '19 at 1:44
  • @NIckD pdf-tools is an Emacs package. – Tobias Sep 2 '19 at 7:38
  • @NickD: As pointed out by Tobias, my question concerns the pdf-tools Emacs package. I added some clarification to the question. – StarBug Sep 2 '19 at 8:07
  • Thanks! I was confused indeed: there's a pdf-tools package on Fedora that has nothing to do with the emacs package of the same name (at least, at first sight). – NickD Sep 2 '19 at 17:02

At first, note that pdf-sync binds mouse-double-1 in the minor mode pdf-sync-minor-mode to pdf-sync-backward-search-mouse. So one should probably only bind it in a minor mode that can be deactivated again.

The following code defines a minor mode pdf-sel-mode that binds mouse-double-1 to a new command pdf-sel-mouse. pdf-sel-mouse selects the word below the mouse pointer and copies it to the kill-ring.

(defvar pdf-sel-mode-map nil
  "Keymap for `pdf-sel-mode'.")

(setq pdf-sel-mode-map
      (let ((map (make-sparse-keymap)))
    (define-key map [double-mouse-1] 'pdf-sel-mouse)

(define-minor-mode pdf-sel-mode
  "\\<pdf-sel-mode-map>Just binding \\[pdf-sel-mouse] to `pdf-sel-mouse'.
`pdf-sel-mouse' selects the text at point and copies it to `kill-ring'."
  :keymap pdf-sel-mode-map)

(defvar pdf-view-active-region) ;; defined in "pdf-view.el"

(defun pdf-sel-mouse (ev)
  "Select word at mouse event EV and copy it to `kill-ring'."
  (interactive "@e")
  (let* ((posn (event-start ev))
     (xy (posn-object-x-y posn))
     (size (pdf-view-image-size))
     (page (pdf-view-current-page))
     (x (/ (car xy) (float (car size))))
         (y (/ (cdr xy) (float (cdr size)))))
    (setq pdf-view-active-region (pdf-info-getselection page (list x y x y) 'word))
    (pdf-view-display-region pdf-view-active-region)
    (kill-new (pdf-info-gettext page (list x y x y) 'word))))

Note, that this function sometimes selects more than a word. But that is what epdfinfo interprets as a word.

  • Works like a charm! Thank you so much. – StarBug Sep 2 '19 at 16:49

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.