获取当前鼠标光标类型

11

如何获取当前GLOBAL鼠标光标类型(沙漏/箭头/...)?在Windows中。

全局 - 我需要它,即使鼠标在我的应用程序之外,或者即使我的程序没有窗口。

使用C#,Delphi或纯WinAPI都可以。

非常感谢您的提前帮助!


1
似乎不可能 :( - Alex from Jitbit
1
感谢您在3年后回答我的问题 - 真的帮了我 :) - barakcaf
6个回答

7

三年后,现在是时候回答我自己的问题了。以下是如何用C#检查当前全局光标是否为沙漏(如果有需要,请根据您自己的需求扩展代码):

private static bool IsWaitCursor()
{
    var h = Cursors.WaitCursor.Handle;

    CURSORINFO pci;
    pci.cbSize = Marshal.SizeOf(typeof(CURSORINFO));
    if(!GetCursorInfo(out pci))
        throw new Win32Exception(Marshal.GetLastWin32Error());

    return pci.hCursor == h;
}

[StructLayout(LayoutKind.Sequential)]
struct POINT
{
    public Int32 x;
    public Int32 y;
}

[StructLayout(LayoutKind.Sequential)]
struct CURSORINFO
{
    public Int32 cbSize;        // Specifies the size, in bytes, of the structure. 
    // The caller must set this to Marshal.SizeOf(typeof(CURSORINFO)).
    public Int32 flags;         // Specifies the cursor state. This parameter can be one of the following values:
    //    0             The cursor is hidden.
    //    CURSOR_SHOWING    The cursor is showing.
    public IntPtr hCursor;          // Handle to the cursor. 
    public POINT ptScreenPos;       // A POINT structure that receives the screen coordinates of the cursor. 
}

[DllImport("user32.dll", SetLastError = true)]
static extern bool GetCursorInfo(out CURSORINFO pci);

1
三年过去了,现在是回答我自己问题的时候了。为什么?这与Gabr所说和我所展示的有何不同?什么使它成为[更]正确的答案? - Sertac Akyuz
1
这并没有回答你最初的问题,你说你想找到全局光标状态,而你的代码只检查了一种可能的状态。此外,你还几乎完全抄袭了另一个问题的答案。 - Lemuel Botha
1
你提到的答案只是给你一个句柄,没有解释接下来该做什么。 - Alex from Jitbit
可能可以通过与所有可能的光标进行比较来确定它是哪个图标? - Charlieface

5

3
无法从中获取游标类型,只能获取处理句柄。 - Alex from Jitbit

4
OEM光标是共享资源,因此所有请求特定光标的进程将检索相同的句柄。应用程序可以在启动时缓存标准系统光标句柄,然后可以使用GetCursorInfo获取全局光标句柄,并在缓存中查找该句柄以检索其种类(如果它是系统光标)。
以下Delphi示例代码演示了这一点。在窗体创建时,使用LoadImage将光标句柄填充到数组中。计时器定期使用GetCursorInfo轮询全局光标,代码在数组中查找句柄以从常量名称数组中检索光标名称:
const
  HighCursor = 13;

