Последовательность SendInput для создания символа Unicode не работает - PullRequest
0 голосов
/ 09 февраля 2010

Я работаю с экранной клавиатурой, которой нужно отправлять нажатия клавиш сторонним приложениям. Они работают на Windows XP. Небольшой набор символов, которые недоступны на американской английской клавиатуре, должен поддерживаться (например, «å» или ñ). После просмотра SendInput казалось, что самым безопасным будет отправить шестнадцатеричное значение Unicode символа в виде последовательности нажатий клавиш. Я написал код, который отправляет события нажатия клавиши «Alt» и «Add», за которыми следуют события нажатия клавиши «вниз» и «вверх» для последовательности символов Unicode из четырех символов с клавишей Alt «ORed», а затем, наконец, события «добавления» и «Alt». В моем приложении C # test. Я использую KeyPreview и, конечно же, все события проходят, однако все, что я получаю, это звуковой сигнал, без символа. Я получил ту же информацию от ввода нажатий клавиш вручную, информация KeyPreview идентична, и появляется символ.

Можно ли использовать SendInput таким образом? Я не использовал ловушку для проверки данных, но я видел посты, которые указывают, что к событиям SendInput прикреплен какой-то «введенный» флаг, может быть, это приводит к сбою последовательности?

Этот демонстрационный код успешно отправляет ключевые события, но последовательность ключевых событий, предназначенных для генерирования символа Unicode, не выполняется.

    private const uint KEYEVENTF_KEYDOWN = 0x0000;
    private const uint KEYEVENTF_EXTENDEDKEY = 0x0001;
    private const uint KEYEVENTF_KEYUP = 0x0002;

    private const int INPUT_KEYBOARD = 1;

    [DllImport ("user32.dll", SetLastError = false)]
    static extern IntPtr GetMessageExtraInfo ();

    [DllImport ("user32.dll", SetLastError = true)]
    static extern uint SendInput (uint nInputs, [MarshalAs (UnmanagedType.LPArray, SizeConst = 1)] INPUT[] pInputs, int cbSize);

    [StructLayout (LayoutKind.Sequential, Size = 24)]
    private struct KEYBDINPUT
    {
        public ushort wVk;
        public ushort wScan;
        public uint dwFlags;
        public uint time;
        public IntPtr dwExtraInfo;
    }

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

    private void PressKey (Keys k)
    {
        PressKeyDown (k);
        PressKeyUp (k);
    }

    private void PressKeyDown (Keys k)
    {
        INPUT input = new INPUT ();
        input.type = INPUT_KEYBOARD;
        input.ki.wVk = (byte)k;
        input.ki.wScan = 0;
        input.ki.time = 0;

        uint flags = KEYEVENTF_KEYDOWN;
        if ((33 <= (byte)k && (byte)k <= 46) || (91 <= (byte)k) && (byte)k <= 93)
            flags |= KEYEVENTF_EXTENDEDKEY;
        input.ki.dwFlags = flags;

        input.ki.dwExtraInfo = GetMessageExtraInfo ();

        Output ("Sending key down {0}. Flags:{1}", k, flags);

        INPUT[] inputs = new INPUT[] { input };
        uint result = SendInput ((uint)inputs.Length, inputs, Marshal.SizeOf (typeof (INPUT)));

        if ((uint)inputs.Length != result)
            MessageBox.Show ("PressKeyDown result = " + Marshal.GetLastWin32Error ());
    }

    private void PressKeyUp (Keys k)
    {
        INPUT input = new INPUT ();
        input.type = INPUT_KEYBOARD;
        input.ki.wVk = (byte)k;
        input.ki.wScan = 0;
        input.ki.time = 0;

        uint flags = KEYEVENTF_KEYUP;
        if ((33 <= (byte)k && (byte)k <= 46) || (91 <= (byte)k) && (byte)k <= 93)
            flags |= KEYEVENTF_EXTENDEDKEY;
        input.ki.dwFlags = flags;

        input.ki.dwExtraInfo = GetMessageExtraInfo ();

        Output ("Sending key up {0}", k);

        INPUT[] inputs = new INPUT[] { input };
        uint result = SendInput ((uint)inputs.Length, inputs, Marshal.SizeOf (typeof (INPUT)));

        if ((uint)inputs.Length != result)
            MessageBox.Show ("PressKeyUp result = " + Marshal.GetLastWin32Error ());
    }

    private void TestSend ()
    {
        System.Threading.Thread.CurrentThread.Join (1000);

        Keys k = Keys.Menu;
        PressKeyDown (k);

        System.Threading.Thread.Sleep (100);

        k = Keys.Add;
        k |= Keys.Alt;
        PressKeyDown (k);

        System.Threading.Thread.Sleep (100);

        k = Keys.NumPad0;
        k |= Keys.Alt;
        PressKey (k);

        System.Threading.Thread.Sleep (100);

        k = Keys.NumPad0;
        k |= Keys.Alt;
        PressKey (k);

        System.Threading.Thread.Sleep (100);

        k = Keys.E;
        k |= Keys.Alt;
        PressKey (k);

        System.Threading.Thread.Sleep (100);

        k = Keys.NumPad5;
        k |= Keys.Alt;
        PressKey (k);

        System.Threading.Thread.Sleep (100);

        PressKeyUp (Keys.Add);
        PressKeyUp (Keys.Menu);
    }

