问题描述
我想对屏幕键盘进行编程.
I want to program an on-screen keyboard.
要将密钥发送到另一个应用程序,我需要在我的应用程序即将获得焦点以及用户按下表单上的按钮发送密钥时存储当前的前景窗口(=具有焦点的窗口), 我将 SetForegroundWindow 设置为这个以前的窗口句柄.
To send keys to another application, I need to store the current foreground window (=the window with the focus) when my app is about to get the focus, and when the user presses a button on my form to send the key, I will SetForegroundWindow to this previous window handle.
这样文本将被发送到先前聚焦的窗口.
This way the text will be sent to the previously focussed window.
但是,我没有找到正确的事件.
However, I don't find the correct event for that.
Form_Activated 为时已晚.
Form_Activated is too late.
使用计时器不断检查当前前景窗口似乎有点粗鲁.
Using a timer to constantly check for the current foreground window seems a bit rude.
是否有官方"?在我的应用获得焦点之前发生的事件?
Is there an "official" event that occurs before my app gets the focus?
推荐答案
- 查找停用窗口的句柄时此窗口已被激活.
当这个窗口被激活时,找到被停用窗口的句柄
您可以使用 SetWinEventHook
你可以收听 一些事件 来自其他进程并注册WinEventProc
回调方法接收事件时引发的事件.
Find handle of the deactivated window when this window has been activated
You can use SetWinEventHook
you can to listen to some events from other processes and register a WinEventProc
callback method to receive the event when the event raised.
这里我们对 EVENT_SYSTEM_FOREGROUND
感兴趣.每次我们收到这个事件,如果激活的窗口不是我们的窗体,我们跟踪已经激活的窗口,然后当我们的窗口被激活时,我们查看被跟踪的窗口的值,它现在是前一个丢失的窗口重点.
Here we are interested in EVENT_SYSTEM_FOREGROUND
. Every time that we receive this event, if the activated window is not our form, we track the window which has been activated, then when our window is activated we look into the value of tracked window which is now the previous window which has lost its focus.
C#
这是我尝试过并且对我来说效果很好的代码:
Here is the code that I tried and worked well for me:
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
这篇关于表单即将获得焦点时的事件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!