Skip to content

Mouse motion events decoded with wrong button in X11 normal encoding (mode 1002) #126

@RiderALT

Description

@RiderALT

When using X11 button-event mouse tracking (mode 1002, \e[?1002h), motion events while dragging are decoded with the wrong button. For example, dragging with Button1 held reports Button4 (scroll up) instead of Button1.

In lTerm_unix.ml, the [M mouse report parser reads the button byte as raw Char.code but doesn't subtract the X11 protocol offset of 32. The coordinate bytes (x, y) correctly subtract 33 (offset 32 + 1 for 1-based indexing), but the button/mask byte is used as-is.

(* Current code — lTerm_unix.ml line ~865 )
Lwt_stream.next stream >|= Char.code >>= fun mask ->
...
if mask = 0b00100011 then raise Exit; (
release check uses raw value )
...
match mask land 0b11000111 with (
button match uses raw value *)

For a Button1 press, the raw byte is 0x20 (32). 32 land 0b11000111 = 0 → Button1. This works by coincidence because the offset (32) maps to zero after masking.

For Button1 motion (drag), the raw byte is 0x40 (64 = 32 offset + 32 motion bit). 64 land 0b11000111 = 0b01000000 → Button4 (scroll up). This is wrong — it should be Button1.

Environment: Linux, Konsole terminal, mode 1002 (button-event tracking

simple test:

  let term = Lwt_main.run (Lazy.force LTerm.stdout) in
  (* Enable mode 1002 for button-event tracking (press + motion + release) *)
  Lwt_main.run (Lwt_io.write Lwt_io.stdout "\027[?1002h");
  Lwt_main.run (Lwt_io.flush Lwt_io.stdout);
  let mode = Lwt_main.run (LTerm.enter_raw_mode term) in
  Printf.eprintf "Mouse test: click, drag, scroll. Press 'q' to quit.\n%!";
  let running = ref true in
  while !running do
    let event = Lwt_main.run (LTerm.read_event term) in
    match event with
    | LTerm_event.Mouse m ->
      let btn =
        match m.LTerm_mouse.button with
        | Button1 -> "Button1"
        | Button2 -> "Button2"
        | Button3 -> "Button3"
        | Button4 -> "Button4"
        | Button5 -> "Button5"
        | Button6 -> "Button6"
        | Button7 -> "Button7"
        | Button8 -> "Button8"
        | Button9 -> "Button9"
      in
      Printf.eprintf "Mouse: %-8s row=%-3d col=%-3d ctrl=%b meta=%b shift=%b\n%!"
        btn m.row m.col m.control m.meta m.shift
    | LTerm_event.Key k ->
      (match k.LTerm_key.code with
       | Char uc when Uchar.to_int uc = Char.code 'q' ->
         running := false
       | _ ->
         Printf.eprintf "Key: %s\n%!" (LTerm_key.to_string k))
    | _ -> ()
  done;
  Lwt_main.run (LTerm.leave_raw_mode term mode);
  Lwt_main.run (Lwt_io.write Lwt_io.stdout "\027[?1002l");
  Lwt_main.run (Lwt_io.flush Lwt_io.stdout);
  Printf.eprintf "Done.\n%!"

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions