6

特定のプロセスでタブキーを押すことをシミュレートするために使用するコードは次のとおりです。

[DllImport("user32.dll")]
static extern bool PostMessage(IntPtr hWnd, UInt32 Msg, int wParam, int lParam);

public Form1()
{
    PostMessage(MemoryHandler.GetMainWindowHandle(), 
               (int)KeyCodes.WMessages.WM_KEYDOWN, 
               (int)KeyCodes.VKeys.VK_TAB, 0);

    InitializeComponent();
}

キーをタップするだけでなく、キーを(たとえば)1秒間押すように拡張する方法はありますか?

Thread.Sleep()UI スレッドをブロックするソリューションには興味がないことに注意してください。

4

6 に答える 6

4

Windows がメッセージに対して行うことをシミュレートする場合は、キーの繰り返し速度がどのくらい速いかを調べる必要があります。それはで見つけることができますHKEY_CURRENT_USER\Control Panel\Keyboard\KeyboardSpeed。値もありKeyboardDelayます。

Windows が行うことは、キーが最初に押されたときにaWM_KEYDOWNと aを送信することです。WM_CHAR次に、KeyboardDelayタイム スパンが経過してもキーが押されたままの場合、キーが押されるまでWM_KEYDOWNandのWM_CHARペアが繰り返されます。KeyboardSpeedキーが押された時点WM_KEYUPで送信されます。

Timerを使用して特定の頻度でメッセージを送信することをお勧めします。

アップデート:

例えば:

int keyboardDelay, keyboardSpeed;
using (var key = Registry.CurrentUser.OpenSubKey(@"Control Panel\Keyboard"))
{
    Debug.Assert(key != null);
    keyboardDelay = 1;
    int.TryParse((String)key.GetValue("KeyboardDelay", "1"), out keyboardDelay);
    keyboardSpeed = 31;
    int.TryParse((String)key.GetValue("KeyboardSpeed", "31"), out keyboardSpeed);
}

maxRepeatedCharacters = 30; // repeat char 30 times
var startTimer = new System.Windows.Forms.Timer {Interval = keyboardSpeed};
startTimer.Tick += startTimer_Tick;
startTimer.Start();
var repeatTimer = new System.Windows.Forms.Timer();
repeatTimer.Interval += keyboardDelay;
repeatTimer.Tick += repeatTimer_Tick;

//...

private static void repeatTimer_Tick(object sender, EventArgs e)
{
    PostMessage(MemoryHandler.GetMainWindowHandle(),
               (int)KeyCodes.WMessages.WM_KEYDOWN,
               (int)KeyCodes.VKeys.VK_TAB, 0);
    PostMessage(MemoryHandler.GetMainWindowHandle(),
                (int)KeyCodes.WMessages.WM_CHAR,
                (int)KeyCodes.VKeys.VK_TAB, 0);

    counter++;
    if (counter > maxRepeatedCharacters)
    {
        Timer timer = sender as Timer;
        timer.Stop();
    }
}

private static void startTimer_Tick(object sender, EventArgs eventArgs)
{
    Timer timer = sender as Timer;
    timer.Stop();
    PostMessage(MemoryHandler.GetMainWindowHandle(),
               (int)KeyCodes.WMessages.WM_KEYDOWN,
               (int)KeyCodes.VKeys.VK_TAB, 0);
    PostMessage(MemoryHandler.GetMainWindowHandle(),
               (int)KeyCodes.WMessages.WM_CHAR,
               (int)KeyCodes.VKeys.VK_TAB, 0);
}
于 2013-08-11T21:38:57.323 に答える
1

何を達成しようとしているのか正確にはわかりませんが、SendInput を使用してテキスト入力をシミュレートするために使用する関数を以下に示します。

これを少し変更して、新しいスレッドから SendInput への最後の呼び出しを行い、ダウン イベントとアップ イベントをタイマーで分離すると、必要なことが達成されますか?

[DllImport("user32.dll", SetLastError = true)]
static extern UInt32 SendInput(UInt32 numberOfInputs, INPUT[] inputs, Int32 sizeOfInputStructure);

public enum InputType : uint
{
    MOUSE = 0,
    KEYBOARD = 1,
    HARDWARE = 2,
}

struct INPUT
{
    public UInt32 Type;
    public MOUSEKEYBDHARDWAREINPUT Data;
}

struct KEYBDINPUT
{
    public UInt16 Vk;
    public UInt16 Scan;
    public UInt32 Flags;
    public UInt32 Time;
    public IntPtr ExtraInfo;
}

public enum KeyboardFlag : uint // UInt32
{
    EXTENDEDKEY = 0x0001,
    KEYUP = 0x0002,
    UNICODE = 0x0004,
    SCANCODE = 0x0008,
}

