asweigart/PyGetWindow

Window.activate() not working in Jupyter Notebook

DleanJeans opened this issue · 12 comments

Works fine in a cmd but when I run it on a Jupyter Notebook (Colab local runtime):

import pyautogui
pyautogui.getWindowsWithTitle('Code')[0].activate()

VSCode flashes on the taskbar but never activated.
image

Strangely if I focus the window first with pywinauto:

import pywinauto
pywinauto.application.Application().connect(best_match='Code').top_window().set_focus()

then it would work normally, until I restarted the notebook. This only affects one window, other windows have to be focused with pywinauto before being able to be activated with pygetwindow.

Kernel output:

---------------------------------------------------------------------------
PyGetWindowException                      Traceback (most recent call last)
<ipython-input-2-f7654fe7bc43> in <module>()
      1 
      2 import pyautogui
----> 3 pyautogui.getWindowsWithTitle('Code')[0].activate()

c:\users\dleanjeans\appdata\local\programs\python\python36\lib\site-packages\pygetwindow\_pygetwindow_win.py in activate(self)
    282         result = ctypes.windll.user32.SetForegroundWindow(self._hWnd)
    283         if result == 0:
--> 284             _raiseWithLastError()
    285 
    286 

c:\users\dleanjeans\appdata\local\programs\python\python36\lib\site-packages\pygetwindow\_pygetwindow_win.py in _raiseWithLastError()
     95     information from GetLastError() and FormatMessage()."""
     96     errorCode = ctypes.windll.kernel32.GetLastError()
---> 97     raise pygetwindow.PyGetWindowException('Error code from Windows: %s - %s' % (errorCode, _formatMessage(errorCode)))
     98 
     99 

PyGetWindowException: Error code from Windows: 0 - The operation completed successfully.

I'm seeing the same thing in Windows simply trying to connect to a Notepad window. I'm using click on the window to achieve an activation instead

fw = pyautogui.getWindowsWithTitle('Notepad')
fw = fw[0]
fw.maximize()
pyautogui.click(fw.center); pyautogui.write('abc', 0.01)

Hello guys,

I have encountered the same issue and I'm sorry if my anwser/workaround looks novice but thats what I am so yeah.

Searching for the reason why this happens I fell down the rabbit whole but I think I some what have an anwser but unfortunately I did not find the sollution.
Any how what appears to be happening that it does not find a procces/window to foccus on when the funtion is called. Just the program. Once you use the following as an example:

import pywinauto
import pygetwindow as gw
def focus_to_window(window_title=None):
    window = gw.getWindowsWithTitle(window_title)[0]
    if window.isActive == False:
        pywinauto.application.Application().connect(handle=window._hWnd).top_window().set_focus()

It now seems to bee connected to the procces. after a function like this it seems that the .activate() function seems to work perfectly fine since its pointed to that procces. Until it is minimized because there in no window to focus on.

I have tested it with multiple windows of notepad and looks like it keeps connected to one specific window since "its pointed" to there to bring it to the foreground.

Hopefully I can find the precise reason and get a fully working sollution instead of a workaround

cheers

I use the following workaround:

<import` pygetwindow, mouse

def activate(win):
win.restore()
mouse.move(*win.center)
mouse.click(button='left')>

type(win)
<class 'pygetwindow._pygetwindow_win.Win32Window'>
``

hicpg commented

Please try run Application with administrator privileges in Windows10.
This may solve activate error.

I'm not pretty sure why this happens, but I also have a workaround that may look cleaner:

import pygetwindow as gw
hwnd = gw.getWindowsWithTitle('Notepad')
if hwnd != []:
    try:
        hwnd[0].activate()
    except:
        hwnd[0].minimize()
        hwnd[0].maximize()

What we do here is try to activate the desired window, then, if this fails, minimize and maximize the same window. No need to import extra libraries or complicated procedures.

I'm not pretty sure why this happens, but I also have a workaround that may look cleaner:

import pygetwindow as gw
hwnd = gw.getWindowsWithTitle('Notepad')
if hwnd != []:
    try:
        hwnd[0].activate()
    except:
        hwnd[0].minimize()
        hwnd[0].maximize()

What we do here is try to activate the desired window, then, if this fails, minimize and maximize the same window. No need to import extra libraries or complicated procedures.

This works great! the only thing I'd add is that I also used hwnd[0].restore() at the end, because my program isn't maximized. So now it works great!

What worked for me was:

import pyautogui as pag

WINDOW_NAME = "WINDOW NAME OF YOUR APP"

app_window = pag.getWindowsWithTitle(WINDOW_NAME)
if len(app_window) > 0:
        print("Application is running...")
    else:
        print("Application is not running...")
        return False

if app_window[0].isActive == False:
        pag.click(app_window[0].activate())
        print("Brought window application to the foreground.")
    else:
        print("Application already in foreground.")
        
    return True

The trick was the pag.click(app_window[0].activate()) part.

hwnd = gw.getWindowsWithTitle('Notepad')
if hwnd != []:
try:
hwnd[0].activate()
except:
hwnd[0].minimize()
hwnd[0].maximize()

This actually works, Thanks Man

mkq10 commented

I'm not pretty sure why this happens, but I also have a workaround that may look cleaner:

import pygetwindow as gw
hwnd = gw.getWindowsWithTitle('Notepad')
if hwnd != []:
    try:
        hwnd[0].activate()
    except:
        hwnd[0].minimize()
        hwnd[0].maximize()

What we do here is try to activate the desired window, then, if this fails, minimize and maximize the same window. No need to import extra libraries or complicated procedures.

It worked. thanks

The trick was the pag.click(app_window[0].activate()) part.

This didn't work for me as written but it got me over the hump and yours lead to what I think is the most elegant solution. You don't need to minimize, maximize, check if activated. You just need to click() and activate().

import pygetwindow as gw
import pyautogui as ag

for window in gw.getWindowsWithTitle(''):
... loop and regex to the window you want ...
ag.click()
window.activate()

Many thanks

5yes commented

#36 (comment)

window.minimize()
window.restore()

window.minimize() is used to minimize the specified window, hiding it in the taskbar or system tray.
window.restore() is used to restore a minimized window to its normal state, bringing it back from the taskbar or system tray and displaying it again on the screen.

LLego años tarde y en español pero esto funciono para mi
Agreguen el envio de ese cartacter antes de cambiar el foco.
Todos los creditos a los sabios de aqui https://stackoverflow.com/questions/14295337/win32gui-setactivewindow-error-the-specified-procedure-could-not-be-found

import win32gui, win32com.client
shell = win32com.client.Dispatch("WScript.Shell")
shell.SendKeys('%')
win32gui.SetForegroundWindow(window)