private bool ReaderScrollCallback(ref Native.READERMODEINFO prmi, int dx, int dy) { if (dy == 0) { _scrollIncrementY = 0; } else { // Could be placebo, but using actual cursor delta rather than dy (which is a much smaller value) // seems to allow for a smoother acceleration curve (I feel like I notice some minor chunkiness // if I use dy) int cursY = Cursor.Position.Y; int origY = PointToScreen(_cursorScrollBounds.Location).Y + (_cursorScrollBounds.Height / 2); int delta = cursY < origY ? origY - cursY : cursY - origY; // Exponential scroll like most apps do - somewhat arbitrary values but has a decent feel. // Clamp to 1 (pixel) to correct for loss of precision in divide where it could end up as 0 for // too long. // OCD int deltaSquared; try { deltaSquared = checked (delta * delta); } catch (OverflowException) { deltaSquared = int.MaxValue; } int increment = (deltaSquared / 640).Clamp(1, 1024); _scrollIncrementY = cursY < origY ? -increment : increment; _endOnMouseUp = true; } return(true); }
private void EnterReaderMode() { _cursorScrollBounds.Location = Point.Subtract(PointToClient(MousePosition), new Size(_cursorScrollBounds.Width / 2, _cursorScrollBounds.Height / 2)); Native.SetCursor(new HandleRef(Cursors.NoMoveVert, Cursors.NoMoveVert.Handle)); _autoScrollTimer.Start(); _endOnMouseUp = false; // bounds to get the scrolling sensitivity // Fen's note: This new Rectangle's dimensions are different, so don't try to get rid of this one and // replace it with the global one, or scroll will break. var scrollBounds = new Rectangle(_cursorScrollBounds.Left, _cursorScrollBounds.Top, _cursorScrollBounds.Right, _cursorScrollBounds.Bottom); IntPtr rectPtr = Marshal.AllocHGlobal(Marshal.SizeOf(scrollBounds)); try { Marshal.StructureToPtr(scrollBounds, rectPtr, true); var readerInfo = new Native.READERMODEINFO { hwnd = Handle, fFlags = Native.ReaderModeFlags.VerticalOnly, prc = rectPtr, lParam = IntPtr.Zero, fFlags2 = TranslateDispatchCallback, pfnScroll = ReaderScrollCallback }; readerInfo.cbSize = Marshal.SizeOf(readerInfo); Native.DoReaderMode(ref readerInfo); } finally { Marshal.FreeHGlobal(rectPtr); } }