【问题标题】:C# Detecting whether cursor is hiddenC#检测光标是否隐藏
【发布时间】:2019-10-31 23:00:06
【问题描述】:

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

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

我还尝试使用 user32.dll 中的GetCursorInfo 并检查标志是否为 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 大部分时间都在工作)。这涵盖了大多数浏览器。

老实说,在检测隐藏光标方面,我认为我们无能为力。在极少数情况下,光标未隐藏但我的应用程序认为隐藏或相反,我决定只提供一个选项,让用户单击设置中的按钮,在设定的时间后将当前光标句柄添加到例外。

【问题讨论】:

  • 您是否尝试过使用System.Windows.Forms.Cursor 并检查其位置是否在您窗口的可见区域内?
  • 当光标被大多数程序隐藏时,CURSORINFO 结构的flagshCursor(句柄)的值都应该为零。但是,当光标被浏览器隐藏时,flags 的值似乎不会改变(保持 1)并且hCursor 的值设置为自定义句柄,看起来每个浏览器都不同。我不确定是否有办法检测到这一点。如果我发现了什么,会通知你。
  • 网页大多使用 CSS(即cursor: none)来临时“隐藏”光标。 cursor: none 所做的是它告诉浏览器使光标不可见。浏览器似乎这样做的方式是使用自定义(不可见)光标。换句话说,实际的操作系统光标仍然存在并且有一个句柄。有 other ways 可以通过 Web 应用程序隐藏光标,该应用程序实际上删除了操作系统光标,但这不是 cursor: none 所做的......
  • ...作为一种解决方法,您可以做的是获取普通浏览器的不可见光标的句柄并将其与CURSORINFO的句柄进行比较无论何时活动窗口是浏览器。这显然是非常hacky,但并非万无一失。希望有人能提出更好的解决方案。
  • 查看我系统上的值,“常规”光标句柄类似于655396554165555。但是,当光标被浏览器隐藏时,我会得到类似-977859735 (0xFFFFFFFFC5B70B69)(64 位指针)的值。我不确定这是否是一个有效的指针,但即使它是,它与通常的值完全不同,看起来你应该能够检查一些非常不同的东西吗?

标签: c# windows


【解决方案1】:

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

在最常见的情况下,当系统本身不渲染光标时,您所要做的就是检查光标标志是否为 0(隐藏)。 (或者看一下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 可能意味着 A 到软件 B 但 C 到软件 D。这不太可能,但如果您想更加安全,例外列表应该是应用程序和句柄的列表.

【讨论】:

    猜你喜欢
    • 2011-06-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-06
    • 1970-01-01
    • 1970-01-01
    • 2019-02-01
    相关资源
    最近更新 更多