目标
我在 Unity3D (C#) 中开发了一个键盘,并希望它在用户单击“编辑”类型控件(例如地址栏或输入字段)时弹出。因此,我需要检测何时单击“编辑”控件。
我试过的
目前我使用SetWinEventHook并监听事件EVENT_OBJECT_FOCUS来获取获得焦点的对象的句柄。之后,我使用GetClassName来查看焦点对象是否是“编辑”控件,单击该控件时会显示一个闪烁的插入符号。但是,以 Google Chrome 为例,无论是点击地址栏还是页面的纯文本,我总是得到Chrome_WidgetWin_1 。做了一些谷歌搜索后,我发现了这篇博客文章是什么让 RealGetWindowClass 比 GetClassName 更真实?说RealGetWindowClass可以获取基类,我认为它将类似于此处列出的“EDIT”或“COMBOBOX”. 事情进展得并不顺利。我尝试使用RealGetWindowClass并且仍然得到相同的结果Chrome_WidgetWin_1。
问题
为什么 GetClassName 和 RealGetWindowClass 返回相同的值?我应该如何让 RealGetWindowClass 返回基类?
编码
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr SetWinEventHook(int eventMin, int eventMax, IntPtr hmodWinEventProc, WinEventProc lpfnWinEventProc, int idProcess, int idThread, int dwflags);
[DllImport("user32.dll", SetLastError = true)]
private static extern int UnhookWinEvent(IntPtr hWinEventHook);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern uint RealGetWindowClass(IntPtr hwnd, [Out] StringBuilder pszType, uint cchType);
private delegate void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hWnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);
private const int WINEVENT_SKIPOWNPROCESS = 2;
private IntPtr windowEventHook;
private const int EVENT_OBJECT_FOCUS = 0x8005;
private void Start()
{
if (windowEventHook == IntPtr.Zero)
{
windowEventHook = SetWinEventHook(
EVENT_OBJECT_FOCUS,
EVENT_OBJECT_FOCUS,
IntPtr.Zero,
WindowEventCallback,
0,
0,
WINEVENT_SKIPOWNPROCESS);
if (windowEventHook == IntPtr.Zero)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
}
private void OnDestroy()
{
UnhookWinEvent(windowEventHook);
}
private void WindowEventCallback(IntPtr hWinEventHook, uint eventType, IntPtr hWnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
UnityEngine.Debug.Log($"[EventType]: {(EventEnum)eventType} [Class Name]: {GetClassName(hWnd)} [Real Class]: {RealGetWindowClassM(hWnd)}");
// Will print out the same log whether I click an address bar or plain text.
// [EventType]: EVENT_OBJECT_FOCUS [Class Name]: Chrome_WidgetWin_1 [Real Class]: Chrome_WidgetWin_1
}
private string GetClassName(IntPtr hWnd)
{
StringBuilder className = new StringBuilder(256);
GetClassName(hWnd, className, className.Capacity);
return className.ToString();
}
private string RealGetWindowClassM(IntPtr hWnd)
{
StringBuilder className = new StringBuilder(256);
RealGetWindowClass(hWnd, className, (UInt32)className.Capacity);
return className.ToString();
}