Date: | August 7, 2003 / year-entry #15 |
Tags: | code |
Orig Link: | https://blogs.msdn.microsoft.com/oldnewthing/20030807-00/?p=42963 |
Comments: | 4 |
Summary: | The mouse wheel is tricky because the mouse wheel UI guidelines indicate that you should scroll by a user-specified amount for each "click" of the mouse, where one click is WHEEL_DELTA mouse units (called a "detent"). There are two subtle points about the above requirement: First, that the amount of scrolling is a user setting... |
The mouse wheel is tricky because the mouse wheel UI guidelines indicate that you
should scroll by a user-specified amount for each "click" of the mouse, where one
click is
In particular, there is the possibility that a high-resolution mouse wheel will report
wheel scroll units smaller than (I once referred to this in email as a "sub-detent wheel" and was accused of coining a phrase.) To handle the first point, we requery the user's desired scroll delta at each mouse wheel message. To handle the second point, we accumulate detents as they arrive and consume as many of them as possible, leaving the extras for the next wheel message. int g_iWheelCarryover; /* Unused wheel ticks */ LRESULT OnMouseWheel(HWND hwnd, int xPos, int yPos, int zDelta, UINT fwKeys) { UINT uScroll; if (!SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &uScroll, 0)) { uScroll = 3; /* default value */ } /* * If user specified scrolling by pages, do so. */ if (uScroll == WHEEL_PAGESCROLL) { uScroll = g_cLinesPerPage; } /* * If user specified no wheel scrolling, then don't do wheel scrolling. * This also avoids a divide-by-zero below. */ if (uScroll == 0) { return 0; } zDelta += g_iWheelCarryover; /* Accumulate wheel motion */ /* * See how many lines we should scroll. * This relies on round-towards-zero. */ int dLines = zDelta * (int)uScroll / WHEEL_DELTA; /* * Record the unused portion as the next carryover. */ g_iWheelCarryover = zDelta - dLines * WHEEL_DELTA / (int)uScroll; /* * Do the scrolling. */ ScrollDelta(hwnd, -dLines); return 0; } /* Add to WndProc */ HANDLE_MSG(hwnd, WM_MOUSEWHEEL, OnMouseWheel);
Exercise: What is the significance of the Exercise: Assuming you don't have a high-resolution wheel mouse, how would you test that your sub-detent mouse wheel handling was working properly? |
Comments (4)
Comments are closed. |
#1: Isn’t that because WHEEL_DELTA might be a float or double, which would cause a truncation (or cast) compiler warning?
#2: Hmmm…maybe you could hard code in a huge value, so that one click of your mouse wheel wouldn’t accumulate to the amount of what your app is looking for.
Those who can’t do math right should not write code. Period.
For those who are looking to use the above to calculate delta carryovers, the above formula for is mathematically wrong. Let’s go through code with the following assumptions:
uScroll = 3;
zDelta = WHEEL_DELTA / 2;
g_iWheelCarryover = 0;
Those are the initial default values the system should give. WHEEL_DELTA, according to MSDN Library, is 120, so zDelta = 60;
zDelta += g_iWheelCarryover;
// zDelta += 0;
// Therefore, zDelta is still 60.
int dLines = zDelta * (int)uScroll / WHEEL_DELTA;
// dLines = 60 * 3 / 120;
// Therefore, dLines = 1. 180 / 120 = 1.5, but this is truncated to 1 because it is an integer.
g_iWheelCarryover = zDelta – (dLines * WHEEL_DELTA / (int)uScroll);
// g_iWheelCarryover = 60 – (1 * 120 / 3);
// Therefore, g_iWheelCarryover = 60 – 40 = 20.
20 is incorrect and that algorithm is _WAY_ off base. 60 is what the value _SHOULD_ be. g_iWheelCarryover is supposed to contain the remainder of the scroll amount in WHEEL_DELTA units. In this case, 1/2 a line (.5) was "lost". The correct algorithm for g_iWheelCarryover should be:
g_iWheelCarryover = (zDelta * (int)uScroll) – (dLines * WHEEL_DELTA);
// g_iWheelCarryover = (60 * 3) – (1 * 120);
// g_iWheelCarryover = (180) – (120);
// g_iWheelCarryover = 60;
This also means that the check for divide by zero is unnecessary.
Learn to write code correctly before posting to the Internet.
(Oh, and the answer to #2 is to use SendMessage() with the appropriate parameters).
Um, no, 20 is the correct value for g_iWheelCarryover at the end. 40 units of zDelta were used to scroll one line, leaving 20 units of carryover.
Learn to write code correctly before posting to the Internet.
PingBack from http://smallcode.weblogs.us/2007/06/03/corrections-to-raymond-chens-wheel-scrolling-code/