草庐IT

python - 键盘事件未使用 pywin32 发送到窗口

coder 2024-06-05 原文

我写了一个代码,可以从我想要的任何程序中获取 HWND。如果你问的话,这就是我得到 hwnd 的方式。

以下代码应调出设备管理器并将向下箭头发送到程序。

但它确实。它确实会调出设备管理器,但它不会向程序发送向下箭头键,至少没有任何 react 。

如果我使用记事本窗口的 hwnd 代码更改 hwndMain 编号,则该代码确实有效并发送向下箭头键

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)

但这也行不通。

我在 python 2.7

最佳答案

每个Win窗口都可以有 0 或更多 子窗口,每个子窗口也可以有 0 个或多个自己的子窗口,依此类推……所以每个窗口可能有一个完整的子树。

有更多关于 window 的东西,而不是眼睛。用户可能看着一个(顶部)窗口并想象它的树以某种方式看起来,而实际上这棵树看起来可能完全不同(更复杂),因为可能有一些窗口不可见。

当向窗口发送消息并期望发生某种行为时,消息 必须发送到确切的窗口 (或其设计为转发它的祖先之一),否则该消息将被简单地忽略(因为错误的窗口不处理这种消息)。在我们的例子中,这意味着 WM_KEYDOWN(或 WM_CHAR)消息应该发送到:

  • 保存记事本文本的(编辑)窗口
  • 保存设备管理器设备列表的 (TreeView) 窗口

  • 您正在使用 [ActiveState.Docs]: win32gui.GetWindow , 包装 [MS.Docs]: GetWindow function其中指出(对于 GW_CHILD ):

    The retrieved handle identifies the child window at the top of the Z order, if the specified window is a parent window; otherwise, the retrieved handle is NULL. The function examines only child windows of the specified window. It does not examine descendant windows.



    巧合 ,对于记事本将消息发送到它的第一个 child 作品,因为那个 child 变成了我上面提到的编辑窗口(除了那个 child ,记事本只有另一个是状态栏,就是这样,这些窗口都没有任何他们自己的 child )。

    另一方面,对于设备管理器,事情就没有那么简单了。如您所见,它的结构更加复杂(例如 ToolBar 窗口可见)。按照建议,为了使用 Windows,我正在使用 [MS.Docs]: EnumChildWindows function .

    代码.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)。显然,它们将无效(因为我关闭了 window ,它们在我的机器上也不再有效),并且它们的值需要更改
  • 为了找到一个窗口的句柄(和它的一些子窗口),我使用了 Spy++ ( [MS.Docs]: How to: Start 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 窗口是 第七个 child (第 7 个 child 的 :) )设备管理器窗口意味着 它们之间有 6 个中间(和不可见)窗口 (忽略该消息)。

    尽管代码对相关窗口起到了作用,当前没有适用于任何窗口的配方 (或者如果有,我不知道)。我必须提到,我已经尝试通过查看树来确定感兴趣的子窗口:
  • 姓名
  • 类(class)
  • 风格(MS doc 在这方面很差)
  • 加长款
  • 位置(相对于其父级)
  • SendMessage 的返回码

  • 但我找不到任何可以将它与其他 window 区分开来的东西。我唯一注意到的是,对于记事本,所需的窗口是枚举的第一个子窗口,而对于设备管理器,它是第 7 个子窗口,所以我根据这个事实 (child_index) 进行了过滤,但我认为它是 完全不可靠 .

    作为替代方案,可以根本不进行过滤,并将消息发送到树中的所有子窗口,但这可能会产生不需要的影响,因为可能有其他窗口响应该消息。例如,设备管理器树由大约 30 个子窗口组成。

    最后,我还想提一下,有些窗口(Chrome 之类的网络浏览器)有自己的 Windows 系统,因此这些都不起作用。

    关于python - 键盘事件未使用 pywin32 发送到窗口,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53778227/

    有关python - 键盘事件未使用 pywin32 发送到窗口的更多相关文章

    1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

      我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

    2. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

      我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

    3. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

      类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

    4. ruby-on-rails - 使用 Ruby on Rails 进行自动化测试 - 最佳实践 - 2

      很好奇,就使用ruby​​onrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提

    5. ruby - 在 Ruby 中使用匿名模块 - 2

      假设我做了一个模块如下:m=Module.newdoclassCendend三个问题:除了对m的引用之外,还有什么方法可以访问C和m中的其他内容?我可以在创建匿名模块后为其命名吗(就像我输入“module...”一样)?如何在使用完匿名模块后将其删除,使其定义的常量不再存在? 最佳答案 三个答案:是的,使用ObjectSpace.此代码使c引用你的类(class)C不引用m:c=nilObjectSpace.each_object{|obj|c=objif(Class===objandobj.name=~/::C$/)}当然这取决于

    6. ruby - 使用 ruby​​ 和 savon 的 SOAP 服务 - 2

      我正在尝试使用ruby​​和Savon来使用网络服务。测试服务为http://www.webservicex.net/WS/WSDetails.aspx?WSID=9&CATID=2require'rubygems'require'savon'client=Savon::Client.new"http://www.webservicex.net/stockquote.asmx?WSDL"client.get_quotedo|soap|soap.body={:symbol=>"AAPL"}end返回SOAP异常。检查soap信封,在我看来soap请求没有正确的命名空间。任何人都可以建议我

    7. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

      关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

    8. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

      我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

    9. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

      我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

    10. ruby - 在 64 位 Snow Leopard 上使用 rvm、postgres 9.0、ruby 1.9.2-p136 安装 pg gem 时出现问题 - 2

      我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po

    随机推荐