Preamble
It so happened that I have long used Logitech mice - MX300 and MX310. They have an extra button above the wheel, on which you can hang various functions. In the old drivers (MouseWare), among these functions was the “Recall Application”, which was switched over to the previous active window - about the same as what happens if you press Alt + Tab once. I immediately liked this opportunity: often there is a situation when you need to switch to some window, do something there (for example, copy a line) and go back (respectively, to paste this copied line). Alt + Tab in this case is less convenient (because the left hand should be removed from the combination Ctrl + C, and then returned to its previous position to press Ctrl + V).
But here I set myself Windows XP x64, and it turned out that MouseWare for 64-bit systems is inaccessible. For the MX310, a more modern SetPoint utility was found, but the “Recall Application” function is no longer there. Fortunately, we managed to adjust the sending of the Alt + Tab shortcut to the desired button, but the flashing of the task list window at the time of switching was a bit annoying. So, having overcome laziness, I was honored to write a small utility that helped eliminate this drawback.
Ambula
In fact, only one thing was required of the utility: hang in the background and, upon receiving a signal to press a button, switch to the “neighboring” window. The problem was not so trivial, as I assumed at first. The signal to press the button directly cannot be obtained, since the list of available actions in SetPoint does not contain such an action “send a signal to press the sixth button”. So I had to cheat a little bit: by pressing a button, emulate some keyboard shortcut, and the program has already caught this combination. Naturally, you need to choose something that is not used in normal work; I chose Ctrl + Alt + Shift + Z.
The second difficulty was choosing the right window. You can navigate through the Z-stack of applications by calling GetWindow (hwnd, GW_HWNDNEXT), but among these windows there are a large number of those that do not need to be switched. For example, invisible. Even if you leave only visible windows, there are many other top-level windows that are not in the regular Alt + Tab list. Here I could not find a satisfactory solution. One option was able to google
Stack overflow , but I didn’t get it right with the enumeration of windows. There are also
TaskSwitchXP source
files , but the attempt to adapt the code to my needs failed (extra windows appeared in the list). I couldn’t figure it out completely in the code, so either I did something wrong, or the code was not originally designed for such inappropriate use. (However, I will continue to deal with it.) In the end, I conducted my own research and determined the empirical conditions for choosing the “right” windows (I will list these conditions at the end). The resulting program code fit on one page:
')
int WinMainCRTStartup(void) { if (!RegisterHotKey(NULL, 0, MOD_CONTROL | MOD_SHIFT | MOD_ALT, 'Z')) return 1; MSG msg = {0}; while (GetMessage(&msg, NULL, 0, 0)) { if (msg.message == WM_HOTKEY) { HWND current_wnd = GetForegroundWindow(); if (current_wnd == NULL) continue;
Small technical comments
- The function is called WinMainCRTStartup , because CRT is not involved here, so I turned it off. As a result, the compiled program takes 3072 bytes. More information about this can be found on the RSDN .
- The empirical conditions for choosing the “right” window are as follows. The window should:
- be visible;
- Do not have an extended style WS_EX_TOOLWINDOW ;
- the owner window for this window must be missing or invisible.
- The first cycle (search for the “root” owner window) is needed to cope with the situation when the current window is the “wrong” window. For example, in the ABBYY Lingvo program, all windows, including card windows, are “wrong”: these are top-level windows, and each of them is owned by some fictitious window that has a visibility flag, but with zero dimensions. If the current window is such a window card, then the GetWindow loop (current_wnd, GW_HWNDNEXT) first of all gets into this most fictitious Lingvo window and, since it is formally “correct,” activates it. Those. switching to another application does not occur. It would be possible to use GetAncestor (current_wnd, GA_ROOTOWNER) instead of a loop, but in this case the visibility of the windows is not taken into account and the result is incorrect.
- Unfortunately, this heuristic algorithm is not perfect. In particular, it works incorrectly with Excel 2003 windows (it is easy to loop in one window). True, this is partly the fault of Excel itself, which organizes windows in some completely unintelligible way, so even the standard Alt + Tab can loop on one window and you need to double-press Tab to skip this cycle. With this mystery, I still plan to sort out. You also need to be careful with virtual machines, because in the case of intercepting keyboard input the key combination will go to the virtual machine and not to the host system.
- In the current version of the correct exit from the program is not provided (therefore, generally speaking, the UnregisterHotKey call at the end of the program is superfluous, but I left it for beauty :-)). If you want to periodically terminate the program, and you don’t want to kill the process, you can add another global keyboard shortcut registration, and in the message processing loop, check which combination was pressed, and if it is not Ctrl + Alt + Shift + Z, - exit the loop.