Start work on intercepting mouse events

This commit is contained in:
Kovid Goyal
2021-05-08 20:55:09 +05:30
parent 5ee889eadd
commit a7933018cb
3 changed files with 38 additions and 24 deletions

View File

@@ -736,27 +736,34 @@ class Boss:
if t is not None: if t is not None:
t.relayout_borders() t.relayout_borders()
def dispatch_action(self, key_action: KeyAction) -> bool: def dispatch_action(
self,
key_action: KeyAction,
window_for_dispatch: Optional[Window] = None,
dispatch_type: str = 'KeyPress'
) -> bool:
if key_action is not None: if key_action is not None:
f = getattr(self, key_action.func, None) f = getattr(self, key_action.func, None)
if f is not None: if f is not None:
if self.args.debug_keyboard: if self.args.debug_keyboard:
print('Keypress matched action:', func_name(f)) print(f'{dispatch_type} matched action:', func_name(f))
passthrough = f(*key_action.args) passthrough = f(*key_action.args)
if passthrough is not True: if passthrough is not True:
return True return True
tab = self.active_tab if window_for_dispatch is None:
if tab is None: tab = self.active_tab
return False window = self.active_window
window = self.active_window else:
if window is None: window = window_for_dispatch
tab = window.tabref()
if tab is None or window is None:
return False return False
if key_action is not None: if key_action is not None:
f = getattr(tab, key_action.func, getattr(window, key_action.func, None)) f = getattr(tab, key_action.func, getattr(window, key_action.func, None))
if f is not None: if f is not None:
passthrough = f(*key_action.args) passthrough = f(*key_action.args)
if self.args.debug_keyboard: if self.args.debug_keyboard:
print('Keypress matched action:', func_name(f)) print(f'{dispatch_type} matched action:', func_name(f))
if passthrough is not True: if passthrough is not True:
return True return True
return False return False

View File

@@ -122,14 +122,19 @@ encode_mouse_scroll(Window *w, bool upwards, int mods) {
// }}} // }}}
static inline void static bool
dispatch_mouse_event(Window *w, int button, int count, int modifiers, bool grabbed) { dispatch_mouse_event(Window *w, int button, int count, int modifiers, bool grabbed) {
if (w->render_data.screen && PyCallable_Check(w->render_data.screen->callbacks)) { bool handled = false;
if (w->render_data.screen && w->render_data.screen->callbacks != Py_None) {
PyObject *callback_ret = PyObject_CallMethod(w->render_data.screen->callbacks, "on_mouse_event", "{si si si sO}", PyObject *callback_ret = PyObject_CallMethod(w->render_data.screen->callbacks, "on_mouse_event", "{si si si sO}",
"button", button, "repeat_count", count, "mods", modifiers, "grabbed", grabbed ? Py_True : Py_False); "button", button, "repeat_count", count, "mods", modifiers, "grabbed", grabbed ? Py_True : Py_False);
if (callback_ret == NULL) PyErr_Print(); if (callback_ret == NULL) PyErr_Print();
else Py_DECREF(callback_ret); else {
handled = callback_ret == Py_True;
Py_DECREF(callback_ret);
}
} }
return handled;
} }
static inline unsigned int static inline unsigned int
@@ -443,6 +448,7 @@ HANDLER(add_click) {
N(0).at = now; N(0).button = button; N(0).modifiers = modifiers; N(0).x = w->mouse_pos.x; N(0).y = w->mouse_pos.y; N(0).at = now; N(0).button = button; N(0).modifiers = modifiers; N(0).x = w->mouse_pos.x; N(0).y = w->mouse_pos.y;
q->length++; q->length++;
double multi_click_allowed_radius = 1.2 * (global_state.callback_os_window ? global_state.callback_os_window->fonts_data->cell_height : 20); double multi_click_allowed_radius = 1.2 * (global_state.callback_os_window ? global_state.callback_os_window->fonts_data->cell_height : 20);
Screen *screen = w->render_data.screen;
// Now dispatch the multi-click if any // Now dispatch the multi-click if any
if (q->length > 2) { if (q->length > 2) {
// possible triple-click // possible triple-click
@@ -450,7 +456,7 @@ HANDLER(add_click) {
N(1).at - N(3).at <= 2 * OPT(click_interval) && N(1).at - N(3).at <= 2 * OPT(click_interval) &&
distance(N(1).x, N(1).y, N(3).x, N(3).y) <= multi_click_allowed_radius distance(N(1).x, N(1).y, N(3).x, N(3).y) <= multi_click_allowed_radius
) { ) {
multi_click(w, 3); if (screen) dispatch_mouse_event(w, button, 3, modifiers, screen->modes.mouse_tracking_mode != 0);
q->length = 0; q->length = 0;
} }
} }
@@ -460,7 +466,7 @@ HANDLER(add_click) {
N(1).at - N(2).at <= OPT(click_interval) && N(1).at - N(2).at <= OPT(click_interval) &&
distance(N(1).x, N(1).y, N(2).x, N(2).y) <= multi_click_allowed_radius distance(N(1).x, N(1).y, N(2).x, N(2).y) <= multi_click_allowed_radius
) { ) {
multi_click(w, 2); if (screen) dispatch_mouse_event(w, button, 2, modifiers, screen->modes.mouse_tracking_mode != 0);
} }
} }
#undef N #undef N
@@ -473,7 +479,7 @@ open_url(Window *w) {
screen_open_url(screen); screen_open_url(screen);
} }
static inline void static void
handle_button_event_in_kitty(Window *w, int button, int modifiers, bool is_release) { handle_button_event_in_kitty(Window *w, int button, int modifiers, bool is_release) {
switch(button) { switch(button) {
case GLFW_MOUSE_BUTTON_LEFT: case GLFW_MOUSE_BUTTON_LEFT:
@@ -500,17 +506,11 @@ HANDLER(handle_button_event) {
} }
Screen *screen = w->render_data.screen; Screen *screen = w->render_data.screen;
if (!screen) return; if (!screen) return;
const int ts1 = OPT(terminal_select_modifiers), ts2 = OPT(terminal_select_modifiers) | OPT(rectangle_select_modifiers); if (!dispatch_mouse_event(w, button, is_release ? -1 : 1, modifiers, screen->modes.mouse_tracking_mode != 0)) {
bool handle_in_kitty = (
modifiers == ts1 || modifiers == ts2 ||
screen->modes.mouse_tracking_mode == 0 ||
(modifiers == (int)OPT(open_url_modifiers) && button == GLFW_MOUSE_BUTTON_LEFT)
);
if (handle_in_kitty) handle_button_event_in_kitty(w, button, modifiers, is_release);
else {
int sz = encode_mouse_button(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); } if (sz > 0) { mouse_event_buf[sz] = 0; write_escape_code_to_child(screen, CSI, mouse_event_buf); }
} }
add_click(w, button, modifiers, 0);
} }
static inline int static inline int

