概述

研究这个主要是为了进一步完善当前的自用软件 Alterful 的激活流程,实现“无热键”键盘增强。 虽然最终没能得到接近完美的解决办法,不过也在这个尝试的过程中取得了一些进展,故简单地记录一下。

Title


其实所研究这个问题的本质就是希望能够实时监测系统当中是否有输入焦点,也就是在文本框中输入内容时一闪一闪的光标,更准确地说应该是叫输入焦点,或者说“插入符”。

归纳了一下,主要有两种办法可以基本实现这一点。

一、GetGUIThreadInfo

作为处于待输入状态的控件,其父窗口一般来讲是当前时刻的顶级窗口,因此考虑通过函数 GetGUIThreadInfo 来获得顶层窗口的相关信息,进而判断顶层窗口是否含有输入焦点来确定系统全局是否含有输入焦点。

下面是 C++ 中 GetGUIThreadInfo 的函数原型:

BOOL GetGUIThreadInfo(
  DWORD          idThread,
  PGUITHREADINFO pgui
);

参数一

其中参数 idThread 是欲取得信息的GUI线程id,如果是要获取一个指定窗口的Info的话,那么可以通过 GetWindowThreadProcessId 来得到其 idThread 值,其函数原型如下:

DWORD GetWindowThreadProcessId(
HWND hWnd,
LPDWORD lpdwProcessId
);

不过我们只是要取的顶级窗口的信息,幸运的是 idThread 接受 NULL,并且当传入 NULL 时将默认认为目标窗口就是顶级窗口,因此此处直接传NULL即可,还是很方便的。

参数二

第二个参数 pgui 是一个 PGUITHREADINFO 类型的结构体指针,在微软官方文档当中给出的定义如下:

typedef struct tagGUITHREADINFO {
  DWORD cbSize;
  DWORD flags;
  HWND  hwndActive;
  HWND  hwndFocus;
  HWND  hwndCapture;
  HWND  hwndMenuOwner;
  HWND  hwndMoveSize;
  HWND  hwndCaret;
  RECT  rcCaret;
} GUITHREADINFO, *PGUITHREADINFO, *LPGUITHREADINFO;

其中对此处比较有用的就是 flags、hwndFocus 以及 hwndCaret 这三个数据成员,其中 hwndFocus 表示具有键盘焦点的窗口的句柄,hwndCaret 表示显示插入符的窗口的句柄,而 flags 表征的是线程的状态。flag 一共有 5 个可取值,具体见下图:

Title

当 flags == 1 时,说明当前窗口中有闪烁的插入符,也就说明当前系统具有输入焦点,处于可输入状态。

相应的,此时就可以通过 hwndCaret 来知道具体的焦点控件句柄。(不过针对此处需要,这些信息都不用管,不过对大多数其它情况和需求而言,这些数据都是有意义的,所以还是提一下)

二、GetCaretPos

GetCaretPos 函数其实是用来获取当前的光标位置的,不过从其函数原型:

BOOL GetCaretPos(
  LPPOINT lpPoint
);

可以看到返回值是布尔型,因此也可以用来判断是否存在输入光标。

很明显 GetCaretPos 函数相比 GetGUIThreadInfo 而言要简洁得多,这也是由函数的使命所决定的。

从 GetCaretPos 你只能得到 "是否有光标?" 以及 "光标坐标是什么?" 这两个问题的答案,而 GetGUIThreadInfo 可以得到的信息要丰富得多。

函数 GetCaretPos 不需要任何有意义的输入参数,只需要一个 LPPOINT 指针用于接受光标的客户坐标。

如果当前屏幕有光标,那么函数返回 true,如果屏幕没有光标,那么函数返回 flase,并且可以通过 GetLastError 来取得错误信息。

三、测试

测试效果在概述当中已经说了,不尽理想。在目前已经试过的所有原生窗口(如记事本、资源管理器等)当中可以正常得到光标信息,

但是在大部分基于ATL或WTL开发的DirectUI窗口(如QQ、WPS、迅雷)和几乎所有的浏览器当中,GetCaretPos 始终返回 true,lpdwProcessId 的 flags 始终为 0,也就是说都无法得到光标信息。

在网上找了一天也没能找到这个问题的原因,虽然有一些相关的提问,但是都没有结帖,并且都是10年前左右的问题,年代久远,也就是目前为止都没有找到有效的解决办法。这一问题只能暂时告一段落了,如果以后有闲情继续研究,会尝试钻研一些开源输入法光标跟踪原理,若取得进展,再回到本篇继续更新。

下面是对有效情况的测试图:

Title