Support more mouse buttons for terminal mouse events

Previously, the mouse back and forward buttons sent the same codes as
scroll up and down. Now they instead send the same codes as xterm. Mouse
button 10 (in X11 numbering) also now sends the same as xterm, instead
of not sending anything.

This also changes the `send_mouse_event` function which can be called
from kittens to use X11 numbering for mouse buttons instead of what it
previously used, which turns out to be a hybrid of X11 and GLFW. It was
documented to use GLFW numbering, but GLFW doesn't have numbers for
scroll events (that's separate events with x/y offsets) and 4 and 5 in
GLFW is actually back and forward, while `send_mouse_event` interpreted
it as scroll up and down.

That means that this is a breaking change for `send_mouse_event` because
it swaps the number for the middle and right button to be consistent
with X11. I did this because I think it's better to use one consistent
numbering scheme for the function, and because people probably know X11
numbering better than GLFW numbering and GLFW doesn't have numbers for
the scroll buttons.
This commit is contained in:
Trygve Aaberge
2020-04-30 01:40:07 +02:00
parent c78563b452
commit 8efe08c45b
3 changed files with 50 additions and 33 deletions

View File

@@ -142,12 +142,13 @@ those using::
send_mouse_event(screen, x, y, button, action, mods)
``screen`` is the ``screen`` attribute of the window you want to send the event
to. ``x`` and ``y`` are the 0-indexed coordinates. ``button`` is
``GLFW_MOUSE_BUTTON_{button}`` where ``{button}`` is one of ``LEFT``,
``RIGHT``, ``MIDDLE`` or a digit from ``1`` to ``8``. ``action`` is one of
``PRESS``, ``RELEASE``, ``DRAG`` or ``MOVE``. ``mods`` is a bitmask of
``GLFW_MOD_{mod}`` where ``{mod}`` is one of ``SHIFT``, ``CONTROL`` or ``ALT``.
All the mentioned constants are imported from ``kitty.fast_data_types``.
to. ``x`` and ``y`` are the 0-indexed coordinates. ``button`` is a number using
the same numbering as X11 (left: ``1``, middle: ``2``, right: ``3``, scroll up:
``4``, scroll down: ``5``, scroll left: ``6``, scroll right: ``7``, back:
``8``, forward: ``9``). ``action`` is one of ``PRESS``, ``RELEASE``, ``DRAG``
or ``MOVE``. ``mods`` is a bitmask of ``GLFW_MOD_{mod}`` where ``{mod}`` is one
of ``SHIFT``, ``CONTROL`` or ``ALT``. All the mentioned constants are imported
from ``kitty.fast_data_types``.
For example, to send a left click at position x: 2, y: 3 to the active window::

View File

@@ -25,27 +25,43 @@ typedef enum MouseActions { PRESS, RELEASE, DRAG, MOVE } MouseAction;
#define ALT_INDICATOR (1 << 3)
#define CONTROL_INDICATOR (1 << 4)
#define MOTION_INDICATOR (1 << 5)
#define EXTRA_BUTTON_INDICATOR (1 << 6)
#define SCROLL_BUTTON_INDICATOR (1 << 6)
#define EXTRA_BUTTON_INDICATOR (1 << 7)
static inline unsigned int
button_map(int button) {
switch(button) {
case GLFW_MOUSE_BUTTON_LEFT:
return 0;
case GLFW_MOUSE_BUTTON_RIGHT:
return 2;
case GLFW_MOUSE_BUTTON_MIDDLE:
return 1;
case GLFW_MOUSE_BUTTON_RIGHT:
return 3;
case GLFW_MOUSE_BUTTON_MIDDLE:
return 2;
case GLFW_MOUSE_BUTTON_4:
return EXTRA_BUTTON_INDICATOR;
case GLFW_MOUSE_BUTTON_5:
return EXTRA_BUTTON_INDICATOR | 1;
case GLFW_MOUSE_BUTTON_6:
case GLFW_MOUSE_BUTTON_7:
case GLFW_MOUSE_BUTTON_8:
return button + 5;
default:
return UINT_MAX;
}
}
static inline unsigned int
encode_button(unsigned int button) {
if (button >= 8 && button <= 11) {
return (button - 8) | EXTRA_BUTTON_INDICATOR;
} else if (button >= 4 && button <= 7) {
return (button - 4) | SCROLL_BUTTON_INDICATOR;
} else if (button >= 1 && button <= 3) {
return button - 1;
} else {
return UINT_MAX;
}
}
static char mouse_event_buf[64];
static inline int
@@ -54,7 +70,7 @@ encode_mouse_event_impl(unsigned int x, unsigned int y, int mouse_tracking_proto
if (action == MOVE) {
cb = 3;
} else {
cb = button_map(button);
cb = encode_button(button);
if (cb == UINT_MAX) return 0;
}
if (action == DRAG || action == MOVE) cb |= MOTION_INDICATOR;
@@ -92,7 +108,16 @@ encode_mouse_event(Window *w, int button, MouseAction action, int mods) {
unsigned int x = w->mouse_pos.cell_x + 1, y = w->mouse_pos.cell_y + 1; // 1 based indexing
Screen *screen = w->render_data.screen;
return encode_mouse_event_impl(x, y, screen->modes.mouse_tracking_protocol, button, action, mods);
}
static int
encode_mouse_button(Window *w, int button, MouseAction action, int mods) {
return encode_mouse_event(w, button_map(button), action, mods);
}
static int
encode_mouse_scroll(Window *w, bool upwards, int mods) {
return encode_mouse_event(w, upwards ? 4 : 5, PRESS, mods);
}
// }}}
@@ -341,7 +366,7 @@ HANDLER(handle_move_event) {
handle_mouse_movement_in_kitty(w, button, mouse_cell_changed | cell_half_changed);
} else {
if (!mouse_cell_changed) return;
int sz = encode_mouse_event(w, MAX(0, button), button >=0 ? DRAG : MOVE, modifiers);
int sz = encode_mouse_button(w, MAX(0, button), button >=0 ? DRAG : MOVE, modifiers);
if (sz > 0) { mouse_event_buf[sz] = 0; write_escape_code_to_child(screen, CSI, mouse_event_buf); }
}
}
@@ -450,34 +475,25 @@ HANDLER(handle_button_event) {
);
if (handle_in_kitty) handle_button_event_in_kitty(w, button, modifiers, is_release);
else {
int sz = encode_mouse_event(w, button, is_release ? RELEASE : PRESS, modifiers);
int sz = encode_mouse_button(w, button, is_release ? RELEASE : PRESS, modifiers);
if (sz > 0) { mouse_event_buf[sz] = 0; write_escape_code_to_child(screen, CSI, mouse_event_buf); }
}
}
static inline int
currently_pressed_button(void) {
for (int i = 0; i < GLFW_MOUSE_BUTTON_5; i++) {
for (int i = 0; i <= GLFW_MOUSE_BUTTON_8; i++) {
if (global_state.callback_os_window->mouse_button_pressed[i]) return i;
}
return -1;
}
HANDLER(handle_event) {
switch(button) {
case -1:
if (button == -1) {
button = currently_pressed_button();
handle_move_event(w, button, modifiers, window_idx);
break;
case GLFW_MOUSE_BUTTON_LEFT:
case GLFW_MOUSE_BUTTON_RIGHT:
case GLFW_MOUSE_BUTTON_MIDDLE:
case GLFW_MOUSE_BUTTON_4:
case GLFW_MOUSE_BUTTON_5:
} else {
handle_button_event(w, button, modifiers, window_idx);
break;
default:
break;
}
}
@@ -690,7 +706,7 @@ scroll_event(double UNUSED xoffset, double yoffset, int flags, int modifiers) {
screen_history_scroll(screen, abs(s), upwards);
} else {
if (screen->modes.mouse_tracking_mode) {
int sz = encode_mouse_event(w, upwards ? GLFW_MOUSE_BUTTON_4 : GLFW_MOUSE_BUTTON_5, PRESS, modifiers);
int sz = encode_mouse_scroll(w, upwards, modifiers);
if (sz > 0) {
mouse_event_buf[sz] = 0;
for (s = abs(s); s > 0; s--) {

View File

@@ -81,7 +81,7 @@ class TestParser(BaseTest):
def test_encode_mouse_event(self):
NORMAL_PROTOCOL, UTF8_PROTOCOL, SGR_PROTOCOL, URXVT_PROTOCOL = range(4)
L, M, R = defines.GLFW_MOUSE_BUTTON_LEFT, defines.GLFW_MOUSE_BUTTON_MIDDLE, defines.GLFW_MOUSE_BUTTON_RIGHT
L, M, R = 1, 2, 3
protocol = SGR_PROTOCOL
def enc(button=L, action=defines.PRESS, mods=0, x=1, y=1):