首页 > 解决方案 > C#检测光标是否隐藏

问题描述

是的,我确实意识到有很多这样的问题,但没有一个对我有用。我需要检查系统光标是否隐藏。

我试过了Cursor.Current == null。它从来没有做任何事情。(我用全屏 Youtube、Discord 和 Krita 隐藏了光标)。

我还尝试使用GetCursorInfouser32.dll 并检查标志是否为 0(隐藏)。没有什么。

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

[StructLayout( LayoutKind.Sequential )]
struct CURSORINFO {
    public Int32 cbSize;        

    public Int32 flags;         

    public IntPtr hCursor;
    public POINT ptScreenPos;
}

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

public static bool CursorHidden () {
    CURSORINFO cinfo;
    cinfo.cbSize = Marshal.SizeOf( typeof( CURSORINFO ) );
    GetCursorInfo( out cinfo );
    return cinfo.flags == 0;
}

我的目标是在光标隐藏时隐藏屏幕覆盖 UI。

那么,如何检查系统光标是否以其他方式隐藏?

编辑:

好的,我在 Ahmed Abdelhameed 的帮助下有了一个发现。基本上,浏览器等不会呈现光标,但系统仍然认为它是可见的。但是,手柄发生了变化。系统默认提供的句柄数量有限(Cursors.<Name>.Handle),并且不可见的浏览器光标不使用它们。

enum CursorTypes { ... }
...
CURSORINFO cinfo;
... // see code above
Cursor[] cursors = new Cursor[] { ... }; // listed all of them in the same order as CursorTypes
int type = 1;
foreach ( Cursor cursor in cursors ) {
    if ( cinfo.hCursor == cursor.Handle ) {
        return (CursorTypes)type;
    }
    type++;
}
return CursorTypes.Other;

然而,这不是一个完整的解决方案,因为浏览器和其他软件可以创建一种新类型的光标,而不是不可见的(如在 VS 中向后倾斜),它也会返回CursorTypes.Other

正如 Herohtar 指出的那样,隐藏游标通常具有较大的指针值(在我的情况下,Math.Abs( pointer ) > 10000000大部分时间都有效)。这涵盖了大多数浏览器。

老实说,我认为在检测隐藏光标方面我们能做的不多。在极少数情况下,光标没有隐藏,但我的应用程序认为它是隐藏的,或者相反,我决定只选择让用户单击设置中的一个按钮,该按钮在一段时间后将当前光标句柄添加到例外。

标签: c#windows

解决方案


检测光标是否隐藏的方法不止一种。有时,系统会被告知不要渲染它,有时软件本身不会渲染它,有时它会将它渲染为不是光标的东西(例如数字艺术画笔轮廓)。

在最常见的情况下,当系统本身不渲染光标时,您所要做的就是检查光标标志是否为 0(隐藏)。(或采取 shrotcut 并检查是否Cursor.Current == null

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

[StructLayout( LayoutKind.Sequential )]
struct CURSORINFO {
    public Int32 cbSize;        

    public Int32 flags;         

    public IntPtr hCursor;
    public POINT ptScreenPos;
}

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

CURSORINFO GetCinfo () {
    CURSORINFO cinfo;
    cinfo.cbSize = Marshal.SizeOf( typeof( CURSORINFO ) );
    GetCursorInfo( out cinfo );
    return cinfo;
}
public bool FlagHidden () {
    CURSORINFO cinfo = GetCinfo();
    return cingo.flags == 0 || Cursor.Current == null; // using both for extra safety
}

现在我们遇到网络浏览器。浏览器不会呈现隐藏的光标,但它们会更改光标句柄。大多数时候,但不一定总是句柄的值会很大。

public bool BrowserHidden () {
    CURSORINFO cinfo = GetCinfo();
    return Math.Abs( cinfo.hCursor.ToInt64() ) > 10000000;
}

现在,我们差不多完成了,但不要忘记会有例外。例如,Krita 在隐藏光标的同时渲染画笔的轮廓,但就系统而言,光标仍然可见。没有一种简单、通用的方法来处理这个问题,因此我们几乎必须明确告诉我们的软件注意这些特定情况。

List<IntPtr> exceptions = new List<IntPtr>{ ... }; // put all the common exceptions here, implement some way to add / remove them
public bool IsException () {
    CURSORINFO cinfo = GetCinfo();
    return exceptions.Contains( cinfo.hCursor );
}

public bool CursorHidden () {
    bool hidden = FlagHidden() || BrowserHidden();
    return hidden != IsException(); // hidden xor exception ( inverts hidden if its an exception )
}

可能存在指针 X 对软件 B 表示 A 而对软件 D 表示 C 的情况。这不太可能,但如果您想更加安全,例外列表应该是应用程序和句柄的列表。


推荐阅读