I'm implementing a task-bar replacement, dock-like application-switcher style program. It's doing some unique stuff with OpenGL, and with keyboard shortcuts, so the way it's set up, the window doesn't always have focus. I'd like to implement it such that I can bring an arbitrary window to the foreground, much like a taskbar or an ALT-TAB program would.
However, my code simply causes the application icon to flash in the taskbar. The Windows API documentation says that this is what is supposed to happen, but I'm looking for a way to work around this.
I've adapted my code from the following examples, which say that attaching to the foreground thread should allow you to set the foreground window. Here are the sites:
http://www.voidnish.com/Articles/ShowArticle.aspx?code=dlgboxtricks
http://invers2008.blogspot.com/2008/10/mfc-how-to-steal-focus-on-2kxp.html
My code looks like this. Note that it's using the win32 wrappers for python (self.hwnd is the handle of the window I want to bring to the front):
fgwin = win32gui.GetForegroundWindow() fg = win32process.GetWindowThreadProcessId(fgwin)[0] current = win32api.GetCurrentThreadId() if current != fg: win32process.AttachThreadInput(fg, current, True) win32gui.SetForegroundWindow(self.hwnd) win32process.AttachThreadInput(fg, win32api.GetCurrentThreadId(), False)
However, unless my window is the foreground window (which it isn't usually), this just causes the program's icon to flash.
Am I doing the thread attaching wrong? Is there another way to work around this? I figure there must be, as there are lots of application switchers out there that seem to be able to do this just fine.
I'm writing this in python, but if there is a solution in another language I will use wrappers or do whatever is necessarry to get this up and running.
Thanks in advance!
EDIT: I'd be open to a way to make it work only on my particular computer, i.e. a way to enable, on my machine, a way for any application to take focus.
Instead of clicking on the picture, just clicking on the icon in the taskbar, should bring the opened app to the foreground.
This activity allows you to set focus to an already open application window brining the window to forefront. You must use this activity before any other activity that requires the window to be in focus to perform the configured action. This activity is especially used with image or surface automation.
Switch Between Windows Using Selenium Python WebDriver supports moving between these windows using the “switch_to_window()” method. Webdriver will now interpret all calls to the driver to be coming from the above window.
I don't like these suggestions of using win32gui
because you can't easily install that via pip
. So here's my solution:
First, install pywinauto
via pip
. If you're on Python 2.7.9 or a newer version on the 2 branch, or Python 3.4.0 or a newer version from the 3 branch, pip
is already installed. For everyone else, update Python to get it (or you can manually download and install it by running this script, if you must run an older version of Python.)
Just run this from the command line (not from within Python):
pip install pywinauto
Next, import what you need from pywinauto
:
from pywinauto.findwindows import find_window from pywinauto.win32functions import SetForegroundWindow
Finally, it's just one actual line:
SetForegroundWindow(find_window(title='taskeng.exe'))
I've had some code that's been running for years, going all the way back to Windows 95. When double clicking the applications system tray icon I always used Win32 API functions such as BringWindowToTop and SetForegroundWindow to bring my application windows to the foreground. This all stopped working as intended on Windows 7, where my input window would end up behind other windows and the window icon would flash on the status bar. The 'work around' that I came up with was this; and it seems to work on all versions of Windows.
//-- show the window as you normally would, and bring window to foreground. // for example; ::ShowWindow(hWnd,SW_SHOW); ::BringWindowToTop(hWnd); ::SetForegroundWindow(hWnd); //-- on Windows 7, this workaround brings window to top ::SetWindowPos(hWnd,HWND_NOTOPMOST,0,0,0,0, SWP_NOMOVE | SWP_NOSIZE); ::SetWindowPos(hWnd,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE); ::SetWindowPos(hWnd,HWND_NOTOPMOST,0,0,0,0,SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With