17

添付の図のプログラムと同じように、私のプログラムで最大のマウス サイズ 32x32 をオーバーライドできるようにしたいと思います。図のカーソルは 72x72 です。ProcMonこれは、カーソルが変化したときに何が起こっているかを示すキャプチャです。

ただし、カーソル ファイルのレジストリ値を自分で変更しようとすると、

SystemParametersInfo(SPI.SPI_SETCURSORS, 0, IntPtr.Zero, SPIF.SPIF_SENDCHANGE);

カーソルは変わりますが、それでも最大サイズは 32x32 に制限されています。このプログラムはどのようにしてその制限を回避できたのでしょうか? また、カーソルはプログラムの終了後も残るため、実行中に実行することはできませんが、どこかで設定をオーバーライドする必要があります。

ここに画像の説明を入力

助けてくれてありがとう、私はネット上でこのようなものを見つけることができなかったので、誰かが答えを持っているかどうかさえわかりません.

編集: というファイルへのアクセスが見られますC:\Windows\SysWOW64\Imageres.dll。それらは読み取りのみですが、おそらくこれらのカーソルはここに保存されているか、何らかの方法でこのファイルを変更しています。しかし、私よりも経験豊富な人が正しい軌道に乗る可能性があると考えました.

編集 2: サイズは SM_CXCURSOR および SM_CYCURSOR 変数によって決定されると思います。これらを設定する方法を見つけることができれば、ビジネスになるかもしれません。プログラムを実行し、巨大なマウス カーソルを使用して、PC でこれらの値を取得する簡単なプログラムを作成し、それが何を返すかを確認します...

編集 3: 運が悪い。大きなカーソルを持つ PC は、SM_CXCURSOR と SM_CYCURSOR に対して 32x32 を返します。

4

4 に答える 4

7

を使用SetSystemCursorすると、標準のカーソルよりもはるかに大きなサイズの画像にカーソルを設定できます。

システムカーソルのサイズを変更するためのクラスを次に示します。

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);
        }

    }
}

で提供されている現在のシステム カーソルを取得しSystem.Windows.Forms.Cursors、 でイメージを作成することで機能しCursor.Drawます。次に、画像が目的のサイズにサイズ変更されます。これには、カーソル イメージを右下隅に移動する (矢印ポインターの場合のように) か、大きなイメージ内でカーソル イメージを中央に配置する (Cross や IBeam の場合のように) 必要があります。

必要に応じて、すべてのサイズ変更コードをバイパスして、カーソルに独自の画像を使用できます。Bitmap を に渡すだけSetCursorです。

新しいカーソル イメージの準備ができたら、最後に必要なデータは、置き換えようとしているカーソルの ID です。それぞれSystem.Windows.Forms.Cursorにこの情報が含まれていますが、プライベート変数に含まれているため、リフレクションを使用して値を取得します。リフレクションを避けたい場合は、代わりにこれらの値のテーブルを作成できます。値の一覧については、MSDN SetSystemCursorを参照してください。

クラスを使用するには、呼び出すだけです

SystemCursors.SetSystemCursorsSize(128);
于 2013-11-22T17:43:06.907 に答える
6

WPF を使用している場合は、独自のマウス カーソルを作成して割り当てることができます。しかし、これはシステム全体のマウス カーソルの変更ではありません。トリックを実行するコードを次に示します。以下のコードでは、50x50 ピクセルのカーソルを作成しています。独自の形状を上に描くことができます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);
            }
        }
    }

}
于 2012-12-03T17:48:50.420 に答える
2

これらのインポートをクラスに追加します。

[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);

LoadImageSetSystemCursorに関する msdn の記事、特にそれらが使用するパラメーターについて読んでください。

次に、コードで関数を使用します。

// "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)
}
于 2012-12-10T00:10:35.727 に答える