2014-12-11 6 views
0

ПРЕДПОСЫЛКА:функция 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)); 

ДРУГИЕ Попытанные ИСПРАВЛЕНИЯ:

  1. Я попытался оставить VirtualCode параметров заготовки (0), когда задано скан (и скан флаг), но это не меняет результата. Идея отсюда: SO question

  2. Я попытался добавить трейлинг-вызов к keybd_event, но это не изменит результат. Идея здесь: MSDN thread

    (keybd_event (0x41, 0, 0, 0);)

  3. Я попытался добавить сон нить между каждым вызовом SendInput, то есть задержка между KeyDown и KeyUp вызовов.

  4. Я изменил мои и определение структур системных функций, чтобы соответствовать Pinvoke.net

  5. Я перекомпилировать мое заявление как 64 бита (на моей машине 64 битной) - это исправил cbSize до 40, но не изменить поведение.

Любая помощь была бы высоко оценена. Также любые предложения относительно других инструментов отладки, которые я мог бы использовать? Я попытался отладить все функции клавиатуры, которые OSK может вызывать (например, для обнаружения других вызовов keybd_event), но ни один из них не регистрируется помимо вызовов SendInput.

+0

Я не могу проверить это до сегодняшнего вечера, но 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

+0

Изменение определений моей структуры и т. Д. В соответствии с определениями PInvoke.net (http://www.pinvoke.net/default.aspx/Structures/INPUT.html) не изменило поведения. Компиляция моего приложения в виде 64-битного приложения (на моей 64-битной ОС) не изменила поведение, но изменила значение cbSize на 40. – Julius

+0

Используя API-монитор (64-разрядный) на моем 64-битном приложении, я вижу, что есть тонны вызовы GetKeyState, ToUnicodeEx, GetKeyboardLayout из clr.dll (которые я явно не делаю и кажутся прикованными к моим 2 вызовам SendInput).После этого есть больше вызовов в GetKeyState и GetKeyboard из IMM32.dll и MSCTF.dll - интересно, что проверяется состояние ключа VK_CONTROL, которое возвращается как -127. Я считаю, что это 1111111110000001 в двоичном формате, поэтому бит высокого порядка включен, что означает, что ключ не работает. ЗАЧЕМ????!!! – Julius

ответ

1

Правильно, поэтому вопрос был PEBCAK.

Я пропустил наиболее очевидную вещь, которую можно вообразить - триггерный сигнал, который я использовал во время тестирования (т. Е. Сигнал, чтобы сказать, что я хочу нажать на экран с нажатой в данный момент экран), является левой клавишей CTRL. Я нажимаю клавишу CTRL, а затем задаюсь вопросом, почему Windows думает, что нажата клавиша CTRL. Убей меня сейчас.

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

Я оставлю это здесь, чтобы напомнить себе, что использовать Бритву Оккама.

Некоторые из отладочных путешествий выше могут быть полезны для кого-то; моя измененная версия кода InputSimulator работает отлично, как и исходный, неизменный код.