diff --git a/kitty/charsets.c b/kitty/charsets.c index c1f55bf8b..6a6d66f6e 100644 --- a/kitty/charsets.c +++ b/kitty/charsets.c @@ -237,3 +237,30 @@ decode_utf8(uint32_t* state, uint32_t* codep, uint8_t byte) { *state = utf8_data[256 + *state*16 + type]; return *state; } + +unsigned int +encode_utf8(uint32_t ch, char* dest) { + if (ch < 0x80) { + dest[0] = (char)ch; + return 1; + } + if (ch < 0x800) { + dest[0] = (ch>>6) | 0xC0; + dest[1] = (ch & 0x3F) | 0x80; + return 2; + } + if (ch < 0x10000) { + dest[0] = (ch>>12) | 0xE0; + dest[1] = ((ch>>6) & 0x3F) | 0x80; + dest[2] = (ch & 0x3F) | 0x80; + return 3; + } + if (ch < 0x110000) { + dest[0] = (ch>>18) | 0xF0; + dest[1] = ((ch>>12) & 0x3F) | 0x80; + dest[2] = ((ch>>6) & 0x3F) | 0x80; + dest[3] = (ch & 0x3F) | 0x80; + return 4; + } + return 0; +} diff --git a/kitty/data-types.h b/kitty/data-types.h index 58c02a740..cdfda785e 100644 --- a/kitty/data-types.h +++ b/kitty/data-types.h @@ -296,6 +296,7 @@ void parse_worker_dump(Screen *screen, PyObject *dump_callback); PyObject* parse_bytes_dump(PyObject UNUSED *, PyObject *); PyObject* parse_bytes(PyObject UNUSED *, PyObject *); uint32_t decode_utf8(uint32_t*, uint32_t*, uint8_t byte); +unsigned int encode_utf8(uint32_t ch, char* dest); void cursor_reset(Cursor*); Cursor* cursor_copy(Cursor*); void cursor_copy_to(Cursor *src, Cursor *dest); diff --git a/kitty/mouse.c b/kitty/mouse.c index eaba0cb00..07f917400 100644 --- a/kitty/mouse.c +++ b/kitty/mouse.c @@ -8,11 +8,13 @@ #include "state.h" #include "screen.h" #include "lineops.h" +#include #include #include extern void set_mouse_cursor(MouseShape); static MouseShape mouse_cursor_shape = BEAM; +typedef enum MouseActions { PRESS, RELEASE, DRAG, MOVE } MouseAction; #define call_boss(name, ...) { \ PyObject *cret_ = PyObject_CallMethod(global_state.boss, #name, __VA_ARGS__); \ @@ -20,6 +22,74 @@ static MouseShape mouse_cursor_shape = BEAM; else Py_DECREF(cret_); \ } +#define SHIFT_INDICATOR (1 << 2) +#define ALT_INDICATOR (1 << 3) +#define CONTROL_INDICATOR (1 << 4) +#define MOTION_INDICATOR (1 << 5) +#define EXTRA_BUTTON_INDICATOR (1 << 6) + +static inline unsigned int +button_map(int button) { + switch(button) { + case GLFW_MOUSE_BUTTON_1: + return 0; + case GLFW_MOUSE_BUTTON_2: + return 1; + case GLFW_MOUSE_BUTTON_3: + return 2; + case GLFW_MOUSE_BUTTON_4: + return EXTRA_BUTTON_INDICATOR; + case GLFW_MOUSE_BUTTON_5: + return EXTRA_BUTTON_INDICATOR | 1; + default: + return UINT_MAX; + } +} + +static char mouse_event_buf[64]; + +unsigned int +encode_mouse_event(Window *w, int button, MouseAction action, int mods) { + unsigned int x = w->mouse_cell_x + 1, y = w->mouse_cell_y + 1; // 1 based indexing + unsigned int cb = 0; + Screen *screen = w->render_data.screen; + + if (action == MOVE) { + if (screen->modes.mouse_tracking_protocol != SGR_PROTOCOL) cb = 3; + } else { + cb = button_map(button); + if (cb == UINT_MAX) return 0; + } + if (action == DRAG || action == MOVE) cb |= MOTION_INDICATOR; + else if (action == RELEASE && screen->modes.mouse_tracking_protocol != SGR_PROTOCOL) cb = 3; + if (mods & GLFW_MOD_SHIFT) cb |= SHIFT_INDICATOR; + if (mods & GLFW_MOD_ALT) cb |= ALT_INDICATOR; + if (mods & GLFW_MOD_CONTROL) cb |= CONTROL_INDICATOR; + switch(screen->modes.mouse_tracking_protocol) { + case SGR_PROTOCOL: + return snprintf(mouse_event_buf, sizeof(mouse_event_buf), "\033[<%d;%d;%d%s", cb, x, y, action == RELEASE ? "m" : "M"); + break; + case URXVT_PROTOCOL: + return snprintf(mouse_event_buf, sizeof(mouse_event_buf), "\033[%d;%d;%dM", cb, x, y); + break; + case UTF8_PROTOCOL: + mouse_event_buf[0] = 033; mouse_event_buf[1] = '['; mouse_event_buf[2] = cb + 32; + unsigned int sz = 3; + sz += encode_utf8(x + 32, mouse_event_buf + sz); + sz += encode_utf8(y + 32, mouse_event_buf + sz); + return sz; + break; + default: + if (x > 223 || y > 223) return 0; + else { + mouse_event_buf[0] = 033; mouse_event_buf[1] = '['; mouse_event_buf[2] = 'M'; mouse_event_buf[3] = cb + 32; mouse_event_buf[4] = x + 32; mouse_event_buf[5] = y + 32; + return 6; + } + break; + } + return 0; +} + static inline bool contains_mouse(Window *w) { WindowGeometry *g = &w->geometry; diff --git a/kitty/mouse.py b/kitty/mouse.py deleted file mode 100644 index 623daf244..000000000 --- a/kitty/mouse.py +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env python -# vim:fileencoding=utf-8 -# License: GPL v3 Copyright: 2016, Kovid Goyal - -from .fast_data_types import ( - GLFW_MOUSE_BUTTON_2, GLFW_MOUSE_BUTTON_3, GLFW_MOD_ALT, GLFW_MOD_CONTROL, - GLFW_MOD_SHIFT, GLFW_MOUSE_BUTTON_4, GLFW_MOUSE_BUTTON_5, - GLFW_MOUSE_BUTTON_1, -) - -PRESS, RELEASE, DRAG, MOVE = range(4) -SHIFT_INDICATOR = 1 << 2 -ALT_INDICATOR = 1 << 3 -CONTROL_INDICATOR = 1 << 4 -MOTION_INDICATOR = 1 << 5 -EXTRA_BUTTON_INDICATOR = 1 << 6 - -cb_map = { - GLFW_MOUSE_BUTTON_1: 0, - GLFW_MOUSE_BUTTON_2: 0b1, - GLFW_MOUSE_BUTTON_3: 0b10, - GLFW_MOUSE_BUTTON_4: EXTRA_BUTTON_INDICATOR, - GLFW_MOUSE_BUTTON_5: EXTRA_BUTTON_INDICATOR | 0b1 -} - - -def encode_mouse_event(tracking_mode, tracking_protocol, button, action, mods, x, y): - x, y = x + 1, y + 1 # One based indexing - cb = 0 - if action is MOVE: - if tracking_protocol != SGR_PROTOCOL: - cb = 0b11 - else: - cb = cb_map.get(button) - if cb is None: - return - if action in (DRAG, MOVE): - cb |= MOTION_INDICATOR - elif action is RELEASE: - if tracking_protocol != SGR_PROTOCOL: - cb = 0b11 - if mods & GLFW_MOD_SHIFT: - cb |= SHIFT_INDICATOR - if mods & GLFW_MOD_ALT: - cb |= ALT_INDICATOR - if mods & GLFW_MOD_CONTROL: - cb |= CONTROL_INDICATOR - ans = None - if tracking_protocol == SGR_PROTOCOL: - ans = '\033[<%d;%d;%d%s' % (cb, x, y, 'm' if action is RELEASE else 'M') - ans = ans.encode('ascii') - elif tracking_protocol == URXVT_PROTOCOL: - ans = '\033[%d;%d;%dM' % (cb + 32, x, y) - ans = ans.encode('ascii') - elif tracking_protocol == UTF8_PROTOCOL: - ans = bytearray([0o33, ord('['), cb + 32]) - ans.extend(chr(x + 32).encode('utf-8') + chr(y + 32).encode('utf-8')) - ans = bytes(ans) - else: - if x <= 223 and y <= 223: - ans = bytearray([0o33, ord('['), ord('M'), cb + 32, x + 32, y + 32]) - return ans diff --git a/kitty/window.py b/kitty/window.py index 899c86bd8..0dfd90368 100644 --- a/kitty/window.py +++ b/kitty/window.py @@ -26,7 +26,6 @@ from .fast_data_types import ( update_window_title, update_window_visibility ) from .keys import get_key_map -from .mouse import DRAG, MOVE, PRESS, RELEASE, encode_mouse_event from .rgb import to_color from .terminfo import get_capabilities from .utils import (