5

Mouse cursor position interpretation in emacs drives me nuts.

Why draw the mouse cursor in emacs window with vertical thin bar if you cannot effectively position it between characters?

Selecting text with mouse in emacs is drastically different from all other editors in both X Window and MS Windows.

I mean when the mouse cursor is exactly between two consequent characters, clicking mouse puts the point one character back from the mouse position.

In other words, to put the point somewhere in the text with the mouse you need to click on the character to the right of the place of expected point appearance.

If you, by muscle memory acquired from years of work in other editors, click exactly between two characters (or just a single pixel to the left for that matter) you end up with the point one character back from what was intended for it.

In my opinion the correct behavior would be to position the point to the left of the character only when the mouse cursor is over the left half of the character, and put it to the right otherwise.

An obvious solution to this would be to draw the mouse cursor offset by half a character width to the left from what it is in emacs by default. Or, to shift the mouse cursor hot point to the right for the emacs windows.

Is there an easy way to achieve that?

I suppose I need to clarify that I use a thin cursor of 2-pixel-wide vertical bar (i.e. (setq-default cursor-type '(bar . 2))). With a cursor in a traditional terminal style of a full-character rectangle this issue would not be so evident.

  • While this question may use slightly different words than those used within Emacs' documentation, I believe it describes the problem quite accurately. I have experienced exactly the same issue, and found it immediately problematic as soon as I switched my mouse pointer to "bar" so that it more closely resembled other editing environments I use. – DavidM Dec 01 '16 at 05:19

3 Answers3

5

First, you are apparently confusing the mouse pointer with the text cursor (aka cursor). It seems that you mostly talking about the latter, but referring to it as the "cursor".

Second, insertion of a character is always between characters (or before the first or after the last character). This is necessarily so, by definition. Even if it were to behave and be conceived as replacing an existing character by the one you want to insert, that insertion would still be between two chars (or before the first or after the last).

Third, as for the representation of the (text) cursor: you have a choice. You can use a narrow vertical bar or a box, hollow or solid (on some platforms there might be additional options). If you choose a box cursor then the box is placed on top of the character to the right of the insertion point.

You apparently already know how to change the (text) cursor style, and have opted for a bar. But your rant/question is more about the mouse pointer shape, I think, as it is apparently the pointer position (the part of the pointer shape that matters, determining where a click really is) that is throwing you off.

Fourth, you ask about setting point (the text cursor position) by clicking the mouse (left mouse button, aka mouse-1). You say that clicking with the mouse pointer positioned exactly between two chars ends up setting point to the left of the character on the left of the pointer, and not at the pointer (between the two characters).

clicking mouse puts the point one character back from the mouse position

And:

Why draw the mouse cursor in emacs window with vertical thin bar if you cannot effectively position it between characters?

I don't see that behavior. I position the I-beam pointer (which is what I think you mean here) between two characters, click it, and get the text insertion position (and the text cursor) between those characters.

If you can reproduce the behavior you describe then it is a bug, I think. Use M-x report-emacs-bug to report it.

However, I suspect that the problem is that you are positioning the wrong part of your mouse pointer. What you call "mouse position" is probably not the position of the part of the pointer that matters.

Just as for text cursor representation, the mouse pointer can be represented in different ways. If it is an arrow of some kind, the pointer position (which sets point when you click mouse-1) is often the tip of the arrow. Find out exactly which part of your pointer is used, and then get used to that.

You say that Emacs behaves differently from the other programs you are used to, with respect to the pointer. Maybe your experience is limited? Having used all kinds of programs on lots of different platforms ever since computers had pointers and cursors, I can say that the behavior and representations are variable. And they vary in Emacs too, depending on the platform.

You can also easily change the pointer representation (choose another pointer). See the Elisp manual, node Pointer Shape.

It is also the case that, by default, the pointer shape changes depending on where it is, depending, in fact, on what you can do with it at that position. At a position where you can insert text it is often a vertical I-beam shape (an insertion pointer). At other positions it is often an arrow.

Drew
  • 75,699
  • 9
  • 109
  • 225
  • 1
    Hm. Well I wasn't *trying* to scold anyone, and I did not intend "condescending dismissal". It is common to mix up pointer and cursor, and it seems to me that the question does that. I could be wrong. I don't think I belittled the OP's experience. I guessed, maybe incorrectly, that it might be limited in this regard, as I don't find that "*emacs is drastically different from all other editors in both X Window and MS Windows*". And no, clicks do not translate to target chars. They target window positions, and then, for text, ultimately *buffer positions*. And buffer positions are between chars. – Drew Feb 13 '16 at 17:58
  • I see that @VladimirPanteleev has now deleted his comment, to which I replied. I'll leave my comment anyway, to make it clear that do not want to belittle anyone, and I am trying to help, by pointing out some info that I think might not be clear to the OP. I could be wrong about that, but in that case the question is not clear (to me). – Drew Feb 13 '16 at 18:01
  • You are right, I was talking about mouse pointer really. And in case you cannot reproduce the behavior when the mouse pointer is exactly in the middle between the two chars, try it with the pointer just one or two pixels to the left and then try the same thing with another editor, e.g. `gedit`. Hope you'll see the difference now. – Alexander Shcheblikin Feb 13 '16 at 21:10
  • . I don't have `gedit`, but I believe you. As I said, please consider filing an Emacs bug. This might be something that can be corrected, if the problem is just being off by a few pixels. (Of course, if the characters or space between them involve an even number of pixels then a choice between left and right needs to be made: "exactly in the middle" would be between two pixels in that case.) It's also possible that the behavior seen is different on different Emacs platforms. – Drew Feb 13 '16 at 21:17
  • I think it is neither a bug nor something platform-specific. I observe similar mouse pointer behavior in `xterm`, so it is more of a convention thing. However, there is a difference between `xterm` and X11 `emacs` in that it is very unusual for xterm cursor to be of an I-beam shape, so such behavior doesn't usually feel so weird. – Alexander Shcheblikin Feb 13 '16 at 22:21
  • 1
    OK, but an I-beam pointer is often used when the text is editable - if not in terminals, at least in text editors. I don't think that the Emacs behavior is an odd man out, in this. – Drew Feb 13 '16 at 23:43
3

I suggest you file this as a bug or a feature request with M-x report-emacs-bug.

It can probably be fixed to some extent in Elisp by tweaking mouse-set-point as Vladimir suggested: this function receives as part of its input a "position" information which includes additionally to the character position (the one you think is wrong) both the DX/DY pixel position of the click within this character and the WIDTH/HEIGHT pixel size of the character, so you should be able to pick the next char when DX is more than half of WIDTH.

Making it 100% reliable would likely be a lot more tricky because "the next char" is not nearly as simple as it sounds when you want to account for bidirectional text, invisible text and whatnot, but at least variable char width, scrollbars, fringes, margins etc... should be a non-issue, contrary to what Vladimir seemed to think.

You can read the details of the format of mouse-set-point's argument in the Elisp manual in Command Loop => Input Events => Click Events.

It'd probably be even better to tweak posn-set-point (used internally be mouse-set-point). E.g. the patch below seems to work for me:

diff --git a/lisp/subr.el b/lisp/subr.el
index 24595e8494..44710c3cb6 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -1369,8 +1369,17 @@ posn-set-point
   (if (not (windowp (posn-window position)))
       (error "Position not in text area of window"))
   (select-window (posn-window position))
-  (if (numberp (posn-point position))
-      (goto-char (posn-point 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)))))

 (defsubst posn-x-y (position)
   "Return the x and y coordinates in POSITION.
Stefan
  • 26,154
  • 3
  • 46
  • 84
  • Reacquainting myself with Emacs after a long hiatus. I had decided that screwing up the location of the cursor was a sign that Emacs was dying and I should exit early and try Atom or Sublime or VSCode or whatever. Anyway, this patch worked perfectly. I took out the (eq 'bar ...) check because I actually think this is correct no matter what the cursor-type. Thank you so much for this. I'm unashamed to admit I use the mouse somewhat frequently, so this seemingly minor improvement makes a huge difference in my satisfaction level. Thank you so, so much. – DavidM Jan 15 '19 at 02:52
  • Note to future viewers: This has a bug. If I remember correctly, clicking beyond the end of the line puts the cursor on the next line instead of at the end of the line as one would expect. Haven't done any thinking about fixes. – DavidM May 06 '20 at 21:27
0

I've reported this as a bug. For convenience, here is a version of @Stefan's code that can be added to .emacs for a temporary bugfix:

(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)))))

This doesn't cover mouse dragging for selecting text, which has the same problem.

telephon
  • 23
  • 6