3

最新の Python Sendkeys モジュールは Python 2.6 用です。Cモジュールを再コンパイルする必要があるため、自分でアップグレードすることはできません。

キーをウィンドウに送信するかなり簡単な代替方法を知っている人はいますか?

win32ui.FindWindow() を使用すると、適切なウィンドウを見つけて PyCWnd.SetActiveWindow() でアクティブにすることができるので、必要なのはキーストロークをアクティブ ウィンドウに送信する簡単な方法だけです。

目的は、メニュー項目を実行することです。

このアプリは Delphi で作成されており、私が知っているプロセス間インターフェイスはありません。

4

4 に答える 4

9

これは、user32.SendInput() を呼び出す作業モジュールです。

完璧ではありませんが、使用できます。

編集:

昨日、私はクラスでバージョンを作成し、それを作業中の tkinter アプリで使用しています。掃除する時間ができたらここに置きます。

これを以下のドキュメント文字列に追加しました:

[ プロファイル内のフォルダから作業しても問題ありません。
これらの問題は、別のパーティションで作業しているときに発生しました。
ファイルのパーミッションは OK だったので、何が 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()
于 2010-01-05T05:03:38.847 に答える
5

少し前に ctypes の sendkeys の C ビットを書き直しました... https://bitbucket.org/markm/sendkeysctypes 他の誰かがそれをやったのを見ました: http://code.google.com/p/sendkeys-ctypes /

私が覚えていれば、sendkeys の代わりにドロップする必要があります (インポート行のみを変更する必要があります)。

于 2011-05-24T14:28:38.743 に答える
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 キーを押しているように動作しました! 他のキーを離す必要はないようです

于 2009-12-01T06:39:13.620 に答える
0

keybd_event API が必要です。私の PushKeys プログラムは、SendKeys と構文互換性があり、スリープ機能が組み込まれています。Python ではありませんが、すぐに翻訳できるはずです (多くの言語に翻訳されています - 少なくとも、使用する API が表示されるはずです)。 . ここでは、さまざまな言語で利用できます。

于 2009-12-01T03:21:16.980 に答える