表单即将获得焦点时的事件?
Posted
技术标签:
【中文标题】表单即将获得焦点时的事件?【英文标题】:Event when form is about to get focus? 【发布时间】:2021-05-23 05:53:21 【问题描述】:我想编写一个屏幕键盘。
要将密钥发送到另一个应用程序,我需要在我的应用程序即将获得焦点时存储当前前台窗口(=具有焦点的窗口),并且当用户按下我的表单上的按钮以发送密钥时,我将SetForegroundWindow到这个前一个窗口句柄。
这样文本将被发送到先前聚焦的窗口。
但是,我没有找到正确的事件。
Form_Activated 为时已晚。
使用计时器不断检查当前前景窗口似乎有点粗鲁。
在我的应用获得焦点之前是否发生了“官方”事件?
【问题讨论】:
当与其子控件之一交互时,您需要一个未激活的窗口(因此它不会成为 ForegroundWindow),并且这些控件在选择时也不会获得焦点。例如:How to keep a Form always on top without stealing focus from the active Window? 和 Use a virtual Keyboard on focused Textboxes and DataGridView Cells 也可以和Move window when external application's window moves等结合使用 @Jimi 谢谢,但这太复杂了。我知道 Windows XP / 7 中的“官方”屏幕键盘以“焦点”方式工作,而不是 GWL_EXSTYLE 方式。我想重新创建它。 你为什么要尝试做坏事?我建议您检查this。它提供了一些现成的类,您可以简单地将它们添加到您的项目中,然后像任何其他控件一样使用,您可以从UnselectableForm
类而不是标准的Form
类继承您的表单。我自己使用它们创建了一个屏幕键盘,它完全按预期工作。这样做是个好主意,但您不需要了解任何代码。
“是否有“官方”活动”。不,没有。 XP/Win7 OSK 不是 WinForms 应用程序。
【参考方案1】:
无礼:,我同意 Jimi 和 jmcilhinney 的 cmets,我也同意 相信这不是实现屏幕键盘的正确方法, 但这篇文章只是想帮助你:
查找停用窗口的句柄时 此窗口已被激活。
当该窗口被激活时,查找已停用窗口的句柄
您可以使用SetWinEventHook
来监听其他进程的some events,并注册一个WinEventProc
回调方法,以便在事件引发时接收事件。
这里我们对EVENT_SYSTEM_FOREGROUND
感兴趣。每次我们收到这个事件,如果激活的窗口不是我们的窗体,我们跟踪已经被激活的窗口,然后当我们的窗口被激活时,我们查看被跟踪的窗口的值,它现在是之前丢失的窗口重点。
C#
这是我尝试过的代码:
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
public class MyForm : Form
public const uint EVENT_SYSTEM_FOREGROUND = 0x0003;
public const uint EVENT_OBJECT_DESTROY = 0x8001;
public const uint WINEVENT_OUTOFCONTEXT = 0;
public delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType,
IntPtr hwnd, int idObject, int idChild,
uint dwEventThread, uint dwmsEventTime);
[DllImport("user32.dll")]
public static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax,
IntPtr hmodWinEventProc, WinEventDelegate lpfnWinEventProc,
uint idProcess, uint idThread, uint dwFlags);
[DllImport("user32.dll")]
public static extern bool UnhookWinEvent(IntPtr hWinEventHook);
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
IntPtr hook = IntPtr.Zero;
protected override void OnLoad(EventArgs e)
previous = GetForegroundWindow();
hook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND,
EVENT_SYSTEM_FOREGROUND,
IntPtr.Zero, new WinEventDelegate(WinEventProc),
0, 0, WINEVENT_OUTOFCONTEXT);
base.OnLoad(e);
protected override void OnFormClosing(FormClosingEventArgs e)
UnhookWinEvent(hook);
base.OnFormClosing(e);
IntPtr? previous = null;
void WinEventProc(IntPtr hWinEventHook, uint eventType,
IntPtr hwnd, int idObject, int idChild, uint dwEventThread,
uint dwmsEventTime)
if (hwnd != this.Handle)
previous = hwnd;
else
if (previous.HasValue)
this.Text = $"Previous window: (int)previous:X";
else
this.Text = $"No idea about previous window.";
VB.NET
Imports System.Runtime.InteropServices
Public Class MyForm
Inherits Form
Public Const EVENT_SYSTEM_FOREGROUND As UInteger = &H3
Public Const EVENT_OBJECT_DESTROY As UInteger = &H8001
Public Const WINEVENT_OUTOFCONTEXT As UInteger = 0
Public Delegate Sub WinEventDelegate(ByVal hWinEventHook As IntPtr,
ByVal eventType As UInteger,
ByVal hwnd As IntPtr,
ByVal idObject As Integer,
ByVal idChild As Integer,
ByVal dwEventThread As UInteger,
ByVal dwmsEventTime As UInteger)
<DllImport("user32.dll")>
Public Shared Function SetWinEventHook(ByVal eventMin As UInteger,
ByVal eventMax As UInteger,
ByVal hmodWinEventProc As IntPtr,
ByVal lpfnWinEventProc As WinEventDelegate,
ByVal idProcess As UInteger,
ByVal idThread As UInteger,
ByVal dwFlags As UInteger) As IntPtr
End Function
<DllImport("user32.dll")>
Public Shared Function UnhookWinEvent(ByVal hWinEventHook As IntPtr) As Boolean
End Function
<DllImport("user32.dll")>
Private Shared Function GetForegroundWindow() As IntPtr
End Function
Private hook As IntPtr = IntPtr.Zero
Protected Overrides Sub OnLoad(ByVal e As EventArgs)
previous = GetForegroundWindow()
hook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND,
EVENT_SYSTEM_FOREGROUND, IntPtr.Zero,
New WinEventDelegate(AddressOf WinEventProc),
0, 0, WINEVENT_OUTOFCONTEXT)
MyBase.OnLoad(e)
End Sub
Protected Overrides Sub OnFormClosing(ByVal e As FormClosingEventArgs)
UnhookWinEvent(hook)
MyBase.OnFormClosing(e)
End Sub
Private previous As IntPtr? = Nothing
Private Sub WinEventProc(ByVal hWinEventHook As IntPtr,
ByVal eventType As UInteger,
ByVal hwnd As IntPtr,
ByVal idObject As Integer,
ByVal idChild As Integer,
ByVal dwEventThread As UInteger,
ByVal dwmsEventTime As UInteger)
If hwnd <> Me.Handle Then
previous = hwnd
Else
If previous.HasValue Then
Me.Text = $"Previous window: CInt(previous):X"
Else
Me.Text = $"No idea about previous window."
End If
End If
End Sub
End Class
【讨论】:
以上是关于表单即将获得焦点时的事件?的主要内容,如果未能解决你的问题,请参考以下文章