Impoerant:, I agree with Jimi's and jmcilhinney's comments and I also
believe it's not the right way of implementing an on-screen keyboard,
but this post it just trying to help you on:
- Finding handle of the deactivated window when
this window has been activated.
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.
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