Использование SendInput для отправки символов Юникода за пределами U + FFFF

Я пишу экранную клавиатуру, похожую на клавиатуру в Windows 8. У меня нет проблем с отправкой большинства символов, которые мне нужны, с помощью Win32 SendInput.

Проблема в том, что речь идет о новых эмодзи в Windows 8. Они начинаются с U + 1F600 с использованием шрифта Segoe UI Symbol.

Используя Spy ++ на экранной клавиатуре Windows 8, я получаю следующий результат для всех глифов Emoji.

<00001> 000C064A P WM_KEYDOWN nVirtKey:VK_PACKET cRepeat:1 ScanCode:00 fExtended:0 fAltDown:0 fRepeat:0 fUp:0
<00002> 000C064A P WM_CHAR chCharCode:'63' (63) cRepeat:1 ScanCode:00 fExtended:0 fAltDown:0 fRepeat:0 fUp:0
<00003> 000C064A P WM_KEYUP nVirtKey:VK_PACKET cRepeat:1 ScanCode:00 fExtended:0 fAltDown:0 fRepeat:1 fUp:1
<00004> 000C064A P WM_KEYDOWN nVirtKey:VK_PACKET cRepeat:1 ScanCode:00 fExtended:0 fAltDown:0 fRepeat:0 fUp:0
<00005> 000C064A P WM_CHAR chCharCode:'63' (63) cRepeat:1 ScanCode:00 fExtended:0 fAltDown:0 fRepeat:0 fUp:0
<00006> 000C064A P WM_KEYUP nVirtKey:VK_PACKET cRepeat:1 ScanCode:00 fExtended:0 fAltDown:0 fRepeat:1 fUp:1

Поскольку все они производят один и тот же результат, я не могу видеть, что отправлено, что на самом деле идентифицирует уникальный глиф.

Я знаю, что SendInput имеет параметр KEYEVENTF_UNICODE для отправки символов Юникода. Но эти символы, похоже, находятся на какой-то расширенной странице Unicode. За пределами 16-битного диапазона Unicode (от U + 0000 до U + FFFF) может представлять C # char или короткое значение wScan в структуре INPUT.

Вот мой метод SendCharUnicode.

public static void SendCharUnicode(char ch)
{
    Win32.INPUT[] input = new Win32.INPUT[2];

    input[0] = new Win32.INPUT();
    input[0].type = Win32.INPUT_KEYBOARD;
    input[0].ki.wVk = 0;
    input[0].ki.wScan = (short)ch;
    input[0].ki.time = 0;
    input[0].ki.dwFlags = Win32.KEYEVENTF_UNICODE;
    input[0].ki.dwExtraInfo = Win32.GetMessageExtraInfo();

    input[1] = new Win32.INPUT();
    input[1].type = Win32.INPUT_KEYBOARD;
    input[1].ki.wVk = 0;
    input[1].ki.wScan = (short)ch;
    input[1].ki.time = 0;
    input[1].ki.dwFlags = Win32.KEYEVENTF_UNICODE | Win32.KEYEVENTF_KEYUP;
    input[1].ki.dwExtraInfo = Win32.GetMessageExtraInfo();

    Win32.SendInput(2, input, Marshal.SizeOf(typeof(Win32.INPUT)));
}

Как я могу изменить этот метод для успешной отправки символа Юникода, такого как ???? (U + 1F600)?


person headkaze    schedule 10.03.2014    source источник
comment
Вы можете использовать WM_UNICHAR?   -  person Cory Nelson    schedule 10.03.2014
comment
Я уже решил проблему; У меня просто недостаточно очков, чтобы опубликовать ответ. Решение состоит в том, чтобы разбить символ UTF-32 на его суррогатную пару UTF-16 и отправить их с помощью SendInput.   -  person headkaze    schedule 10.03.2014


Ответы (1)


Я использовал API Monitor на экранной клавиатуре Windows 8, и он действительно использует SendInput. После дальнейшего расследования я обнаружил, что вам нужно разбить символ Unicode UTF-32 на его суррогатную пару UTF-16, например. ???? U + 1F604 становится [U + D83D U + DE04]. Итак, если я отправлю D83D, а затем DE04, я могу успешно отправить U + 1F604.

Вот способ работы:

public static void SendCharUnicode(int utf32)
{
    string unicodeString = Char.ConvertFromUtf32(utf32);
    Win32.INPUT[] input = new Win32.INPUT[unicodeString.Length];

    for (int i = 0; i < input.Length; i++)
    {
        input[i] = new Win32.INPUT();
        input[i].type = Win32.INPUT_KEYBOARD;
        input[i].ki.wVk = 0;
        input[i].ki.wScan = (short)unicodeString[i];
        input[i].ki.time = 0;
        input[i].ki.dwFlags = Win32.KEYEVENTF_UNICODE;
        input[i].ki.dwExtraInfo = IntPtr.Zero;
    }

    Win32.SendInput((uint)input.Length, input, Marshal.SizeOf(typeof(Win32.INPUT)));
}
person headkaze    schedule 10.03.2014
comment
Нет. Нет проблем с 64-битными приложениями. Неправильно то, что этот код просто не может отправить KEYEVENTF_KEYUP входные события. - person David Heffernan; 14.02.2019