2009-12-01 39 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