How to override maximum 32x32 mouse size in Windows like this program can

前端 未结 4 1745
猫巷女王i
猫巷女王i 2020-12-08 16:37

I\'d like for my program to be able to override the maximum imposed mouse size of 32x32 much like the program in the picture attached does, the cursor pictured is 72x72. Thi

相关标签:
4条回答
  • 2020-12-08 16:46

    If you are working with WPF, you can create your own Mouse cursor and assign it. But this is not a system wide mouse cursor change. Here's some code that would do the trick. In the code below I am creating a cursor 50x50 pixels. You can draw your own shape on to the RenderTargetBitmap

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
    
            Mouse.OverrideCursor = CreateCursor(50,50, Brushes.Gold, null);
        }
    
        Cursor CreateCursor(double rx, double ry, SolidColorBrush brush, Pen pen)
        {
            var vis = new DrawingVisual();
            using (var dc = vis.RenderOpen())
            {
                dc.DrawRectangle(brush, new Pen(Brushes.Black, 0.1), new Rect(0, 0, rx, ry));
                dc.Close();
            }
            var rtb = new RenderTargetBitmap(64, 64, 96, 96, PixelFormats.Pbgra32);
            rtb.Render(vis);
    
            using (var ms1 = new MemoryStream())
            {
                var penc = new PngBitmapEncoder();
                penc.Frames.Add(BitmapFrame.Create(rtb));
                penc.Save(ms1);
    
                var pngBytes = ms1.ToArray();
                var size = pngBytes.GetLength(0);
    
                //.cur format spec http://en.wikipedia.org/wiki/ICO_(file_format)
                using (var ms = new MemoryStream())
                {
                    {//ICONDIR Structure
                        ms.Write(BitConverter.GetBytes((Int16)0), 0, 2);//Reserved must be zero; 2 bytes
                        ms.Write(BitConverter.GetBytes((Int16)2), 0, 2);//image type 1 = ico 2 = cur; 2 bytes
                        ms.Write(BitConverter.GetBytes((Int16)1), 0, 2);//number of images; 2 bytes
                    }
    
                    {//ICONDIRENTRY structure
                        ms.WriteByte(32); //image width in pixels
                        ms.WriteByte(32); //image height in pixels
    
                        ms.WriteByte(0); //Number of Colors in the color palette. Should be 0 if the image doesn't use a color palette
                        ms.WriteByte(0); //reserved must be 0
    
                        ms.Write(BitConverter.GetBytes((Int16)(rx / 2.0)), 0, 2);//2 bytes. In CUR format: Specifies the horizontal coordinates of the hotspot in number of pixels from the left.
                        ms.Write(BitConverter.GetBytes((Int16)(ry / 2.0)), 0, 2);//2 bytes. In CUR format: Specifies the vertical coordinates of the hotspot in number of pixels from the top.
    
                        ms.Write(BitConverter.GetBytes(size), 0, 4);//Specifies the size of the image's data in bytes
                        ms.Write(BitConverter.GetBytes((Int32)22), 0, 4);//Specifies the offset of BMP or PNG data from the beginning of the ICO/CUR file
                    }
    
                    ms.Write(pngBytes, 0, size);//write the png data.
                    ms.Seek(0, SeekOrigin.Begin);
                    return new Cursor(ms);
                }
            }
        }
    
    }
    
    0 讨论(0)
  • 2020-12-08 16:53

    Using SetSystemCursor it is possible to set a cursor to an image of much larger size than the standard cursor.

    Here is a class I have for resizing the system cursors:

    using System;
    using System.Drawing;
    using System.Reflection;
    using System.Runtime.InteropServices;
    
    namespace WindowsFormsApplication1
    {
        class SystemCursors
        {
            [DllImport("user32.dll")]
            static extern bool SetSystemCursor(IntPtr hcur, uint id);
    
            enum CursorShift
            {
                Centered,
                LowerRight,
            }
    
            public static void SetSystemCursorsSize(int newSize)
            {
                ResizeCursor(System.Windows.Forms.Cursors.AppStarting, newSize, CursorShift.LowerRight);
                ResizeCursor(System.Windows.Forms.Cursors.Arrow, newSize, CursorShift.LowerRight);
                ResizeCursor(System.Windows.Forms.Cursors.Cross, newSize, CursorShift.Centered);
                ResizeCursor(System.Windows.Forms.Cursors.Hand, newSize, CursorShift.LowerRight);
                ResizeCursor(System.Windows.Forms.Cursors.Help, newSize, CursorShift.LowerRight);
                ResizeCursor(System.Windows.Forms.Cursors.HSplit, newSize, CursorShift.Centered);
                ResizeCursor(System.Windows.Forms.Cursors.IBeam, newSize, CursorShift.Centered);
                ResizeCursor(System.Windows.Forms.Cursors.No, newSize, CursorShift.LowerRight);
                ResizeCursor(System.Windows.Forms.Cursors.NoMove2D, newSize, CursorShift.LowerRight);
                ResizeCursor(System.Windows.Forms.Cursors.NoMoveHoriz, newSize, CursorShift.LowerRight);
                ResizeCursor(System.Windows.Forms.Cursors.NoMoveVert, newSize, CursorShift.LowerRight);
                ResizeCursor(System.Windows.Forms.Cursors.PanEast, newSize, CursorShift.Centered);
                ResizeCursor(System.Windows.Forms.Cursors.PanNE, newSize, CursorShift.Centered);
                ResizeCursor(System.Windows.Forms.Cursors.PanNorth, newSize, CursorShift.Centered);
                ResizeCursor(System.Windows.Forms.Cursors.PanNW, newSize, CursorShift.Centered);
                ResizeCursor(System.Windows.Forms.Cursors.PanSE, newSize, CursorShift.Centered);
                ResizeCursor(System.Windows.Forms.Cursors.PanSouth, newSize, CursorShift.Centered);
                ResizeCursor(System.Windows.Forms.Cursors.PanSW, newSize, CursorShift.Centered);
                ResizeCursor(System.Windows.Forms.Cursors.PanWest, newSize, CursorShift.Centered);
                ResizeCursor(System.Windows.Forms.Cursors.SizeAll, newSize, CursorShift.Centered);
                ResizeCursor(System.Windows.Forms.Cursors.SizeNESW, newSize, CursorShift.Centered);
                ResizeCursor(System.Windows.Forms.Cursors.SizeNS, newSize, CursorShift.Centered);
                ResizeCursor(System.Windows.Forms.Cursors.SizeNWSE, newSize, CursorShift.Centered);
                ResizeCursor(System.Windows.Forms.Cursors.SizeWE, newSize, CursorShift.Centered);
                ResizeCursor(System.Windows.Forms.Cursors.UpArrow, newSize, CursorShift.Centered);
                ResizeCursor(System.Windows.Forms.Cursors.VSplit, newSize, CursorShift.Centered);
                ResizeCursor(System.Windows.Forms.Cursors.WaitCursor, newSize, CursorShift.LowerRight);
            }
    
            private static void ResizeCursor(System.Windows.Forms.Cursor cursor, 
                int newSize, CursorShift cursorShift)
            {
                Bitmap cursorImage = GetSystemCursorBitmap(cursor);
                cursorImage = ResizeCursorBitmap(cursorImage, new Size(newSize, newSize), cursorShift);
                SetCursor(cursorImage, getResourceId(cursor));
            }
    
            public static Bitmap GetSystemCursorBitmap(System.Windows.Forms.Cursor cursor)
            {
                Bitmap bitmap = new Bitmap(
                    cursor.Size.Width, cursor.Size.Height,
                    System.Drawing.Imaging.PixelFormat.Format32bppArgb);
    
                Graphics graphics = Graphics.FromImage(bitmap);
    
                cursor.Draw(graphics,
                    new Rectangle(new Point(0, 0), cursor.Size));
    
                bitmap = Crop(bitmap);
    
                return bitmap;
            }
    
            private static Bitmap Crop(Bitmap bmp)
            {
                //code from http://stackoverflow.com/a/10392379/935052
    
                int w = bmp.Width;
                int h = bmp.Height;
    
                Func<int, bool> allWhiteRow = row =>
                {
                    for (int i = 0; i < w; ++i)
                        if (bmp.GetPixel(i, row).A != 0)
                            return false;
                    return true;
                };
    
                Func<int, bool> allWhiteColumn = col =>
                {
                    for (int i = 0; i < h; ++i)
                        if (bmp.GetPixel(col, i).A != 0)
                            return false;
                    return true;
                };
    
                int topmost = 0;
                for (int row = 0; row < h; ++row)
                {
                    if (allWhiteRow(row))
                        topmost = row;
                    else break;
                }
    
                int bottommost = 0;
                for (int row = h - 1; row >= 0; --row)
                {
                    if (allWhiteRow(row))
                        bottommost = row;
                    else break;
                }
    
                int leftmost = 0, rightmost = 0;
                for (int col = 0; col < w; ++col)
                {
                    if (allWhiteColumn(col))
                        leftmost = col;
                    else
                        break;
                }
    
                for (int col = w - 1; col >= 0; --col)
                {
                    if (allWhiteColumn(col))
                        rightmost = col;
                    else
                        break;
                }
    
                if (rightmost == 0) rightmost = w; // As reached left
                if (bottommost == 0) bottommost = h; // As reached top.
    
                int croppedWidth = rightmost - leftmost;
                int croppedHeight = bottommost - topmost;
    
                if (croppedWidth == 0) // No border on left or right
                {
                    leftmost = 0;
                    croppedWidth = w;
                }
    
                if (croppedHeight == 0) // No border on top or bottom
                {
                    topmost = 0;
                    croppedHeight = h;
                }
    
                try
                {
                    var target = new Bitmap(croppedWidth, croppedHeight);
                    using (Graphics g = Graphics.FromImage(target))
                    {
                        g.DrawImage(bmp,
                          new RectangleF(0, 0, croppedWidth, croppedHeight),
                          new RectangleF(leftmost, topmost, croppedWidth, croppedHeight),
                          GraphicsUnit.Pixel);
                    }
                    return target;
                }
                catch (Exception ex)
                {
                    throw new Exception(
                      string.Format("Values are topmost={0} btm={1} left={2} right={3} croppedWidth={4} croppedHeight={5}", topmost, bottommost, leftmost, rightmost, croppedWidth, croppedHeight),
                      ex);
                }
            }
    
            private static Bitmap ResizeCursorBitmap(Bitmap bitmap, Size size, CursorShift cursorShift)
            {
                if (size.Width > 32)
                {
                    //shifting must occur
                    Bitmap intermediateBitmap = new Bitmap(64, 64);
                    Graphics intermediateGraphics = Graphics.FromImage(intermediateBitmap);
                    if (cursorShift == CursorShift.LowerRight)
                        //place the mouse cursor in the lower right hand quadrant of the bitmap
                        intermediateGraphics.DrawImage(bitmap,
                            intermediateBitmap.Width / 2, intermediateBitmap.Height / 2);
                    else if (cursorShift == CursorShift.Centered)
                        intermediateGraphics.DrawImage(bitmap,
                            intermediateBitmap.Width / 2 - bitmap.Width / 2,
                            intermediateBitmap.Height / 2 - bitmap.Height / 2);
    
                    //now we have a shifted bitmap; use it to draw the resized cursor
                    //Bitmap finalBitmap = new Bitmap(intermediateBitmap, size);    //normal quality
                    Bitmap finalBitmap = new Bitmap(size.Width, size.Height);
                    Graphics finalGraphics = Graphics.FromImage(finalBitmap);
                    finalGraphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
                    finalGraphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                    finalGraphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                    finalGraphics.DrawImage(intermediateBitmap, 0, 0, finalBitmap.Width, finalBitmap.Height);
                    return finalBitmap;
                }
                else
                {
                    Bitmap newBitmap = new Bitmap(bitmap, size);
                    return newBitmap;
                }
            }
    
            private static uint getResourceId(System.Windows.Forms.Cursor cursor)
            {
                FieldInfo fi = typeof(System.Windows.Forms.Cursor).GetField(
                    "resourceId", BindingFlags.NonPublic | BindingFlags.Instance);
                object obj = fi.GetValue(cursor);
                return Convert.ToUInt32((int)obj);
            }
    
            private static void SetCursor(Bitmap bitmap, uint whichCursor)
            {
                IntPtr ptr = bitmap.GetHicon();
                bool retval = SetSystemCursor(ptr, whichCursor);
            }
    
        }
    }
    

    It works by getting the current system cursor as provided in System.Windows.Forms.Cursors and making an image from it with Cursor.Draw. The image is then resized to the desired size. This requires shifting the cursor image, either to the lower right hand corner (like for arrow pointers) or centering the cursor image inside the larger image (like for Cross and IBeam).

    You can use your own image for the cursor if desired, bypassing all the resizing code. Just supply the Bitmap to SetCursor.

    Once the new cursor image is ready, the last piece of data needed is the ID of the cursor we are trying to replace. Each System.Windows.Forms.Cursor does contain this information, but in a private variable, so reflection is used to get the value. If you prefer to avoid reflection, you could build a table of these values instead. See MSDN SetSystemCursor for a list of values.

    To use the class just call

    SystemCursors.SetSystemCursorsSize(128);
    
    0 讨论(0)
  • 2020-12-08 17:00

    Add these imports to your class:

    [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    static extern IntPtr LoadImage(IntPtr hinst, string lpszName, uint uType, int cxDesired, int cyDesired, uint fuLoad);
    
    [DllImport("user32.dll")]
    static extern bool SetSystemCursor(IntPtr hcur, uint id);
    

    read msdn articles about LoadImage and SetSystemCursor, especially about parameters they use.

    Then use functions in your code:

    // "cursor.cur" - cursor image of any size you want
    // 2 == IMAGE_CURSOR (from Winuser.h)
    // cxDesired = 0 and cyDesired = 0, using original image size
    // 0x8010 == LR_DEFAULTCOLOR | LR_SHARED | LR_LOADFROMFILE (from Winuser.h)
    var ptr = LoadImage(IntPtr.Zero, "cursor.cur", 2, 0, 0, 0x8010);
    if(ptr != IntPtr.Zero)
    {
        SetSystemCursor(ptr, 32512); // 32512 == OCR_NORMAL (from Winuser.h)
    }
    
    0 讨论(0)
  • 2020-12-08 17:04

    I Solve this problem by Useing intrueder's way.Supplement, the API LoadImage cannot Load.png. Use System.drawing.BitMap.Like this:Bitmap bmp = new Bitmap(str, true); IntPtr p = bmp.GetHicon(); SetSystemCursor(p, OCR_NORMAL);

    0 讨论(0)
提交回复
热议问题