2011-02-17 17 views
13

Recientemente desarrollé una aplicación de teclado virtual para un cliente. El programa funciona bien con casi todos los programas, pero ciertos comandos como {ENTER} o {DEL} no funcionan con Citrix. ¿Hay una solución alternativa o una alternativa al SendKeys?SendKeys alternativa que funciona en Citrix

Edición 1: Probé el método SendInput (Windows Input Simulator usa SendInput) y la tecla DEL así como las teclas de flecha todavía no están funcionando. La tecla ENTER funciona sin embargo.

Editar 2: Resuelto. Probado con dos versiones diferentes de Citrix. This question helped me a lot.:

clientes ligeros Citrix utiliza el código de rastreo parámetro de keybd_event aun cuando MS dice que no se utiliza y debe ser 0. Es necesario para suministrar el código de rastreo física aswell para el cliente Citrix para conseguirlo. El cliente Citrix también tiene el problema principal con la entrada del teclado generada con la API SendInput .

remendé el código en Windows Input Simulator:

// Function used to get the scan code 
[DllImport("user32.dll")] 
static extern uint MapVirtualKey(uint uCode, uint uMapType); 


/// <summary> 
/// Calls the Win32 SendInput method ... 
/// </summary> 
/// <param name="keyCode">The VirtualKeyCode to press</param> 
public static void SimulateKeyPress(VirtualKeyCode keyCode) 
{ 
    var down = new INPUT(); 
    down.Type = (UInt32)InputType.KEYBOARD; 
    down.Data.Keyboard = new KEYBDINPUT(); 
    down.Data.Keyboard.Vk = (UInt16)keyCode; 
    // Scan Code here, was 0 
    down.Data.Keyboard.Scan = (ushort) MapVirtualKey((UInt16)keyCode, 0); 
    down.Data.Keyboard.Flags = 0; 
    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 = (UInt16)keyCode; 
    // Scan Code here, was 0 
    up.Data.Keyboard.Scan = (ushort)MapVirtualKey((UInt16)keyCode, 0); 
    up.Data.Keyboard.Flags = (UInt32)KeyboardFlag.KEYUP; 
    up.Data.Keyboard.Time = 0; 
    up.Data.Keyboard.ExtraInfo = IntPtr.Zero; 

    INPUT[] inputList = new INPUT[2]; 
    inputList[0] = down; 
    inputList[1] = up; 

    var numberOfSuccessfulSimulatedInputs = SendInput(2, 
     inputList, Marshal.SizeOf(typeof(INPUT))); 
    if (numberOfSuccessfulSimulatedInputs == 0) 
     throw new Exception(
     string.Format("The key press simulation for {0} was not successful.", 
     keyCode)); 
} 
+2

Gracias !!! XSL. ¡Gran hallazgo! Yo también estaba usando InputSimulator (herramienta fab por cierto), pero necesitaba este truco que me proporcionó (ushort) MapVirtualKey ((UInt16) keyCode, 0); Excelente trabajo: muchas gracias –

+0

¿Tiene un método para enviar una cadena completa en lugar de presionar una tecla? – Mathias

Respuesta

8

Intente utilizar Windows Input Simulator. No estoy seguro de si es compatible con Citrix pero es mucho más potente en comparación con SendKeys.

+0

Gracias por su rápida respuesta. Lo intentaré y te contaré los resultados. – xsl

3

Trate de utilizar la API llamada WIA P-Invoke firma (contenido editado: este ejemplo ahora está trabajando - Estoy enviando carácter 'a' a la caja de texto, con el clic de un botón):

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Text; 
using System.Windows.Forms; 
using System.Runtime; 
using System.Runtime.InteropServices; 

namespace Test2 
{ 
    public partial class Form1 : Form 
    { 
     [StructLayout(LayoutKind.Sequential)] 
     public struct KEYBOARD_INPUT 
     { 
      public const uint Type = 1; 
      public ushort wVk; 
      public ushort wScan; 
      public uint dwFlags; 
      public uint time; 
      public IntPtr dwExtraInfo; 
     } 

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

     [StructLayout(LayoutKind.Explicit)] 
     struct KEYBDINPUT 
     { 
      [FieldOffset(0)] 
      public ushort wVk; 
      [FieldOffset(2)] 
      public ushort wScan; 
      [FieldOffset(4)] 
      public uint dwFlags; 
      [FieldOffset(8)] 
      public uint time; 
      [FieldOffset(12)] 
      public IntPtr dwExtraInfo; 
     }; 

     [StructLayout(LayoutKind.Sequential)] 
     struct HARDWAREINPUT 
     { 
      public uint uMsg; 
      public ushort wParamL; 
      public ushort 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; 
     }; 
     [DllImport("user32.dll", SetLastError = true)] 
     static extern uint SendInput(uint nInputs, IntPtr pInput, int cbSize); 

     public Form1() 
     { 
      InitializeComponent(); 
     } 

     private void button1_Click(object sender, EventArgs e) 
     { 
      textBox1.Focus(); 
      INPUT Input = new INPUT(); 

      Input.type = 1; 
      Input.ki.wVk = 0x41; //ASCII for letter 'A' 
      Input.ki.dwFlags = 0; //Key is pressed down 
      Input.ki.dwExtraInfo = IntPtr.Zero; 
      IntPtr pInput; 
      pInput = Marshal.AllocHGlobal(Marshal.SizeOf(Input)); 

      Marshal.StructureToPtr(Input, pInput, false); 
      SendInput(1, pInput, Marshal.SizeOf(Input)); 
      Input.ki.dwFlags = 2; //Key is released on the keyboard 

      Marshal.StructureToPtr(Input, pInput, false); 
      SendInput(1, pInput, Marshal.SizeOf(Input)); 
     } 
    } 
} 
3