Ответы [ 3 ]

4 голосов
/ 12 декабря 2011
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace Simulate
{
    public class Simulate
    {
        [DllImport("USER32.DLL", CharSet = CharSet.Unicode)]
        static extern UInt32 SendInput(UInt32 numberOfInputs, INPUT[] input, Int32 sizeOfInputStructure);

        [StructLayout(LayoutKind.Sequential, Size = 24)]
        struct KEYBDINPUT
        {
            public UInt16 Vk;
            public UInt16 Scan;
            public UInt32 Flags;
            public UInt32 Time;
            public UInt32 ExtraInfo;
        }

        [StructLayout(LayoutKind.Explicit)]
        private struct INPUT
        {
            [FieldOffset(0)]
            public int Type;
            [FieldOffset(4)]
            public KEYBDINPUT ki;
        } 

        public static void TextInput(string text)
        {
            char[] chars = text.ToCharArray();

            for (int i = 0; i < chars.Length; i++)
            {
                UInt16 unicode = chars[i];

                INPUT down = new INPUT();
                down.Type = 1; //INPUT_KEYBOARD
                down.ki.Vk = 0;
                down.ki.Scan = unicode;
                down.ki.Time = 0;
                down.ki.Flags = 0x0004; //KEYEVENTF_UNICODE
                down.ki.ExtraInfo = 0;

                INPUT up = new INPUT();
                up.Type = 1; //INPUT_KEYBOARD
                up.ki.Vk = 0;
                up.ki.Scan = unicode;
                up.ki.Time = 0;
                up.ki.Flags = 0x0004; //KEYEVENTF_UNICODE
                up.ki.ExtraInfo = 0;

                INPUT[] input = new INPUT[2];
                input[0] = down;
                input[1] = up;
                SendInput(1, input, Marshal.SizeOf(typeof(INPUT)));
            }
        }
    }
}

// Call the API :
Simulate.TextInput("AbCçDeFgĞhİiJkLmNoÖpQrSşTuÜvXyZ - äÄß_0123456789");
1 голос
/ 09 февраля 2010

Вы можете сгенерировать их, удерживая клавишу Alt и введя 4-значный код Unicode на цифровой клавиатуре. å = Alt + 0229, ñ = Alt + 0241. Найдите другие коды с помощью апплета Charmap.exe.

0 голосов
/ 23 февраля 2010

Очевидно, что обработка последовательности нажатий клавиш для представления символа Юникода выполняется на уровне, который недоступен через SendInput. Я изменил свой код, чтобы установить флаг Unicode для dwFlags и установить значение Unicode для параметра данных wScan. Мне удалось убедить себя после тестирования на нескольких европейских и азиатских языках, что это приводит к тем же результатам, что и метод множественного нажатия клавиш.

...