C# 全屏坐标及区域坐标获取。自定义光标及系统光标描边捕捉显示。

   最近手头工作比较轻松了一点就继续研究和完善之前的录屏软件,使用AForge最大的问题在于:最原始的只能够录全屏,而自定义的录屏需要更改非常多的细节:like follows:

1、需要支持区域化录屏;

2、需要支持麦克风录音,并且混音在视频中,同步;

3、需要支持系统声音录取、并且需要混音在视频中,同步;

4、需要支持捕获光标,并且自定义颜色、描边,最重要的是你需要在区域录屏的时候支持坐标位置更新(相对比较难);

   前面3个已经在前面的文章介绍了,这里不再赘述。着重列出第4点的内容以及如何解决。如果正在研究录屏这块的朋友们,千万别去copy那什么网上有限制时间录制和收费的录制,特别是有些很恶心的还发表长篇大论写的如何如何实现(的确技术不可否认是实现了),其实最后还是要你付费才能完全使用,就问你恶不恶心!

   好了,废话不多说,我们来一一解决;

首先获取系统光标有两种方式,第一种是直接通过系统API进行获取光标,这个是完全记录系统光标在做什么。随着系统光标变化而变化的。这边有用到的是几个类:

第一种方式:【CursorHelper.cs】、【GDIStuff.cs】、【Win32Stuff.cs】相对复杂一些;我就在代码中直接显示就好了,不需要引用任何其他的东西;

    /// <summary>
    ///     The rt global cursor.
    /// </summary>
    public class CursorHelper
    {
        #region Constants

        /// <summary>
        ///     The curso r_ showing.
        /// </summary>
        private const int CURSOR_SHOWING = 1;

        #endregion

        #region Public Methods and Operators

        /// <summary>
        /// The capture cursor.
        /// </summary>
        /// <param name="x">
        /// The x.
        /// </param>
        /// <param name="y">
        /// The y.
        /// </param>
        /// <returns>
        /// The <see cref="Bitmap"/>.
        /// </returns>
        public static Bitmap CaptureCursor(ref int x, ref int y)
        {
            Win32Stuff.CURSORINFO cursorInfo = new Win32Stuff.CURSORINFO();
            cursorInfo.cbSize = Marshal.SizeOf(cursorInfo);
            if (!Win32Stuff.GetCursorInfo(out cursorInfo))
            {
                return null;
            }

            if (cursorInfo.flags != Win32Stuff.CURSOR_SHOWING)
            {
                return null;
            }

            IntPtr hicon = Win32Stuff.CopyIcon(cursorInfo.hCursor);
            if (hicon == IntPtr.Zero)
            {
                return null;
            }

            Win32Stuff.ICONINFO iconInfo;
            if (!Win32Stuff.GetIconInfo(hicon, out iconInfo))
            {
                return null;
            }

            x = cursorInfo.ptScreenPos.x - ((int)iconInfo.xHotspot);
            y = cursorInfo.ptScreenPos.y - ((int)iconInfo.yHotspot);

            using (Bitmap maskBitmap = Bitmap.FromHbitmap(iconInfo.hbmMask))
            {
                // Is this a monochrome cursor?
                if (maskBitmap.Height == maskBitmap.Width * 2)
                {
                    Bitmap resultBitmap = new Bitmap(maskBitmap.Width, maskBitmap.Width);

                    using (Graphics desktopGraphics = Graphics.FromHwnd(Win32Stuff.GetDesktopWindow()))
                    {
                        IntPtr desktopHdc = desktopGraphics.GetHdc();

                        IntPtr maskHdc = GDIStuff.CreateCompatibleDC(desktopHdc);
                        IntPtr oldPtr = GDIStuff.SelectObject(maskHdc, maskBitmap.GetHbitmap());

                        using (Graphics resultGraphics = Graphics.FromImage(resultBitmap))
                        {
                            IntPtr resultHdc = resultGraphics.GetHdc();

                            // These two operation will result in a black cursor over a white background.
                            // Later in the code, a call to MakeTransparent() will get rid of the white background.
                            GDIStuff.BitBlt(
                                resultHdc,
                                0,
                                0,
                                32,
                                32,
                                maskHdc,
                                0,
                                32,
                                (int)GDIStuff.TernaryRasterOperations.SRCCOPY);
                            GDIStuff.BitBlt(
                                resultHdc,
                                0,
                                0,
                                32,
                                32,
                                maskHdc,
                                0,
                                0,
                                (int)GDIStuff.TernaryRasterOperations.SRCINVERT);

                            resultGraphics.ReleaseHdc(resultHdc);
                            GDIStuff.DeleteDC(resultHdc);
                            GDIStuff.DeleteObject(resultHdc);
                        }

                        IntPtr newPtr = GDIStuff.SelectObject(maskHdc, oldPtr);
                        GDIStuff.DeleteObject(oldPtr);
                        GDIStuff.DeleteObject(newPtr);
                        GDIStuff.DeleteDC(maskHdc);
                        desktopGraphics.ReleaseHdc(desktopHdc);
                        GDIStuff.DeleteDC(desktopHdc);
                    }
                    
                    // Remove the white background from the BitBlt calls,
                    // resulting in a black cursor over a transparent background.
                    resultBitmap.MakeTransparent(Color.White);
                    return resultBitmap;
                }
            }

            //// Delete the mask, if present.
            // if (iconInfo.hbmMask != IntPtr.Zero)
            // {
            // DeleteObject(iconInfo.hbmMask);
            // }

            //// Delete the color bitmap, if present.
            // if (iconInfo.hbmColor != IntPtr.Zero)
            // {
            // DeleteObject(iconInfo.hbmColor);
            // }
            using (Icon icon = Icon.FromHandle(hicon))
            {
                return icon.ToBitmap();
            }
        }

        #endregion

        #region Methods

        /// <summary>
        /// The copy icon.
        /// </summary>
        /// <param name="hIcon">
        /// The h icon.
        /// </param>
        /// <returns>
        /// The <see cref="IntPtr"/>.
        /// </returns>
        [DllImport("user32.dll")]
        private static extern IntPtr CopyIcon(IntPtr hIcon);

        /// <summary>
        /// The delete object.
        /// </summary>
        /// <param name="hDc">
        /// The h dc.
        /// </param>
        /// <returns>
        /// The <see cref="IntPtr"/>.
        /// </returns>
        [DllImport("gdi32.dll")]
        private static extern IntPtr DeleteObject(IntPtr hDc);

        /// <summary>
        /// The destroy icon.
        /// </summary>
        /// <param name="hIcon">
        /// The h icon.
        /// </param>
        /// <returns>
        /// The <see cref="bool"/>.
        /// </returns>
        [DllImport("user32.dll")]
        private static extern bool DestroyIcon(IntPtr hIcon);

        /// <summary>
        /// The get cursor info.
        /// </summary>
        /// <param name="pci">
        /// The pci.
        /// </param>
        /// <returns>
        /// The <see cref="bool"/>.
        /// </returns>
        [DllImport("user32.dll")]
        private static extern bool GetCursorInfo(out CURSORINFO pci);

        /// <summary>
        ///     The get gdi handle count.
        /// </summary>
        /// <returns>
        ///     The <see cref="int" />.
        /// </returns>
        private static int GetGDIHandleCount()
        {
            return GetGuiResources(Process.GetCurrentProcess().Handle, 0);
        }

        /// <summary>
        /// The get gui resources.
        /// </summary>
        /// <param name="hProcess">
        /// The h process.
        /// </param>
        /// <param name="uiFlags">
        /// The ui flags.
        /// </param>
        /// <returns>
        /// The <see cref="int"/>.
        /// </returns>
        [DllImport("user32.dll")]
        private static extern int GetGuiResources(IntPtr hProcess, int uiFlags);

        /// <summary>
        /// The get icon info.
        /// </summary>
        /// <param name="hIcon">
        /// The h icon.
        /// </param>
        /// <param name="piconinfo">
        /// The piconinfo.
        /// </param>
        /// <returns>
        /// The <see cref="bool"/>.
        /// </returns>
        [DllImport("user32.dll")]
        private static extern bool GetIconInfo(IntPtr hIcon, out ICONINFO piconinfo);

        /// <summary>
        ///     The get user handle count.
        /// </summary>
        /// <returns>
        ///     The <see cref="int" />.
        /// </returns>
        private static int GetUserHandleCount()
        {
            return GetGuiResources(Process.GetCurrentProcess().Handle, 1);
        }

        /// <summary>
        /// The handle message.
        /// </summary>
        /// <param name="message">
        /// The message.
        /// </param>
        private static void HandleMessage(string message)
        {
            Debug.WriteLine("HC: " + message + ": GDI: " + GetGDIHandleCount() + ": User: " + GetUserHandleCount());
        }

        #endregion

        /// <summary>
        ///     The cursorinfo.
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        private struct CURSORINFO
        {
            // Fields
            /// <summary>
            ///     The cb size.
            /// </summary>
            [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation", Justification = "Reviewed. Suppression is OK here."),
            SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:AccessibleFieldsMustBeginWithUpperCaseLetter", Justification = "Reviewed. Suppression is OK here.")]
            public int cbSize;

            /// <summary>
            ///     The flags.
            /// </summary>
            [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation", Justification = "Reviewed. Suppression is OK here."),
            SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:AccessibleFieldsMustBeginWithUpperCaseLetter", Justification = "Reviewed. Suppression is OK here.")]
            public int flags;

            /// <summary>
            ///     The h cursor.
            /// </summary>
            [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation", Justification = "Reviewed. Suppression is OK here."),
            SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:AccessibleFieldsMustBeginWithUpperCaseLetter", Justification = "Reviewed. Suppression is OK here.")]
            public IntPtr hCursor;

            /// <summary>
            ///     The pt screen pos.
            /// </summary>
            [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation", Justification = "Reviewed. Suppression is OK here."),
            SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:AccessibleFieldsMustBeginWithUpperCaseLetter", Justification = "Reviewed. Suppression is OK here.")]
            public POINT ptScreenPos;
        }

        /// <summary>
        ///     The iconinfo.
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        private struct ICONINFO
        {
            // Fields
            /// <summary>
            ///     The f icon.
            /// </summary>
            public bool fIcon;

            /// <summary>
            ///     The x hotspot.
            /// </summary>
            public int xHotspot;

            /// <summary>
            ///     The y hotspot.
            /// </summary>
            public int yHotspot;

            // Handle of the icon’s bitmask bitmap.
            /// <summary>
            ///     The hbm mask.
            /// </summary>
            public IntPtr hbmMask;

            // Handle of the icon’s color bitmap. Optional for monochrome icons.
            /// <summary>
            ///     The hbm color.
            /// </summary>
            public IntPtr hbmColor;
        }

        /// <summary>
        ///     The point.
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        private struct POINT
        {
            // Fields
            /// <summary>
            ///     The x.
            /// </summary>
            public int x;

            /// <summary>
            ///     The y.
            /// </summary>
            public int y;
        }

        ///// <summary>
        ///// The capture cursor.
        ///// </summary>
        ///// <param name="x">
        ///// The x.
        ///// </param>
        ///// <param name="y">
        ///// The y.
        ///// </param>
        ///// <returns>
        ///// The <see cref="Bitmap"/>.
        ///// </returns>
        // public static Bitmap CaptureCursor(ref int x, ref int y)
        // {
        // try
        // {
        // // Return value initially nothing
        // Bitmap bmp = null;

        // CURSORINFO curInfo = new CURSORINFO();
        // curInfo.cbSize = Marshal.SizeOf(curInfo);

        // // HandleMessage("Start")
        // if (GetCursorInfo(ref curInfo))
        // {
        // if (curInfo.flags == CURSOR_SHOWING)
        // {
        // IntPtr hicon = CopyIcon(curInfo.hCursor);

        // if (hicon != IntPtr.Zero)
        // {
        // ICONINFO icoInfo = default(ICONINFO);
        // if (GetIconInfo(hicon, ref icoInfo))
        // {
        // // Delete the mask, if present.
        // if (icoInfo.hbmMask != IntPtr.Zero)
        // {
        // DeleteObject(icoInfo.hbmMask);
        // }

        // // Delete the color bitmap, if present.
        // if (icoInfo.hbmColor != IntPtr.Zero)
        // {
        // DeleteObject(icoInfo.hbmColor);
        // }

        // x = curInfo.ptScreenPos.x - icoInfo.xHotspot;
        // y = curInfo.ptScreenPos.y - icoInfo.yHotspot;
        // }

        // Icon ic = Icon.FromHandle(hicon);
        // bmp = ic.ToBitmap();

        // // Must destroy the icon object we got from CopyIcon
        // DestroyIcon(hicon);
        // }
        // }
        // }

        // // HandleMessage("End")
        // return bmp;
        // }
        // catch
        // {
        // return null;
        // }
        // }
    }
CursorHelper.cs
    /// <summary>
    ///     The gdi stuff.
    /// </summary>
    internal class GDIStuff
    {
        #region Constants

        /// <summary>
        ///     The srccopy.
        /// </summary>
        public const int SRCCOPY = 13369376;

        #endregion

        #region Enums

        /// <summary>
        ///     Specifies a raster-operation code. These codes define how the color data for the
        ///     source rectangle is to be combined with the color data for the destination
        ///     rectangle to achieve the final color.
        /// </summary>
        public enum TernaryRasterOperations
        {
            /// <summary>dest = source</summary>
            SRCCOPY = 0x00CC0020, 

            /// <summary>dest = source OR dest</summary>
            SRCPAINT = 0x00EE0086, 

            /// <summary>dest = source AND dest</summary>
            SRCAND = 0x008800C6, 

            /// <summary>dest = source XOR dest</summary>
            SRCINVERT = 0x00660046, 

            /// <summary>dest = source AND (NOT dest)</summary>
            SRCERASE = 0x00440328, 

            /// <summary>dest = (NOT source)</summary>
            NOTSRCCOPY = 0x00330008, 

            /// <summary>dest = (NOT src) AND (NOT dest)</summary>
            NOTSRCERASE = 0x001100A6, 

            /// <summary>dest = (source AND pattern)</summary>
            MERGECOPY = 0x00C000CA, 

            /// <summary>dest = (NOT source) OR dest</summary>
            MERGEPAINT = 0x00BB0226, 

            /// <summary>dest = pattern</summary>
            PATCOPY = 0x00F00021, 

            /// <summary>dest = DPSnoo</summary>
            PATPAINT = 0x00FB0A09, 

            /// <summary>dest = pattern XOR dest</summary>
            PATINVERT = 0x005A0049, 

            /// <summary>dest = (NOT dest)</summary>
            DSTINVERT = 0x00550009, 

            /// <summary>dest = BLACK</summary>
            BLACKNESS = 0x00000042, 

            /// <summary>dest = WHITE</summary>
            WHITENESS = 0x00FF0062, 

            /// <summary>
            ///     Capture window as seen on screen.  This includes layered windows
            ///     such as WPF windows with AllowsTransparency="true"
            /// </summary>
            CAPTUREBLT = 0x40000000
        }

        #endregion

        #region Public Methods and Operators

        /// <summary>
        /// The bit blt.
        /// </summary>
        /// <param name="hdcDest">
        /// The hdc dest.
        /// </param>
        /// <param name="xDest">
        /// The x dest.
        /// </param>
        /// <param name="yDest">
        /// The y dest.
        /// </param>
        /// <param name="wDest">
        /// The w dest.
        /// </param>
        /// <param name="hDest">
        /// The h dest.
        /// </param>
        /// <param name="hdcSource">
        /// The hdc source.
        /// </param>
        /// <param name="xSrc">
        /// The x src.
        /// </param>
        /// <param name="ySrc">
        /// The y src.
        /// </param>
        /// <param name="RasterOp">
        /// The raster op.
        /// </param>
        /// <returns>
        /// The <see cref="bool"/>.
        /// </returns>
        [DllImport("gdi32.dll", EntryPoint = "BitBlt")]
        [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation", Justification = "Reviewed. Suppression is OK here.")]
        [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1306:FieldNamesMustBeginWithLowerCaseLetter", Justification = "Reviewed. Suppression is OK here.")]
        public static extern bool BitBlt(
            IntPtr hdcDest, 
            int xDest, 
            int yDest, 
            int wDest, 
            int hDest, 
            IntPtr hdcSource, 
            int xSrc, 
            int ySrc, 
            int RasterOp);

        /// <summary>
        /// The create compatible bitmap.
        /// </summary>
        /// <param name="hdc">
        /// The hdc.
        /// </param>
        /// <param name="nWidth">
        /// The n width.
        /// </param>
        /// <param name="nHeight">
        /// The n height.
        /// </param>
        /// <returns>
        /// The <see cref="IntPtr"/>.
        /// </returns>
        [DllImport("gdi32.dll", EntryPoint = "CreateCompatibleBitmap")]
        [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1305:FieldNamesMustNotUseHungarianNotation", Justification = "Reviewed. Suppression is OK here.")]
        public static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int nWidth, int nHeight);

        /// <summary>
        /// The create compatible dc.
        /// </summary>
        /// <param name="hdc">
        /// The hdc.
        /// </param>
        /// <returns>
        /// The <see cref="IntPtr"/>.
        /// </returns>
        [DllImport("gdi32.dll", EntryPoint = "CreateCompatibleDC")]
        public static extern IntPtr CreateCompatibleDC(IntPtr hdc);

        /// <summary>
        /// The create dc.
        /// </summary>
        /// <param name="lpszDriver">
        /// The lpsz driver.
        /// </param>
        /// <param name="lpszDevice">
        /// The lpsz device.
        /// </param>
        /// <param name="lpszOutput">
        /// The lpsz output.
        /// </param>
        /// <param name="lpInitData">
        /// The lp init data.
        /// </param>
        /// <returns>
        /// The <see cref="IntPtr"/>.
        /// </returns>
        [DllImport("gdi32.dll", EntryPoint = "CreateDC")]
        public static extern IntPtr CreateDC(IntPtr lpszDriver, string lpszDevice, IntPtr lpszOutput, IntPtr lpInitData);

        /// <summary>
        /// The delete dc.
        /// </summary>
        /// <param name="hDc">
        /// The h dc.
        /// </param>
        /// <returns>
        /// The <see cref="IntPtr"/>.
        /// </returns>
        [DllImport("gdi32.dll", EntryPoint = "DeleteDC")]
        public static extern IntPtr DeleteDC(IntPtr hDc);

        /// <summary>
        /// The delete object.
        /// </summary>
        /// <param name="hDc">
        /// The h dc.
        /// </param>
        /// <returns>
        /// The <see cref="IntPtr"/>.
        /// </returns>
        [DllImport("gdi32.dll", EntryPoint = "DeleteObject")]
        public static extern IntPtr DeleteObject(IntPtr hDc);

        /// <summary>
        /// The select object.
        /// </summary>
        /// <param name="hdc">
        /// The hdc.
        /// </param>
        /// <param name="bmp">
        /// The bmp.
        /// </param>
        /// <returns>
        /// The <see cref="IntPtr"/>.
        /// </returns>
        [DllImport("gdi32.dll", EntryPoint = "SelectObject")]
        public static extern IntPtr SelectObject(IntPtr hdc, IntPtr bmp);

        #endregion
    }
GDIStuff.cs
 /// <summary>
    ///     The win 32 stuff.
    /// </summary>
    internal class Win32Stuff
    {
        #region Constants

        /// <summary>
        ///     The curso r_ showing.
        /// </summary>
        public const int CURSOR_SHOWING = 0x00000001;

        /// <summary>
        ///     The s m_ cxscreen.
        /// </summary>
        public const int SM_CXSCREEN = 0;

        /// <summary>
        ///     The s m_ cyscreen.
        /// </summary>
        public const int SM_CYSCREEN = 1;

        #endregion

        #region Public Methods and Operators

        /// <summary>
        /// The copy icon.
        /// </summary>
        /// <param name="hIcon">
        /// The h icon.
        /// </param>
        /// <returns>
        /// The <see cref="IntPtr"/>.
        /// </returns>
        [DllImport("user32.dll", EntryPoint = "CopyIcon")]
        public static extern IntPtr CopyIcon(IntPtr hIcon);

        /// <summary>
        /// The get cursor info.
        /// </summary>
        /// <param name="pci">
        /// The pci.
        /// </param>
        /// <returns>
        /// The <see cref="bool"/>.
        /// </returns>
        [DllImport("user32.dll", EntryPoint = "GetCursorInfo")]
        public static extern bool GetCursorInfo(out CURSORINFO pci);

        /// <summary>
        /// The get dc.
        /// </summary>
        /// <param name="ptr">
        /// The ptr.
        /// </param>
        /// <returns>
        /// The <see cref="IntPtr"/>.
        /// </returns>
        [DllImport("user32.dll", EntryPoint = "GetDC")]
        public static extern IntPtr GetDC(IntPtr ptr);

        /// <summary>
        ///     The get desktop window.
        /// </summary>
        /// <returns>
        ///     The <see cref="IntPtr" />.
        /// </returns>
        [DllImport("user32.dll", EntryPoint = "GetDesktopWindow")]
        public static extern IntPtr GetDesktopWindow();

        /// <summary>
        /// The get icon info.
        /// </summary>
        /// <param name="hIcon">
        /// The h icon.
        /// </param>
        /// <param name="piconinfo">
        /// The piconinfo.
        /// </param>
        /// <returns>
        /// The <see cref="bool"/>.
        /// </returns>
        [DllImport("user32.dll", EntryPoint = "GetIconInfo")]
        public static extern bool GetIconInfo(IntPtr hIcon, out ICONINFO piconinfo);

        /// <summary>
        /// The get system metrics.
        /// </summary>
        /// <param name="abc">
        /// The abc.
        /// </param>
        /// <returns>
        /// The <see cref="int"/>.
        /// </returns>
        [DllImport("user32.dll", EntryPoint = "GetSystemMetrics")]
        public static extern int GetSystemMetrics(int abc);

        /// <summary>
        /// The get window dc.
        /// </summary>
        /// <param name="ptr">
        /// The ptr.
        /// </param>
        /// <returns>
        /// The <see cref="IntPtr"/>.
        /// </returns>
        [DllImport("user32.dll", EntryPoint = "GetWindowDC")]
        public static extern IntPtr GetWindowDC(int ptr);

        /// <summary>
        /// The release dc.
        /// </summary>
        /// <param name="hWnd">
        /// The h wnd.
        /// </param>
        /// <param name="hDc">
        /// The h dc.
        /// </param>
        /// <returns>
        /// The <see cref="IntPtr"/>.
        /// </returns>
        [DllImport("user32.dll", EntryPoint = "ReleaseDC")]
        public static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDc);

        #endregion

        /// <summary>
        ///     The cursorinfo.
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct CURSORINFO
        {
            /// <summary>
            ///     The cb size.
            /// </summary>
            public int cbSize; // Specifies the size, in bytes, of the structure. 

            /// <summary>
            ///     The flags.
            /// </summary>
            public int flags; // Specifies the cursor state. This parameter can be one of the following values:

            /// <summary>
            ///     The h cursor.
            /// </summary>
            public IntPtr hCursor; // Handle to the cursor. 

            /// <summary>
            ///     The pt screen pos.
            /// </summary>
            public POINT ptScreenPos; // A POINT structure that receives the screen coordinates of the cursor. 
        }

        /// <summary>
        ///     The iconinfo.
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct ICONINFO
        {
            /// <summary>
            ///     The f icon.
            /// </summary>
            public bool fIcon;

            // Specifies whether this structure defines an icon or a cursor. A value of TRUE specifies 

            /// <summary>
            ///     The x hotspot.
            /// </summary>
            public int xHotspot;

            // Specifies the x-coordinate of a cursor's hot spot. If this structure defines an icon, the hot 

            /// <summary>
            ///     The y hotspot.
            /// </summary>
            public int yHotspot;

            // Specifies the y-coordinate of the cursor's hot spot. If this structure defines an icon, the hot 

            /// <summary>
            ///     The hbm mask.
            /// </summary>
            public IntPtr hbmMask;

            // (HBITMAP) Specifies the icon bitmask bitmap. If this structure defines a black and white icon, 

            /// <summary>
            ///     The hbm color.
            /// </summary>
            public IntPtr hbmColor; // (HBITMAP) Handle to the icon color bitmap. This member can be optional if this 
        }

        /// <summary>
        ///     The point.
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct POINT
        {
            /// <summary>
            ///     The x.
            /// </summary>
            public int x;

            /// <summary>
            ///     The y.
            /// </summary>
            public int y;
        }
    }
Win32Stuff.cs

OK,类已经铺垫好了,接下来就在你的视频捕获方法中放入:关键方法--CursorHelper.CaptureCursor(ref x,ref y);

 1                                        Graphics g = Graphics.FromImage(bitmap);//编辑原始视频帧
 2                                        g.SmoothingMode = SmoothingMode.AntiAlias;//设置鼠标质量
 3                                        g.InterpolationMode = InterpolationMode.HighQualityBicubic;
 4                                        g.PixelOffsetMode = PixelOffsetMode.HighQuality;
 5                                        var x = _currentPoint.X;
 6                                        var y = _currentPoint.Y;
 7                                        var cursorBmp = CursorHelper.CaptureCursor(ref x, ref y);
 8                                        if (cursorBmp != null)
 9                                        {
10                                            g.DrawImage(cursorBmp, _currentPoint);
11                                        }
12                                        cursorBmp.Dispose();

**注释说明:其中_currentPoint 是相对于屏幕的坐标Point** 获取方法是--

 _currentPoint = System.Windows.Forms.Cursor.Position;//(大屏坐标)

**注释说明:其中bitmap是当前获取的最原始的视频帧(不包含任何的例如光标-声音-什么锤子之类的哈哈哈)**,此类方法就是把原始视频帧重新编辑!

第二种方式:相对简单一点,获取光标_currentPoint还是使用上面的方法,但是不同的地方是我要自定义光标icon,这个又有一点难点就是如何画怎么画;---项目中采用的是外圈描边,内边填充方式;

 1  SolidBrush myBrush = new SolidBrush(System.Drawing.Color.FromArgb(50, ColorTranslator.FromHtml("#你的填充颜色")));//设置透明度跟填充颜色
 2                                        System.Drawing.Pen p = new System.Drawing.Pen(ColorTranslator.FromHtml("#你的描边颜色"));//设置透明度跟描边颜色
 3                                        Graphics g = Graphics.FromImage(bitmap);//编辑原始视频帧
 4                                        g.SmoothingMode = SmoothingMode.AntiAlias;//设置鼠标质量
 5                                        g.InterpolationMode = InterpolationMode.HighQualityBicubic;
 6                                        g.PixelOffsetMode = PixelOffsetMode.HighQuality;
 7                                        g.DrawEllipse(p, new Rectangle(_currentPoint.X - this.screenArea.Left, _currentPoint.Y - this.screenArea.Top, 25, 25));//描边
 8                                        g.FillEllipse(myBrush, new Rectangle(_currentPoint.X - this.screenArea.Left, _currentPoint.Y - this.screenArea.Top, 25, 25));//填充圆形区域
 9                                        myBrush.Dispose();
10                                        p.Dispose();
11                                        g.Flush();

**注释:在上述这种方式中特别注意,原始的方法比如你是全屏录制则采用以下方式即可,还有自定义笔刷的画法,我想做完给大家分享。**

1                                        g.DrawEllipse(p, new Rectangle(_currentPoint.X , _currentPoint.Y, 25, 25));//描边
2                                        g.FillEllipse(myBrush, new Rectangle(_currentPoint.X , _currentPoint.Y, 25, 25));//填充圆形区域

**注释:如果你的录屏方式也存在区域模式,那么就采用 当前光标位置X轴减去你录屏区域的左坐标,当前光标位置Y轴减去你录屏的顶坐标即可获取,这种方式自适应任何区域**

以上是个人在完善时候研究的成果,在此希望把它们分享给更多正在研究的伙伴们,因为研究的时候的确遇到了非常多的问题,我希望这些文章能够给你们一些方向研究,加快你们的开发进度。

原文地址:https://www.cnblogs.com/BarryJames/p/6950813.html