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%!"
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: