Rework mouse event processing

X11's triple-click bug is gone, and we may pass modifier state.
This commit is contained in:
Přemysl Eric Janouch 2022-08-25 00:10:17 +02:00
parent a77d872e7f
commit 2d219f1a4b
Signed by: p
GPG Key ID: A0420B94F92B9493
1 changed files with 51 additions and 34 deletions

View File

@ -2728,8 +2728,11 @@ app_editor_process_action (enum action action)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Carefully chosen to limit the possibility of ever hitting termo keymods.
enum { APP_KEYMOD_DOUBLE_CLICK = 1 << 15 };
static bool static bool
app_process_left_mouse_click (struct widget *w, int x, int y, bool double_click) app_process_left_mouse_click (struct widget *w, int x, int y, int modifiers)
{ {
switch (w->id) switch (w->id)
{ {
@ -2772,7 +2775,7 @@ app_process_left_mouse_click (struct widget *w, int x, int y, bool double_click)
tab->item_selected = row_index + tab->item_top; tab->item_selected = row_index + tab->item_top;
app_invalidate (); app_invalidate ();
if (double_click) if (modifiers & APP_KEYMOD_DOUBLE_CLICK)
app_process_action (ACTION_CHOOSE); app_process_action (ACTION_CHOOSE);
break; break;
} }
@ -2793,7 +2796,7 @@ app_process_left_mouse_click (struct widget *w, int x, int y, bool double_click)
static bool static bool
app_process_mouse (termo_mouse_event_t type, int x, int y, int button, app_process_mouse (termo_mouse_event_t type, int x, int y, int button,
bool double_click) int modifiers)
{ {
// XXX: Terminals don't let us know which button has been released, // XXX: Terminals don't let us know which button has been released,
// so we can't press buttons at that point. We'd need a special "click" // so we can't press buttons at that point. We'd need a special "click"
@ -2817,7 +2820,7 @@ app_process_mouse (termo_mouse_event_t type, int x, int y, int button,
x -= target->x; x -= target->x;
y -= target->y; y -= target->y;
return app_process_left_mouse_click (target, x, y, double_click); return app_process_left_mouse_click (target, x, y, modifiers);
} }
if (g.editor.line) if (g.editor.line)
@ -2840,7 +2843,7 @@ app_process_mouse (termo_mouse_event_t type, int x, int y, int button,
{ {
case 1: case 1:
g.ui_dragging = target->id; g.ui_dragging = target->id;
return app_process_left_mouse_click (target, x, y, double_click); return app_process_left_mouse_click (target, x, y, modifiers);
case 4: case 4:
if (target->id == WIDGET_LIST) if (target->id == WIDGET_LIST)
return app_process_action (ACTION_SCROLL_UP); return app_process_action (ACTION_SCROLL_UP);
@ -5243,23 +5246,25 @@ tui_on_tty_event (termo_key_t *event, int64_t event_ts)
static int64_t last_event_ts; static int64_t last_event_ts;
static int last_button; static int last_button;
int y, x, button, y_last, x_last; int y, x, button, y_last, x_last, modifiers = 0;
termo_mouse_event_t type, type_last; termo_mouse_event_t type, type_last;
if (termo_interpret_mouse (g.tk, event, &type, &button, &y, &x)) if (termo_interpret_mouse (g.tk, event, &type, &button, &y, &x))
{ {
bool double_click = termo_interpret_mouse if (termo_interpret_mouse
(g.tk, &last_event, &type_last, NULL, &y_last, &x_last) (g.tk, &last_event, &type_last, NULL, &y_last, &x_last)
&& event_ts - last_event_ts < 500 && event_ts - last_event_ts < 500
&& type_last == TERMO_MOUSE_RELEASE && type == TERMO_MOUSE_PRESS && type_last == TERMO_MOUSE_RELEASE && type == TERMO_MOUSE_PRESS
&& y_last == y && x_last == x && last_button == button; && y_last == y && x_last == x && last_button == button)
if (!app_process_mouse (type, x, y, button, double_click)) {
beep (); modifiers |= APP_KEYMOD_DOUBLE_CLICK;
// Prevent interpreting triple clicks as two double clicks.
// Prevent interpreting triple clicks as two double clicks
if (double_click)
last_button = 0; last_button = 0;
}
else if (type == TERMO_MOUSE_PRESS) else if (type == TERMO_MOUSE_PRESS)
last_button = button; last_button = button;
if (!app_process_mouse (type, x, y, button, modifiers))
beep ();
} }
else if (!app_process_termo_event (event)) else if (!app_process_termo_event (event))
beep (); beep ();
@ -6001,43 +6006,55 @@ x11_init_pixmap (void)
= XRenderCreatePicture (g.dpy, g.x11_pixmap, format, 0, NULL); = XRenderCreatePicture (g.dpy, g.x11_pixmap, format, 0, NULL);
} }
static int
x11_state_to_modifiers (unsigned int state)
{
int modifiers = 0;
if (state & ShiftMask) modifiers |= TERMO_KEYMOD_SHIFT;
if (state & ControlMask) modifiers |= TERMO_KEYMOD_CTRL;
if (state & Mod1Mask) modifiers |= TERMO_KEYMOD_ALT;
return modifiers;
}
static bool static bool
on_x11_input_event (XEvent *ev) on_x11_input_event (XEvent *ev)
{ {
static XEvent last_button_event; static XEvent last_press_event;
if (ev->type == KeyPress) if (ev->type == KeyPress)
{ {
last_button_event = (XEvent) {}; last_press_event = (XEvent) {};
return on_x11_keypress (ev); return on_x11_keypress (ev);
} }
if (ev->type == MotionNotify) if (ev->type == MotionNotify)
{ {
// We only select for Button1MotionMask, so this works out. return app_process_mouse (TERMO_MOUSE_DRAG,
int x = ev->xmotion.x, y = ev->xmotion.y; ev->xmotion.x, ev->xmotion.y, 1 /* Button1MotionMask */,
return app_process_mouse (TERMO_MOUSE_DRAG, x, y, 1, false); x11_state_to_modifiers (ev->xmotion.state));
} }
// See tui_on_tty_event(). Just here we know the button on button release. // This is nearly the same as tui_on_tty_event().
int x = ev->xbutton.x, y = ev->xbutton.y; int x = ev->xbutton.x, y = ev->xbutton.y;
unsigned int button = ev->xbutton.button; unsigned int button = ev->xbutton.button;
bool double_click = ev->xbutton.time - last_button_event.xbutton.time < 500 int modifiers = x11_state_to_modifiers (ev->xbutton.state);
&& last_button_event.type == ButtonRelease && ev->type == ButtonPress if (ev->type == ButtonPress
&& abs (last_button_event.xbutton.x - x) < 5 && ev->xbutton.time - last_press_event.xbutton.time < 500
&& abs (last_button_event.xbutton.y - y) < 5 && abs (last_press_event.xbutton.x - x) < 5
&& last_button_event.xbutton.button == button; && abs (last_press_event.xbutton.y - y) < 5
&& last_press_event.xbutton.button == button)
// Prevent interpreting triple clicks as two double clicks. {
// FIXME: This doesn't work: we skip ButtonPress, but use ButtonRelease. modifiers |= APP_KEYMOD_DOUBLE_CLICK;
last_button_event = (XEvent) {}; // Prevent interpreting triple clicks as two double clicks.
if (!double_click) last_press_event = (XEvent) {};
last_button_event = *ev; }
else if (ev->type == ButtonPress)
last_press_event = *ev;
if (ev->type == ButtonPress) if (ev->type == ButtonPress)
return app_process_mouse return app_process_mouse
(TERMO_MOUSE_PRESS, x, y, button, double_click); (TERMO_MOUSE_PRESS, x, y, button, modifiers);
if (ev->type == ButtonRelease) if (ev->type == ButtonRelease)
return app_process_mouse return app_process_mouse
(TERMO_MOUSE_RELEASE, x, y, button, double_click); (TERMO_MOUSE_RELEASE, x, y, button, modifiers);
return false; return false;
} }