Commit: e6e87c06a0103378165dc3fd65c7a9e16d9412ad
Parent: 3b575234f1161b46ba4df154e7fa5a40592531ca
Author: Randy Palamar
Date: Sun, 17 Nov 2024 17:55:30 -0700
support mouse motion tracking and SGR reporting scheme
Diffstat:
M | terminal.c | | | 16 | ++++++++++++---- |
M | util.h | | | 7 | +++++-- |
M | vtgl.c | | | 125 | +++++++++++++++++++++++++++++++++++++++++++------------------------------------ |
3 files changed, 85 insertions(+), 63 deletions(-)
diff --git a/terminal.c b/terminal.c
@@ -570,10 +570,6 @@ set_mode(Term *t, CSI *csi, b32 set, ModeState src, ModeState *dest)
dest->win &= ~WM_REVERSE;
if (set) dest->win |= (src.win & WM_REVERSE);
break;
- case PRIV(1000): /* xterm: report mouse button presses */
- dest->win &= ~WM_MOUSE_MASK;
- if (set) dest->win |= (src.win & WM_MOUSE_BTN);
- break;
case PRIV(6): /* DECOM: Cursor Origin Mode */
if (set) t->cursor.state |= CURSOR_ORIGIN;
else t->cursor.state &= ~CURSOR_ORIGIN;
@@ -583,6 +579,18 @@ set_mode(Term *t, CSI *csi, b32 set, ModeState src, ModeState *dest)
dest->term &= ~TM_AUTO_WRAP;
if (set) dest->term |= (src.term & TM_AUTO_WRAP);
break;
+ case PRIV(1000): /* xterm: report mouse button presses */
+ dest->win &= ~WM_MOUSE_MASK;
+ if (set) dest->win |= (src.win & WM_MOUSE_BTN);
+ break;
+ case PRIV(1002): /* xterm: cell motion tracking */
+ dest->win &= ~WM_MOUSE_MASK;
+ if (set) dest->win |= (src.win & WM_MOUSE_TRK);
+ break;
+ case PRIV(1006): /* xterm: SGR mouse mode */
+ dest->win &= ~WM_MOUSE_SGR;
+ if (set) dest->win |= (src.win & WM_MOUSE_SGR);
+ break;
case PRIV(3): /* DECCOLM: 132/80 Column Mode */
case PRIV(4): /* DECSCLM: Fast/Slow Scroll */
case PRIV(8): /* DECARM: Auto-Repeat Keys */
diff --git a/util.h b/util.h
@@ -260,10 +260,11 @@ enum window_mode {
WM_MOUSE_X10 = 1 << 5,
WM_MOUSE_BTN = 1 << 6,
WM_MOUSE_TRK = 1 << 7,
+ WM_MOUSE_SGR = 1 << 8,
- WM_MOUSE_MASK = WM_MOUSE_X10|WM_MOUSE_BTN|WM_MOUSE_TRK,
+ WM_MOUSE_MASK = WM_MOUSE_X10|WM_MOUSE_BTN|WM_MOUSE_TRK|WM_MOUSE_SGR,
- WM_ALL_MASK = WM_MOUSE_TRK|(WM_MOUSE_TRK - 1),
+ WM_ALL_MASK = WM_MOUSE_SGR|(WM_MOUSE_SGR - 1),
};
#define MODE_STATE_ALL_MASK (ModeState){.term = TM_ALL_MASK, .win = WM_ALL_MASK}
@@ -483,6 +484,8 @@ typedef struct {
u32 click_count;
f32 multi_click_t;
+
+ iv2 last_cell_report;
} InteractionState;
enum selection_states {
diff --git a/vtgl.c b/vtgl.c
@@ -199,13 +199,6 @@ pressed_last_frame(ButtonState *button)
return result;
}
-static b32
-released_last_frame(ButtonState *button)
-{
- b32 result = !button->ended_down && button->transitions;
- return result;
-}
-
static void
set_projection_matrix(GLCtx *gl)
{
@@ -767,21 +760,42 @@ KEYBIND_FN(zoom)
}
static void
-report_mouse(Term *t, TerminalInput *input, b32 pressed)
+report_mouse(Term *t, TerminalInput *input, b32 released, b32 beginning)
{
- i32 value;
+ if ((t->mode.win & WM_MOUSE_X10) && released)
+ return;
+
+ iv2 pos = mouse_to_cell_space(t, input->mouse);
+ if ((pos.x > (255 - 32)) || (pos.y > (255 - 32)))
+ return;
+
/* TODO: pass the button into this function once they are given in order */
/* TODO: extended mouse buttons (up to button 11) should also be encoded */
- if (!pressed) value = 3;
- else if (pressed_last_frame(input->keys + MOUSE_LEFT)) value = 0;
- else if (pressed_last_frame(input->keys + MOUSE_MIDDLE)) value = 1;
- else if (pressed_last_frame(input->keys + MOUSE_RIGHT)) value = 2;
- else if (input->mouse_scroll.y > 0) value = 64 + (4 - 4);
- else if (input->mouse_scroll.y < 0) value = 64 + (5 - 4);
- else return;
-
- if ((t->mode.win & WM_MOUSE_X10) && !pressed)
- return;
+ i32 button = 0;
+ if (input->keys[MOUSE_LEFT].ended_down) button = 1;
+ else if (input->keys[MOUSE_MIDDLE].ended_down) button = 2;
+ else if (input->keys[MOUSE_RIGHT].ended_down) button = 3;
+ else if (input->mouse_scroll.y > 0) button = 4;
+ else if (input->mouse_scroll.y < 0) button = 5;
+
+ i32 value;
+ if (t->mode.win & WM_MOUSE_TRK && !beginning && !released) {
+ if (equal_iv2(t->interaction.last_cell_report, pos))
+ return;
+ value = 32;
+ } else {
+ value = 0;
+ }
+ t->interaction.last_cell_report = pos;
+
+ if ((t->mode.win & WM_MOUSE_SGR) && !button)
+ value += 0;
+ else if (!button)
+ value += 3;
+ else if (button >= 4)
+ value += 64 + button - 4;
+ else
+ value += button - 1;
if (!(t->mode.win & WM_MOUSE_X10)) {
value += ((input->modifiers & MOD_SHIFT) ? 4 : 0)
@@ -789,22 +803,33 @@ report_mouse(Term *t, TerminalInput *input, b32 pressed)
+ ((input->modifiers & MOD_CONTROL) ? 16 : 0);
}
- iv2 pos = mouse_to_cell_space(t, input->mouse);
- if ((pos.x < (255 - 32)) && (pos.y < (255 - 32))) {
- Stream buf = arena_stream(t->arena_for_frame);
+ Stream buf = arena_stream(t->arena_for_frame);
+ if (t->mode.win & WM_MOUSE_SGR) {
+ stream_push_s8(&buf, s8("\x1B[<"));
+ stream_push_i64(&buf, value);
+ stream_push_byte(&buf, ';');
+ stream_push_i64(&buf, pos.x + 1);
+ stream_push_byte(&buf, ';');
+ stream_push_i64(&buf, pos.y + 1);
+ stream_push_byte(&buf, released? 'm' : 'M');
+ } else if ((pos.x < (255 - 32)) && (pos.y < (255 - 32))) {
stream_push_s8(&buf, s8("\x1B[M"));
stream_push_byte(&buf, 32 + value);
stream_push_byte(&buf, 32 + pos.x + 1);
stream_push_byte(&buf, 32 + pos.y + 1);
- t->platform->write(t->child, stream_to_s8(&buf), 0);
+ } else {
+ INVALID_CODE_PATH;
+ return;
}
+
+ t->platform->write(t->child, stream_to_s8(&buf), 0);
}
static void
begin_terminal_interaction(Term *t, TerminalInput *input, u32 click_count)
{
if (t->mode.win & WM_MOUSE_MASK) {
- report_mouse(t, input, 1);
+ report_mouse(t, input, 0, 1);
} else {
if (pressed_last_frame(input->keys + MOUSE_LEFT))
begin_selection(t, click_count, input->mouse);
@@ -814,12 +839,14 @@ begin_terminal_interaction(Term *t, TerminalInput *input, u32 click_count)
static b32
terminal_interaction(Term *t, PlatformAPI *platform, TerminalInput *input, u32 click_count)
{
- b32 should_end_interaction = 0;
+
+ b32 should_end_interaction = !input->keys[MOUSE_LEFT].ended_down &&
+ !input->keys[MOUSE_MIDDLE].ended_down &&
+ !input->keys[MOUSE_RIGHT].ended_down;
if (t->mode.win & WM_MOUSE_MASK) {
- should_end_interaction = released_last_frame(input->keys + MOUSE_LEFT) ||
- released_last_frame(input->keys + MOUSE_MIDDLE) ||
- released_last_frame(input->keys + MOUSE_RIGHT);
+ if (t->mode.win & WM_MOUSE_TRK)
+ report_mouse(t, input, should_end_interaction, 0);
} else {
update_selection(t, input);
if (pressed_last_frame(input->keys + MOUSE_MIDDLE))
@@ -848,18 +875,6 @@ terminal_interaction(Term *t, PlatformAPI *platform, TerminalInput *input, u32 c
return should_end_interaction;
}
-static void
-end_terminal_interaction(Term *t, TerminalInput *input)
-{
- if (t->mode.win & WM_MOUSE_MASK) {
- b32 end_from_release = released_last_frame(input->keys + MOUSE_LEFT) ||
- released_last_frame(input->keys + MOUSE_MIDDLE) ||
- released_last_frame(input->keys + MOUSE_RIGHT);
- if (end_from_release)
- report_mouse(t, input, 0);
- }
-}
-
DEBUG_EXPORT VTGL_HANDLE_KEYS_FN(vtgl_handle_keys)
{
Term *t = memory->memory;
@@ -1010,11 +1025,7 @@ begin_interaction(InteractionState *is, TerminalInput *input)
static void
end_interaction(InteractionState *is, TerminalInput *input)
{
- switch (is->active.type) {
- case IS_TERM: end_terminal_interaction(is->active.var.value, input); break;
- default: break;
- }
- is->active = (Interaction){0};
+ is->active = (Interaction){.type = IS_NONE};
}
static void
@@ -1034,19 +1045,19 @@ handle_interactions(Term *t, TerminalInput *input, PlatformAPI *platform)
end_interaction(is, input);
begin_interaction(is, input);
}
+ }
- switch (is->active.type) {
- case IS_NONE: break;
- case IS_NOP: break;
- case IS_SET: end_interaction(is, input); break;
- case IS_AUTO: /* TODO */ break;
- case IS_DRAG: /* TODO */ break;
- case IS_DEBUG: /* TODO */ break;
- case IS_TERM: {
- if (terminal_interaction(t, platform, input, is->click_count))
- end_interaction(is, input);
- } break;
- }
+ switch (is->active.type) {
+ case IS_NONE: break;
+ case IS_NOP: break;
+ case IS_SET: end_interaction(is, input); break;
+ case IS_AUTO: /* TODO */ break;
+ case IS_DRAG: /* TODO */ break;
+ case IS_DEBUG: /* TODO */ break;
+ case IS_TERM: {
+ if (terminal_interaction(t, platform, input, is->click_count))
+ end_interaction(is, input);
+ } break;
}
}