Implement high precision scrolling with the trackpad on platforms such as macOS and Wayland that implement it.
Fixes #819. Note that I have no idea whether the code works well on retina screens, might have to multiple the pixel count by the scale factor on those screens?
This commit is contained in:
parent
0e0e25f986
commit
009ef54de7
@ -20,6 +20,9 @@ Changelog
|
||||
- Add an option :opt:`env` to set environment variables in child processes
|
||||
from kitty.conf
|
||||
|
||||
- Implement high precision scrolling with the trackpad on platforms such as
|
||||
macOS and Wayland that implement it. (:pull:`819`)
|
||||
|
||||
- macOS: Allow scrolling window contents using mouse wheel/trackpad even when the
|
||||
window is not the active window (:iss:`729`)
|
||||
|
||||
|
||||
@ -884,15 +884,10 @@ is_ascii_control_char(char x) {
|
||||
|
||||
deltaX = [event scrollingDeltaX];
|
||||
deltaY = [event scrollingDeltaY];
|
||||
|
||||
if ([event hasPreciseScrollingDeltas])
|
||||
{
|
||||
deltaX *= 0.1;
|
||||
deltaY *= 0.1;
|
||||
}
|
||||
int flags = [event hasPreciseScrollingDeltas] ? 1 : 0;
|
||||
|
||||
if (fabs(deltaX) > 0.0 || fabs(deltaY) > 0.0)
|
||||
_glfwInputScroll(window, deltaX, deltaY);
|
||||
_glfwInputScroll(window, deltaX, deltaY, flags);
|
||||
}
|
||||
|
||||
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
|
||||
|
||||
4
glfw/glfw3.h
vendored
4
glfw/glfw3.h
vendored
@ -1372,15 +1372,17 @@ typedef void (* GLFWcursorenterfun)(GLFWwindow*,int);
|
||||
* @param[in] window The window that received the event.
|
||||
* @param[in] xoffset The scroll offset along the x-axis.
|
||||
* @param[in] yoffset The scroll offset along the y-axis.
|
||||
* @param[in] flags A bit-mask providing extra data about the event. flags & 1 will be true if and only if the offset values are "high-precision". Typically pixel values. Otherwise the offset values are number of lines.
|
||||
*
|
||||
* @sa @ref scrolling
|
||||
* @sa @ref glfwSetScrollCallback
|
||||
*
|
||||
* @since Added in version 3.0. Replaces `GLFWmousewheelfun`.
|
||||
* @since Changed in version 4.0. Added `flags` parameter.
|
||||
*
|
||||
* @ingroup input
|
||||
*/
|
||||
typedef void (* GLFWscrollfun)(GLFWwindow*,double,double);
|
||||
typedef void (* GLFWscrollfun)(GLFWwindow*,double,double,int);
|
||||
|
||||
/*! @brief The function signature for key callbacks.
|
||||
*
|
||||
|
||||
4
glfw/input.c
vendored
4
glfw/input.c
vendored
@ -286,10 +286,10 @@ void _glfwInputKeyboard(_GLFWwindow* window, int key, int scancode, int action,
|
||||
|
||||
// Notifies shared code of a scroll event
|
||||
//
|
||||
void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset)
|
||||
void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset, int flags)
|
||||
{
|
||||
if (window->callbacks.scroll)
|
||||
window->callbacks.scroll((GLFWwindow*) window, xoffset, yoffset);
|
||||
window->callbacks.scroll((GLFWwindow*) window, xoffset, yoffset, flags);
|
||||
}
|
||||
|
||||
// Notifies shared code of a mouse button click event
|
||||
|
||||
2
glfw/internal.h
vendored
2
glfw/internal.h
vendored
@ -717,7 +717,7 @@ void _glfwInputWindowCloseRequest(_GLFWwindow* window);
|
||||
void _glfwInputWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor);
|
||||
|
||||
void _glfwInputKeyboard(_GLFWwindow* window, int key, int scancode, int action, int mods, const char* text, int state);
|
||||
void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset);
|
||||
void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset, int flags);
|
||||
void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods);
|
||||
void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos);
|
||||
void _glfwInputCursorEnter(_GLFWwindow* window, GLFWbool entered);
|
||||
|
||||
11
glfw/wl_init.c
vendored
11
glfw/wl_init.c
vendored
@ -319,11 +319,6 @@ static void pointerHandleAxis(void* data,
|
||||
{
|
||||
_GLFWwindow* window = _glfw.wl.pointerFocus;
|
||||
double x = 0.0, y = 0.0;
|
||||
// Wayland scroll events are in pointer motion coordinate space (think two
|
||||
// finger scroll). The factor 10 is commonly used to convert to "scroll
|
||||
// step means 1.0.
|
||||
const double scrollFactor = 1.0 / 10.0;
|
||||
|
||||
if (!window)
|
||||
return;
|
||||
|
||||
@ -331,11 +326,11 @@ static void pointerHandleAxis(void* data,
|
||||
axis == WL_POINTER_AXIS_VERTICAL_SCROLL);
|
||||
|
||||
if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL)
|
||||
x = wl_fixed_to_double(value) * scrollFactor;
|
||||
x = wl_fixed_to_double(value) * -1;
|
||||
else if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL)
|
||||
y = wl_fixed_to_double(value) * scrollFactor;
|
||||
y = wl_fixed_to_double(value) * -1;
|
||||
|
||||
_glfwInputScroll(window, x, y);
|
||||
_glfwInputScroll(window, x, y, 1);
|
||||
}
|
||||
|
||||
static const struct wl_pointer_listener pointerListener = {
|
||||
|
||||
8
glfw/x11_window.c
vendored
8
glfw/x11_window.c
vendored
@ -1309,13 +1309,13 @@ static void processEvent(XEvent *event)
|
||||
|
||||
// Modern X provides scroll events as mouse button presses
|
||||
else if (event->xbutton.button == Button4)
|
||||
_glfwInputScroll(window, 0.0, 1.0);
|
||||
_glfwInputScroll(window, 0.0, 1.0, 0);
|
||||
else if (event->xbutton.button == Button5)
|
||||
_glfwInputScroll(window, 0.0, -1.0);
|
||||
_glfwInputScroll(window, 0.0, -1.0, 0);
|
||||
else if (event->xbutton.button == Button6)
|
||||
_glfwInputScroll(window, 1.0, 0.0);
|
||||
_glfwInputScroll(window, 1.0, 0.0, 0);
|
||||
else if (event->xbutton.button == Button7)
|
||||
_glfwInputScroll(window, -1.0, 0.0);
|
||||
_glfwInputScroll(window, -1.0, 0.0, 0);
|
||||
|
||||
else
|
||||
{
|
||||
|
||||
@ -302,8 +302,9 @@ INPUT_LINE_NUMBER in the command line above will be replaced by an integer
|
||||
representing which line should be at the top of the screen.'''))
|
||||
|
||||
o('wheel_scroll_multiplier', 5.0, long_text=_('''
|
||||
Modify the amount scrolled by the mouse wheel or touchpad. Use
|
||||
negative numbers to change scroll direction.'''))
|
||||
Modify the amount scrolled by the mouse wheel. Note this is only used for low
|
||||
precision scrolling devices, not for high precision scrolling on platforms such
|
||||
as macOS and Wayland. Use negative numbers to change scroll direction.'''))
|
||||
# }}}
|
||||
|
||||
g('mouse') # {{{
|
||||
|
||||
@ -284,7 +284,7 @@ void enter_event();
|
||||
void mouse_event(int, int);
|
||||
void focus_in_event();
|
||||
void wakeup_io_loop(bool);
|
||||
void scroll_event(double, double);
|
||||
void scroll_event(double, double, int);
|
||||
void fake_scroll(int, bool);
|
||||
void set_special_key_combo(int glfw_key, int mods, bool is_native);
|
||||
void on_key_input(int key, int scancode, int action, int mods, const char*, int);
|
||||
|
||||
2
kitty/glfw-wrapper.h
generated
2
kitty/glfw-wrapper.h
generated
@ -1141,7 +1141,7 @@ typedef void (* GLFWcursorenterfun)(GLFWwindow*,int);
|
||||
*
|
||||
* @ingroup input
|
||||
*/
|
||||
typedef void (* GLFWscrollfun)(GLFWwindow*,double,double);
|
||||
typedef void (* GLFWscrollfun)(GLFWwindow*,double,double,int);
|
||||
|
||||
/*! @brief The function signature for key callbacks.
|
||||
*
|
||||
|
||||
@ -178,12 +178,12 @@ cursor_pos_callback(GLFWwindow *w, double x, double y) {
|
||||
}
|
||||
|
||||
static void
|
||||
scroll_callback(GLFWwindow *w, double xoffset, double yoffset) {
|
||||
scroll_callback(GLFWwindow *w, double xoffset, double yoffset, int flags) {
|
||||
if (!set_callback_window(w)) return;
|
||||
show_mouse_cursor(w);
|
||||
double now = monotonic();
|
||||
global_state.callback_os_window->last_mouse_activity_at = now;
|
||||
if (is_window_ready_for_callbacks()) scroll_event(xoffset, yoffset);
|
||||
if (is_window_ready_for_callbacks()) scroll_event(xoffset, yoffset, flags);
|
||||
global_state.callback_os_window = NULL;
|
||||
}
|
||||
|
||||
|
||||
@ -527,13 +527,7 @@ mouse_event(int button, int modifiers) {
|
||||
}
|
||||
|
||||
void
|
||||
scroll_event(double UNUSED xoffset, double yoffset) {
|
||||
// glfw inverts the y-axis when reporting scroll events under wayland
|
||||
// Until this is fixed in upstream, invert y ourselves.
|
||||
if (global_state.is_wayland) yoffset *= -1;
|
||||
int s = (int) round(yoffset * OPT(wheel_scroll_multiplier));
|
||||
if (s == 0) return;
|
||||
bool upwards = s > 0;
|
||||
scroll_event(double UNUSED xoffset, double yoffset, int flags) {
|
||||
bool in_tab_bar;
|
||||
unsigned int window_idx = 0;
|
||||
Window *w = window_for_event(&window_idx, &in_tab_bar);
|
||||
@ -544,17 +538,36 @@ scroll_event(double UNUSED xoffset, double yoffset) {
|
||||
Tab *t = global_state.callback_os_window->tabs + global_state.callback_os_window->active_tab;
|
||||
if (t) w = t->windows + t->active_window;
|
||||
}
|
||||
if (w) {
|
||||
Screen *screen = w->render_data.screen;
|
||||
if (screen->linebuf == screen->main_linebuf) {
|
||||
screen_history_scroll(screen, abs(s), upwards);
|
||||
if (!w) return;
|
||||
|
||||
int s;
|
||||
if (flags & 1) {
|
||||
if (yoffset * global_state.callback_os_window->pending_scroll_pixels < 0) {
|
||||
global_state.callback_os_window->pending_scroll_pixels = 0; // change of direction
|
||||
}
|
||||
double pixels = global_state.callback_os_window->pending_scroll_pixels + yoffset;
|
||||
if (fabs(pixels) < global_state.callback_os_window->fonts_data->cell_height) {
|
||||
global_state.callback_os_window->pending_scroll_pixels = pixels;
|
||||
return;
|
||||
}
|
||||
s = abs(((int)round(pixels))) / global_state.callback_os_window->fonts_data->cell_height;
|
||||
if (pixels < 0) s *= -1;
|
||||
global_state.callback_os_window->pending_scroll_pixels = pixels - s;
|
||||
} else {
|
||||
s = (int) round(yoffset * OPT(wheel_scroll_multiplier));
|
||||
global_state.callback_os_window->pending_scroll_pixels = 0;
|
||||
}
|
||||
if (s == 0) return;
|
||||
bool upwards = s > 0;
|
||||
Screen *screen = w->render_data.screen;
|
||||
if (screen->linebuf == screen->main_linebuf) {
|
||||
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, 0);
|
||||
if (sz > 0) { mouse_event_buf[sz] = 0; write_escape_code_to_child(screen, CSI, mouse_event_buf); }
|
||||
} else {
|
||||
if (screen->modes.mouse_tracking_mode) {
|
||||
int sz = encode_mouse_event(w, upwards ? GLFW_MOUSE_BUTTON_4 : GLFW_MOUSE_BUTTON_5, PRESS, 0);
|
||||
if (sz > 0) { mouse_event_buf[sz] = 0; write_escape_code_to_child(screen, CSI, mouse_event_buf); }
|
||||
} else {
|
||||
fake_scroll(abs(s), upwards);
|
||||
}
|
||||
fake_scroll(abs(s), upwards);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -124,6 +124,7 @@ typedef struct {
|
||||
float background_opacity;
|
||||
FONTS_DATA_HANDLE fonts_data;
|
||||
id_type temp_font_group_id;
|
||||
double pending_scroll_pixels;
|
||||
} OSWindow;
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user