diff options
| author | Eli Zaretskii | 2021-12-01 15:36:55 +0200 |
|---|---|---|
| committer | Eli Zaretskii | 2021-12-01 15:36:55 +0200 |
| commit | bab29694047d060bb58ff88e1a4d2cc7ef05df2a (patch) | |
| tree | 25dffd70f392ccace1007b53b491707ad44dda1a /src/w32term.c | |
| parent | c13b49a110ffd23975e98c053746054492a3908a (diff) | |
| download | emacs-bab29694047d060bb58ff88e1a4d2cc7ef05df2a.tar.gz emacs-bab29694047d060bb58ff88e1a4d2cc7ef05df2a.zip | |
Support precision mouse scrolling on MS-Windows
* src/w32fns.c (w32_wnd_proc): Pass the WM_SETTINGCHANGE message
to the Lisp thread.
* src/w32term.c (w32_construct_mouse_wheel): Support mice with
precision scrolling wheel.
(w32_get_mouse_wheel_vertical_delta): New function.
(w32_read_socket): When the WM_SETTINGCHANGE is received, call
'w32_get_mouse_wheel_vertical_delta'.
(w32_initialize): Call 'w32_get_mouse_wheel_vertical_delta' at
startup.
* src/nsterm.m (syms_of_nsterm):
* src/haikuterm.c (syms_of_haikuterm):
* src/xterm.c (syms_of_xterm): Remove window-system specific
variables for coalescing mwheel events.
* src/keyboard.c (syms_of_keyboard)
<mwheel-coalesce-scroll-events>: New variable, to replace the
above platform-specific ones.
* doc/lispref/commands.texi (Misc Events): Improve wording of the
description of mouse-wheel events.
Diffstat (limited to 'src/w32term.c')
| -rw-r--r-- | src/w32term.c | 99 |
1 files changed, 94 insertions, 5 deletions
diff --git a/src/w32term.c b/src/w32term.c index 07a5cd35649..6b7cbbea6ca 100644 --- a/src/w32term.c +++ b/src/w32term.c | |||
| @@ -164,6 +164,10 @@ int last_scroll_bar_drag_pos; | |||
| 164 | /* Keyboard code page - may be changed by language-change events. */ | 164 | /* Keyboard code page - may be changed by language-change events. */ |
| 165 | int w32_keyboard_codepage; | 165 | int w32_keyboard_codepage; |
| 166 | 166 | ||
| 167 | /* The number of screen lines to scroll for the default mouse-wheel | ||
| 168 | scroll amount, given by WHEEL_DELTA. */ | ||
| 169 | static UINT w32_wheel_scroll_lines; | ||
| 170 | |||
| 167 | #ifdef CYGWIN | 171 | #ifdef CYGWIN |
| 168 | int w32_message_fd = -1; | 172 | int w32_message_fd = -1; |
| 169 | #endif /* CYGWIN */ | 173 | #endif /* CYGWIN */ |
| @@ -272,6 +276,19 @@ XGetGCValues (void *ignore, XGCValues *gc, | |||
| 272 | #endif | 276 | #endif |
| 273 | 277 | ||
| 274 | static void | 278 | static void |
| 279 | w32_get_mouse_wheel_vertical_delta (void) | ||
| 280 | { | ||
| 281 | if (os_subtype != OS_SUBTYPE_NT) | ||
| 282 | return; | ||
| 283 | |||
| 284 | UINT scroll_lines; | ||
| 285 | BOOL ret = SystemParametersInfo (SPI_GETWHEELSCROLLLINES, 0, | ||
| 286 | &scroll_lines, 0); | ||
| 287 | if (ret) | ||
| 288 | w32_wheel_scroll_lines = scroll_lines; | ||
| 289 | } | ||
| 290 | |||
| 291 | static void | ||
| 275 | w32_set_clip_rectangle (HDC hdc, RECT *rect) | 292 | w32_set_clip_rectangle (HDC hdc, RECT *rect) |
| 276 | { | 293 | { |
| 277 | if (rect) | 294 | if (rect) |
| @@ -3203,32 +3220,94 @@ w32_construct_mouse_wheel (struct input_event *result, W32Msg *msg, | |||
| 3203 | { | 3220 | { |
| 3204 | POINT p; | 3221 | POINT p; |
| 3205 | int delta; | 3222 | int delta; |
| 3223 | static int sum_delta_y = 0; | ||
| 3206 | 3224 | ||
| 3207 | result->kind = msg->msg.message == WM_MOUSEHWHEEL ? HORIZ_WHEEL_EVENT | 3225 | result->kind = msg->msg.message == WM_MOUSEHWHEEL ? HORIZ_WHEEL_EVENT |
| 3208 | : WHEEL_EVENT; | 3226 | : WHEEL_EVENT; |
| 3209 | result->code = 0; | 3227 | result->code = 0; |
| 3210 | result->timestamp = msg->msg.time; | 3228 | result->timestamp = msg->msg.time; |
| 3229 | result->arg = Qnil; | ||
| 3211 | 3230 | ||
| 3212 | /* A WHEEL_DELTA positive value indicates that the wheel was rotated | 3231 | /* A WHEEL_DELTA positive value indicates that the wheel was rotated |
| 3213 | forward, away from the user (up); a negative value indicates that | 3232 | forward, away from the user (up); a negative value indicates that |
| 3214 | the wheel was rotated backward, toward the user (down). */ | 3233 | the wheel was rotated backward, toward the user (down). */ |
| 3215 | delta = GET_WHEEL_DELTA_WPARAM (msg->msg.wParam); | 3234 | delta = GET_WHEEL_DELTA_WPARAM (msg->msg.wParam); |
| 3235 | if (delta == 0) | ||
| 3236 | { | ||
| 3237 | result->kind = NO_EVENT; | ||
| 3238 | return Qnil; | ||
| 3239 | } | ||
| 3240 | |||
| 3241 | /* With multiple monitors, we can legitimately get negative | ||
| 3242 | coordinates, so cast to short to interpret them correctly. */ | ||
| 3243 | p.x = (short) LOWORD (msg->msg.lParam); | ||
| 3244 | p.y = (short) HIWORD (msg->msg.lParam); | ||
| 3245 | |||
| 3246 | if (eabs (delta) < WHEEL_DELTA) | ||
| 3247 | { | ||
| 3248 | /* This is high-precision mouse wheel, which sends | ||
| 3249 | fine-resolution wheel events. Produce a wheel event only if | ||
| 3250 | the conditions for sending such an event are fulfilled. */ | ||
| 3251 | int scroll_unit = max (w32_wheel_scroll_lines, 1), nlines; | ||
| 3252 | double value_to_report; | ||
| 3253 | |||
| 3254 | /* w32_wheel_scroll_lines == INT_MAX means the user asked for | ||
| 3255 | "entire page" to be the scroll unit. We interpret that as | ||
| 3256 | the height of the window under the mouse pointer. */ | ||
| 3257 | if (w32_wheel_scroll_lines == INT_MAX) | ||
| 3258 | { | ||
| 3259 | Lisp_Object window = window_from_coordinates (f, p.x, p.y, NULL, | ||
| 3260 | false, false); | ||
| 3261 | if (!WINDOWP (window)) | ||
| 3262 | { | ||
| 3263 | result->kind = NO_EVENT; | ||
| 3264 | return Qnil; | ||
| 3265 | } | ||
| 3266 | scroll_unit = XWINDOW (window)->pixel_height; | ||
| 3267 | if (scroll_unit < 1) /* paranoia */ | ||
| 3268 | scroll_unit = 1; | ||
| 3269 | } | ||
| 3270 | |||
| 3271 | /* If mwheel-coalesce-scroll-events is non-nil, report a wheel event | ||
| 3272 | only when we have accumulated enough delta's for WHEEL_DELTA. */ | ||
| 3273 | if (mwheel_coalesce_scroll_events) | ||
| 3274 | { | ||
| 3275 | /* If the user changed the direction, reset the accumulated | ||
| 3276 | deltas. */ | ||
| 3277 | if ((delta > 0) != (sum_delta_y > 0)) | ||
| 3278 | sum_delta_y = 0; | ||
| 3279 | sum_delta_y += delta; | ||
| 3280 | /* https://docs.microsoft.com/en-us/previous-versions/ms997498(v=msdn.10) */ | ||
| 3281 | if (eabs (sum_delta_y) < WHEEL_DELTA) | ||
| 3282 | { | ||
| 3283 | result->kind = NO_EVENT; | ||
| 3284 | return Qnil; | ||
| 3285 | } | ||
| 3286 | value_to_report = | ||
| 3287 | ((double)FRAME_LINE_HEIGHT (f) * scroll_unit) | ||
| 3288 | / ((double)WHEEL_DELTA / sum_delta_y); | ||
| 3289 | sum_delta_y = 0; | ||
| 3290 | } | ||
| 3291 | else | ||
| 3292 | value_to_report = | ||
| 3293 | ((double)FRAME_LINE_HEIGHT (f) * scroll_unit) | ||
| 3294 | / ((double)WHEEL_DELTA / delta); | ||
| 3295 | nlines = value_to_report / FRAME_LINE_HEIGHT (f) + 0.5; | ||
| 3296 | result->arg = list3 (make_fixnum (nlines), | ||
| 3297 | make_float (0.0), | ||
| 3298 | make_float (value_to_report)); | ||
| 3299 | } | ||
| 3216 | 3300 | ||
| 3217 | /* The up and down modifiers indicate if the wheel was rotated up or | 3301 | /* The up and down modifiers indicate if the wheel was rotated up or |
| 3218 | down based on WHEEL_DELTA value. */ | 3302 | down based on WHEEL_DELTA value. */ |
| 3219 | result->modifiers = (msg->dwModifiers | 3303 | result->modifiers = (msg->dwModifiers |
| 3220 | | ((delta < 0 ) ? down_modifier : up_modifier)); | 3304 | | ((delta < 0 ) ? down_modifier : up_modifier)); |
| 3221 | 3305 | ||
| 3222 | /* With multiple monitors, we can legitimately get negative | ||
| 3223 | coordinates, so cast to short to interpret them correctly. */ | ||
| 3224 | p.x = (short) LOWORD (msg->msg.lParam); | ||
| 3225 | p.y = (short) HIWORD (msg->msg.lParam); | ||
| 3226 | /* For the case that F's w32 window is not msg->msg.hwnd. */ | 3306 | /* For the case that F's w32 window is not msg->msg.hwnd. */ |
| 3227 | ScreenToClient (FRAME_W32_WINDOW (f), &p); | 3307 | ScreenToClient (FRAME_W32_WINDOW (f), &p); |
| 3228 | XSETINT (result->x, p.x); | 3308 | XSETINT (result->x, p.x); |
| 3229 | XSETINT (result->y, p.y); | 3309 | XSETINT (result->y, p.y); |
| 3230 | XSETFRAME (result->frame_or_window, f); | 3310 | XSETFRAME (result->frame_or_window, f); |
| 3231 | result->arg = Qnil; | ||
| 3232 | return Qnil; | 3311 | return Qnil; |
| 3233 | } | 3312 | } |
| 3234 | 3313 | ||
| @@ -4905,6 +4984,14 @@ w32_read_socket (struct terminal *terminal, | |||
| 4905 | } | 4984 | } |
| 4906 | break; | 4985 | break; |
| 4907 | 4986 | ||
| 4987 | case WM_SETTINGCHANGE: | ||
| 4988 | /* We are only interested in changes of the number of lines | ||
| 4989 | to scroll when the vertical mouse wheel is moved. This | ||
| 4990 | is only supported on NT. */ | ||
| 4991 | if (msg.msg.wParam == SPI_SETWHEELSCROLLLINES) | ||
| 4992 | w32_get_mouse_wheel_vertical_delta (); | ||
| 4993 | break; | ||
| 4994 | |||
| 4908 | case WM_KEYDOWN: | 4995 | case WM_KEYDOWN: |
| 4909 | case WM_SYSKEYDOWN: | 4996 | case WM_SYSKEYDOWN: |
| 4910 | f = w32_window_to_frame (dpyinfo, msg.msg.hwnd); | 4997 | f = w32_window_to_frame (dpyinfo, msg.msg.hwnd); |
| @@ -7522,6 +7609,8 @@ w32_initialize (void) | |||
| 7522 | horizontal_scroll_bar_left_border = horizontal_scroll_bar_right_border | 7609 | horizontal_scroll_bar_left_border = horizontal_scroll_bar_right_border |
| 7523 | = GetSystemMetrics (SM_CYHSCROLL); | 7610 | = GetSystemMetrics (SM_CYHSCROLL); |
| 7524 | } | 7611 | } |
| 7612 | |||
| 7613 | w32_get_mouse_wheel_vertical_delta (); | ||
| 7525 | } | 7614 | } |
| 7526 | 7615 | ||
| 7527 | void | 7616 | void |