vtgl

terminal emulator implemented in OpenGL
git clone anongit@rnpnr.xyz:vtgl.git
Log | Files | Refs | Feed | LICENSE

Commit: bdb41e690d9a63bf913dac552fdc7bc9d0dcd6ef
Parent: 23f2ec265786458a85285e0305e5d9ab8c5da993
Author: Randy Palamar
Date:   Sun, 17 Nov 2024 12:26:42 -0700

support mouse reporting

Diffstat:
Mdebug.h | 4++--
Mplatform_linux_x11.c | 3+++
Mterminal.c | 7+++++++
Mutil.h | 5+++++
Mvtgl.c | 145++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
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; } }