2011-02-17 4 views
13

저는 최근에 고객을위한 가상 키보드 응용 프로그램을 개발했습니다. 프로그램이 거의 모든 프로그램에서 제대로 작동하지만 {ENTER} 또는 {DEL}과 같은 특정 명령이 Citrix에서 작동하지 않습니다. 해결 방법이 있거나 SendKeys의 대안이 있습니까?Citrix에서 작동하는 SendKeys 대안

편집 1 : SendInput 메서드 (Windows 입력 시뮬레이터에서 SendInput 사용)를 시도했지만 화살표 키와 함께 DEL 키가 여전히 작동하지 않습니다. 그러나 ENTER 키는 작동합니다.

편집 2 : 해결했습니다. 두 가지 버전의 Citrix에서 테스트되었습니다. This question helped me a lot. : MS는 그것이 사용되지 않고 당신은 그것을 얻을 수있는 시트릭스 클라이언트 aswell 물리적 스캔 코드를 제공 할 을 필요로 0이되어야 을 말한다하더라도

시트릭스 씬 클라이언트는 keybd_event의 스캔 코드 PARAM를 사용합니다. 또한 SendInput API를 사용하여 키보드 입력을 생성하는 중대한 문제가 있습니다.

나는 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

감사 XSL에 전달 된 가상 키와 관련된 스캔 코드를 보내드립니다! 위대한 발견! 나는 InputSimulator (fab tool btw)를 사용하고 있었지만 MapVirtualKey (UInt16) keyCode, 0); 훌륭한 작업 - 많은 감사합니다 –

+0

키 누르기 대신 전체 문자열을 보내는 방법이 있습니까? – Mathias

답변

8

시도가 시트릭스를 지원하지만 그것을에서 SendKeys에 비해 훨씬 더 강력한 경우 확실하지 Windows Input Simulator.를 사용하여. API 호출 WIA P-호출 서명을 활용하는

+0

빠른 응답을 보내 주셔서 감사합니다. 나는 그것을 시도하고 당신에게 결과를 말할 것이다. – xsl

3

봅니다 (이 지금 작업 예 - 나는 버튼 클릭에, 'A'텍스트 상자에 문자를 보내고있다 콘텐츠 편집) :

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

Windows InputSimulator 라이브러리를 사용하여 citrix 응용 프로그램을 제어하려고 시도하고 있습니다. 위의 코드가 유망 해 보였으므로 InputSimulator의 최신 버전 (InputSimulator.SimulateKeyPress 대신 sim.Keyboard.Keypress를 사용)과 함께 작동하도록 업데이트했습니다. 다음은 InputSimulator에 추가 한 코드입니다. 예상대로 작동한다는 것을보고하게되어 기쁘게 생각합니다. 이전에는 불가능하다고 생각했던 문제를 해결했습니다. 정말 고마워. 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); 

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

나는 똑같은 일을하려고 애 쓰고있다. 비평 용 애플리케이션에 문자열을 보낸다. ur 값을 문자열 값으로 전달하는 법 – prasy

0

, 당신은 직접 소스 코드를 수정 기능을 내장 보낼 수 있도록 할 수 있습니다 가상 키로 코드를 스캔하십시오.

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; 
} 

KeyPressModifiedKeyStroke