2015-10-27 1 views
0

J'ai essayé d'envoyer des raccourcis clavier à une application DirectX pendant un petit moment maintenant, et je continue de la supprimer. Je suis nouveau à C#, donc certaines des fonctions les plus compliquées me passent par la tête, mais j'ai essayé de le faire le mieux possible. SendInput est une de ces choses que je n'arrive pas à saisir.Problèmes d'envoi d'une séquence de touches à l'application DirectX à l'aide de l'encapsuleur SendInput

J'ai essayé d'utiliser quelques différents emballages de SendInput pour simplifier les choses pour moi, y compris:

http://inputsimulator.codeplex.com/

http://www.codeproject.com/Articles/117657/InputManager-library-Track-user-input-and-simulate

et un autre appelé intercepteurs

Toutes les enverra La touche appuie bien sur la plupart des applications, mais je n'arrive toujours pas à les envoyer dans une fenêtre de jeu active.

J'ai également essayé SendKeys.

J'ai essayé de placer moi-même un raccourci clavier, mais il est trop avancé pour que je puisse me débrouiller tout seul, et mon code finit par être criblé d'erreurs. J'espérais que si je publie mon code ici (application serveur simple) quelqu'un pourrait être en mesure de m'expliquer où et comment placer le crochet du clavier.

namespace ServerApp 
{ 
public partial class Form1 : Form 
{ 
    private TcpListener tcpListener; 
    private Thread listenThread; 
    private int connectedClients = 0; 
    private delegate void WriteMessageDelegate(string msg); 

    public Form1() 
    { 
     InitializeComponent(); 
     Server(); 
    } 

    private void Server() 
    { 
     this.tcpListener = new TcpListener(IPAddress.Any, 8888); 
     this.listenThread = new Thread(new ThreadStart(ListenForClients)); 
     this.listenThread.Start(); 
    } 

