【问题标题】:SendKeys alternative that works on Citrix适用于 Citrix 的 SendKeys 替代方案
【发布时间】:2011-06-29 01:40:55
【问题描述】:

我最近为客户开发了一个虚拟键盘应用程序。该程序几乎适用于所有程序,但某些命令(如 {ENTER}{DEL})不适用于 Citrix。是否有解决方法或替代SendKeys

编辑 1:我尝试了 SendInput 方法(Windows 输入模拟器使用 SendInput)并且 DEL 键以及箭头键仍然不起作用。但是,ENTER 键有效。

编辑 2:已解决。使用两种不同版本的 Citrix 进行了测试。 This question helped me a lot.:

Citrix 瘦客户端使用扫描码 即使MS说keybd_event的参数 它未使用,应该为 0。你需要 同时提供物理扫描码 让 citrix 客户端获取它。 Citrix客户端也有大问题 使用生成的键盘输入 发送输入 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));
}

【问题讨论】:

  • 感谢 xsl !!!伟大的发现!我也在使用 InputSimulator (fab tool btw),但我需要你提供的这个调整 (ushort)MapVirtualKey((UInt16)keyCode, 0);出色的工作 - 非常感谢
  • 你有发送整个字符串而不是按键的方法吗?
  • 这可以在 Python 脚本中使用吗?

标签: c# .net sendkeys citrix virtual-keyboard


【解决方案1】:

尝试使用Windows Input Simulator. 不确定它是否支持Citrix,但与SendKeys 相比它更强大。

【讨论】:

  • 感谢您的快速回复。我会尝试并告诉你结果。
【解决方案2】:

对于windows输入模拟器方案,可以直接修改源码,让内置函数通过虚拟按键发送扫码。

InputBuilder.cs:

using System.Runtime.InteropServices;
.
.
.
[DllImport("user32.dll")]
static extern uint MapVirtualKeyEx(uint uCode, uint uMapType, IntPtr dwhkl);

[DllImport("user32.dll", CharSet = CharSet.Unicode)]
static extern short VkKeyScanEx(char ch, IntPtr dwhkl);
.
.
.
public InputBuilder AddKeyDown(VirtualKeyCode keyCode)
{
    var down =
        new INPUT
        {
            Type = (UInt32)InputType.Keyboard,
            Data =
                    {
                        Keyboard =
                            new KEYBDINPUT
                                {
                                    KeyCode = (UInt16) keyCode,
                                    Scan = (UInt16)MapVirtualKeyEx((UInt16)keyCode, 0, IntPtr.Zero),
                                    Flags = IsExtendedKey(keyCode) ? (UInt32) KeyboardFlag.ExtendedKey : (UInt32) KeyboardFlag.ScanCode,
                                    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)MapVirtualKeyEx((UInt16)keyCode, 0,IntPtr.Zero),
                                    Flags = (UInt32) (IsExtendedKey(keyCode)
                                                          ? KeyboardFlag.KeyUp | KeyboardFlag.ExtendedKey
                                                          : KeyboardFlag.KeyUp | KeyboardFlag.ScanCode),
                                    Time = 0,
                                    ExtraInfo = IntPtr.Zero
                                }
                    }
            };

    _inputList.Add(up);
    return this;
}
.
.
.
public InputBuilder AddCharacter(char character)
{
    bool shiftChr = ((UInt16)VkKeyScanEx(character, IntPtr.Zero) >> 8).Equals(1);
    if (shiftChr)
    {
        AddKeyDown(VirtualKeyCode.VK_SHIFT);
    }

    UInt16 scanCode = shiftChr ? (UInt16)MapVirtualKeyEx((UInt16)(VkKeyScanEx(character, IntPtr.Zero) & 0xff),0,IntPtr.Zero) : (UInt16)MapVirtualKeyEx((UInt16)VkKeyScanEx(character, IntPtr.Zero), 0, IntPtr.Zero);

    var down = new INPUT
                   {
                       Type = (UInt32)InputType.Keyboard,
                       Data =
                           {
                               Keyboard =
                                   new KEYBDINPUT
                                       {
                                           KeyCode = 0,
                                           Scan = scanCode,
                                           Flags = (UInt32)KeyboardFlag.ScanCode,
                                           Time = 0,
                                           ExtraInfo = IntPtr.Zero
                                       }
                           }
                   };

    var up = new INPUT
                 {
                     Type = (UInt32)InputType.Keyboard,
                     Data =
                         {
                             Keyboard =
                                 new KEYBDINPUT
                                     {
                                         KeyCode = 0,
                                         Scan = scanCode,
                                         Flags =
                                             (UInt32)(KeyboardFlag.KeyUp | KeyboardFlag.ScanCode),
                                         Time = 0,
                                         ExtraInfo = IntPtr.Zero
                                     }
                         }
                 };

    _inputList.Add(down);
    _inputList.Add(up);

    if (shiftChr)
    {
        AddKeyUp(VirtualKeyCode.VK_SHIFT);
    }

    return this;
}

通过这些更改,TextEntryKeyPressModifiedKeyStroke 将发送与传入的虚拟键关联的扫描码。

【讨论】:

    【解决方案3】:

    我还尝试使用 Windows InputSimulator 库控制 citrix 应用程序。您上面的代码看起来很有希望,所以我更新了它以使用最新版本的 InputSimulator(您使用 sim.Keyboard.Keypress 而不是 InputSimulator.SimulateKeyPress)。这是我添加到 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;
        }
    

    【讨论】:

    • 我正在尝试将字符串发送到 critix 应用程序,我如何将字符串值传递给您的代码
    【解决方案4】:

    尝试通过 P-Invoke 签名使用 API 调用(内容已编辑:这是现在工作的示例 - 我正在通过单击按钮将字符“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));
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-14
      相关资源
      最近更新 更多