También estoy intentando controlar una aplicación citrix utilizando la biblioteca de Windows InputSimulator. Su código anterior parecía prometedor, así que lo actualicé para que funcione con la última versión de InputSimulator (donde se usa sim.Keyboard.Keypress en lugar de InputSimulator.SimulateKeyPress). Aquí está el código que agregué a InputSimulator, y estoy encantado de informar que funciona como se esperaba, y resuelve un problema que previamente pensé que no era posible. Muchas gracias.

En IKeyboardSimulator.cs:

/// <summary> 
    /// Simulates the key press gesture for the specified key. 
    /// </summary> 
    /// <param name="keyCode">The <see cref="VirtualKeyCode"/> for the key.</param> 
    IKeyboardSimulator CITRIXKeyPress(VirtualKeyCode keyCode); 

En KeyboardSimulator.cs:

using System.Runtime.InteropServices; 

    . 
    . 
    . 

    // CITRIX HACK 
    // Function used to get the scan code 
    [DllImport("user32.dll")] 
    static extern uint MapVirtualKey(uint uCode, uint uMapType); 

    [DllImport("User32.dll")] 
    private static extern uint SendInput(uint numberOfInputs, [MarshalAs(UnmanagedType.LPArray, SizeConst = 1)] INPUT[] input, int structSize); 


    /// <summary> 
    /// Calls the Win32 SendInput method ... 
    /// </summary> 
    /// <param name="keyCode">The VirtualKeyCode to press</param> 
    public IKeyboardSimulator CITRIXKeyPress(VirtualKeyCode keyCode) //prev public static void 
    { 
     var down = new INPUT(); 
     down.Type = (UInt32)InputType.Keyboard; 
     down.Data.Keyboard = new KEYBDINPUT(); 
     down.Data.Keyboard.KeyCode = (UInt16)keyCode; //prev .Keyboard.Vk 
     // Scan Code here, was 0 
     down.Data.Keyboard.Scan = (ushort)MapVirtualKey((UInt16)keyCode, 0); 
     down.Data.Keyboard.Flags = 0; 
     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.KeyCode = (UInt16)keyCode; 
     // Scan Code here, was 0 
     up.Data.Keyboard.Scan = (ushort)MapVirtualKey((UInt16)keyCode, 0); 
     up.Data.Keyboard.Flags = (UInt32)KeyboardFlag.KeyUp; 
     up.Data.Keyboard.Time = 0; 
     up.Data.Keyboard.ExtraInfo = IntPtr.Zero; 

     INPUT[] inputList = new INPUT[2]; 
     inputList[0] = down; 
     inputList[1] = up; 

     var numberOfSuccessfulSimulatedInputs = SendInput(2, 
      inputList, Marshal.SizeOf(typeof(INPUT))); 
     if (numberOfSuccessfulSimulatedInputs == 0) 
      throw new Exception(
      string.Format("The key press simulation for {0} was not successful.", 
      keyCode)); 
     return this; 
    } 
+0

Estoy intentando lo mismo enviar una cadena a la aplicación critix, ¿cómo paso un valor de cadena a tu código – prasy

0

Para la solución simulador de entrada de Windows, puede modificar el código fuente directamente para que el construido en funciones enviará escanear códigos con las teclas virtuales.

InputBuilder.cs:

using System.Runtime.InteropServices; 

. 
. 
. 

[DllImport("user32.dll")] 
static extern uint MapVirtualKey(uint uCode, uint uMapType); 

. 
. 
. 

public InputBuilder AddKeyDown(VirtualKeyCode keyCode) 
{ 
    var down = 
     new INPUT 
     { 
      Type = (UInt32)InputType.Keyboard, 
      Data = 
        { 
         Keyboard = 
          new KEYBDINPUT 
           { 
            KeyCode = (UInt16) keyCode, 
            Scan = (UInt16)MapVirtualKey((UInt16)keyCode, 0), 
            Flags = IsExtendedKey(keyCode) ? (UInt32) KeyboardFlag.ExtendedKey : 0, 
            Time = 0, 
            ExtraInfo = IntPtr.Zero 
           } 
        } 
      }; 

    _inputList.Add(down); 
    return this; 
} 

public InputBuilder AddKeyUp(VirtualKeyCode keyCode) 
{ 
    var up = 
     new INPUT 
      { 
       Type = (UInt32) InputType.Keyboard, 
       Data = 
        { 
         Keyboard = 
          new KEYBDINPUT 
           { 
            KeyCode = (UInt16) keyCode, 
            Scan = (UInt16)MapVirtualKey((UInt16)keyCode, 0), 
            Flags = (UInt32) (IsExtendedKey(keyCode) 
                  ? KeyboardFlag.KeyUp | KeyboardFlag.ExtendedKey 
                  : KeyboardFlag.KeyUp), 
            Time = 0, 
            ExtraInfo = IntPtr.Zero 
           } 
        } 
      }; 

    _inputList.Add(up); 
    return this; 
} 

Con estos cambios KeyPress y ModifiedKeyStroke enviará los códigos de exploración asociados con las teclas virtuales aprobadas en

Cuestiones relacionadas