So what I need do to is periodically change the active window, my issue is that they all have the same name and using their HWND only works for the first window. Besides that i'd like to not have to insert it's HWND everytime
import win32gui, time
def main():
while(1):
win32gui.SetForegroundWindow(788574)#win2
side()
time.sleep(5)
def side():
while(1):
win32gui.SetForegroundWindow(3147934)#win1
main()
time.sleep(5)
if __name__ == '__main__':
main()
To cycle through selected windows, there's a few steps:
Use win32gui.EnumWindows to go through all open windows
Use win32gui.GetWindowText to get the title bar text from a window
Use win32com.client.Dispatch and SendKeys to activate the switch process
Use win32gui.SetForegroundWindow to select the window to activate
Here's the code:
import win32com.client as win32
import win32gui
import time
title = "Untitled - Notepad2" # cycle all windows with this title
def windowEnumerationHandler(hwnd, top_windows):
top_windows.append((hwnd, win32gui.GetWindowText(hwnd)))
top_windows = [] # all open windows
win32gui.EnumWindows(windowEnumerationHandler, top_windows)
winlst = [] # windows to cycle through
for i in top_windows: # all open windows
if i[1] == title:
winlst.append(i)
for x in range(5): # cycle 5 times
for w in winlst: # each window with selected title
shell = win32.Dispatch("WScript.Shell") # set focus on desktop
shell.SendKeys('%') # Alt key
win32gui.SetForegroundWindow(w[0]) # bring to front, activate
time.sleep(2) # 2 seconds
Related
My program pops up a window every time the user presses F2 (in any application).
I'm using pynput to capture the F2 button (works ok)
I'm using tkinter to create the popup window (works ok)
I'm using win32gui.SetForegroundWindow(windowHandel) to bring the tkinter window to the front and set the focus. And there is the problem.
If the python windows is selected when I press F2, everything works ok, and the tkinter window both moves to front and gets focus.
BUT - if any other window is selected when I press F2, the tkinter window does moves to the front, but it is not selected (i.e. focused).
Here is the relevant section from the code (find full code below):
while not windowFound and counter < MAX_TRIES_TO_FIND_THE_FLIPPER_WINDOW:
try:
windowHandel = win32gui.FindWindow(None, windowName)
win32gui.SetForegroundWindow(windowHandel)
except:
windowFound = False
else:
print("Success, Window found on the " + str(counter + 1) + " tries")
windowFound = True
After looking for an answer for a while, I found someone saying that this can be solved by using win32process. So I tried adding:
windowHandelID, _ = win32process.GetWindowThreadProcessId(windowHandel)
win32process.AttachThreadInput(win32api.GetCurrentThreadId(), windowHandelID, True)
win32gui.SetFocus(windowHandel)
Yet, it resulted in the same behavior.
Here below is the full (simplified, without exit conditions) code.
Try pressing F2 while pythong is focused.
And then try pressing F2 while any other window (e.g. notepad) is focused.
You'll see that in one case you can just start writing and the tkinter window will receive the input while in the other case, you'll still have to click the window.
I'd appreciate any help or suggestions.
import pyautogui # For keyboard shortcuts and moving the cursor and selecting the window
import time # For the delay function
from pynput import keyboard # For catching keyboard strokes
import tkinter # GUI
import threading # For Threading
import win32gui # For Setting Focus on the Flipper Window
import win32process
import win32api
# Resetting Variables / Settings
start_flipping_text_sequence = False
ContinueThreads = True
SearchForFlipperWindow = False
window_name = "tk"
MAX_TRIES_TO_FIND_THE_FLIPPER_WINDOW = 10
# This function runs in a separate thread
def selectFlipperWindow(windowName):
# Since the thread runs constantly, it will only start looking for the flipper window when this variable is True
global SearchForFlipperWindow
# How many loops should the program go through before it gives up on finding the window
global MAX_TRIES_TO_FIND_THE_FLIPPER_WINDOW
# While program was not ended
while True:
# This is False, unless F2 is pressed
if SearchForFlipperWindow:
# Did the program find the flipper window
windowFound = False
counter = 0
while not windowFound and counter < MAX_TRIES_TO_FIND_THE_FLIPPER_WINDOW:
try:
windowHandel = win32gui.FindWindow(None, windowName)
win32gui.SetForegroundWindow(windowHandel)
except:
windowFound = False
else:
print("Success, Window found on the " + str(counter + 1) + " tries")
windowHandelID, _ = win32process.GetWindowThreadProcessId(windowHandel)
win32process.AttachThreadInput(win32api.GetCurrentThreadId(), windowHandelID, True)
win32gui.SetFocus(windowHandel)
windowFound = True
counter += 1
time.sleep(0.1)
SearchForFlipperWindow = False
time.sleep(0.1)
# Execute functions based on the clicked key
def on_press(key):
global start_flipping_text_sequence
# If the user pressed the F2 key
if key == keyboard.Key.f2:
start_flipping_text_sequence = True
def okButton():
root.destroy()
def enter(event):
okButton()
# Assigning event to function
listener = keyboard.Listener(on_press=on_press)
# initiating listener
listener.start()
# Start a thread for searching for the flipper window
selectWindowThread = threading.Thread(target=selectFlipperWindow, args=(window_name,))
selectWindowThread.start()
while 1 == 1:
time.sleep(.05)
if start_flipping_text_sequence:
SearchForFlipperWindow = True
root = tkinter.Tk()
tk_window_input = tkinter.Entry(root, width=100)
tk_window_input.pack(padx=20)
tk_window_input.focus()
# Binds the OK button to the okButton function above
tk_window_ok = tkinter.Button(root, width=20, text="OK", command=okButton)
tk_window_ok.pack(pady=20)
# Binds the "Enter" keyboard key to the "enter" event above
tk_window_input.bind('<Return>', enter)
# the main looper of the tkinter window
# runs until root.destroy() to executed above
root.mainloop()
start_flipping_text_sequence = False
```
What you see is an intentional restriction in Windows. The restriction is described by Raymond Chen in article Foreground activation permission is like love: You can’t steal it, it has to be given to you. Remarks section of the SetForegroundWindow documentation gives more technical details about the restriction.
There are ways to be exempt from the restriction. One good way to do so is described by Raymond Chen in article Pressing a registered hotkey gives you the foreground activation love.
The following code shows one more, strange way to bypass the restriction:
kbd.press(keyboard.Key.alt)
try:
win32gui.SetForegroundWindow(windowHandel)
finally:
kbd.release(keyboard.Key.alt)
where kbd was created like this:
from pynput.keyboard import Controller
kbd = Controller()
Here is an explanation why this workaround works: link.
A good way to get rid of this workaround may be to require a user to press Alt-F2 in order to switch to your application.
Good luck with coding ;-)
the problem i am trying to solve is when the user starts the program , a file explorer opens. if the user exist the window i want to ask the user if they want to quit the program y or n.
from tkinter.filedialog import askdirectory
import pyinputplus as py
def get_location_path():
while True:
path = askdirectory(title='Select Folder') # shows dialog box and return the path to the folder the user picks
if path == '':
y = py.inputYesNo("would you like to quit the program? ")
if y == 'yes':
break
if y == 'no':
continue
else:
return path
y = get_location_path()
print(y)
when i run the program and i exist the window without picking a folder, it will ask me if i want to quit the program, if i type y it quits the program but if i type n it does nothing and i cant even exist the program by pressing CTRL + C
enter n:
would you like to quit the program? n
empyty space
I've had to add some code to get your code to work as a tkinter app - it seems like you want this to run as a command line app which isn't what tkinter is for; however, I've tried to come up with a solution that uses tkinter since that's how this question is tagged.
import tkinter as tk
# import pyinputplus as py # (you don't need this if using tkinter)
from tkinter import messagebox as tkm # use native tkinter dialogs instead
from tkinter.filedialog import askdirectory
class App(tk.Tk):
def __init__(self):
super().__init__(). # initialize tk
self.title('My App')
self.geometry('640x480')
self.path = '' # create a variable to store the path
self.get_location_path() # prompt the user for a path
def get_location_path(self):
self.path = askdirectory(title='Select Folder') # show file dailog
if self.path: # if a path is selected...
self.use_location_path() # do whatever needs to be done with the path
elif ( # no path selected; ask the user if they want to quit
tkm.askyesno(
title='Exit Program?',
message='Would you like to quit the program?'
)
):
self.destroy() # yes, quit
else:
self.get_location_path() # no, ask for path again
def use_location_path(self):
print(self.path) # do some work...
self.destroy() # quit once the work is done
if __name__ == '__main__':
App().mainloop() # run the app
I'm working on an automation program in python, I've two windows of cmd open on my screen. I want my code to only close the first window, and leave the second window as it is. How will I make my code determine which window to close?
To close the window I'm using the keyboard package in python, the code writes exit in the cmd window and generates an enter key press to exit the window.
keyboard.write("exit") # closes main cmd window
keyboard.press_and_release("enter") # window closes
If you use Windows OS, you can use the pywin32 and win32gui libraries which contain the modules win32gui and win32con which will help search through windows matching a certain name and getting the window handle number (hwnd). Given a hwnd, you can then close the first window that was opened.
You will first need to install pywin32 and wind32gui:
pip install win32gui
pip install pywin32
Here's the code to close the first command prompt window:
import win32gui
import win32con
def windowEnumerationHandler(hwnd, top_windows):
top_windows.append((hwnd, win32gui.GetWindowText(hwnd)))
def return_window_hwnd(window_name):
'''Return list window handles of that match a given window name'''
windows = []
win32gui.EnumWindows(windowEnumerationHandler, windows)
print(windows) #[(67084, 'Command Prompt'), (65868, ''), (722426, 'Command Prompt'), ...]
hwnds = []
for wind in windows:
if window_name in wind[1] or window_name == wind[1]:
hwnds.append(wind[0])
return hwnds
# search for Command Prompt windows and return the list of hwnd
command_hwnd_arr = return_window_hwnd('Command Prompt')
# if more than 1 is window open, close the first opened window
if len(command_hwnd_arr) > 1:
window_handle_to_close = command_hwnd_arr[1]
win32gui.PostMessage(window_handle_to_close, win32con.WM_CLOSE, 0, 0)
I'm trying to listen for mouse click events on task bar app icons for currently running apps in windows using python. In the example below, I use python to initiate the internet explorer application. After the app initiates, I then use the FindWindow windows API function to get the window ID/handle.
Is there a way to listen for mouse clicks on the internet explorer task bar icon by the user using windows API or some other method? I need to print a message when the IE icon in the task bar is clicked.
Here is the code I am working with currently:
from win32gui import GetWindowText, GetForegroundWindow, FindWindow
import win32api, win32gui
import win32con
import sys, os
os.system('"C:\Program Files (x86)\Internet Explorer\iexplore.exe"') #open internet explorer application.. this will make the internet explorer icon appear in the taskbar..
window_id = FindWindow(0, 'Internet Explorer') #find the newly opened IE window's id/handle
print (window_id)
class test:
def __init__(self, **kwargs):
super(test, self).__init__(**kwargs)
self.oldWndProc = win32gui.SetWindowLong(window_id, win32con.GWL_WNDPROC, self.MyWndProc)
self.msgdict = {}
for name in dir(win32con):
if name.startswith("WM_"):
value = getattr(win32con, name)
self.msgdict[value] = name
print (self.msgdict) #I can access all the win32 window events using this dictionary..
#listener to track win32 window events related to the newly opened internet explorer window..
#how do I track when the internet explorer icon is CLICKED in the task bar??
def MyWndProc(self, hWnd, msg, wParam, lParam):
print (self.msgdict.get(msg)) #none of the window events print here..
return win32gui.CallWindowProc(self.oldWndProc, hWnd, msg, wParam, lParam)
t = test()
Try to use UI Automation.
The window class name of the taskbar is MSTaskListWClass:
And you can also see the UIA element and its BoundingRectangle from inspect.exe:
You could first get the click event on desktop and then get the task icon's IUIAutomationElement, then use GetClickablePoint to determine whether the click is on the element.
Thanks to Drake Wu pointing me in the right direction, I was able to use python to get UI Automation info about the element that is clicked and its parent. Using that information, I can tell that an app icon in the taskbar is clicked when the ControlType of the element clicked is 'ButtonControl' and the class name of its parent is 'MSTaskListWClass'. You can figure out which application was clicked by looking at the Automation ID of the clicked element.
You need to pip install uiautomation for this example. I had to add a few additional functions/methods to the uiautomation.py file because it was missing functions that were needed.
Here are the methods that I added to the uiautomation.py file to make it more useful for this example (see where it says NEW CODE HERE):
def ControlFromPoint(x: int, y: int) -> Control:
"""
Call IUIAutomation ElementFromPoint x,y. May return None if mouse is over cmd's title bar icon.
Return `Control` subclass or None.
"""
element = _AutomationClient.instance().IUIAutomation.ElementFromPoint(ctypes.wintypes.POINT(x, y))
return Control.CreateControlFromElement(element)
#NEW CODE HERE
def GetElementFromPoint(x: int, y: int) -> Control: #gets the element from a point (x, y)
element = _AutomationClient.instance().IUIAutomation.ElementFromPoint(ctypes.wintypes.POINT(x, y))
return element
#NEW CODE HERE
def GetParentElement(element): #gets the parent of an element input
parent_element = _AutomationClient.instance().ViewWalker.GetParentElement(element)
return parent_element
#NEW CODE HERE
def GetElementInfo(element): #gets the property information about an element
element_info = Control.CreateControlFromElement(element)
return element_info
I then utilized these newly added uiautomation methods in the main example below:
import sys, os
from pynput import mouse
from pynput.mouse import Controller
from pynput.mouse import Listener
import uiautomation
from uiautomation import GetElementFromPoint, GetParentElement, GetElementInfo #these are newly added methods to make this example work
mouse2 = mouse.Controller()
class test:
last_mouse_pos_x = ''
last_mouse_pos_y = ''
def __init__(self, **kwargs):
super(test, self).__init__(**kwargs)
self.mouse_listener() #start mouse listener
def mouse_listener(self):
global element_clicked
while True:
if mouse2.position[0] != test.last_mouse_pos_x or mouse2.position[1] != test.last_mouse_pos_y:
element_clicked = uiautomation.GetElementFromPoint(mouse2.position[0], mouse2.position[1]) #returns the element that you clicked (this has to run here or it errors)
test.last_mouse_pos_x = mouse2.position[0]
test.last_mouse_pos_y = mouse2.position[1]
def on_click(x, y, button, pressed):
if pressed:
try:
element_clicked_info = GetElementInfo(element_clicked) #returns info about the element you clicked
parent_of_element_clicked = uiautomation.GetParentElement(element_clicked) #returns the parent of the element that you clicked
parent_of_element_clicked_info = GetElementInfo(parent_of_element_clicked) #returns info about the parent of the element you clicked
#print info about the element you clicked and its parent
print ("ELEMENT CLICKED INFO: " + str(element_clicked_info))
print ("PARENT ELEMENT INFO: " + str(parent_of_element_clicked_info))
except:
pass #skip over any errors
#ANALYSIS: If ControlType of element clicked = 'ButtonControl' AND class name of its parent = 'MSTaskListWClass', then an app icon in the taskbar was clicked!
listener = mouse.Listener(on_click=on_click)
listener.start()
t = test()
I'm looking for a way to find out what order windows are open on my desktop in order to tell what parts of what windows are visible to the user.
Say, in order, I open up a maximized chrome window, a maximized notepad++ window, and then a command prompt that only covers a small portion of the screen. Is there a way using the win32api (or possibly other library) that can tell me the stack of windows open so I can take the window dimensions and find out what is visible? I already know how to get which window has focus and the top-level window, but I'm looking for more info than that.
In the example I mentioned above, I'd return that the full command prompt is visible but in the places it isn't, the notepad++ window is visible for example. No part of the chrome window would be visible.
import win32gui
import win32con
def get_windows():
def sort_windows(windows):
sorted_windows = []
# Find the first entry
for window in windows:
if window["hwnd_above"] == 0:
sorted_windows.append(window)
break
else:
raise(IndexError("Could not find first entry"))
# Follow the trail
while True:
for window in windows:
if sorted_windows[-1]["hwnd"] == window["hwnd_above"]:
sorted_windows.append(window)
break
else:
break
# Remove hwnd_above
for window in windows:
del(window["hwnd_above"])
return sorted_windows
def enum_handler(hwnd, results):
window_placement = win32gui.GetWindowPlacement(hwnd)
results.append({
"hwnd":hwnd,
"hwnd_above":win32gui.GetWindow(hwnd, win32con.GW_HWNDPREV), # Window handle to above window
"title":win32gui.GetWindowText(hwnd),
"visible":win32gui.IsWindowVisible(hwnd) == 1,
"minimized":window_placement[1] == win32con.SW_SHOWMINIMIZED,
"maximized":window_placement[1] == win32con.SW_SHOWMAXIMIZED,
"rectangle":win32gui.GetWindowRect(hwnd) #(left, top, right, bottom)
})
enumerated_windows = []
win32gui.EnumWindows(enum_handler, enumerated_windows)
return sort_windows(enumerated_windows)
if __name__ == "__main__":
windows = get_windows()
for window in windows:
print(window)
print()
# Pretty print
for window in windows:
if window["title"] == "" or not window["visible"]:
continue
print(window)
Microsoft MSDN has good artice on zorder info with GetWindow() and GW_HWNDNEXT
https://msdn.microsoft.com/en-us/library/windows/desktop/ms633515(v=vs.85).aspx