private void EnterReaderMode() { _pbGlyph.Location = Point.Subtract(PointToClient(MousePosition), new Size(_pbGlyph.Width / 2, _pbGlyph.Height / 2)); SetCursor(new HandleRef(Cursors.NoMoveVert, Cursors.NoMoveVert.Handle)); _autoScrollTimer.Start(); _endOnMouseUp = false; // bounds to get the scrolling sensitivity var scrollBounds = new Rectangle(_pbGlyph.Left, _pbGlyph.Top, _pbGlyph.Right, _pbGlyph.Bottom); IntPtr rectPtr = Marshal.AllocHGlobal(Marshal.SizeOf(scrollBounds)); try { Marshal.StructureToPtr(scrollBounds, rectPtr, true); var readerInfo = new READERMODEINFO { hwnd = Handle, fFlags = ReaderModeFlags.VerticalOnly, prc = rectPtr, lParam = IntPtr.Zero, fFlags2 = TranslateDispatchCallback, pfnScroll = ReaderScrollCallback }; readerInfo.cbSize = Marshal.SizeOf(readerInfo); DoReaderMode(ref readerInfo); } finally { Marshal.FreeHGlobal(rectPtr); } }
private bool ReaderScrollCallback(ref 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(_pbGlyph.Location).Y + (_pbGlyph.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); }
static extern void DoReaderMode(ref READERMODEINFO prmi);
private bool ReaderScrollCallback(ref READERMODEINFO prmi, int dx, int dy) { // TODO: Scroll around within your control here return false; }
private void EnterReaderMode() { READERMODEINFO readerInfo = new READERMODEINFO { hwnd = this.textBox1.Handle, fFlags = 0, prc = IntPtr.Zero, lParam = IntPtr.Zero, fFlags2 = new TranslateDispatchCallbackDelegate(this.TranslateDispatchCallback), pfnScroll = new ReaderScrollCallbackDelegate(this.ReaderScrollCallback) }; readerInfo.cbSize = Marshal.SizeOf(readerInfo); DoReaderMode(ref readerInfo); }
internal static extern void DoReaderMode(ref READERMODEINFO prmi);