2012-12-03 15 views
16

vorrei per il mio programma per essere in grado di ignorare la dimensione massima imposta del mouse di 32x32 molto simile al programma nella foto allegata fa, il cursore nella foto è 72x72 . Questa è una cattura da ProcMon che mostra cosa succede quando i cursori cambiano.Come ignorare la dimensione massima 32x32 del mouse in Windows, come questo programma può

Tuttavia, se provo a cambiare i valori di registro per i file il cursore me stesso e quindi spingere le modifiche utilizzando

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

poi il cursore cambierà, ma è ancora limitata alle dimensioni 32x32 massima. In che modo questo programma è stato in grado di aggirare questa restrizione? Inoltre, i cursori rimangono dopo la fine del programma, quindi non può essere qualcosa che sta facendo mentre è in esecuzione, ma deve ignorare un'impostazione da qualche parte.

enter image description here

Grazie per il vostro aiuto, non sono stati in grado di trovare qualcosa di simile in rete, in modo da non so nemmeno se qualcuno avrà la risposta.

EDIT: vedo un po 'l'accesso ad un file chiamato C:\Windows\SysWOW64\Imageres.dll. Vengono solo letti, ma forse questi cursori sono memorizzati qui o hanno modificato questo file in qualche modo. Ma ho pensato che potrebbe portare qualcuno con più esperienza di me sulla strada giusta.

EDIT 2: Credo che le dimensioni sono dettate dalle variabili SM_CXCURSOR e SM_CYCURSOR. Se potessi trovare un modo per impostarli, potrei essere in affari. Andando a scrivere un rapido programma per ottenere me quei valori sul PC con il programma in esecuzione e il cursore del mouse enorme e vedere che cosa ritorna ...

EDIT 3: Nessuna fortuna; il PC con l'enorme cursore restituisce 32x32 perché è SM_CXCURSOR e SM_CYCURSOR.

+0

Forse potresti impostare il ridimensionamento dello schermo al 150%? È per l'impostazione della risoluzione dello schermo –

+0

Ma non è così che questo programma è in grado di farlo. Nient'altro cambia tranne il cursore del mouse, che è l'effetto che spero di replicare. –

+1

Dovresti pubblicare il tuo tentativo di cambiare la dimensione del puntatore del mouse. –

risposta

6

usando SetSystemCursor è possibile impostare un cursore a un'immagine di dimensioni molto più grande il cursore standard.

Ecco una classe che ho per il ridimensionamento delle cursori di sistema:

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

    } 
} 

Agisce ricevendo il cursore del sistema attuale come previsto System.Windows.Forms.Cursors e fare un'immagine da esso con Cursor.Draw. L'immagine viene quindi ridimensionata alla dimensione desiderata. Ciò richiede spostando l'immagine del cursore, sia per il basso a destra (come per i puntatori a freccia) e centrare l'immagine del cursore all'interno dell'immagine più grande (come per Cross e IBeam).

È possibile utilizzare la propria immagine per il cursore se lo si desidera, ignorando tutto il codice di ridimensionamento. Fornisci la bitmap a SetCursor.

Una volta che la nuova immagine del cursore è pronta, l'ultimo pezzo di dati necessario è l'ID del cursore che stiamo cercando di sostituire. Ogni System.Windows.Forms.Cursor contiene queste informazioni, ma in una variabile privata, quindi viene utilizzato il reflection per ottenere il valore. Se preferisci evitare la riflessione, potresti invece creare una tabella con questi valori. Vedi MSDN SetSystemCursor per un elenco di valori.

utilizzare la classe basta chiamare

SystemCursors.SetSystemCursorsSize(128); 
+0

Hey, questo è sicuramente il più vicino che abbia mai ottenuto per quello che stavo cercando. Ho intenzione di curiosare un po ', ma l'unico problema con questo è che non c'è modo di tornare al set predefinito reale di cursori, e se dovessi andare avanti e indietro chiamando 'SetSystemCursorSize' da dire, Da 32 a 128 a 32 più e più volte diventerà così distorto che alla fine finisce come un quadrato nero. Come ho detto, mi guarderò intorno ma ero solo curioso di sapere se avessi qualche idea! Grazie per il post! –

+0

Se si conoscono in anticipo le dimensioni necessarie, è possibile salvare ogni cursore come file immagine e quindi caricare ogni dimensione secondo necessità. Qualcosa come 'SetCursor (nuova Bitmap (Image.FromFile (arrow32.png)), ...);'. Per immagini superiori a 32, è necessario salvare l'immagine spostata, come fa ResizeCursorBitmap. Un'altra possibilità sarebbe quella di mantenere una copia della Bitmap di ogni cursore all'avvio del programma, quindi ridimensionare e spostare, o semplicemente ripristinare l'originale. – endofzero

+0

Sfortunatamente questo non funziona in Windows 10. Anche quando si carica una bitmap esterna più grande con 'SetCursor', viene ridimensionato a 32x32. – kwill

6

Se si lavora con WPF, è possibile creare il proprio cursore del mouse e assegnarlo. Ma questo non è un cambio di cursore del mouse di sistema. Ecco un codice che farebbe il trucco. Nel codice qui sotto sto creando un cursore 50x50 pixel. È possibile disegnare la tua forma al 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

Apprezzo l'aiuto e il codice di esempio, ma purtroppo sarebbe necessario per tutto il sistema. Non sono sicuro del tipo di magia nera che queste persone hanno funzionato, ma sono determinato a capirlo: P Grazie ancora! –

0

Aggiungi queste importazioni alla classe:

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

leggere articoli di MSDN su LoadImage e SetSystemCursor, in particolare sui parametri che utilizzano.

Poi utilizzare le funzioni nel codice:

// "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

ho risolvere questo problema useing way.Supplement di intrueder, il LoadImage API non può Load.png. Usa System.drawing.BitMap.Like: Bitmap bmp = new Bitmap(str, true); IntPtr p = bmp.GetHicon(); SetSystemCursor(p, OCR_NORMAL);