summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBerke Güzel <wenekar1@gmail.com>2026-10-13 17:07:12 +0300
committerBerke Güzel <wenekar1@gmail.com>2026-10-13 17:07:12 +0300
commit2d02d39d2cd32e9eb559638865d2746f02c08556 (patch)
treea54055b20284f5e7c2e4f66cad3d3ec4e217eebb
parent1e69599900a753e2d7275d7ba714202b7d9c843e (diff)
Fix extra mouse button encoding collision with Alt bit and document API gaps
- Encode buttons 8 through 11 (EXTRA_1..4) with offset 128 (128..131) per xterm mouse tracking, resolving collisions with the Alt modifier bit (8) - Drop EXTRA_5 from enum term_mouse_button since xterm mouse tracking defines four extra buttons (8 to 11) and codes beyond 131 collide with modifier bits - Replace literal 3 with TERM_MOUSE_BUTTON_NONE for hover motion check in mode 1002 - Document button field semantics in struct term_mouse_event for press, release, motion, and scroll events - Document OSC 52 target buffer selections ("c", "p", "q", "s", "0".."7") in term.h - Add unit tests for extra button encoding, SGR release, hover motion suppression in mode 1002, and non-collision with Alt modifiers
-rw-r--r--include/term/term.h12
-rw-r--r--include/term/term_input.h8
-rw-r--r--src/input.c6
-rw-r--r--tests/input_test.c21
4 files changed, 37 insertions, 10 deletions
diff --git a/include/term/term.h b/include/term/term.h
index 4853ebf..9c6281b 100644
--- a/include/term/term.h
+++ b/include/term/term.h
@@ -120,7 +120,17 @@ struct term_callbacks {
/* Bytes the terminal sends back to the program (replies to queries). */
void (*reply)(void *ud, const char *bytes, size_t len);
void (*title)(void *ud, const char *title);
- /* OSC 52. selection names the target, such as "c". */
+ /*
+ * OSC 52 clipboard callback.
+ * selection names the target clipboard buffer(s), commonly:
+ * "c" - clipboard (system clipboard)
+ * "p" - primary selection (X11 primary)
+ * "q" - secondary selection
+ * "s" - select selection
+ * "0".."7" - cut buffers 0 to 7
+ * A parameter may contain multiple targets (e.g. "cp").
+ * data contains decoded bytes of length len.
+ */
void (*clipboard)(void *ud, const char *selection, const char *data, size_t len);
void (*notify)(void *ud, const char *title, const char *body);
void (*bell)(void *ud);
diff --git a/include/term/term_input.h b/include/term/term_input.h
index 4b0a8d9..c317bea 100644
--- a/include/term/term_input.h
+++ b/include/term/term_input.h
@@ -118,11 +118,11 @@ enum term_mouse_button {
TERM_MOUSE_BUTTON_MIDDLE,
TERM_MOUSE_BUTTON_SECONDARY,
TERM_MOUSE_BUTTON_NONE,
+ /* Extra buttons 8 through 11 in xterm mouse reporting (encoded as 128..131). */
TERM_MOUSE_BUTTON_EXTRA_1,
TERM_MOUSE_BUTTON_EXTRA_2,
TERM_MOUSE_BUTTON_EXTRA_3,
TERM_MOUSE_BUTTON_EXTRA_4,
- TERM_MOUSE_BUTTON_EXTRA_5,
TERM_MOUSE_WHEEL_UP = 16,
TERM_MOUSE_WHEEL_DOWN,
TERM_MOUSE_WHEEL_LEFT,
@@ -152,6 +152,12 @@ struct term_key_event {
struct term_mouse_event {
struct term_vector2i pos; /* Grid cell coordinates (col, row) */
struct term_vector2i pixel; /* Absolute pixel position in terminal grid */
+ /*
+ * Button identifier:
+ * - Press and release: the button that changed state (TERM_MOUSE_BUTTON_*).
+ * - Motion: the held button for drag events, or TERM_MOUSE_BUTTON_NONE for hover.
+ * - Scroll: the wheel direction (TERM_MOUSE_WHEEL_*).
+ */
int button;
unsigned mods;
int scroll_lines;
diff --git a/src/input.c b/src/input.c
index 63313be..5625825 100644
--- a/src/input.c
+++ b/src/input.c
@@ -604,14 +604,14 @@ struct term_input_result term_input_encode_mouse(const struct term_mouse_event *
return out;
}
if (ev->kind == TERM_MOUSE_MOTION && (m->mouse == TERM_MOUSE_NORMAL ||
- (m->mouse == TERM_MOUSE_BUTTON && ev->button == 3))) {
+ (m->mouse == TERM_MOUSE_BUTTON && ev->button == TERM_MOUSE_BUTTON_NONE))) {
return out;
}
int button;
if (ev->button >= TERM_MOUSE_BUTTON_PRIMARY && ev->button <= TERM_MOUSE_BUTTON_NONE)
button = ev->button;
- else if (ev->button >= TERM_MOUSE_BUTTON_EXTRA_1 && ev->button <= TERM_MOUSE_BUTTON_EXTRA_5)
- button = 8 + ev->button - TERM_MOUSE_BUTTON_EXTRA_1;
+ else if (ev->button >= TERM_MOUSE_BUTTON_EXTRA_1 && ev->button <= TERM_MOUSE_BUTTON_EXTRA_4)
+ button = 128 + ev->button - TERM_MOUSE_BUTTON_EXTRA_1;
else if (ev->button >= TERM_MOUSE_WHEEL_UP && ev->button <= TERM_MOUSE_WHEEL_RIGHT)
button = 64 + ev->button - TERM_MOUSE_WHEEL_UP;
else {
diff --git a/tests/input_test.c b/tests/input_test.c
index 1a44f42..78dad07 100644
--- a/tests/input_test.c
+++ b/tests/input_test.c
@@ -234,14 +234,15 @@ int main(void)
m.mouse_encoding = TERM_MOUSE_ENC_X10;
m.mouse = TERM_MOUSE_BUTTON;
- MOUSE(2, 1, .kind = TERM_MOUSE_MOTION, .button = 3); expect("");
- MOUSE(2, 1, .kind = TERM_MOUSE_MOTION, .button = 0);
+ MOUSE(2, 1, .kind = TERM_MOUSE_MOTION, .button = TERM_MOUSE_BUTTON_NONE); expect("");
+ MOUSE(2, 1, .kind = TERM_MOUSE_MOTION, .button = TERM_MOUSE_BUTTON_PRIMARY);
expect("\033[M\100\043\042");
m.mouse_encoding = TERM_MOUSE_ENC_SGR;
- MOUSE(2, 1, .kind = TERM_MOUSE_MOTION, .button = 0, .mods = TERM_MOD_CTRL);
+ MOUSE(2, 1, .kind = TERM_MOUSE_MOTION, .button = TERM_MOUSE_BUTTON_NONE); expect("");
+ MOUSE(2, 1, .kind = TERM_MOUSE_MOTION, .button = TERM_MOUSE_BUTTON_PRIMARY, .mods = TERM_MOD_CTRL);
expect("\033[<48;3;2M");
m.mouse = TERM_MOUSE_ANY;
- MOUSE(2, 1, .kind = TERM_MOUSE_MOTION, .button = 3); expect("\033[<35;3;2M");
+ MOUSE(2, 1, .kind = TERM_MOUSE_MOTION, .button = TERM_MOUSE_BUTTON_NONE); expect("\033[<35;3;2M");
m.mouse_encoding = TERM_MOUSE_ENC_X10;
MOUSE(2, 1, .button = TERM_MOUSE_WHEEL_UP); expect("\033[M\140\043\042");
@@ -336,10 +337,20 @@ int main(void)
}
m.mouse = TERM_MOUSE_ANY;
m.mouse_encoding = TERM_MOUSE_ENC_SGR;
- MOUSE(2, 1, .button = TERM_MOUSE_BUTTON_EXTRA_1); expect("\033[<8;3;2M");
+ MOUSE(2, 1, .button = TERM_MOUSE_BUTTON_EXTRA_1); expect("\033[<128;3;2M");
+ MOUSE(2, 1, .button = TERM_MOUSE_BUTTON_EXTRA_2); expect("\033[<129;3;2M");
+ MOUSE(2, 1, .button = TERM_MOUSE_BUTTON_EXTRA_3); expect("\033[<130;3;2M");
+ MOUSE(2, 1, .button = TERM_MOUSE_BUTTON_EXTRA_4); expect("\033[<131;3;2M");
MOUSE(2, 1, .button = TERM_MOUSE_WHEEL_LEFT); expect("\033[<66;3;2M");
MOUSE(2, 1, .button = TERM_MOUSE_WHEEL_RIGHT); expect("\033[<67;3;2M");
+ /* Ensure Alt modifier does not collide with extra buttons */
+ MOUSE(2, 1, .button = TERM_MOUSE_BUTTON_PRIMARY, .mods = TERM_MOD_ALT); expect("\033[<8;3;2M");
+ MOUSE(2, 1, .button = TERM_MOUSE_BUTTON_EXTRA_1, .mods = TERM_MOD_ALT); expect("\033[<136;3;2M");
+ MOUSE(2, 1, .button = TERM_MOUSE_BUTTON_MIDDLE, .mods = TERM_MOD_ALT); expect("\033[<9;3;2M");
+ MOUSE(2, 1, .button = TERM_MOUSE_BUTTON_EXTRA_2, .mods = TERM_MOD_ALT); expect("\033[<137;3;2M");
+ MOUSE(2, 1, .kind = TERM_MOUSE_RELEASE, .button = TERM_MOUSE_BUTTON_EXTRA_1); expect("\033[<128;3;2m");
+
{
/* A host sizes the paste buffer from the text alone. */
static const char text[] = "ls\r\n\033[31m\u202erm\x7f\t\xe4\xb8\xad";