Как я могу что-то сделать после того, как событие запустилось в C#?

Я использую следующий проект для обработки глобальных подключений клавиатуры и мыши в моем Приложение С#.

Этот проект в основном представляет собой оболочку вызова Win API SetWindowsHookEx с использованием констант WH_MOUSE_LL или WH_KEYBOARD_LL. Он также управляет определенным состоянием и, как правило, делает этот вид подключения довольно безболезненным.

Я использую это для программного обеспечения для распознавания жестов мыши, над которым я работаю. По сути, я настроил его таким образом, что он определяет, когда нажата глобальная горячая клавиша (скажем, CTRL), затем пользователь перемещает мышь в форме заранее определенного жеста, а затем отпускает глобальную горячую клавишу.

Событие для KeyDown обрабатывается и говорит моей программе начать запись местоположений мыши, пока не получит событие KeyUp. Это работает нормально и позволяет пользователям легко входить в режим жестов мышью. Как только событие KeyUp срабатывает и обнаруживает соответствующий жест, предполагается, что в активное окно отправляются определенные нажатия клавиш, которые пользователь определил для этого конкретного жеста, который он только что нарисовал.

Я использую методы SendKeys.Send/SendWait для отправки вывода в текущее окно.

Моя проблема заключается в следующем: когда пользователь отпускает свою глобальную горячую клавишу (скажем, CTRL), он запускает событие KeyUp. Моя программа берет записанные точки мыши, определяет соответствующий жест и пытается отправить правильный ввод через SendKeys.

Однако, поскольку все это находится в событии KeyUp, эта глобальная горячая клавиша не закончила обработку. Так, например, если я определил жест для отправки клавиши «A» при ее обнаружении, а моя глобальная горячая клавиша — CTRL, при ее обнаружении SendKeys отправит «A», но пока CTRL все еще «нажат». Итак, вместо того, чтобы просто отправить A, я получаю CTRL-A. Итак, в этом примере вместо физической отправки одного символа «A» он выбирает все с помощью сочетания клавиш CTRL-A. Несмотря на то, что пользователь отпустил CTRL (глобальную горячую клавишу), система по-прежнему считает его выключенным.

После того, как мое событие KeyUp сработает, как я могу заставить свою программу ждать какой-то период времени или какое-то событие, чтобы я мог быть уверен, что глобальная горячая клавиша действительно больше не регистрируется системой и только затем отправляет правильный ввод через SendKeys?


person Siracuse    schedule 03.05.2010    source источник


Ответы (1)


Вы можете просто установить таймер и запустить SendKeys через долю секунды (скажем, 100 мс), пользователь не заметит небольшой задержки, но будет достаточно, чтобы это произошло вне обработчика событий для KeyUp.

Другой альтернативой было бы опубликовать собственное окно (используя PostMessage) пользовательское сообщение, чтобы сигнализировать, когда оно должно «запустить» эффект, и фактически выполнить материал SendKeys в этом пользовательском обработчике сообщений. Это имеет то преимущество, что не используется произвольная «задержка». Однако его немного сложнее настроить (особенно в .NET, где вам нужно будет P/Invoke еще несколько вызовов API, чтобы заставить его работать, переопределить функцию WndProc и так далее...

person Dean Harding    schedule 03.05.2010
comment
Он может использовать BeginInvoke, чтобы получить моральный эквивалент PostMessage без всей этой утомительной возни с P/Invoke. - person Logan Capaldo; 03.05.2010
comment
Можете ли вы, ребята, описать немного подробнее, что именно я буду вызывать? Я бы использовал BeginInvoke для вызова чего? - person Siracuse; 03.05.2010
comment
Вы бы сделали window.BeginInvoke(DoStuff);, где DoStuff — это метод, который делает вещи SendKeys. - person R. Martinho Fernandes; 03.05.2010
comment
Вау, я только что попробовал это, и при первом тестировании это работает. Как это работает? Вызывая материал SendKeys асинхронно, я гарантирую, что событие KeyUp завершилось? - person Siracuse; 03.05.2010
comment
@Siracuse Вы бы использовали BeginInvoke для вызова делегата, который будет делать то, что вы сейчас делаете в KeyUp. Вызов BeginInvoke из KeyUp в основном поставит в очередь некоторый код для запуска после KeyUp. - person Logan Capaldo; 03.05.2010
comment
BeginInvoke в основном делает то, что я сказал о размещении вашего собственного пользовательского сообщения: он отправляет сообщение в очередь сообщений окна и вызывает делегата, когда это сообщение приходит. Обычно он используется для обеспечения того, чтобы фоновые потоки обновляли пользовательский интерфейс в потоке пользовательского интерфейса (как и предполагалось), но он работает и в этой ситуации. - person Dean Harding; 03.05.2010