ПРЕДПОСЫЛКА:функция SendInput обрабатывается в блокноте/WordPad, как если модификатор CTRL вниз
Я пишу приложение 32 битой WPF (C#), который функционирует в качестве экранной клавиатуры. Он публикует выбранные нажатия клавиш для сфокусированного окна, как если бы были нажаты физические клавиши, точно так же, как работает экранная клавиатура Microsoft OSK.exe.
ПРОБЛЕМА:
Я использую библиотеку InputSimulator с некоторым успехом (код здесь: InputSimulator class which builds the INPUT array), но обнаружили, что некоторые ключевые ходы не были признаны Блокнота, как и ожидалось, например, клавиши со стрелками ведут себя так, как если бы удерживался CTRL. Аналогично, WIN-ключ работал не так, как ожидалось, что также можно было бы объяснить, если Windows обрабатывала ввод как Ctrl + Win.
ПОПЫТКИ РЕШЕНИЕ:
Я перенес источник InputSimulator в мой проект и внесли некоторые изменения в том, как нажатия клавиш посылаются SendInput, на основе обращений к SendInput, что OSK.exe посылаемых (захвачено с использованием API Monitor) , Основные различия я наблюдал (и реплицируются в моем коде) для KeyDown/KeyUp являются:
- InputSimulator проходит Keycode и флаг ExtendedKey (если ключ Extended), плюс флаг KeyUp при отпускании клавиши ,
- OSK добавляет Scancode ключа и флаг ScanCode для большинства ключей.
- OSK также имеет некоторые другие отличия; отдельные ключи, где KeyCode не передается вообще, где ScanCode не передается вообще, и различия в ключах требуют флаг ExtendedKey.
В результате моего изменения кода, чтобы повторить, как OSK называет SendInput, что даже несколько ключей теперь ведут себя так, как будто CTRL обнаруживаетс моей целевой/сфокусированного приложения (как правило, Notepad или Wordpad). Однако из прямого сравнения моего приложения и OSK в API Monitor я считаю, что мои вызовы SendInput идентичны вызовам OSK.
N.B. OSK работает безупречно на моем Windows 8.1 (64-разрядном) ноутбуке.
ISOLATED ПРОБЛЕМА ПЛОЩАДЬ:
Чтобы минимизировать пространство проблемы я имитируется один ключ вниз/ключ совмещение ключа «S» из моего приложения на новом перезапуске компьютера (так что я могу быть уверен, состояния нажатия клавиш не были заражены предыдущими прогонами или физическими нажатиями клавиш). Целью был «Блокнот», а затем «WordPad» - оба реагировали, открыв диалог «Сохранить как», предположив, что они интерпретировали мои нажатия клавиш как CTRL + S. API Monitor обнаружил только 2 вызова SendInput (KeyDown, а затем KeyUp), и эти вызовы совпадали с тем же экспериментом, используя OSK. Вот журнал;
2014-12-10 21:29:54,650 Calling native method SendInput with params:
nInputs:1
pInputs[0]:
Type:1(Keyboard)
Data:
MOUSEINPUT:
X:2031699
Y:8
MouseData:0
Flags:0()
Time:0
KEYBDINPUT:
KeyCode:83(VK_S)
Scan:31
Flags:8 (KEYEVENTF_SCANCODE)
Time:0
ExtraInfo:0
HARDWAREINPUT:
Msg:2031699
ParamL:8
ParamH:0
cbSize:28
2014-12-10 21:29:54,651 Calling native method SendInput with params:
nInputs:1
pInputs[0]:
Type:1(Keyboard)
Data:
MOUSEINPUT:
X:2031699
Y:10
MouseData:0
Flags:0()
Time:0
KEYBDINPUT:
KeyCode:83(VK_S)
Scan:31
Flags:10 (KEYEVENTF_KEYUP | KEYEVENTF_SCANCODE)
Time:0
ExtraInfo:0
HARDWAREINPUT:
Msg:2031699
ParamL:10
ParamH:0
cbSize:28
Единственное заметное отличие заключается в том, что ОСК проходит из параметров cbSize, как 40, которые я могу не подделка (вызов завершается неудачно, если я вручную передать 40). Мой размер 28, который я получаю, передавая ниже. Я не знаю, почему размеры отличаются, поскольку мои определения структуры соответствуют документации MSDN (я не изменил их с исходного кода InputSimulator).
var cbSize = Marshal.SizeOf(typeof (INPUT));
ДРУГИЕ Попытанные ИСПРАВЛЕНИЯ:
Я попытался оставить VirtualCode параметров заготовки (0), когда задано скан (и скан флаг), но это не меняет результата. Идея отсюда: SO question
Я попытался добавить трейлинг-вызов к keybd_event, но это не изменит результат. Идея здесь: MSDN thread
(keybd_event (0x41, 0, 0, 0);)
Я попытался добавить сон нить между каждым вызовом SendInput, то есть задержка между KeyDown и KeyUp вызовов.
Я изменил мои и определение структур системных функций, чтобы соответствовать Pinvoke.net
Я перекомпилировать мое заявление как 64 бита (на моей машине 64 битной) - это исправил cbSize до 40, но не изменить поведение.
Любая помощь была бы высоко оценена. Также любые предложения относительно других инструментов отладки, которые я мог бы использовать? Я попытался отладить все функции клавиатуры, которые OSK может вызывать (например, для обнаружения других вызовов keybd_event), но ни один из них не регистрируется помимо вызовов SendInput.
Я не могу проверить это до сегодняшнего вечера, но 2 точки выделяются; Я на 64-битной системе, а мой cbSize - 28 (а не OSK 40). Это привело меня к этому (http://stackoverflow.com/questions/15394487/sendinput-does-not-work-in-windows-864-bit-but-work-in-windows-732bit). Вопрос, который предполагает, что там это проблема с размерами указателей, которые должны быть разными на 32-битных и 64-битных машинах. Это напрямую связано с этим вопросом (http://stackoverflow.com/questions/6830651/sendinput-and-64bits), который включает потенциальное решение. Я буду обновлять после тестирования. – Julius
Изменение определений моей структуры и т. Д. В соответствии с определениями PInvoke.net (http://www.pinvoke.net/default.aspx/Structures/INPUT.html) не изменило поведения. Компиляция моего приложения в виде 64-битного приложения (на моей 64-битной ОС) не изменила поведение, но изменила значение cbSize на 40. – Julius
Используя API-монитор (64-разрядный) на моем 64-битном приложении, я вижу, что есть тонны вызовы GetKeyState, ToUnicodeEx, GetKeyboardLayout из clr.dll (которые я явно не делаю и кажутся прикованными к моим 2 вызовам SendInput).После этого есть больше вызовов в GetKeyState и GetKeyboard из IMM32.dll и MSCTF.dll - интересно, что проверяется состояние ключа VK_CONTROL, которое возвращается как -127. Я считаю, что это 1111111110000001 в двоичном формате, поэтому бит высокого порядка включен, что означает, что ключ не работает. ЗАЧЕМ????!!! – Julius