From e5fc266cdbd032b094ce487c0f2a6b9b44371c32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Fri, 5 Jul 2019 14:24:51 +0200 Subject: [PATCH] vt: add support for \E[?1000h - report mouse button events --- csi.c | 38 +++++++++---------- input.c | 38 +++++++++++++++++-- terminal.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++++ terminal.h | 24 ++++++++++++ 4 files changed, 183 insertions(+), 24 deletions(-) diff --git a/csi.c b/csi.c index 04174aa6..67d78720 100644 --- a/csi.c +++ b/csi.c @@ -593,23 +593,32 @@ csi_dispatch(struct terminal *term, uint8_t final) break; case 1000: - LOG_WARN("unimplemented: report mouse clicks"); + term->mouse_tracking = MOUSE_CLICK; break; case 1002: - LOG_WARN("unimplemented: report cell mouse motion"); + LOG_WARN("unimplemented: report button and mouse motion"); + /* term->mouse_tracking = MOUSE_DRAG; */ + break; + + case 1003: + LOG_WARN("unimplemented: report all mouse events"); + /* term->mouse_tracking = MOUSE_MOTION; */ break; case 1005: LOG_WARN("unimplemented: UTF-8 mouse"); + /* term->mouse_reporting = MOUSE_UTF8 */ break; case 1006: LOG_WARN("unimplemented: SGR mouse"); + /* term->mouse_reporting = MOUSE_SGR */ break; case 1015: LOG_WARN("unimplemented: URXVT mosue"); + /* term->mouse_reporting = MOUSE_URXVT */ break; case 1049: @@ -665,24 +674,13 @@ csi_dispatch(struct terminal *term, uint8_t final) term->hide_cursor = true; break; - case 1000: - LOG_WARN("unimplemented: report mouse clicks"); - break; - - case 1002: - LOG_WARN("unimplemented: report cell mouse motion"); - break; - - case 1005: - LOG_WARN("unimplemented: UTF-8 mouse"); - break; - - case 1006: - LOG_WARN("unimplemented: SGR mouse"); - break; - - case 1015: - LOG_WARN("unimplemented: URXVT mosue"); + case 1000: /* MOUSE_NORMAL */ + case 1002: /* MOUSE_BUTTON_EVENT */ + case 1003: /* MOUSE_ANY_EVENT */ + case 1005: /* MOUSE_UTF8 */ + case 1006: /* MOUSE_SGR */ + case 1015: /* MOUSE_URXVT */ + term->mouse_tracking = MOUSE_NONE; break; case 1049: diff --git a/input.c b/input.c index ee06f3e7..36e9096c 100644 --- a/input.c +++ b/input.c @@ -320,10 +320,41 @@ static void wl_pointer_button(void *data, struct wl_pointer *wl_pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state) { - if (state != WL_POINTER_BUTTON_STATE_PRESSED) - return; + LOG_DBG("BUTTON: button=%x, state=%u", button, state); - //struct terminal *term = data; + struct terminal *term = data; + + static bool mods_initialized = false; + static xkb_mod_index_t shift, alt, ctrl; + + if (!mods_initialized) { + struct xkb_keymap *map = term->kbd.xkb_keymap; + shift = xkb_keymap_mod_get_index(map, "Shift"); + alt = xkb_keymap_mod_get_index(map, "Mod1") ; + ctrl = xkb_keymap_mod_get_index(map, "Control"); + mods_initialized = true; + } + + int col = term->mouse.x / term->cell_width; + int row = term->mouse.y / term->cell_height; + + struct xkb_state *xkb = term->kbd.xkb_state; + bool shift_active = xkb_state_mod_index_is_active( + xkb, shift, XKB_STATE_MODS_DEPRESSED); + bool alt_active = xkb_state_mod_index_is_active( + xkb, alt, XKB_STATE_MODS_DEPRESSED); + bool ctrl_active = xkb_state_mod_index_is_active( + xkb, ctrl, XKB_STATE_MODS_DEPRESSED); + + switch (state) { + case WL_POINTER_BUTTON_STATE_PRESSED: + term_mouse_down(term, button, row, col, shift_active, alt_active, ctrl_active); + break; + + case WL_POINTER_BUTTON_STATE_RELEASED: + term_mouse_up(term, button, row, col, shift_active, alt_active, ctrl_active); + break; + } } static void @@ -366,4 +397,3 @@ const struct wl_pointer_listener pointer_listener = { .axis_stop = wl_pointer_axis_stop, .axis_discrete = wl_pointer_axis_discrete, }; - diff --git a/terminal.c b/terminal.c index a4466d90..37cb9bbd 100644 --- a/terminal.c +++ b/terminal.c @@ -1,6 +1,7 @@ #include "terminal.h" #include +#include #include #define LOG_MODULE "terminal" @@ -374,3 +375,109 @@ term_scroll_reverse(struct terminal *term, int rows) { term_scroll_reverse_partial(term, term->scroll_region, rows); } + +#include + +static int +linux_mouse_button_to_x(int button) +{ + switch (button) { + case BTN_LEFT: return 1; + case BTN_RIGHT: return 3; + case BTN_MIDDLE: return 2; + case BTN_SIDE: return 8; + case BTN_EXTRA: return 9; + case BTN_FORWARD: return 4; + case BTN_BACK: return 5; + case BTN_TASK: return -1; /* TODO: ??? */ + + default: + LOG_WARN("unrecognized mouse button: %d (0x%x)", button, button); + return -1; + } +} + +static int +encode_xbutton(int xbutton) +{ + switch (xbutton) { + case 1: case 2: case 3: + return xbutton - 1; + + case 4: case 5: + /* Like button 1 and 2, but with 64 added */ + return xbutton - 4 + 64; + + case 6: case 7: + /* Same as 4 and 5. Note: the offset should be something else? */ + return xbutton - 6 + 64; + + case 8: case 9: case 10: case 11: + /* Similar to 4 and 5, but adding 128 instead of 64 */ + return xbutton - 8 + 128; + + default: + LOG_ERR("cannot encode X mouse button: %d", xbutton); + return -1; + } +} + +static void +report_mouse_click(struct terminal *term, int button, int row, int col, + bool release, bool shift, bool alt, bool ctrl) +{ + /* Map libevent button event code to X button number */ + int xbutton = linux_mouse_button_to_x(button); + if (xbutton == -1) + return; + + if (release && (xbutton == 4 || xbutton == 5)) { + /* No button release events for scroll buttons */ + return; + } + + int encoded = release ? 3 : encode_xbutton(xbutton); + if (encoded == -1) + return; + + encoded += (shift ? 4 : 0) + (alt ? 8 : 0) + (ctrl ? 16 : 0); + + char response[16]; + snprintf(response, sizeof(response), "\033[M%c%c%c", + 32 + encoded, 32 + col + 1, 32 + row + 1); + write(term->ptmx, response, strlen(response)); +} + +void +term_mouse_down(struct terminal *term, int button, int row, int col, + bool shift, bool alt, bool ctrl) +{ + switch (term->mouse_tracking) { + case MOUSE_NONE: + break; + + case MOUSE_X10: + case MOUSE_CLICK: + case MOUSE_DRAG: + case MOUSE_MOTION: + report_mouse_click(term, button, row, col, false, shift, alt, ctrl); + break; + } +} + +void +term_mouse_up(struct terminal *term, int button, int row, int col, + bool shift, bool alt, bool ctrl) +{ + switch (term->mouse_tracking) { + case MOUSE_NONE: + break; + + case MOUSE_X10: + case MOUSE_CLICK: + case MOUSE_DRAG: + case MOUSE_MOTION: + report_mouse_click(term, button, row, col, true, shift, alt, ctrl); + break; + } +} diff --git a/terminal.h b/terminal.h index 4c1e604e..2aa8699e 100644 --- a/terminal.h +++ b/terminal.h @@ -151,6 +151,23 @@ enum decckm { DECCKM_CSI, DECCKM_SS3 }; enum keypad_mode { KEYPAD_NUMERICAL, KEYPAD_APPLICATION }; enum charset { CHARSET_ASCII, CHARSET_GRAPHIC }; +/* *What* to report */ +enum mouse_tracking { + MOUSE_NONE, + MOUSE_X10, /* ?9h */ + MOUSE_CLICK, /* ?1000h - report mouse clicks*/ + MOUSE_DRAG, /* ?1002h - report clicks and drag motions */ + MOUSE_MOTION, /* ?1003h - report clicks and motion*/ +}; + +/* *How* to report */ +enum mouse_reporting { + MOUSE_NORMAL, + MOUSE_UTF8, /* ?1005h */ + MOUSE_SGR, /* ?1006h */ + MOUSE_URXVT, /* ?1015h */ +}; + struct terminal { pid_t slave; int ptmx; @@ -162,6 +179,8 @@ struct terminal { bool auto_margin; bool insert_mode; bool bracketed_paste; + enum mouse_tracking mouse_tracking; + enum mouse_reporting mouse_reporting; int selected_charset; enum charset charset[4]; /* G0-G3 */ @@ -226,3 +245,8 @@ void term_scroll_reverse_partial( struct terminal *term, struct scroll_region region, int rows); int term_cursor_linear(const struct terminal *term, int row, int col); + +void term_mouse_down(struct terminal *term, int button, int row, int col, + bool shift, bool alt, bool ctrl); +void term_mouse_up(struct terminal *term, int button, int row, int col, + bool shift, bool alt, bool ctrl);