Событие клавиатуры не отправлено в окно с pywin32 - PullRequest
0 голосов
/ 14 декабря 2018

Я написал код, который получает HWND от любой программы, которую я хочу.Вот так я и получил hwnd, если вы спрашиваете.

Следующий код должен вызвать диспетчер устройств и отправить стрелку вниз в программу.

Но это не так.Он вызывает диспетчер устройств, но не отправляет в клавиатуру клавишу со стрелкой вниз, по крайней мере, ничего не происходит.

Если я изменю число hwndMain на код hwnd окна блокнота, код работает ипосылает стрелку вниз

import win32api
import win32con
import win32gui
import time

hwndMain = 133082
hwndChild = win32gui.GetWindow(hwndMain, win32con.GW_CHILD)
win32gui.SetForegroundWindow(hwndMain)
time.sleep(1)

win32api.SendMessage(hwndChild, win32con.WM_CHAR, 0x28, 0)

РЕДАКТИРОВАТЬ

Я пробовал

win32api.SendMessage(hwndChild, win32con.WM_CHAR, win32con.WM_KEYDOWN, 0)

Вместо

win32api.SendMessage(hwndChild, win32con.WM_CHAR, 0x28, 0)

Но это тоже не работает.

Я на питоне 2.7

1 Ответ

0 голосов
/ 28 января 2019

Каждое Win окно может иметь 0 или более дочерних окон, и каждое из этих дочерних окон также может иметь 0 или более собственных дочерних окон, ии так далее. Таким образом, у каждого окна может быть целое дерево детей.

В окнах больше, чем кажется на первый взгляд.Пользователь может взглянуть на одно (верхнее) окно и представить, что его дерево выглядит определенным образом, хотя на самом деле это дерево может выглядеть совершенно иначе (более сложным), поскольку могут быть некоторые окна, которые не видны.

При отправке сообщения в окно и в ожидании определенного поведения сообщение должно быть отправлено в точное окно (или одному из его предков, которые сконструированы таким образом, чтобы пересылать его)в противном случае сообщение будет просто проигнорировано (так как окно неправильно не обрабатывает такого рода сообщения).
В нашем случае это означает, что сообщение WM_KEYDOWN (или WM_CHAR ) должно быть отправлено:

  • ( Редактировать *)1024 *) окно, которое содержит текст для Блокнот
  • Окно ( TreeView ), которое содержит список устройств для Диспетчер устройств

Вы используете [ActiveState.Docs]: win32gui.GetWindow , который включает [MS.Docs]: функция GetWindow , которая сообщает (для * 1041)* GW_CHILD ):

Полученный дескриптор идентифицирует дочернее окно вверху Z-порядка, если указанное окно является родительским окном;в противном случае извлекаемый дескриптор равен NULL .Функция проверяет только дочерние окна указанного окна.Он не проверяет дочерние окна.

По совпадению , для Блокнот , отправляющий сообщение своему 1 st дочернему элементу, потому что этоchild оказался тем самым окном Edit , о котором я упоминал выше (кроме этого дочернего элемента, Notepad есть только еще одно - StatusBar , и это все, ни одногоиз этих окон есть собственные дочерние элементы).

Для Диспетчер устройств с другой стороны, все не так просто.Как видите, его структура более сложная (например, окно ToolBar видно).В соответствии с рекомендациями, для работы с окнами я использую [MS.Docs]: функцию EnumChildWindows .

code.py :

#!/usr/bin/env python3

import sys
import pywintypes
import win32gui
import win32con


def enum_child_proc(wnd, param):
    print("    Handling child 0x{:08X} - [{:}] - 0x{:08X}".format(wnd, win32gui.GetWindowText(wnd), win32gui.GetParent(wnd)))
    if param[0] >= 0:
        if param[1] == param[0]:
            win32gui.SendMessage(wnd, win32con.WM_KEYDOWN, win32con.VK_DOWN, 0)
            return 0
        param[1] += 1


def handle_window(wnd, child_index=-1):
    print("Handling 0x{:08X} - [{:}]".format(wnd, win32gui.GetWindowText(wnd)))
    cur_child = 0
    param = [child_index, cur_child]
    try:
        win32gui.EnumChildWindows(wnd, enum_child_proc, param)
    except pywintypes.error as e:
        if child_index < 0 or e.args[0]:
            raise e


def main():
    np_wnd = 0x01DB1EE2  # Notepad handle
    dm_wnd = 0x000E2042  # Device Manager handle

    handle_window(np_wnd, child_index=0)
    handle_window(dm_wnd, child_index=6)


if __name__ == "__main__":
    print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
    main()

Примечания :

  • Я жестко закодировал 2 дескриптора окна ( np_wnd , dm_wnd ).Очевидно, что они не будут действительными (они больше не действительны на моей машине, так как я закрыл окна), и их значения необходимо изменить
  • , чтобы найти дескриптор окна (и некоторые егодети) Я использую Spy ++ ( [MS.Docs]: Как: запустить Spy ++ ), который является частью VStudio , но я уверенЕсть множество других подобных приложений

Вывод :

e:\Work\Dev\StackOverflow\q053778227>"e:\Work\Dev\VEnvs\py_064_03.06.08_test0\Scripts\python.exe" code.py
Python 3.6.8 (tags/v3.6.8:3c6b436a57, Dec 24 2018, 00:16:47) [MSC v.1916 64 bit (AMD64)] on win32

Handling 0x01DB1EE2 - [Untitled - Notepad]
    Handling child 0x01811FA4 - [] - 0x01DB1EE2
Handling 0x000E2042 - [Device Manager]
    Handling child 0x00621A5A - [] - 0x000E2042
    Handling child 0x01991F44 - [Device Manager] - 0x00621A5A
    Handling child 0x01691F3E - [] - 0x01991F44
    Handling child 0x000C20B0 - [] - 0x01691F3E
    Handling child 0x004D2000 - [] - 0x000C20B0
    Handling child 0x004420CA - [] - 0x004D2000
    Handling child 0x01191F20 - [] - 0x004420CA

Как видно из вывода, TreeViewОкно является 7 th child (из 7 th child :)) окна Device Manager , означающее, что есть 6 промежуточных (и невидимых) окон между ними (которые игнорируют это сообщение).

Хотя код справился с этими окнами, нет действующего рецепта, который работаетдля любого окна (или, если есть, я не знаю об этом).Я должен упомянуть, что я попытался определить дочернее окно интереса в дереве, взглянув на его:

  • Имя
  • Класс
  • Стиль ( MS документация в этой области довольно плохая)
    • Расширенный стиль
  • Положение (по отношению к своему родителю)
  • SendMessage код возврата

но я не смог найти ничего, что отличало бы его от других окон.Единственное, что я заметил, это то, что для Notepad желаемым окном является перечисляемый дочерний элемент 1 st , а для Диспетчер устройств это 7 st один, поэтому я сделал фильтрацию на основе этого факта ( child_index ), но я считаю его совершенно ненадежным .

В качестве альтернативы, может бытьнет никакой фильтрации, и сообщение отправляется всем дочерним окнам в дереве, но это может иметь нежелательные последствия, так как могут быть другие окна, которые отвечают на это сообщение.Например, Диспетчер устройств * Дерево 1159 * состоит из ~ 30 дочерних окон.

В заключение я также хотел бы отметить, что некоторые окна (веб-браузеры, такие как )Chrome ), имеют свои собственные системы Windows, поэтому ничего из этого не будет работать.

...