For a project I am doing i need a console window to become the focus window when a hotkey is pressed. In this case it is F2. I have fixed the hotkey segment of the code now i need to have the console window become the focus.
I currently have:
import win32gui
import win32con, ctypes.wintypes, ctypes
def bringtofront():
#win32gui.ShowWindow(self, win32con.SW_MAXIMIZE) something like this?
print "now at the front!"
ctypes.windll.user32.RegisterHotKey(None, 1, 0, win32con.VK_F2)
while True:
try:
msg = ctypes.wintypes.MSG()
while ctypes.windll.user32.GetMessageA(ctypes.byref(msg), None, 0, 0) != 0:
if msg.message == win32con.WM_HOTKEY:
bringtofront()
ctypes.windll.user32.TranslateMessage(ctypes.byref(msg))
ctypes.windll.user32.DispatchMessageA(ctypes.byref(msg))
finally:
ctypes.windll.user32.UnregisterHotKey(None, 1)
Just to clarify the part of the code i am having trouble with is
win32gui.ShowWindow(self, win32con.SW_MAXIMIZE)
Based on https://msdn.microsoft.com/en-us/library/windows/desktop/ms633548%28v=vs.85%29.aspx it would seem you need to use SW_SHOWMAXIMIZED, although I haven't tried it...
Related
I have a console application written in python using pyinstaller. I need the program window to be hidden (if the user specified it), but at the same time it continued to work in the background, and when you click on the icon again, the previously hidden window just showed.
Usually such applications are displayed on the taskbar when you click on the arrow with the text - show hidden icons.
import win32gui
import win32con
def main():
while True:
c_out = input(f"Enter command: ")
if c_out.lower() == 'hide':
window('hide')
def window(mode: str):
the_program_to_hide = win32gui.GetForegroundWindow()
if mode == 'show':
win32gui.ShowWindow(the_program_to_hide, win32con.SW_SHOW)
else:
win32gui.ShowWindow(the_program_to_hide, win32con.SW_HIDE)
main()
I want to hook the left mouse button down event on any window, my code as following :
import win32gui
import win32ui
import win32con
def onMousePressed(self):
print('onMousePressed', win32gui.GetCursorPos())
def listener():
windowHandle = win32gui.WindowFromPoint(win32gui.GetCursorPos())
clickedWindow = win32ui.CreateWindowFromHandle(windowHandle)
clickedWindow.HookMessage(onMousePressed, win32con.WM_LBUTTONDOWN)
# print('-------------registerMouseEvent', clickedWindow)
while True:
listener()
However , the onMousePressed function was never called when clicked, what is wrong ?
P.S. I know some similar projects such as PyUserInput, mouse, pynput, just want to know why my code didn't work.
I was having trouble formatting the title of this question, because I wasn't sure I'm going about this the right way, so let me explain.
I want to try and add a right-click context menu to an existing program for which I don't have the source code. wxPython is generally my framework of choice. I figured there was a couple ways of doing this:
1) Create a transparent wx.Frame which is tied to and sits on top of the existing program, intercepting mouse events. If I did this, I wasn't sure if the mouse events could then be passed to the underlying window. I like this option, because it would allow adding more useful information in the overlay.
2) Create a headless program which globally intercepts right-click events, and spawns the context menu at the pointer location when certain conditions are met. Based on the research I've done so far, this didn't seem possible without continuously polling for mouse position.
What am I missing? Is there a more elegant solution for this? Is this even possible using Python?
edit: I have a partial proof-of-concept working which looks like this:
import wx
import win32gui
import win32api
import win32con
class POC_Frame(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent, id=wx.ID_ANY, title='POC', pos=(0,0), size=wx.Size(500, 500), style=wx.DEFAULT_FRAME_STYLE)
self.ToggleWindowStyle(wx.STAY_ON_TOP)
extendedStyleSettings = win32gui.GetWindowLong(self.GetHandle(), win32con.GWL_EXSTYLE)
win32gui.SetWindowLong(self.GetHandle(), win32con.GWL_EXSTYLE,
extendedStyleSettings | win32con.WS_EX_LAYERED | win32con.WS_EX_TRANSPARENT)
win32gui.SetLayeredWindowAttributes(self.GetHandle(), win32api.RGB(0,0,0), 100, win32con.LWA_ALPHA)
self.Bind(wx.EVT_RIGHT_DOWN, self.onRightDown)
self.Bind(wx.EVT_RIGHT_UP, self.onRightUp)
self.CaptureMouse()
def onRightDown(self, event):
print(event)
def onRightUp(self, event):
print(event)
app = wx.App(False)
MainFrame = POC_Frame(None)
MainFrame.Show()
app.MainLoop()
This seems to work OK, as it passes the right click events to the underlying window, while still recognizing them, but it only does it exactly once. As soon as it loses focus, it stops working and nothing I've tried to return focus to it seems to work.
I've always had better luck hooking global mouse and keyboard events with pyHook rather than wx. Here is a simple example:
import pyHook
import pyHook.cpyHook # ensure its included by cx-freeze
class ClickCatcher:
def __init__(self):
self.hm = None
self._is_running = True
self._is_cleaned_up = False
self._is_quitting = False
self.set_hooks()
# this is only necessary when not using wx
# def send_quit_message(self):
# import ctypes
# win32con_WM_QUIT = 18
# ctypes.windll.user32.PostThreadMessageW(self.pump_message_thread.ident, win32con_WM_QUIT, 0, 0)
def __del__(self):
self.quit()
def quit(self):
if not self._is_running:
return
self._is_quitting = True
self._is_running = False
if self.hm:
# self.hm.UnhookKeyboard()
self.hm.UnhookMouse()
# self.send_quit_message()
self._is_cleaned_up = True
def set_hooks(self):
self._is_running = True
self._is_cleaned_up = False
self.hm = pyHook.HookManager()
self.hm.MouseRightUp = self.on_right_click
# self.hm.HookKeyboard()
self.hm.HookMouse()
def on_right_click(self):
# create your menu here
pass
If you weren't using wx, you'd have to use pythoncom.PumpMessages to push mouse and keyboard events to you program, but App.Mainloop() accomplishes the same thing (if you use PumpMessages and Mainloop together about half of the events won't be push to your program).
Creating a wx.Menu is easy enough. You can find the mouse coordinates using wx.GetMousePosition()
I have a touchscreen laptop that folds back enough to become like a tablet. If I put it down on the table, I don't want to be hitting keys accidentally, so I'm working on a script to disable the keyboard when I hit Ctrl-F10 and then re-enable it when I do that again. I'm using xlib from PyPI, and I've gotten this so far:
from Xlib.display import Display
from Xlib.ext import xinput
class Handler:
def __init__(self, display):
self.enabled = True
self.display = display
def handle(self, event):
if event.data['detail'] == 76 and event.data['mods']['base_mods'] == 4:
if self.enabled:
self.display.grab_server()
else:
self.display.ungrab_server()
self.enabled = not self.enabled
try:
display = Display()
handler = Handler(display)
screen = display.screen()
screen.root.xinput_select_events([
(xinput.AllDevices, xinput.KeyPressMask),
])
while True:
event = display.next_event()
handler.handle(event)
finally:
display.close()
It does disable the keyboard on Ctrl-F10, but as soon as I re-enable, all the keys I pressed when it was disabled are activated all at once. Is there a way to clear the queue before re-enabling, or a better way to disable the keyboard?
Try XGrabKeyboard: https://tronche.com/gui/x/xlib/input/XGrabKeyboard.html
(But this requires you to create your own window for grabbing; you can e.g. create a window of size 1x1 at position -10x-10)
I think the values for things like owner_events and keyboard_mode do not matter much. The main effect should be that the input focus goes to your own window. time should be CurrentTime (which is 0) and pointer_mode should be GrabModeAsync, so that you do not interfere with the pointer.
I have a python script which uses selenium to automate web page, drawing focus away from the terminal where user input is required.
Is there anyway in python to switch focus back to the terminal, programmatically?
I will be running my program in the Windows Command Prompt on Windows 7, if it matters, but a cross platform answer would be most useful.
Attempts
Looking at the pywin32 package bindings for the win32 API I have the following:
import win32console
import win32gui
from selenium import webdriver as wd
d = wd.Firefox()
win32gui.SetFocus(win32console.GetConsoleWindow())
win32gui.FlashWindow(win32console.GetConsoleWindow(), False)
input('Should have focus: ')
SetFocus causes the error pywintypes.error: (5, 'SetFocus', 'Access is denied.') due to Microsoft removing the ability to take focus from another application.
FlashWindow appears to do nothing.
Here is what I came up with that seems to be working.
class WindowManager:
def __init__(self):
self._handle = None
def _window_enum_callback( self, hwnd, wildcard ):
if re.match(wildcard, str(win32gui.GetWindowText(hwnd))) != None:
self._handle = hwnd
#CASE SENSITIVE
def find_window_wildcard(self, wildcard):
self._handle = None
win32gui.EnumWindows(self._window_enum_callback, wildcard)
def set_foreground(self):
win32gui.ShowWindow(self._handle, win32con.SW_RESTORE)
win32gui.SetWindowPos(self._handle,win32con.HWND_NOTOPMOST, 0, 0, 0, 0, win32con.SWP_NOMOVE + win32con.SWP_NOSIZE)
win32gui.SetWindowPos(self._handle,win32con.HWND_TOPMOST, 0, 0, 0, 0, win32con.SWP_NOMOVE + win32con.SWP_NOSIZE)
win32gui.SetWindowPos(self._handle,win32con.HWND_NOTOPMOST, 0, 0, 0, 0, win32con.SWP_SHOWWINDOW + win32con.SWP_NOMOVE + win32con.SWP_NOSIZE)
shell = win32com.client.Dispatch("WScript.Shell")
shell.SendKeys('%')
win32gui.SetForegroundWindow(self._handle)
def find_and_set(self, search):
self.find_window_wildcard(search)
self.set_foreground()
Then to find a window and make it active you can...
w = WindowManager()
w.find_and_set(".*cmd.exe*")
This is in python 2.7, also here are some links I found to explain why you have to go through so much trouble to switch active windows.
win32gui.SetActiveWindow() ERROR : The specified procedure could not be found
Windows 7: how to bring a window to the front no matter what other window has focus?
This doesn't really answer your question, but the easy solution is to not take the focus away in the first place:
driver = webdriver.PhantomJS()
# ...
The PhantomJS webdriver doesn't have any UI, so does not steal the focus.
For getting focus, check the comments to this answer.
A cross-platform method could be to use Tkinter for the user GUI, as it has methods to grab and set focus for its windows.
If you don't care about clearing any figure displayed in the matplotlib frame -- which I believe is normally the case when one wants to get the focus back on the console for user input -- use simply this:
plt.close("all")