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:
- run the combined code below
- open some text buffer and click into the text in different places
- 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:
Mouse pointer between characters and the text cursor misplacement
How to use mouse click to the right or to the left of the text to move cursor to this line?
EDIT: another solution for the correction of the click between characters is here: https://www.emacswiki.org/emacs/DelicateMouseClick It has the same issue that it breaks the click on fringe (cursor jumps to the next beginning of line when on right fringe)