Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>The only way to do this is to scan the cursors MASK and find the distance between the last set pixel in the cursor mask and the cursors Y hotspot, I had to do this up today, so heres the code:</p> <pre><code>#define useUnsafe using System.Drawing; using System.Drawing.Imaging; using System.Runtime.InteropServices; using System; using System.Windows.Forms; namespace Utils { /// &lt;summary&gt; /// Provides extension methods for the Cursor class /// &lt;/summary&gt; /// &lt;remarks&gt;By Aaron Murgatroyd&lt;/remarks&gt; public static class CursorExtensionMethods { #region API Functions /// &lt;summary&gt; /// Contains the icon information for a Windows API icon /// &lt;/summary&gt; private struct IconInfo { public bool fIcon; public int xHotspot; public int yHotspot; public IntPtr hbmMask; public IntPtr hbmColor; } /// &lt;summary&gt; /// Gets the icon information for a Windows API icon /// &lt;/summary&gt; /// &lt;param name="hIcon"&gt;The icon to get the info for&lt;/param&gt; /// &lt;param name="pIconInfo"&gt;The object to receive the info&lt;/param&gt; /// &lt;returns&gt;True on success, false on failure&lt;/returns&gt; [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool GetIconInfo(IntPtr hIcon, ref IconInfo pIconInfo); [DllImport("gdi32.dll")] static extern bool DeleteObject(IntPtr hObject); #endregion #region Private Static Methods /// &lt;summary&gt; /// Scans bits in bitmap data for a set or unset bit /// &lt;/summary&gt; /// &lt;param name="byteData"&gt;The pointer to the first byte of the first scanline&lt;/param&gt; /// &lt;param name="start"&gt;The vertical position to start the scan&lt;/param&gt; /// &lt;param name="lineInc"&gt;The number of bytes to move per line&lt;/param&gt; /// &lt;param name="maxLines"&gt;The number of lines to scan&lt;/param&gt; /// &lt;param name="set"&gt;True to scan for set bits, false to scan for unset bits&lt;/param&gt; /// &lt;param name="fromBottom"&gt;True to scan from the bottom of the bitmap, false to scan from the top&lt;/param&gt; /// &lt;returns&gt;The number of lines scanned before a bit was found, or -1 if none found before reaching max lines&lt;/returns&gt; #if useUnsafe private static unsafe int ScanBits(IntPtr byteData, int start, int lineInc, int maxLines, bool set, bool fromBottom) #else private static int ScanBits(IntPtr byteData, int start, int lineInc, int maxLines, bool set, bool fromBottom) #endif { // Calculate the starting byte of the first scanline #if useUnsafe byte* lbLine = ((byte*)byteData) + (start * lineInc); #else int lbLine = ((int)(byteData) + (start * lineInc)); #endif int liLine = 0; // Use lineInc to determines bytes per line int liBytesPerLine = (lineInc &lt; 0 ? -lineInc : lineInc); // If we want to search in reverse order if (fromBottom) { // Move to the START of the line lbLine += lineInc * (maxLines - 1); // Negate the line increment lineInc = -lineInc; } while (maxLines &gt; 0) { // Setup the line scan #if useUnsafe byte* lbData = lbLine; #else int lbData = lbLine; #endif int liByte = liBytesPerLine; // For each byte in the line while (liByte &gt; 0) { #if !useUnsafe byte lbByte = Marshal.ReadByte((IntPtr)lbData); #endif // If we want set bits, and a bit is set #if useUnsafe if (set &amp;&amp; *lbData != 0) #else if (set &amp;&amp; lbByte != 0) #endif // Return the line number return liLine; else // If we want unset bits and any bits arent set #if useUnsafe if (!set &amp;&amp; *lbData != byte.MaxValue) #else if (!set &amp;&amp; lbByte != byte.MaxValue) #endif // Return the line number return liLine; // Next byte for scan line liByte--; lbData++; } // Next scan line liLine++; maxLines--; lbLine += lineInc; } // If all lines were scanned, return -1 if (maxLines == 0) return -1; else // Return number of lines scanned return liLine; } #endregion #region Public Static Methods /// &lt;summary&gt; /// Gets the number of pixels between the Y hotspot /// and the last physical line of a cursor /// &lt;/summary&gt; /// &lt;param name="cursor"&gt;The cursor to scan&lt;/param&gt; /// &lt;returns&gt; /// The number of lines between the Y hotspot /// and the last physical line of the cursor /// &lt;/returns&gt; public static int GetBaseLineHeight(this Cursor cursor) { return GetBaseLine(cursor) - cursor.HotSpot.Y; } /// &lt;summary&gt; /// Gets the physical base line of the cursor, that is, /// the distance between the top of the virtual cursor /// and the physical base line of the cursor /// &lt;/summary&gt; /// &lt;param name="cursor"&gt;The cursor to scan&lt;/param&gt; /// &lt;returns&gt;The number of lines between the top of the virtual cursor /// and the physical base line of the curosr&lt;/returns&gt; public static int GetBaseLine(this Cursor cursor) { IconInfo liiInfo = new IconInfo(); if (!GetIconInfo(cursor.Handle, ref liiInfo)) return cursor.Size.Height; Bitmap lbmpBitmap = Bitmap.FromHbitmap(liiInfo.hbmMask); try { BitmapData lbdData = lbmpBitmap.LockBits( new Rectangle(0, 0, lbmpBitmap.Width, lbmpBitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format1bppIndexed); try { // Calculate number of lines in AND scan before any found int liLine = ScanBits(lbdData.Scan0, 0, lbdData.Stride, cursor.Size.Height, false, true); // If no AND scan bits found then scan for XOR bits if (liLine == -1 &amp;&amp; lbdData.Height == cursor.Size.Height * 2) liLine = ScanBits(lbdData.Scan0, cursor.Size.Height, lbdData.Stride, cursor.Size.Height, true, true); return cursor.Size.Height-liLine; } finally { lbmpBitmap.UnlockBits(lbdData); } } finally { DeleteObject(liiInfo.hbmMask); DeleteObject(liiInfo.hbmColor); lbmpBitmap.Dispose(); } } #endregion } } </code></pre> <p>You can undefine the conditional define "useUnsafe" at the top so you dont have to enable unsafe code if you like, but be warned it will run slower in this mode.</p> <p>So this uses extension methods, so all you have to do is add Cursor.Current.GetBaseLineHeight() to your Cursor.Position.Y and that will be the first blank line under the cursor.</p> <p>ie. </p> <pre><code>Point lptBlankLineUnderCursor = new Point(Cursor.Position.X, Cursor.Position.Y + Cursor.Current.GetBaseLineHeight()) </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload