Answer the question
In order to leave comments, you need to log in
How to pass a key combination (CTRL+A, etc.) to an inactive window?
There was a need to transfer a key combination to an adjacent, not active and not minimized window.
In the case of transmitting single keystrokes, there were no problems, however, it hung with key combinations.
I read that a simple SendMessage / PostMessage is not enough to send a combination.
You also need to set the state of the keyboard, for which they use AttachThreadInput and SetKeyboardState .
AttachThreadInput works (if you really hold down the CTRL key in the active [ not Notepad ] window, then when the script is executed, text is selected in Notepad)
But SetKeyboardStateeither does not work or something else is needed, tk. instead of highlighting the text, the letter "a" is simply printed.
What could be the catch?
import ctypes, win32con, win32api, win32gui
import time
PBYTE256 = ctypes.c_ubyte * 256
_user32 = ctypes.WinDLL("user32")
GetKeyboardState = _user32.GetKeyboardState
SetKeyboardState = _user32.SetKeyboardState
MapVirtualKeyA = _user32.MapVirtualKeyA
AttachThreadInput = _user32.AttachThreadInput
oldKeyboardState = PBYTE256()
keyboardStateBuffer = PBYTE256()
GetKeyboardState(ctypes.byref(oldKeyboardState))
hwnd=0x000D1494 # hwnd окна Edit процесса notepad
current = win32api.GetCurrentThreadId()
key='A'
key=ord(key)
lparam = win32api.MAKELONG(0,MapVirtualKeyA(key, 0)) | 0x00000001
# | 0x00000001 прописал лишь потому что при перехвате нажатий вручную lparam отличался от генерируемого именно на этот последний бит, без | 0x00000001 результат работы скрипта абсолютно такой же
lparam_ctrl = win32api.MAKELONG(0,MapVirtualKeyA(win32con.VK_CONTROL, 0)) | 0x00000001
win32gui.SendMessage(hwnd, win32con.WM_ACTIVATE, win32con.WA_ACTIVE, 0)
AttachThreadInput(current, hwnd, True)
GetKeyboardState( ctypes.byref(oldKeyboardState) )
keyboardStateBuffer[win32con.VK_CONTROL] |= 128
SetKeyboardState( ctypes.byref(keyboardStateBuffer) )
time.sleep(0.1) # тестирования ради
win32api.PostMessage(hwnd, win32con.WM_KEYDOWN, win32con.VK_CONTROL, lparam_ctrl)
time.sleep(0.1)
win32api.PostMessage(hwnd, win32con.WM_KEYDOWN, key, lparam)
time.sleep(0.1)
win32api.PostMessage(hwnd, win32con.WM_KEYUP, key, lparam | 0xC0000000)
time.sleep(0.1)
win32api.PostMessage(hwnd, win32con.WM_KEYUP, win32con.VK_CONTROL, lparam_ctrl | 0xC0000000)
time.sleep(0.1)
SetKeyboardState( ctypes.byref(oldKeyboardState) )
time.sleep(0.1)
AttachThreadInput(current, hwnd, False)
Answer the question
In order to leave comments, you need to log in
Found a solution:
import ctypes, time, win32con, win32api, win32gui
PBYTE256 = ctypes.c_ubyte * 256
_user32 = ctypes.WinDLL("user32")
GetKeyboardState = _user32.GetKeyboardState
SetKeyboardState = _user32.SetKeyboardState
PostMessage = win32api.PostMessage
SendMessage = win32gui.SendMessage
FindWindow = win32gui.FindWindow
IsWindow = win32gui.IsWindow
GetCurrentThreadId = win32api.GetCurrentThreadId
GetWindowThreadProcessId = _user32.GetWindowThreadProcessId #очень важно брать функцию из dll, т.к. питоновский враппер (win32process.GetWindowThreadProcessId) выдаёт неправильные значения
AttachThreadInput = _user32.AttachThreadInput
MapVirtualKeyA = _user32.MapVirtualKeyA
MapVirtualKeyW = _user32.MapVirtualKeyW
MakeLong = win32api.MAKELONG
w = win32con #так короче запись
def PostKeyEx( hwnd, key, shift, specialkey):
if IsWindow(hwnd):
ThreadId = GetWindowThreadProcessId(hwnd, None)
lparam = MakeLong(0, MapVirtualKeyA(key, 0))
msg_down=w.WM_KEYDOWN
msg_up=w.WM_KEYUP
if specialkey:
lparam = lparam | 0x1000000
if len(shift) > 0: #Если есть модификаторы - используем PostMessage и AttachThreadInput
pKeyBuffers = PBYTE256()
pKeyBuffers_old = PBYTE256()
SendMessage(hwnd, w.WM_ACTIVATE, w.WA_ACTIVE, 0)
AttachThreadInput(GetCurrentThreadId(), ThreadId, True)
GetKeyboardState( ctypes.byref(pKeyBuffers_old ))
for modkey in shift:
if modkey == w.VK_MENU:
lparam = lparam | 0x20000000
msg_down=w.WM_SYSKEYDOWN
msg_up=w.WM_SYSKEYUP
pKeyBuffers[modkey] |= 128
SetKeyboardState( ctypes.byref(pKeyBuffers) )
time.sleep(0.01)
PostMessage( hwnd, msg_down, key, lparam)
time.sleep(0.01)
PostMessage( hwnd, msg_up, key, lparam | 0xC0000000)
time.sleep(0.01)
SetKeyboardState( ctypes.byref(pKeyBuffers_old) )
time.sleep(0.01)
AttachThreadInput(GetCurrentThreadId(), ThreadId, False)
else: #Если нету модификаторов - используем SendMessage
SendMessage( hwnd, msg_down, key, lparam)
SendMessage( hwnd, msg_up, key, lparam | 0xC0000000)
hwnd=FindWindow("Notepad", None)
PostKeyEx(hwnd,ord('A'),[w.VK_CONTROL],False)
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question