2009-12-01 86 views
3

最新的Python Sendkeys模块适用于Python 2.6。我不能自己升级它,因为它需要重新编译C模块。Windows上的SendKeys for Python 3.1

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

使用win32ui.FindWindow()我可以找到合适的窗口,然后使其与PyCWnd.SetActiveWindow()一起激活,因此只需要一个简单的方法将击键发送到活动窗口。

目的是执行一个菜单项。

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

回答

9

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

不完美,但可用。

编辑:

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

[它是好,如果我从一个文件夹我的个人资料中工作:

在下面的文档字符串添加此。
这些问题发生在另一个分区上时。
文件权限正常,所以不知道什么阻止了SendInput。 ]

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

#!/usr/bin/python 
# -*- coding: utf-8 -*- 

''' send_input for python 3, from [email protected] 

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() 
0

你想要keybd_event API。我的PushKeys程序与SendKeys语法兼容,并且内置了睡眠函数。虽然它不在Python中,但它应该足够易于翻译(它已被翻译成许多语言 - 至少它应该会显示您要使用的API) 。这是available here在各种语言。

+0

谢谢克里斯,但我不足够聪明,弄清楚如何在Python中使用它;)我希望我知道如何告诉pywin32发送密钥。 pywin32的win32ui在HookKeyStroke()中提到了WM_CHAR,但是hook似乎与send相反。 (希望我可以在星期四晚上得到这个工作:) – jh45dev 2009-12-01 04:08:20

+0

在pywin32中有明显的和迷人的帮助;)那里有一个win32api.keybd_event,所以也许我现在可以做这件事。只需要查找虚拟键码。 – jh45dev 2009-12-01 04:20:30

+0

您可以从链接中的VB源获取虚拟键码。如果我知道Python,我会为你翻译它 - 代码非常简单。 – 2009-12-01 06:01:51

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键! 似乎不需要释放其他键

+0

当我有空时,我会尝试通过ctypes调用SendInput。 顺便说一句,我会在一个tk应用程序中使用它来修改另一个应用程序使用的文件。它需要告诉另一个应用程序保存之前和之后重新加载。不错的应用程序不锁定文件:) – jh45dev 2009-12-01 06:56:55

+0

使用'SetFocus()'方法给我一个错误,但幸运的是它不是必需的。 – hazzey 2014-06-29 02:57:29

5

我重写了ctypes前一段时间的sendkeys的C位... https://bitbucket.org/markm/sendkeysctypes ,我看到别人这样做是太: http://code.google.com/p/sendkeys-ctypes/

如果我记得应该是在替代的SendKeys下降(只有进口线必须改变)

+0

没有得到它与py2.7,win7 64bits,SendInput在运行功能中没有做任何事情;;( – 2012-05-07 19:43:13

+0

我给我的问题在这里提出一个新的问题,http://stackoverflow.com/questions/10503170/how-可以-I-调试sendkeysctypes,进一步 – 2012-05-08 17:13:50