View File

@@ -19,7 +19,7 @@ from typing import (
from .child import ProcessDesc from .child import ProcessDesc
from .cli_stub import CLIOptions from .cli_stub import CLIOptions
from .config import build_ansi_color_table from .config import build_ansi_color_table
from .constants import appname, wakeup, is_macos from .constants import appname, is_macos, wakeup
from .fast_data_types import ( from .fast_data_types import (
BGIMAGE_PROGRAM, BLIT_PROGRAM, CELL_BG_PROGRAM, CELL_FG_PROGRAM, BGIMAGE_PROGRAM, BLIT_PROGRAM, CELL_BG_PROGRAM, CELL_FG_PROGRAM,
CELL_PROGRAM, CELL_SPECIAL_PROGRAM, DCS, DECORATION, DIM, GLFW_MOD_CONTROL, CELL_PROGRAM, CELL_SPECIAL_PROGRAM, DCS, DECORATION, DIM, GLFW_MOD_CONTROL,
@@ -36,7 +36,7 @@ from .notify import NotificationCommand, handle_notification_cmd
from .options_stub import Options from .options_stub import Options
from .rgb import to_color from .rgb import to_color
from .terminfo import get_capabilities from .terminfo import get_capabilities
from .types import ScreenGeometry, WindowGeometry from .types import MouseEvent, ScreenGeometry, WindowGeometry
from .typing import BossType, ChildType, EdgeLiteral, TabType, TypedDict from .typing import BossType, ChildType, EdgeLiteral, TabType, TypedDict
from .utils import ( from .utils import (
color_as_int, get_primary_selection, load_shaders, log_error, open_cmd, color_as_int, get_primary_selection, load_shaders, log_error, open_cmd,
@@ -530,6 +530,13 @@ class Window:
def use_utf8(self, on: bool) -> None: def use_utf8(self, on: bool) -> None:
get_boss().child_monitor.set_iutf8_winid(self.id, on) get_boss().child_monitor.set_iutf8_winid(self.id, on)
def on_mouse_event(self, event: Dict[str, Any]) -> bool:
ev = MouseEvent(**event)
action = self.opts.mousemap.get(ev)
if action is None:
return False
return get_boss().dispatch_action(action, window_for_dispatch=self, dispatch_type='MouseEvent')
def open_url(self, url: str, hyperlink_id: int, cwd: Optional[str] = None) -> None: def open_url(self, url: str, hyperlink_id: int, cwd: Optional[str] = None) -> None:
if hyperlink_id: if hyperlink_id:
if not self.opts.allow_hyperlinks: if not self.opts.allow_hyperlinks: