Evento de teclado no enviado a la ventana con pywin32

Escribí un código A que obtiene el HWND de cualquier progtwig que quiera. Así es como conseguí el hwnd si tu preguntas.

El siguiente código debe mostrar el administrador del dispositivo y enviar la flecha hacia abajo al progtwig.

Pero sí lo hace. Hace aparecer el administrador de dispositivos pero no envía la flecha hacia abajo al progtwig, al menos no sucede nada.

Si cambio el número hwndMain con el código hwnd de una ventana de bloc de notas, el código funciona y envía la flecha hacia abajo.

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) 

EDITAR

He intentado

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

En lugar de

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

Pero eso tampoco funciona.

Estoy en Python 2.7

Cada ventana de Windows puede tener 0 o más ventanas secundarias, y cada una de esas ventanas secundarias también puede tener 0 o más hijos propios, y así sucesivamente … Entonces, cada ventana puede tener un árbol completo de niños.

Hay más sobre las ventanas, de lo que parece. El usuario puede mirar una ventana (superior) e imaginar que su árbol se ve de cierta manera, cuando en realidad ese árbol puede verse totalmente diferente (más complejo), ya que puede haber algunas ventanas que no son visibles.

Cuando se envía el mensaje a una ventana y se espera que ocurra un cierto comportamiento, el mensaje debe enviarse a la ventana exacta (o a uno de sus antepasados ​​que estén diseñados para reenviarlo), de lo contrario, el mensaje simplemente se ignorará. (ya que la ventana incorrecta no maneja ese tipo de mensaje).
En nuestro caso, significa que el mensaje WM_KEYDOWN (o WM_CHAR ) debe enviarse a:

  • La ventana ( Editar ) que contiene el texto para el Bloc de notas
  • La ventana ( TreeView ) que contiene la lista de dispositivos para el Administrador de dispositivos

Está utilizando [ActiveState.Docs]: win32gui.GetWindow , que envuelve [MS.Docs]: función GetWindow que indica (para GW_CHILD ):

El identificador recuperado identifica la ventana secundaria en la parte superior del orden Z, si la ventana especificada es una ventana principal; de lo contrario, el identificador recuperado es NULL . La función examina solo las ventanas secundarias de la ventana especificada. No examina ventanas descendientes.

Casualmente , para el Bloc de notas, el envío del mensaje a su primer hijo funciona porque ese niño se convirtió en la misma ventana de Edición que mencioné anteriormente (además de ese niño, el Bloc de notas solo tiene otro que es la Barra de estado , y eso es todo, ninguno de estos Windows tiene hijos propios).

Para el Administrador de dispositivos, por otro lado, las cosas no son tan simples. Como puede ver, su estructura es más compleja (por ejemplo, la ventana de la barra de herramientas es visible). Como se recomienda, para trabajar con Windows, estoy usando la función [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() 

Notas :

  • Codifiqué los 2 manejadores de ventana ( np_wnd , dm_wnd ). Obviamente, no serán válidos (tampoco serán válidos en mi máquina desde que cerré las ventanas) y es necesario cambiar sus valores.
  • Para encontrar el identificador de una ventana (y algunos de sus hijos) estoy usando Spy ++ ( [MS.Docs]: Cómo: Iniciar Spy ++ ), que es parte de VStudio , pero estoy seguro de que hay muchos otros similares aplicaciones

Salida :

 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 

Como se ve en la salida, la ventana TreeView es el séptimo hijo (del séptimo hijo :)) de la ventana del Administrador de dispositivos, lo que significa que hay 6 ventanas intermedias (e invisibles) entre ellas (que ignoran ese mensaje).

Aunque el código hizo el truco para las ventanas en cuestión, no hay una receta actual que funcione para ninguna ventana (o si la hay, no lo conozco). Debo mencionar que he tratado de determinar la ventana secundaria de interés en el árbol al mirar su:

  • Nombre
  • Clase
  • Estilo ( MS doc es bastante pobre en esta área)
    • Estilo extendido
  • Posición (en relación a su padre)
  • Código de devolución de SendMessage

pero no pude encontrar nada que lo diferenciara de otras ventanas. Lo único que noté es que para el Bloc de notas , la ventana deseada es el primer niño enumerado, mientras que para el Administrador de dispositivos es el séptimo, así que hice el filtrado basado en este hecho ( child_index ), pero lo considero totalmente poco confiable .

Como alternativa, no puede haber ningún filtro y el mensaje se envía a todas las ventanas secundarias del árbol, pero esto puede tener efectos no deseados, ya que podría haber otras ventanas que respondan a ese mensaje. Por ejemplo , el árbol del Administrador de dispositivos consta de ~ 30 ventanas secundarias.

Al final, también me gustaría mencionar que algunas ventanas (navegadores web como Chrome ) tienen sus propios sistemas de ventanas, por lo que nada de esto funcionará.