Port mouse event encoding code to C

This commit is contained in:
Kovid Goyal 2017-09-14 16:44:00 +05:30
parent b9ac13c379
commit 43c4c71abd
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
5 changed files with 98 additions and 63 deletions

View File

@ -237,3 +237,30 @@ decode_utf8(uint32_t* state, uint32_t* codep, uint8_t byte) {
*state = utf8_data[256 + *state*16 + type]; *state = utf8_data[256 + *state*16 + type];
return *state; 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;
}

View File

@ -296,6 +296,7 @@ void parse_worker_dump(Screen *screen, PyObject *dump_callback);
PyObject* parse_bytes_dump(PyObject UNUSED *, PyObject *); PyObject* parse_bytes_dump(PyObject UNUSED *, PyObject *);
PyObject* parse_bytes(PyObject UNUSED *, PyObject *); PyObject* parse_bytes(PyObject UNUSED *, PyObject *);
uint32_t decode_utf8(uint32_t*, uint32_t*, uint8_t byte); uint32_t decode_utf8(uint32_t*, uint32_t*, uint8_t byte);
unsigned int encode_utf8(uint32_t ch, char* dest);
void cursor_reset(Cursor*); void cursor_reset(Cursor*);
Cursor* cursor_copy(Cursor*); Cursor* cursor_copy(Cursor*);
void cursor_copy_to(Cursor *src, Cursor *dest); void cursor_copy_to(Cursor *src, Cursor *dest);

View File

@ -8,11 +8,13 @@
#include "state.h" #include "state.h"
#include "screen.h" #include "screen.h"
#include "lineops.h" #include "lineops.h"
#include <limits.h>
#include <math.h> #include <math.h>
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
extern void set_mouse_cursor(MouseShape); extern void set_mouse_cursor(MouseShape);
static MouseShape mouse_cursor_shape = BEAM; static MouseShape mouse_cursor_shape = BEAM;
typedef enum MouseActions { PRESS, RELEASE, DRAG, MOVE } MouseAction;
#define call_boss(name, ...) { \ #define call_boss(name, ...) { \
PyObject *cret_ = PyObject_CallMethod(global_state.boss, #name, __VA_ARGS__); \ PyObject *cret_ = PyObject_CallMethod(global_state.boss, #name, __VA_ARGS__); \
@ -20,6 +22,74 @@ static MouseShape mouse_cursor_shape = BEAM;
else Py_DECREF(cret_); \ 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 static inline bool
contains_mouse(Window *w) { contains_mouse(Window *w) {
WindowGeometry *g = &w->geometry; WindowGeometry *g = &w->geometry;

View File

@ -1,62 +0,0 @@
#!/usr/bin/env python
# vim:fileencoding=utf-8
# License: GPL v3 Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
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

View File

@ -26,7 +26,6 @@ from .fast_data_types import (
update_window_title, update_window_visibility update_window_title, update_window_visibility
) )
from .keys import get_key_map from .keys import get_key_map
from .mouse import DRAG, MOVE, PRESS, RELEASE, encode_mouse_event
from .rgb import to_color from .rgb import to_color
from .terminfo import get_capabilities from .terminfo import get_capabilities
from .utils import ( from .utils import (