Start work on intercepting mouse events
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
Reference in New Issue
Block a user