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:
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:
f = getattr(self, key_action.func, None)
if f is not None:
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)
if passthrough is not True:
return True
tab = self.active_tab
if tab is None:
return False
window = self.active_window
if window is None:
if window_for_dispatch is None:
tab = self.active_tab
window = self.active_window
else:
window = window_for_dispatch
tab = window.tabref()
if tab is None or window is None:
return False
if key_action is not None:
f = getattr(tab, key_action.func, getattr(window, key_action.func, None))
if f is not None:
passthrough = f(*key_action.args)
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:
return True
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) {
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}",
"button", button, "repeat_count", count, "mods", modifiers, "grabbed", grabbed ? Py_True : Py_False);
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
@@ -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;
q->length++;
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
if (q->length > 2) {
// possible triple-click
@@ -450,7 +456,7 @@ HANDLER(add_click) {
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
) {
multi_click(w, 3);
if (screen) dispatch_mouse_event(w, button, 3, modifiers, screen->modes.mouse_tracking_mode != 0);
q->length = 0;
}
}
@@ -460,7 +466,7 @@ HANDLER(add_click) {
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
) {
multi_click(w, 2);
if (screen) dispatch_mouse_event(w, button, 2, modifiers, screen->modes.mouse_tracking_mode != 0);
}
}
#undef N
@@ -473,7 +479,7 @@ open_url(Window *w) {
screen_open_url(screen);
}
static inline void
static void
handle_button_event_in_kitty(Window *w, int button, int modifiers, bool is_release) {
switch(button) {
case GLFW_MOUSE_BUTTON_LEFT:
@@ -500,17 +506,11 @@ HANDLER(handle_button_event) {
}
Screen *screen = w->render_data.screen;
if (!screen) return;
const int ts1 = OPT(terminal_select_modifiers), ts2 = OPT(terminal_select_modifiers) | OPT(rectangle_select_modifiers);
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 {
if (!dispatch_mouse_event(w, button, is_release ? -1 : 1, modifiers, screen->modes.mouse_tracking_mode != 0)) {
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); }
}
add_click(w, button, modifiers, 0);
}
static inline int

View File

@@ -19,7 +19,7 @@ from typing import (
from .child import ProcessDesc
from .cli_stub import CLIOptions
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 (
BGIMAGE_PROGRAM, BLIT_PROGRAM, CELL_BG_PROGRAM, CELL_FG_PROGRAM,
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 .rgb import to_color
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 .utils import (
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:
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:
if hyperlink_id:
if not self.opts.allow_hyperlinks: