0

How can I send keys to another application so that they're held down? I want something like

keystate(keys.A) = down (to hold button)

and

keystate(keys.A) = up (to release the button)

  • i dont care if its c# or visual basic i know them
  • using visual studio
Athena
  • 3,200
  • 3
  • 27
  • 35
123neri123
  • 19
  • 4
  • In your game Update() loop, you can check the key state, and move the car accordingly. – Jon Jul 15 '16 at 17:06
  • @Mangist Something tells me this is not for his own game. He's trying to send keypresses to another game. – Athena Jul 15 '16 at 17:07
  • @Ares you might be right, but not sure what the purpose would be. – Jon Jul 15 '16 at 17:11
  • There are a lot of games that stupidly require you to hold down keys. Or maybe he wants to automate the use of an application. In any case, I've detailed both possible cases, repeated keys and held down keys. – Athena Jul 15 '16 at 17:12

3 Answers3

2

If you want to send multiple keys in a row, use SendKeys.Send

https://msdn.microsoft.com/en-us/library/system.windows.forms.sendkeys.send(v=vs.110).aspx

If you want to hold down keys, you need to import a User32 library call:

Private Declare Sub keybd_event Lib "user32.dll" (ByVal bVk As Byte, ByVal bScan As Byte, ByVal dwFlags As Integer, ByVal dwExtraInfo As Integer)

You'll also need MapVirtualKey. This transfers the layout of the keys on your physical board (driver oriented) to a virtual keyset that's invariant of hardware (software oriented.)

<DllImport("User32.dll", SetLastError:=False, CallingConvention:=CallingConvention.StdCall, _
       CharSet:=CharSet.Auto)> _
Public Shared Function MapVirtualKey(ByVal uCode As UInt32, ByVal uMapType As MapVirtualKeyMapTypes) As UInt32
End Function

Then just do something like this:

Private Sub HoldKeyDown(ByVal key As Byte, ByVal durationInSeconds As Integer)
    Dim targetTime As DateTime = DateTime.Now().AddSeconds(durationInSeconds)
    keybd_event(key, MapVirtualKey(key, 0), 0, 0) ' Down
    While targetTime.Subtract(DateTime.Now()).TotalSeconds > 0
        Application.DoEvents()
    End While
    keybd_event(key, MapVirtualKey(key, 0), 2, 0) ' Up
End Sub
Visual Vincent
  • 18,045
  • 5
  • 28
  • 75
Athena
  • 3,200
  • 3
  • 27
  • 35
  • Can you explain me where I put the DllImport part? – 123neri123 Jul 15 '16 at 17:25
  • Just put those two methods at the top of your class. You may have to do a couple of imports to get it to work. – Athena Jul 15 '16 at 17:26
  • `Imports System.Runtime.InteropServices` is the one you need – Athena Jul 15 '16 at 17:27
  • really thanks for your help , still have some problems like keybd_event(key, MapVirtualKey(key, error), 0, 0) ' Down *the problem is in the error, its 0 and its say int value cannot change.. – 123neri123 Jul 15 '16 at 17:32
  • You should leave it as zero. If you want to change what key is being modified, pass a different `key` into the function. – Athena Jul 15 '16 at 17:35
  • You shouldn't call `Application.DoEvents()` in order to keep the application responsive. Use a Thread or a Task instead. – Visual Vincent Jul 15 '16 at 18:05
  • I agree this solution has flaws, but given the complexity of introducing another thread, I think this will work for the asker's purposes. – Athena Jul 15 '16 at 18:07
  • It's not that complex actually. You can even use lambdas for the sake of simplicity if you/the OP uses .NET 4.0 or higher. The point is that this will most likely eat up much CPU, especially since there's no delay, and the `DoEvents()` call might cause issues. --- Apart from that, this is a rather good solution! Good job! – Visual Vincent Jul 15 '16 at 18:09
  • Would the behavior be different if this was called from an event? As in, if this was in a method handling an OnClick event. – Athena Jul 15 '16 at 18:11
  • Nope. Everything is handled in the same way (the event handler is still a method). – Visual Vincent Jul 15 '16 at 18:12
0

Here is a simple Form, that will move a Car around the form based on the left/right/up/down keys being pressed on the keyboard. I've set my game update loop to 30 frames per second, but you could change this using a different Thread.Sleep():

there is a label on my form called "lblCar", which I'm moving the position of in every game update loop.

public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            ThreadPool.QueueUserWorkItem(new WaitCallback(GameUpdate));
        }

        private bool leftPressed;
        private bool rightPressed;
        private bool upPressed;
        private bool downPressed;

        private void GameUpdate(object state)
        {
            bool gameRunning = true;

            do
            {
                if (leftPressed)
                {
                    BeginInvoke(new Action(() => { lblCar.Location = new Point(lblCar.Location.X - 1, lblCar.Location.Y); }));
                }
                if (rightPressed)
                {
                    BeginInvoke(new Action(() => { lblCar.Location = new Point(lblCar.Location.X + 1, lblCar.Location.Y); }));
                }
                if (upPressed)
                {
                    BeginInvoke(new Action(() => { lblCar.Location = new Point(lblCar.Location.X, lblCar.Location.Y - 1); }));
                }
                if (downPressed)
                {
                    BeginInvoke(new Action(() => { lblCar.Location = new Point(lblCar.Location.X, lblCar.Location.Y + 1); }));
                }

                Thread.Sleep(33); // 30 frames per second
            } while (gameRunning);
        }

        private void Form1_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                case Keys.Left: leftPressed = true; break;
                case Keys.Right: rightPressed = true; break;
                case Keys.Up: upPressed = true; break;
                case Keys.Down: downPressed = true; break;
                default: break;
            }
        }

        private void Form1_KeyUp(object sender, KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                case Keys.Left: leftPressed = false; break;
                case Keys.Right: rightPressed = false; break;
                case Keys.Up: upPressed = false; break;
                case Keys.Down: downPressed = false; break;
                default: break;
            }
        }
    }
Jon
  • 3,230
  • 1
  • 16
  • 28
0

(visul studio) the code is

Imports System.Runtime.InteropServices

Public Class Form1
    Private Declare Sub keybd_event Lib "user32.dll" (ByVal bVk As Byte, ByVal bScan As Byte, ByVal dwFlags As Integer, ByVal dwExtraInfo As Integer)


    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

    End Sub

    <DllImport("User32.dll", SetLastError:=False, CallingConvention:=CallingConvention.StdCall, _
           CharSet:=CharSet.Auto)> _
    Public Shared Function MapVirtualKey(ByVal uCode As UInt32, ByVal uMapType As UInt32) As UInt32
    End Function

    Private Sub HoldKeyDown(ByVal key As Byte, ByVal durationInSeconds As Integer)
        Dim targetTime As DateTime = DateTime.Now().AddSeconds(durationInSeconds)
        keybd_event(key, MapVirtualKey(key, 0), 0, 0) ' Down
        While targetTime.Subtract(DateTime.Now()).TotalSeconds > 0
            Application.DoEvents()
        End While
        keybd_event(key, MapVirtualKey(key, 0), 2, 0) ' Up
    End Sub

    Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
        HoldKeyDown(Keys.A, 5)
    End Sub
End Class
Visual Vincent
  • 18,045
  • 5
  • 28
  • 75
123neri123
  • 19
  • 4