public static void SimulateTextEntry(string text)
{
    if (text.Length > UInt32.MaxValue / 2) throw new ArgumentException(string.Format("The text parameter is too long. It must be less than {0} characters.", UInt32.MaxValue / 2), "text");

    var chars = UTF8Encoding.ASCII.GetBytes(text);
    var len = chars.Length;
    INPUT[] inputList = new INPUT[len * 2];
    for (int x = 0; x < len; x++)
    {
        UInt16 scanCode = chars[x];

        var down = new INPUT();
        down.Type = (UInt32)InputType.KEYBOARD;
        down.Data.Keyboard = new KEYBDINPUT();
        down.Data.Keyboard.Vk = 0;
        down.Data.Keyboard.Scan = scanCode;
        down.Data.Keyboard.Flags = (UInt32)KeyboardFlag.UNICODE;
        down.Data.Keyboard.Time = 0;
        down.Data.Keyboard.ExtraInfo = IntPtr.Zero;

        var up = new INPUT();
        up.Type = (UInt32)InputType.KEYBOARD;
        up.Data.Keyboard = new KEYBDINPUT();
        up.Data.Keyboard.Vk = 0;
        up.Data.Keyboard.Scan = scanCode;
        up.Data.Keyboard.Flags = (UInt32)(KeyboardFlag.KEYUP | KeyboardFlag.UNICODE);
        up.Data.Keyboard.Time = 0;
        up.Data.Keyboard.ExtraInfo = IntPtr.Zero;

        // Handle extended keys:
        // If the scan code is preceded by a prefix byte that has the value 0xE0 (224),
        // we need to include the KEYEVENTF_EXTENDEDKEY flag in the Flags property. 
        if ((scanCode & 0xFF00) == 0xE000)
        {
            down.Data.Keyboard.Flags |= (UInt32)KeyboardFlag.EXTENDEDKEY;
            up.Data.Keyboard.Flags |= (UInt32)KeyboardFlag.EXTENDEDKEY;
        }

        inputList[2*x] = down;
        inputList[2*x + 1] = up;

    }

    var numberOfSuccessfulSimulatedInputs = SendInput((UInt32)len*2, inputList, Marshal.SizeOf(typeof(INPUT)));
}
于 2013-08-10T19:33:14.023 に答える
1

UIスレッドをスリープさせてブロックしないために、スレッドでそれを行います。これを見てください:

System.Threading.Thread KeyThread = new System.Threading.Thread(() => {
       //foreach process
       // press key now
       PostMessage(MemoryHandler.GetMainWindowHandle(), 
              (int)KeyCodes.WMessages.WM_KEYDOWN, 
              (int)KeyCodes.VKeys.VK_TAB, 0);
       System.Threading.Thread.Sleep(1000); // wait 1 second

       //foreach process
       // release keys again
       PostMessage(MemoryHandler.GetMainWindowHandle(), 
              (int)KeyCodes.WMessages.WM_KEYUP, 
              (int)KeyCodes.VKeys.VK_TAB, 0);
});

もちろん、あなたはそれを始めなければなりません。

于 2013-08-09T12:10:43.960 に答える
1

物理キーボードでキーを押したままにすると、繰り返されるキーストロークがアクティブ ウィンドウに渡されます。これはキーボードには組み込まれていませんが、Windows の機能です。

これをシミュレートするには、次の手順を順番に実行します。

  1. キーダウン メッセージを送信します。
  2. タイマーを 30 ミリ秒間隔で実行し (Windows の既定値で、簡単操作の設定で変更できます)、ティックごとにウィンドウにキープレス メッセージを送信します。
  3. キーアップ メッセージを送信します。
于 2013-08-05T00:33:54.483 に答える
0

PostMessage で何をしているのかわかりませんが、ここからいくつかのコードを変更します: SendKey.Send() 動作しません

   [DllImport("user32.dll", SetLastError = true)]
    static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, UIntPtr dwExtraInfo);
    public static void PressKey(Keys key, bool up)
    {
        const int KEYEVENTF_EXTENDEDKEY = 0x1;
        const int KEYEVENTF_KEYUP = 0x2;
        if (up)
        {
            keybd_event((byte)key, 0x45, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, (UIntPtr)0);
        }
        else
        {
            keybd_event((byte)key, 0x45, KEYEVENTF_EXTENDEDKEY, (UIntPtr)0);
        }
    }

    void TestProc()
    {
        PressKey(Keys.Tab, false);
        Thread.Sleep(1000);
        PressKey(Keys.Tab, true);
    }

多分これはあなたのために働くかもしれません。キーを下げてからキーを上げ、その間にスリープを入れます。これにさらに追加して、キーを押したままにする時間の値を渡すこともできます。

于 2013-08-01T01:58:33.900 に答える