type
  TForm1 = class(TForm)
    Timer1: TTimer;
    Label1: TLabel;
    procedure FormCreate(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
  private
    FCursorHandles: array [0..HighCursor] of HCURSOR;
  public
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

const
  OEMCursors: array [0..HighCursor] of Integer = (OCR_NORMAL, OCR_IBEAM,
      OCR_WAIT, OCR_CROSS, OCR_UP, OCR_SIZENWSE, OCR_SIZENESW, OCR_SIZEWE,
      OCR_SIZENS, OCR_SIZEALL, OCR_NO, OCR_HAND, OCR_APPSTARTING,
      32651 {OCR_HELP?});

  CursorNames: array [0..HighCursor] of string = ('OCR_NORMAL', 'OCR_IBEAM',
      'OCR_WAIT', 'OCR_CROSS', 'OCR_UP', 'OCR_SIZENWSE', 'OCR_SIZENESW',
      'OCR_SIZEWE', 'OCR_SIZENS', 'OCR_SIZEALL', 'OCR_NO', 'OCR_HAND',
      'OCR_APPSTARTING', 'OCR_HELP');

procedure TForm1.FormCreate(Sender: TObject);
var
  i: Integer;
begin
  for i := 0 to HighCursor do
    FCursorHandles[i] := LoadImage(0, MakeIntResource(OEMCursors[i]),
        IMAGE_CURSOR, 0, 0, LR_DEFAULTCOLOR or LR_DEFAULTSIZE or LR_SHARED);
end;

procedure TForm1.Timer1Timer(Sender: TObject);

  function GetCursorName(Cursor: HCURSOR): string;
  var
    i: Integer;
  begin
    for i := 0 to HighCursor do
      if Cursor = FCursorHandles[i] then begin
        Result := CursorNames[i];
        Exit;
      end;
    Result := 'Unknown Cursor';  // A custom cursor.
  end;

var
  CursorInfo: TCursorInfo;
begin
  CursorInfo.cbSize := SizeOf(CursorInfo);
  if GetCursorInfo(CursorInfo) then
    Label1.Caption := GetCursorName(CursorInfo.hCursor)
  else
    Label1.Caption := 'Fail: ' + SysErrorMessage(GetLastError);
end;

请注意,使用Delphi时不必缓存光标句柄,因为Delphi通过其Screen.Cursors列表实现了缓存。示例代码没有使用它以获得更好的可移植性。
还要注意,在'winuser.h'中没有'OCE_HELP',但是提供的常量对应于'IDC_HELP'似乎可以正常工作(尽管我找不到在W7中使用“帮助选择”光标的对话框)。

4

使用 Delphi 语言

Screen.MouseCursor.

当前鼠标光标。

通用Win32(user32)提供:

function GetCursor: HCURSOR; stdcall;

这应该适用于其他 win32 语言。


2
那不对。正如我在另一个问题中学到的那样,GetCursor 不再适用于其他程序的光标:http://stackoverflow.com/questions/358527/how-to-tell-if-mouse-pointer-icon-changed - Rob Kennedy

0

@Alex 你救了我一天。我允许自己修改你的代码,这样每个光标都可以被反映出来...可能对其他人也有帮助:

public enum Cursor
{
    UNKOWNCURSOR,
    AppStarting,
    Arrow,
    Cross,
    Default,
    IBeam,
    No,
    SizeAll,
    SizeNESW,
    SizeNS,
    SizeNWSE,
    SizeWE,
    UpArrow,
    WaitCursor,
    Help,
    HSplit,
    VSplit,
    NoMove2D,
    NoMoveHoriz,
    NoMoveVert,
    PanEast,
    PanNE,
    PanNorth,
    PanNW,
    PanSE,
    PanSouth,
    PanSW,
    PanWest,
    Hand
}

public static Cursor GetCursor()
{
    CURSORINFO pci;
    pci.cbSize = Marshal.SizeOf(typeof(CURSORINFO));
    if (!GetCursorInfo(out pci))
        throw new Win32Exception(Marshal.GetLastWin32Error());

    var h = pci.hCursor;
    if (h == Cursors.AppStarting.Handle) return Cursor.AppStarting;
    if (h == Cursors.Arrow.Handle) return Cursor.Arrow;
    if (h == Cursors.Cross.Handle) return Cursor.Cross;
    if (h == Cursors.Default.Handle) return Cursor.Default;
    if (h == Cursors.IBeam.Handle) return Cursor.IBeam;
    if (h == Cursors.No.Handle) return Cursor.No;
    if (h == Cursors.SizeAll.Handle) return Cursor.SizeAll;
    if (h == Cursors.SizeNESW.Handle) return Cursor.SizeNESW;
    if (h == Cursors.SizeNS.Handle) return Cursor.SizeNS;
    if (h == Cursors.SizeNWSE.Handle) return Cursor.SizeNWSE;
    if (h == Cursors.SizeWE.Handle) return Cursor.SizeWE;
    if (h == Cursors.UpArrow.Handle) return Cursor.UpArrow;
    if (h == Cursors.WaitCursor.Handle) return Cursor.WaitCursor;
    if (h == Cursors.Help.Handle) return Cursor.Help;
    if (h == Cursors.HSplit.Handle) return Cursor.HSplit;
    if (h == Cursors.VSplit.Handle) return Cursor.VSplit;
    if (h == Cursors.NoMove2D.Handle) return Cursor.NoMove2D;
    if (h == Cursors.NoMoveHoriz.Handle) return Cursor.NoMoveHoriz;
    if (h == Cursors.NoMoveVert.Handle) return Cursor.NoMoveVert;
    if (h == Cursors.PanEast.Handle) return Cursor.PanEast;
    if (h == Cursors.PanNE.Handle) return Cursor.PanNE;
    if (h == Cursors.PanNorth.Handle) return Cursor.PanNorth;
    if (h == Cursors.PanNW.Handle) return Cursor.PanNW;
    if (h == Cursors.PanSE.Handle) return Cursor.PanSE;
    if (h == Cursors.PanSouth.Handle) return Cursor.PanSouth;
    if (h == Cursors.PanSW.Handle) return Cursor.PanSW;
    if (h == Cursors.PanWest.Handle) return Cursor.PanWest;
    if (h == Cursors.Hand.Handle) return Cursor.Hand;
    return Cursor.UNKOWNCURSOR;
}

[StructLayout(LayoutKind.Sequential)]
struct POINT
{
    public Int32 x;
    public Int32 y;
}

[StructLayout(LayoutKind.Sequential)]
struct CURSORINFO
{
    public Int32 cbSize;        // Specifies the size, in bytes, of the structure. 
    // The caller must set this to Marshal.SizeOf(typeof(CURSORINFO)).
    public Int32 flags;         // Specifies the cursor state. This parameter can be one of the following values:
    //    0             The cursor is hidden.
    //    CURSOR_SHOWING    The cursor is showing.
    public IntPtr hCursor;          // Handle to the cursor. 
    public POINT ptScreenPos;       // A POINT structure that receives the screen coordinates of the cursor. 
}

[DllImport("user32.dll", SetLastError = true)]
static extern bool GetCursorInfo(out CURSORINFO pci);

0

注:使用 Delphi

大多数可视化对象可以使用 Cursor 属性,否则使用 Screen.Cursor 属性。 将其设置回 crDefault 可以取消先前所做的更改。


这不会让你的光标离开程序。 - Rob Kennedy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接