    private void ListenForClients() 
    { 
     this.tcpListener.Start(); 

     while (true) 
     { 
      TcpClient client = this.tcpListener.AcceptTcpClient(); 

      connectedClients++; 
      lblNumberOfConnections.Text = connectedClients.ToString(); 

      Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm)); 
      clientThread.Start(client); 

     } 
    } 

    private void HandleClientComm(object client) 
    { 
     TcpClient tcpClient = (TcpClient)client; 
     NetworkStream clientStream = tcpClient.GetStream(); 

     byte[] message = new byte[4096]; 
     int bytesRead; 

     while (true) 
     { 
      bytesRead = 0; 

      try 
      { 
       bytesRead = clientStream.Read(message, 0, 4096); 
      } 
      catch 
      { 
       break; 
      } 

      if (bytesRead == 0) 
      { 
       connectedClients--; 
       lblNumberOfConnections.Text = connectedClients.ToString(); 
       break; 
      } 

      ASCIIEncoding encoder = new ASCIIEncoding(); 


      //Write message in RichTextBox 

      string msg = encoder.GetString(message, 0, bytesRead); 
      WriteMessage(msg); 

     } 

     tcpClient.Close(); 
    } 

    private void WriteMessage(string msg) 
    { 
     if (this.rtbServer.InvokeRequired) 
     { 
      WriteMessageDelegate d = new WriteMessageDelegate(WriteMessage); 
      this.rtbServer.Invoke(d, new object[] { msg }); 

     } 
     else 
     { 
      this.rtbServer.AppendText(msg + Environment.NewLine); 

      // SEND KEYSTROKES TO ACTIVE WINDOW 
      if (msg.Equals("CTRL-T")) 
      { 
       // Keyboard.KeyDown(Keys.LControlKey); 
       // Keyboard.KeyPress(Keys.T);    // I was using this for the InputManager Wrapper 
       // Keyboard.KeyUp(Keys.LControlKey); 
      } 

Après une recherche dans tous les sens, l'extrait suivant semble être ma meilleure chance d'obtenir de touches simulées pour travailler dans une application DirectX, mais je n'ai pas été en mesure de mettre en œuvre dans mon code avec des nombreuses erreurs et code inutilisable.

namespace DirectInput 
{ 
class cDirectInput 
{ 
    [DllImport("user32.dll")] 
    static extern UInt32 SendInput(UInt32 nInputs, [MarshalAs(UnmanagedType.LPArray, SizeConst = 1)] INPUT[] pInputs, Int32 cbSize); 

    [StructLayout(LayoutKind.Sequential)] 
    struct MOUSEINPUT 
    { 
     public int dx; 
     public int dy; 
     public int mouseData; 
     public int dwFlags; 
     public int time; 
     public IntPtr dwExtraInfo; 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    struct KEYBDINPUT 
    { 
     public short wVk; 
     public short wScan; 
     public int dwFlags; 
     public int time; 
     public IntPtr dwExtraInfo; 
    } 

    [StructLayout(LayoutKind.Sequential)] 
    struct HARDWAREINPUT 
    { 
     public int uMsg; 
     public short wParamL; 
     public short wParamH; 
    } 

    [StructLayout(LayoutKind.Explicit)] 
    struct INPUT 
    { 
     [FieldOffset(0)] 
     public int type; 
     [FieldOffset(4)] 
     public MOUSEINPUT mi; 
     [FieldOffset(4)] 
     public KEYBDINPUT ki; 
     [FieldOffset(4)] 
     public HARDWAREINPUT hi; 
    } 

    const int KEYEVENTF_EXTENDEDKEY = 0x0001; 
    const int KEYEVENTF_KEYUP = 0x0002; 
    const int KEYEVENTF_UNICODE = 0x0004; 
    const int KEYEVENTF_SCANCODE = 0x0008; 

Je crois que la section suivante travaillerait pour moi d'envoyer la commande CTRL+T, mais je ne suis pas sûr à 100%

// SEND KEYSTROKES TO ACTIVE WINDOW 

      if (msg.Equals("CTRL-T")) 
{ 
     INPUT[] InputData = new INPUT[1]; 

     InputData[0].type = 1; 
     InputData[0].ki.wScan = 0x1D; 
     InputData[0].ki.time = 0; 
     InputData[0].ki.dwExtraInfo = IntPtr.Zero; 

     InputData[0].type = 1; 
     InputData[0].ki.wScan = 0x14;    
     InputData[0].ki.time = 0; 
     InputData[0].ki.dwExtraInfo = IntPtr.Zero; 

     InputData[0].type = 1; 
     InputData[0].ki.wScan = 0x1D; 
     InputData[0].ki.dwFlags = 0x0002; 
     InputData[0].ki.time = 0; 
     InputData[0].ki.dwExtraInfo = IntPtr.Zero; 

     SendInput(1, InputData, Marshal.SizeOf(typeof(INPUT))); 
} 

La principale chose que je suis vraiment aux prises avec ici est de savoir comment placez le crochet du clavier dans mon code existant, et faites fonctionner correctement le reste de mon serveur. Obtenir ces frappes au clavier est la dernière partie de mon projet, et ça commence à être assez frustrant, alors toute aide est appréciée!



MISE À JOUR Je l'ai fait une autre tentative, cette fois en utilisant keybd_event(), mais pour une raison quelconque, j'ai la même question; ça marche partout mais dans le jeu. J'utilise des codes VK, pas des codes DirectInput, je ne suis pas sûr que ce soit le problème ici, mais je suis inquiet si j'utilise les codes DI à la place qu'il y a une autre partie du code que je voudrais besoin de changer ce que je ne sais pas.

Voici un extrait de ce que j'ai essayé cette fois-ci:

[DllImport("user32.dll", SetLastError = true)] 
    static extern void keybd_event(byte bVk, byte bScan, int dwFlags, int dwExtraInfo); 

    public const int KEYEVENTF_KEYUP = 0x0002; 
    public const int VK_LCONTROL = 0xA2; 
    public const int SEMICOLON = 0xBA; 
    public const int QUOTE = 0xDE; 
    public const int T = 0x54; 
    public const int H = 0x48; 
    public const int R = 0x52; 
    public const int Z = 0x5A; 
    public const int X = 0x58; 
    public const int NUM8 = 0x68; 
    public const int NUM2 = 0x62; 
    public const int NUM4 = 0x64; 
    public const int NUM6 = 0x66; 
    public const int NUM5 = 0x65; 
    public const int UP = 0x26; 
    public const int DOWN = 0x28; 
    public const int LEFT = 0x25; 
    public const int RIGHT = 0x27; 
    public const int RETURN = 0x0D; 

// ..... 

if (msg.Equals("CTRL-T")) 
    { 
     keybd_event(VK_LCONTROL, 0, 0, 0); 
     keybd_event(T, 0, 0, 0); 
     keybd_event(T, 0, KEYEVENTF_KEYUP, 0); 
     keybd_event(VK_LCONTROL, 0, KEYEVENTF_KEYUP, 0); 
     } 

Je ne peux pas comprendre si elle est quelque chose de mal avec mon code, ou si je suis encore en utilisant la mauvaise méthode.



MISE À JOUR 2 Je l'ai essayé à nouveau, cette fois en utilisant SendMessage, mais je suis incapable de construire, parce que je reçois des erreurs avec hWnd. « Le nom hWnd n'existe pas dans le contexte actuel »

[DllImport("user32.dll")] 
    public static extern IntPtr SetActiveWindow(IntPtr hWnd); 

    [DllImport("user32.dll")] 
    public static extern int SendMessage(IntPtr hWnd, int Msg, uint wParam, int lParam); 

    public const ushort WM_KEYDOWN = 0x0100; 
    public const ushort WM_KEYUP = 0x0101; 

    private void WriteMessage(string msg) 
    { 
     if (this.rtbServer.InvokeRequired) 
     { 
      WriteMessageDelegate d = new WriteMessageDelegate(WriteMessage); 
      this.rtbServer.Invoke(d, new object[] { msg }); 

     } 
     else 
     { 
      this.rtbServer.AppendText(msg + Environment.NewLine); 

      // SEND KEYSTROKES TO ACTIVE WINDOW 
      if (msg.Equals("CTRL-T")) 
      { 

       SetActiveWindow(hWnd); 
       SendMessage(hWnd, WM_KEYDOWN, 0x1D, 0); 
       SendMessage(hWnd, WM_KEYDOWN, 0x14, 0); 
       SendMessage(hWnd, WM_KEYUP, 0x1D, 0); 
       SendMessage(hWnd, WM_KEYUP, 0x14, 0); 

      } 
+0

Est-il possible que je dois définir hWnd que je suis absent? Ou y a-t-il un moyen de le faire automatiquement par défaut dans la fenêtre active? – Patrick

+0

Voir ma réponse: http://stackoverflow.com/questions/28854034/simulate-keyboard-click-in-gtasa/28854801#28854801 –

Répondre

0

j'ai fini par tout fonctionne parfaitement en utilisant le « InputManager » wrapper SendInput.

using InputManager 

//...... 

Keyboard.KeyPress(Keys.YourSelectedKeyHere); 

fin de compte, tout ce que je devais faire différemment mon code a été exécuté en tant qu'administrateur ...