【问题标题】:SendKeys for Python 3.1 on WindowsWindows 上 Python 3.1 的 SendKeys
【发布时间】:2011-05-24 23:31:44
【问题描述】:

最新的 Python Sendkeys 模块适用于 Python 2.6。我无法自己升级它,因为它需要重新编译 C 模块。

有没有人知道将密钥发送到窗口的相当简单的替代方法?

使用 win32ui.FindWindow() 我可以找到正确的窗口,然后使用 PyCWnd.SetActiveWindow() 使其处于活动状态,因此只需要一种将击键发送到活动窗口的简单方法。

目的是执行一个菜单项。

该应用程序是用 Delphi 编写的,没有我知道的任何进程间接口。

【问题讨论】:

    标签: python sendkeys


    【解决方案1】:

    这是一个调用 user32.SendInput() 的工作模块。

    不完美,但可以使用。

    编辑:

    昨天我做了一个带有类的版本,并在一个工作的 tkinter 应用程序中使用它。等我有时间清理它会放在这里。

    在下面的文档字符串中添加了这个:

    [ 如果我在个人资料中的文件夹中工作,则可以。
    在另一个分区上工作时会出现这些问题。
    文件权限没问题,所以不知道是什么阻止了 SendInput。 ]

    SciTE 仍然需要 完全准确 窗口标题。

    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    
    ''' send_input for python 3, from jh45dev@gmail.com
    
    code from Daniel F is adapted here. The original is at:
    http://mail.python.org/pipermail/python-win32/2005-April/003131.html
    
    
    SendInput sends to the window that has the keyboard focus.
    That window must not be minimized.
    
    
    There seem to be some strange limitations with user32.SendInput()
    Here is what happened in my testing (on Vista sp2).
    
     [edit: It is OK if I work from a folder within my profile.    
     These problems happened when working on another partition.    
     File permissions were OK, so do not know what blocked SendInput.]
    
    1
    I opened Notepad from the Start menu,
    then in Notepad opened test.txt,
    and all worked fine.
    
    2
    I opened Notepad by opening test.txt in Explorer.
    find_window() found Notepad, but user32.SendInput() had no effect.
    If Notepad was minimized, it did not get restored or focussed.
    
    The same happened with SciTE and Notepad2.
    
    
    Another strangeness:
    For SciTE I had to put in the whole window title, eg "test.txt - SciTE",
    but for Notepad and Notepad2, only the app name, eg "Notepad".
    
    
    '''
    
    import ctypes as ct
    from win32con import SW_MINIMIZE, SW_RESTORE
    from win32ui import FindWindow, error as ui_err
    from time import sleep
    
    
    class cls_KeyBdInput(ct.Structure):
        _fields_ = [
            ("wVk", ct.c_ushort),
            ("wScan", ct.c_ushort),
            ("dwFlags", ct.c_ulong),
            ("time", ct.c_ulong),
            ("dwExtraInfo", ct.POINTER(ct.c_ulong) )
        ]
    
    class cls_HardwareInput(ct.Structure):
        _fields_ = [
            ("uMsg", ct.c_ulong),
            ("wParamL", ct.c_short),
            ("wParamH", ct.c_ushort)
        ]
    
    class cls_MouseInput(ct.Structure):
        _fields_ = [
            ("dx", ct.c_long),
            ("dy", ct.c_long),
            ("mouseData", ct.c_ulong),
            ("dwFlags", ct.c_ulong),
            ("time", ct.c_ulong),
            ("dwExtraInfo", ct.POINTER(ct.c_ulong) )
        ]
    
    class cls_Input_I(ct.Union):
        _fields_ = [
            ("ki", cls_KeyBdInput),
            ("mi", cls_MouseInput),
            ("hi", cls_HardwareInput)
        ]
    
    class cls_Input(ct.Structure):
        _fields_ = [
            ("type", ct.c_ulong),
            ("ii", cls_Input_I)
        ]
    
    
    def find_window( s_app_name ):
    
        try:
            window1 = FindWindow(  None, s_app_name,)
            return window1
        except ui_err:
            pass
        except:
            raise
    
        try:
            window1 = FindWindow( s_app_name, None, )
            return window1
        except ui_err:
            return None
        except:
            raise
    
    
    def make_input_objects( l_keys ):
    
        p_ExtraInfo_0 = ct.pointer(ct.c_ulong(0))
    
        l_inputs = [ ]
        for n_key, n_updown in l_keys:
            ki = cls_KeyBdInput( n_key, 0, n_updown, 0, p_ExtraInfo_0 )
            ii = cls_Input_I()
            ii.ki = ki
            l_inputs.append( ii )
    
        n_inputs = len(l_inputs)
    
        l_inputs_2=[]
        for ndx in range( 0, n_inputs ):
            s2 = "(1, l_inputs[%s])" % ndx
            l_inputs_2.append(s2)
        s_inputs = ', '.join(l_inputs_2)
    
    
        cls_input_array = cls_Input * n_inputs
        o_input_array = eval( "cls_input_array( %s )" % s_inputs )
    
        p_input_array = ct.pointer( o_input_array )
        n_size_0 = ct.sizeof( o_input_array[0] )
    
        # these are the args for user32.SendInput()
        return ( n_inputs, p_input_array, n_size_0 )
    
        '''It is interesting that o_input_array has gone out of scope
        by the time p_input_array is used, but it works.'''
    
    
    def send_input( window1, t_inputs, b_minimize=True ):
    
        tpl1 = window1.GetWindowPlacement()
        was_min = False
        if tpl1[1] == 2:
            was_min = True
            window1.ShowWindow(SW_RESTORE)
            sleep(0.2)
    
        window1.SetForegroundWindow()
        sleep(0.2)
        window1.SetFocus()
        sleep(0.2)
        rv = ct.windll.user32.SendInput( *t_inputs )
    
        if was_min and b_minimize:
            sleep(0.3) # if the last input was Save, it may need time to take effect
            window1.ShowWindow(SW_MINIMIZE)
    
        return rv
    
    
    
    # define some commonly-used key sequences
    t_ctrl_s = (  # save in many apps
        ( 0x11, 0 ),
        ( 0x53, 0 ),
        ( 0x11, 2 ),
    )
    t_ctrl_r = (  # reload in some apps
        ( 0x11, 0 ),
        ( 0x52, 0 ),
        ( 0x11, 2 ),
    )
    
    
    def test():
    
        # file > open; a non-invasive way to test
        t_ctrl_o = ( ( 0x11, 0 ), ( 0x4F, 0 ), ( 0x11, 2 ), )
    
        # writes "Hello\n"
        # 0x10 is shift.  note that to repeat a key, as with 4C here, you have to release it after the first press
        t_hello = ( ( 0x10, 0 ), ( 0x48, 0 ), ( 0x10, 2 ), ( 0x45, 0 ), ( 0x4C, 0 ), ( 0x4C, 2 ), ( 0x4C, 0 ), ( 0x4F, 0 ), ( 0x0D, 0 ), )
    
    
        l_keys = [ ]
        ## l_keys.extend( t_ctrl_o )
        l_keys.extend( t_hello )
        l_keys.extend( t_ctrl_s )
    
        ## s_app_name = "SciTE"
        ## s_app_name = "(Untitled) - SciTE"
        s_app_name = "test.txt - SciTE"
        ## s_app_name = "Notepad2"
        ## s_app_name = "Notepad"
    
        window1 = find_window( s_app_name )
        if window1 == None:
            print( "%r has no window." % s_app_name )
            input( 'press enter to close' )
            exit()
    
        t_inputs = make_input_objects( l_keys )
    
        n = send_input( window1, t_inputs )
    
        ## print( "SendInput returned: %r" % n )
        ## print( "GetLastError: %r" % ct.windll.kernel32.GetLastError() )
        ## input( 'press enter to close' )
    
    
    
    if __name__ == '__main__':
        test()
    

    【讨论】:

      【解决方案2】:

      我不久前在 ctypes 中重写了 sendkeys 的 C 位... https://bitbucket.org/markm/sendkeysctypes 我看到其他人也这样做了: http://code.google.com/p/sendkeys-ctypes/

      如果我记得它应该是替换 sendkeys (只有导入行必须更改)

      【讨论】:

      【解决方案3】:

      使用 win32api.keybd_event 得到了一些有用的东西。

      看起来 SendInput 会更安全,但 pywin32 不包含它。

      [ 编辑:在下面接受的答案中查看 SendInput 版本。如果有人更喜欢使用 sendkeys,我会在此处留下此消息。 jh]

      此页面有帮助:http://social.msdn.microsoft.com/Search/en-us/?Query=keybd_event

      有效的代码:

      import win32api; import win32ui

      PyCWnd1 = win32ui.FindWindow( None, "an_app" )
      PyCWnd1.SetForegroundWindow()
      PyCWnd1.SetFocus()
      
      win32api.keybd_event(0x12, 0, ) # Alt
      win32api.keybd_event(0x12, 0, 2 ) # Alt release
      win32api.keybd_event(0x46, 0, ) # F
      win32api.keybd_event(0x52, 0, ) # R
      

      这会在应用程序中执行文件 > 重新加载。应用最小化时不起作用

      在不释放 Alt 的情况下,运行此命令后,键盘的行为就像我按住 Alt 键一样! 似乎不需要释放其他键

      【讨论】:

      • 有时间我会尝试通过 ctypes 调用 SendInput。顺便说一句,我将在修改其他应用程序使用的文件的 tk 应用程序中使用它。它需要告诉其他应用程序在之前保存并在之后重新加载。不错的那个应用程序不锁定文件:)
      • 使用 SetFocus() 方法给我一个错误,但幸运的是它不需要。
      【解决方案4】:

      您需要 keybd_event API。我的 PushKeys 程序的语法与 SendKeys 兼容,并且内置了睡眠功能。虽然它不是 Python 中的,但它应该很容易翻译(它已被翻译成多种语言 - 至少它应该向您展示要使用的 API) .它是多种语言的available here

      【讨论】:

      • 谢谢克里斯,但我不够聪明,无法弄清楚如何在 Python 中使用它;)希望我知道如何告诉 pywin32 发送密钥。 pywin32的win32ui在HookKeyStroke()中提到了WM_CHAR,但是hook似乎是send的反面。 (希望我能在星期四晚上之前完成这项工作:)
      • 在 pywin32 帮助中做了显而易见的事情;) 那里有一个 win32api.keybd_event,所以也许我现在可以让它工作。只需要去查找虚拟键代码。
      • 您可以从链接中的VB源码中获取虚拟键码。如果我知道 Python,我会为你翻译——代码很简单。
      • 这是我在 Stack Overflow 上的第一篇文章。不知道在这种情况下如何给予积分......请告知;)
      • 您做对了,并用解决方案回答了您自己的问题。您应该将其标记为已接受的答案,以便人们知道该问题已得到解答。至于分数,如果答案有帮助或信息丰富,请单击向上箭头,否则没有理由
      猜你喜欢
      • 2023-01-28
      • 2019-02-01
      • 2013-08-08
      • 1970-01-01
      • 2016-04-17
      • 1970-01-01
      • 1970-01-01
      • 2013-01-11
      • 1970-01-01
      相关资源
      最近更新 更多