Windows上Python3.1的SendKeys

2024-04-26 13:05:06 发布

您现在位置:Python中文网/ 问答频道 /正文


Tags: python
3条回答

使用win32api.keybd_事件得到了一些有用的东西。

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

[编辑:请参阅下面接受的答案中的SendInput版本。我把这条消息留在这里,以防有人喜欢使用sendkeys。金华]

此页有帮助: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键一样! 似乎不需要释放其他钥匙

下面是一个工作模块,它调用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()

我刚才用ctypes重写了sendkeys的C位。。。 https://bitbucket.org/markm/sendkeysctypes 我看到别人也这么做了: http://code.google.com/p/sendkeys-ctypes/

如果我记得它应该是一个替换sendkeys的下拉列表(只有导入行必须更改)

相关问题 更多 >