1

There are subtle issues with mouse-click cursor positioning which I try to get fixed.

The first patch makes sure that the cursor falls on the correct side of a character when clicked left of right from its center.

The second patch makes sure that when we click left or right of text, the cursor ends up at the beginning or end of the text.

Separately, they work fine. When combined, they lead to an erratic jump-back of the cursor after it had been already placed.

Here is a reproducer:

  1. run the combined code below
  2. open some text buffer and click into the text in different places
  3. observe where exactly the cursor bar ends up with relation to the positon of the mouse click

At some positions, the cursor bar is briefly visible in the correct position, and then jumps back one step. This is the position it would have ended up with out the fix in posn-set-point

The question is how to make the cursor end up in the right position always.

Here is the combined code:


(setq-default cursor-type 'bar)

(defun posn-set-point (position)
  "Move point to POSITION.
Select the corresponding window as well."
  (if (not (windowp (posn-window position)))
      (error "Position not in text area of window"))
  (select-window (posn-window position))
 (let ((pos (posn-point position)))
    (if (numberp pos)
        (goto-char (if (and (eq 'bar (or (car-safe cursor-type) cursor-type))
                            (< pos (point-max))
                            (consp position)
                            (numberp (car-safe (posn-object-x-y position)))
                            (numberp (car-safe (posn-object-width-height position)))
                            (> (* 2 (car (posn-object-x-y position)))
                               (car (posn-object-width-height position))))
                       (1+ pos)
                     pos)))))


(defun mouse-goto-bol (click)
  "Move to beginning of line for mouse-1 click in left fringe."
  (interactive "e")
  (mouse-goto-line click 'left))
(defun mouse-goto-eol (click)
  "Move to beginning of line for mouse-1 click in left fringe."
  (interactive "e")
  (mouse-goto-line click 'right))
(defun mouse-goto-line (click left/right)
  "Helper for `mouse-goto-(bol|eol)'."
  (let* ((posn      (event-start click))
         (click-pt  (posn-point posn))
         (window    (posn-window posn))
         (buf       (window-buffer window))
         (clicks    (if (eq mouse-selection-click-count-buffer buf)
                        (event-click-count click)
                      0)))
    (when (= clicks 1)                  ; No-op if not single-click.
      (with-current-buffer buf
        (goto-char click-pt)
        (if (eq 'left left/right)
            (line-beginning-position)
          (line-end-position))))))
 
(global-set-key [left-fringe mouse-1]  'mouse-goto-bol)
;;(global-set-key [right-fringe mouse-1] 'mouse-goto-eol)
(global-set-key (kbd "<mouse-1>") 'mouse-goto-eol)

The solutions are from:

4
  • Please post two separate questions. Only one question per question, please. – Drew Apr 3 at 14:10
  • I've rephrased to make it clearer that it is one question only. – telephon Apr 3 at 15:04
  • The actual problem you're asking about isn't clear. This is all you say about it, and it's unclear (to me at least): "When combined, they lead to an erratic jump-back of the cursor after it had been already placed. How to make them work together?" – Drew Apr 3 at 22:09
  • ok, I see. Thanks! I've written up a step by step reproducer. – telephon Apr 4 at 9:42
1

Does using <down-mouse-1> instead of <mouse-1> fix it?

If I use your original code and then use C-h k to check the command run by a mouse click, I'm seeing commands running for both those events -- which probably explains the odd behaviour.

5
  • I was too optimistic: changing it to "<down-mouse-1>" doesn't result in the correct behaviour (clicking into the empty part of a line for jumping to the end), and it makes selections extend after a mouse-up. – telephon Apr 5 at 9:50
  • I see now that there's a default binding for each of those events. Presumably the defaults don't conflict with one another, though? Does binding one of the events and unbinding the other make a difference? My guess is still that you're conflicting with those default behaviours. – phils Apr 5 at 11:09
  • When I do not bind posn-set-point, then (global-set-key (kbd "<down-mouse-1>") 'mouse-goto-eol) does correctly move the cursor to EOL when clicked on the right of a newline character. But it also messes up selection, making it "sticky" (on mouse-up, the selection end is still bound to wherever the next mouse down happens). So there are two separate issues with this solution. – telephon Apr 5 at 14:00
  • Ah, I hadn't read the question carefully enough -- I didn't even notice that you were clobbering a standard function. That would certainly have the potential to cause problems, yes :) – phils Apr 5 at 19:21
  • (: clobbering a standard function seemed necessary … I have already filed a bug report here: debbugs.gnu.org/cgi/bugreport.cgi?bug=bug%2347360 But I also am not sure why setting down-mouse to go to eol would work at all, since I don't want to go there when the click is in the text. – telephon Apr 5 at 20:07

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.