Commit: bdb41e690d9a63bf913dac552fdc7bc9d0dcd6ef
Parent: 23f2ec265786458a85285e0305e5d9ab8c5da993
Author: Randy Palamar
Date: Sun, 17 Nov 2024 12:26:42 -0700
support mouse reporting
Diffstat:
5 files changed, 131 insertions(+), 33 deletions(-)
diff --git a/debug.h b/debug.h
@@ -79,9 +79,10 @@ typedef DEBUG_BEGIN_FRAME_FN(debug_begin_frame_fn);
#define DEBUG_END_FRAME_FN(name) void name(TerminalMemory *memory)
typedef DEBUG_END_FRAME_FN(debug_end_frame_fn);
+#define INVALID_CODE_PATH ASSERT(0)
+
#ifndef _DEBUG
#define ASSERT(c) do { (void)(c); } while(0)
-#define INVALID_CODE_PATH
#define DEBUG_EXPORT static
#define BEGIN_TIMED_BLOCK(...)
@@ -98,7 +99,6 @@ DEBUG_END_FRAME_FN(debug_end_frame) {}
#else
#define ASSERT(c) do { if (!(c)) asm("int3; nop"); } while(0)
-#define INVALID_CODE_PATH ASSERT(0)
#define DEBUG_EXPORT
enum debug_event_types {
diff --git a/platform_linux_x11.c b/platform_linux_x11.c
@@ -325,6 +325,9 @@ update_input(PlatformCtx *ctx)
ctx->char_stream.widx = 0;
+ /* TODO: we need to maintain the order events occured in; instead of doing this
+ * we should have some sort of event list that the terminal can pull off of to
+ * process these in order. */
glfwPollEvents();
/* TODO: pselect should include x11 fd after removing glfw */
diff --git a/terminal.c b/terminal.c
@@ -548,6 +548,8 @@ set_mode(Term *t, CSI *csi, b32 set, b32 simulate)
{
BEGIN_TIMED_BLOCK();
i32 alt = t->view_idx;
+
+ /* TODO: this whole thing should be a lookup table */
#define PRIV(a) ((1 << 30) | (a))
for (i32 i = 0; i < csi->argc; i++) {
i32 arg = (csi->argv[i]) | ((csi->priv & 1) << 30);
@@ -568,6 +570,11 @@ set_mode(Term *t, CSI *csi, b32 set, b32 simulate)
if (set) t->gl.mode |= WIN_MODE_REVERSE;
else t->gl.mode &= ~WIN_MODE_REVERSE;
break;
+ case PRIV(1000): /* xterm: report mouse button presses */
+ t->gl.mode &= ~WIN_MODE_MOUSE_MASK;
+ if (set) t->gl.mode |= WIN_MODE_MOUSE_BTN;
+ else t->gl.mode &= ~WIN_MODE_MOUSE_BTN;
+ break;
case PRIV(6): /* DECOM: Cursor Origin Mode */
if (set) t->cursor.state |= CURSOR_ORIGIN;
else t->cursor.state &= ~CURSOR_ORIGIN;
diff --git a/util.h b/util.h
@@ -262,6 +262,11 @@ enum win_mode {
WIN_MODE_BRACKPASTE = 1 << 2,
WIN_MODE_8BIT = 1 << 3,
WIN_MODE_REVERSE = 1 << 4,
+ WIN_MODE_MOUSE_X10 = 1 << 5,
+ WIN_MODE_MOUSE_BTN = 1 << 6,
+ WIN_MODE_MOUSE_TRK = 1 << 7,
+
+ WIN_MODE_MOUSE_MASK = WIN_MODE_MOUSE_X10|WIN_MODE_MOUSE_BTN|WIN_MODE_MOUSE_TRK,
};
enum shader_stages {
diff --git a/vtgl.c b/vtgl.c
@@ -199,6 +199,13 @@ 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)
{
@@ -759,6 +766,100 @@ KEYBIND_FN(zoom)
return 1;
}
+static void
+report_mouse(Term *t, TerminalInput *input, b32 pressed)
+{
+ i32 value;
+ /* 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->gl.mode & WIN_MODE_MOUSE_X10) && !pressed)
+ return;
+
+ if (!(t->gl.mode & WIN_MODE_MOUSE_X10)) {
+ value += ((input->modifiers & MOD_SHIFT) ? 4 : 0)
+ + ((input->modifiers & MOD_ALT) ? 8 : 0)
+ + ((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_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);
+ }
+}
+
+static void
+begin_terminal_interaction(Term *t, TerminalInput *input, u32 click_count)
+{
+ if (t->gl.mode & WIN_MODE_MOUSE_MASK) {
+ report_mouse(t, input, 1);
+ } else {
+ if (pressed_last_frame(input->keys + MOUSE_LEFT))
+ begin_selection(t, click_count, input->mouse);
+ }
+}
+
+static b32
+terminal_interaction(Term *t, PlatformAPI *platform, TerminalInput *input, u32 click_count)
+{
+ b32 should_end_interaction = 0;
+
+ if (t->gl.mode & WIN_MODE_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);
+ } else {
+ update_selection(t, input);
+ if (pressed_last_frame(input->keys + MOUSE_MIDDLE))
+ paste(t, platform, (Arg){.i = CLIPBOARD_1});
+
+ b32 shift_down = input->modifiers & MOD_SHIFT;
+ if (input->mouse_scroll.y) {
+ if (t->mode & TM_ALTSCREEN) {
+ iptr child = t->child;
+ if (input->mouse_scroll.y > 0) {
+ if (shift_down) platform->write(child, s8("\x1B[5;2~"), 0);
+ else platform->write(child, s8("\x19"), 0);
+ } else {
+ if (shift_down) platform->write(child, s8("\x1B[6;2~"), 0);
+ else platform->write(child, s8("\x05"), 0);
+ }
+ } else {
+ Arg a = {.i = (i32)input->mouse_scroll.y};
+ if (shift_down)
+ a.i *= 5;
+ scroll(t, platform, a);
+ }
+ }
+ }
+
+ return should_end_interaction;
+}
+
+static void
+end_terminal_interaction(Term *t, TerminalInput *input)
+{
+ if (t->gl.mode & WIN_MODE_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;
@@ -872,7 +973,9 @@ static b32
should_start_interaction(TerminalInput *input)
{
b32 result = input->mouse_scroll.y || input->mouse_scroll.x ||
- pressed_last_frame(input->keys + MOUSE_LEFT);
+ pressed_last_frame(input->keys + MOUSE_LEFT) ||
+ pressed_last_frame(input->keys + MOUSE_MIDDLE) ||
+ pressed_last_frame(input->keys + MOUSE_RIGHT);
return result;
}
@@ -894,8 +997,7 @@ begin_interaction(InteractionState *is, TerminalInput *input)
switch (is->active.type) {
case IS_TERM:
- if (pressed_last_frame(input->keys + MOUSE_LEFT))
- begin_selection(is->active.var.value, is->click_count, input->mouse);
+ begin_terminal_interaction(is->active.var.value, input, is->click_count);
break;
default:
break;
@@ -906,8 +1008,12 @@ begin_interaction(InteractionState *is, TerminalInput *input)
}
static void
-end_interaction(InteractionState *is)
+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};
}
@@ -917,7 +1023,6 @@ handle_interactions(Term *t, TerminalInput *input, PlatformAPI *platform)
InteractionState *is = &t->interaction;
ButtonState *mouse_left = input->keys + MOUSE_LEFT;
- b32 shift_down = input->modifiers & MOD_SHIFT;
is->multi_click_t -= dt_for_frame;
if (!mouse_left->ended_down && is->multi_click_t < 0) {
@@ -926,42 +1031,20 @@ handle_interactions(Term *t, TerminalInput *input, PlatformAPI *platform)
if (is->hot.type != IS_NONE) {
if (should_start_interaction(input)) {
- end_interaction(is);
+ 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); 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: {
- update_selection(t, input);
- if (input->mouse_scroll.y) {
- if (t->mode & TM_ALTSCREEN) {
- iptr child = t->child;
- if (input->mouse_scroll.y > 0) {
- if (shift_down)
- platform->write(child, s8("\x1B[5;2~"), 0);
- else
- platform->write(child, s8("\x19"), 0);
- } else {
- if (shift_down)
- platform->write(child, s8("\x1B[6;2~"), 0);
- else
- platform->write(child, s8("\x05"), 0);
- }
- } else {
- Arg a = {.i = (i32)input->mouse_scroll.y};
- if (shift_down)
- a.i *= 5;
- scroll(t, platform, a);
- }
- }
- if (pressed_last_frame(input->keys + MOUSE_MIDDLE))
- paste(t, platform, (Arg){.i = CLIPBOARD_1});
+ if (terminal_interaction(t, platform, input, is->click_count))
+ end_interaction(is, input);
} break;
}
}