Playing a sound every time the foreground window changes


Today's Little Program plays a little sound every time the foreground window changes. One of my colleagues wondered if such a program was possible, "so that I stop accidentally typing the second halves of paragraphs into windows that pop up and steal focus." It's not clear whether this program will actually solve the bigger problem, but it was fun writing the program, and maybe you can use it for something.

#define STRICT
#include <windows.h>
#include <mmsystem.h>

void CALLBACK WinEventProc(
    HWINEVENTHOOK hWinEventHook,
    DWORD event,
    HWND hwnd,
    LONG idObject,
    LONG idChild,
    DWORD dwEventThread,
    DWORD dwmsEventTime
)
{
  if (hwnd &&
      idObject == OBJID_WINDOW &&
      idChild == CHILDID_SELF &&
      event == EVENT_SYSTEM_FOREGROUND) {
   PlaySound(TEXT("C:\\Windows\\Media\\Speech Misrecognition.wav"),
             NULL, SND_FILENAME | SND_ASYNC);
 }
}

int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev,
                   LPSTR lpCmdLine, int nShowCmd)
{
  HWINEVENTHOOK hWinEventHook = SetWinEventHook(
     EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND,
     NULL, WinEventProc, 0, 0,
     WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);

  MSG msg;
  while (GetMessage(&msg, NULL, 0, 0)) {
   TranslateMessage(&msg);
   DispatchMessage(&msg);
  }

  if (hWinEventHook) UnhookWinEvent(hWinEventHook);

  return 0;
}

This program installs an accessibility hook that listens for changes to the system foreground. And when it happens, we play a little sound.

I chose the Windows 7 Speech Misrecognition sound because it's relatively unobtrusive. And the sound is played asynchronously so as not to block the message pump thread. It also has as a pleasant side-effect that if the foreground changes many times rapidly, the new sound will interrupt the old one rather than queueing up behind it.

Note that there is no way to exit this program short of killing it in Task Manager. That's why it's a Little Program rather than a real program.

Comments (22)
  1. Joshua says:

    I suppose you could use sendkeys to actually prevent keystroke stealing; however this gets hairy fast.

  2. Random832 says:

    The problem with the bigger problem is that it's got infinite variations. In particular, even if this "solution" works perfectly, it can't handle the case where you press enter (or space) _immediately_ after a dialog box pops up.

  3. Dan Bugglin says:

    @Random832 IIRC if the dev followed MS guidelines, the default option in the dialog should be the safest, least destructive one.

    That is a pretty big IF, of course.

  4. AC says:

    The better solution would be for programs to not steal focus in the first place.

  5. >The better solution would be for programs to not steal focus in the first place.

    Tell that to Internet Explorer devs. They've been very successful in overcoming whatever USER32 devs were throwing at them.

    Though it looks like USER32 team finally won.

  6. John says:

    "IIRC if the dev followed MS guidelines, the default option in the dialog should be the safest, least destructive one."

    I'm still mad about the XP Automatic Updates reboot dialog (http://www.codinghorror.com/…/please-dont-steal-my-focus.html).

  7. db2 says:

    Yes, use it for "something", such as driving your coworkers straight into madness.

  8. Anon says:

    Windows badly needs a setting/GPO/Whathaveyou that says "Prohibit any application which is not the currently focused window from programmatically altering the currently focused window under any and all circumstances."

    (If it was up to me, this would be an unalterable part of the UI.)

    I'm certain that I've never once been pleased that any window took focus away from the current window. I'm equally certain that I've never once encountered a circumstance where it was necessary or pertinent for any window that wasn't a child of the currently focused window to be granted focus.

  9. Danny says:

    A hook, huh? Funny, me being a fan of hooks and always preaching that if you want something done 100% sure eventually a hook will be the only approach, on various occasions here in the past comments, and you always saying a hook takes resources blah blah, hook is evil blah blah.

    [Hooks take resources, injected hooks are even worse, etc. But if your feature requires a hook, then the best you can do is choose the least expensive one. Out-of-context asynchronous accessibility hooks are the cheapest of the accessibility hooks, and are way cheaper than injected hooks. -Raymond]
  10. Skip says:

    I must be the only Windows user on the planet who runs silent most of the time. No speakers, no sounds, no music. Occasionally when my cubicle neighbors get oppressively loud, I'll remember that I have iTunes and ChatterBlocker installed, and dig up my headphones, but most of the time I'm not listening to anything at all.

  11. ChrisR says:

    @Anon:  One good use of focus stealing, that you may have found useful, is the debugger taking focus from the program being debugged when it hits a breakpoint.

  12. I wish there were many more sound events built into Windows. Although there have been some additions in each release, the events themselves are far too less. :)

  13. Joshua says:

    @Rodger: The app steals focus by spawning a new program that calls SetFocus. Microsoft can't block that. Users would revolt.

  14. voo says:

    @Danny Clearly if hooks are the solution to one problem, that means it's *not* stupid to abuse them in cases where other less intrusive, resource stealing solutions would work? I assume that's what you're trying to tell us?

  15. Deduplicator says:

    How about if the OS notes the the WindowStation(s) on which the parent had the focus, in addition to the time the process launched? Then deny SetFocus if not in magic time or parent did not have focus.

    The only problem I see is a process not owning the focus window even if it's the logical owner just then (think console app/helper app).

  16. Rodger says:

    This programs reminded me of how Comodo updater, a background app that steals focus when it runs and checks for updates.

    I reported the issue several years ago.

    Another company that doesn't know what to do with bug reports and feedback.

    This started me to think about how to block programs from stealing focus again. Implement some sort of dll that patches all the window stealing api's and either removes the focus stealing flags (filtering) or simply returns nops the api if the program is not allowed to steal focus.

    Sort of like how some firewall programs work.

    I wonder how many windows programs would break *cough* metro and office if I implemented this.

    Thoughts anyone?

  17. Georg Rottensteiner says:

    Windows could detect if the user is currently in a state of "writing text". In this mode not even a newly started app may receive focus.

    I don't dare to think on that many cases where this could go wrong though.

  18. Christian says:

    How does a programm even accomplish this Focus stealing?

    I certainly don't want to do it in my programms, but in order to understand how e.g. Rodger would want to block the API, I really wonder how it's actually done: Is it that one undocumented, now documented api call? Do these programms modify FlashTimeout registry keys? Use foreground?

    There must be some info about it somewhere, but I was not able to find it.

    And without knowing what's happening, one can't patch it away, e.g. with idapro.

  19. Neil says:

    A hack to make the program easier to close might be to display a message box (and you get a message loop for free!)

  20. Deduplicator says:

    AFAIK newly started programs (can) gain the focus for their start-window if they open it early enough, independent of their long-runnung demon parent, of which they are a logical part. Not sure if its automatic or on request…

    Multi-stealing is possible because this May-Force-Focus privilege is not rescinded on first use, but stays valid for the duration.

  21. >Multi-stealing is possible because this May-Force-Focus privilege is not rescinded on first use, but stays valid for the duration.

    May-Force-Focus privilege be with you.

  22. e says:

    >blogs.msdn.com/…/10452928.aspx

    >Windows could detect if the user is currently in a state of "writing text". In this >mode not even a newly started app may receive focus.

    I was thinking the same. Registry-configurable cool-down timer after writing during which non-user initiated programs can't become foreground. Also need to factor in the mouse somehow, although keyboard input is the larger problem.

    [This is what the foreground lock timeout tried to be, but people found holes in its initial implementation, and those holes are now de facto features. -Raymond]

Comments are closed.