I am trying to detect Alt+Tab in a Win Event Hook using SetWinEventHook
. However the callback for the hook is never triggering for Alt+Tab, even though I have a message pump (I am on windows 10)
I came across this idea to process Alt+Tab like this when I stumbled across this series of posts:
Alt Tab overlay Win32 identificator
SetWinEventHook does not catch any event
Which describe using a WinEventHook to get the Alt+Tab message (which I don't know if it is even efficient or not to use in the modern day). I found an article by Raymond Chen detailing it (however it doesn't work anymore and I don't know why, but it should.)
How do I get the Alt+Tab message in my event callback?
EDIT: Here is my example to mimic what I was doing on a large scale (the small program doesn't work) and to remove doubt from the comments. Here is the entire program plus compile script that shows what I am trying to do but doesn't work at all (what am I doing wrong? the above Raymond Chen Program seems to be effected by it). I am on Windows 10
(Edit, I found EVENT_MIN and EVENT_MAX give me events in the hook, but never the EVENT_SYSTEM_SWITCHSTART and EVENT_SYSTEM_SWITCHEND events)
Compile.bat:
@echo off
if not defined DevEnvDir (
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat"
)
if "%Platform%" neq "x64" (
echo ERROR: Platform is not "x64" - previous bat call failed.
exit /b 1
)
set FILES=main.cpp
set RELEASEFLAGS=/O2 /DMAINDEBUG=0
set DEBUGFLAGS=/Zi /DMAINDEBUG=1
set LIBS=kernel32.lib user32.lib gdi32.lib Winmm.lib
::Release
cl /nologo /W3 /GS- /Gs999999 %RELEASEFLAGS% %FILES% /Fe: AnnoyingSound.exe %LIBS% /link /incremental:no /opt:icf /opt:ref /subsystem:windows
::Debug
cl /nologo /W3 /GS- /Gs999999 %DEBUGFLAGS% %FILES% /FC /Fe: AnnoyingSoundDebug.exe %LIBS% /link /incremental:no /opt:icf /opt:ref /subsystem:console
main.cpp:
#define STRICT
#include <windows.h>
#include <mmsystem.h>
#include <stdio.h>
HINSTANCE hinst;
HWND hwndMain;
LRESULT CALLBACK
WndProc(
HWND Window,
UINT Message,
WPARAM WParam,
LPARAM LParam)
{
if( Message == WM_CLOSE )
{
PostQuitMessage(0);
}
else
{
LRESULT Result = DefWindowProc( Window, Message, WParam, LParam );
return Result;
}
return 0;
}
HWND g_hwndAltTab = nullptr;
void CALLBACK WinEventProc(
HWINEVENTHOOK hWinEventHook,
DWORD event,
HWND hwnd,
LONG idObject,
LONG idChild,
DWORD dwEventThread,
DWORD dwmsEventTime
)
{
printf("Here!\n"); //This never gets called when Alt+Tab pressed
PCTSTR pszSound = nullptr;
switch (event)
{
case EVENT_SYSTEM_SWITCHSTART:
if (!g_hwndAltTab)
{
g_hwndAltTab = hwnd;
pszSound = "C:\\Windows\\Media\\Speech On.wav";
}
break;
case EVENT_SYSTEM_SWITCHEND:
if (g_hwndAltTab)
{
g_hwndAltTab = nullptr;
pszSound = "C:\\Windows\\Media\\Speech Sleep.wav";
}
break;
}
if (pszSound) {
PlaySound(pszSound, nullptr, SND_FILENAME | SND_ASYNC);
}
}
#if MAINDEBUG
int main()
#else
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hinstPrev,
LPSTR lpCmdLine, int nShowCmd)
#endif
{
#if !MAINDEBUG
UNREFERENCED_PARAMETER(lpCmdLine);
#endif
{
WNDCLASS wc;
wc.style = 0;
wc.lpfnWndProc = (WNDPROC) WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = GetModuleHandle( NULL );
wc.hIcon = LoadIcon((HINSTANCE) NULL,
IDI_APPLICATION);
wc.hCursor = LoadCursor((HINSTANCE) NULL,
IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(DKGRAY_BRUSH);
wc.lpszMenuName = "MainMenu";
wc.lpszClassName = "MainWndClass";
if (!RegisterClass(&wc))
return FALSE;
}
hinst = GetModuleHandle( NULL ); // save instance handle
HWINEVENTHOOK hWinEventHook = SetWinEventHook(
EVENT_SYSTEM_SWITCHSTART, EVENT_SYSTEM_SWITCHEND,
nullptr, WinEventProc, 0, 0,
WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);
hwndMain = CreateWindow("MainWndClass", "Sample",
WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT, (HWND) NULL,
(HMENU) NULL, hinst, (LPVOID) NULL);
// If the main window cannot be created, terminate
// the application.
if (!hwndMain)
return FALSE;
if (hWinEventHook)
{
ShowWindow(hwndMain, SW_SHOW);
UpdateWindow(hwndMain);
MSG msg;
while(GetMessage( &msg, NULL, 0, 0 ))
{
if( msg.message == WM_QUIT )
{
PostQuitMessage(0);
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
UnhookWinEvent(hWinEventHook);
}
return 0;
}
For context of what I am doing:
I am making my own rendering engine in DirectX12, and I am doing all the Win32 stuff manually. One thing I want to do is minimize the window on Alt+Tab when in fullscreen. (I heard DirectX renders on top of the window, so that the window is minimized, but DirectX keeps rendering on top of where the window was, so I need to process Alt+Tab and then stop the rendering (I don't know if that I true, just saw it in a forum post)). So I need a way of detecting Alt+Tab and processing it. (if this doesn't work, I may look into accelerators, but I don't know if that will work with Alt + Tab)
Going through old StackOverflow stuff, I found these two links, but all the examples are either dead or irrelevant: