Я не эксперт в win32, но я не могу не чувствовать, что если вы проигрываете события, в любом случае ничто не будет абсолютно надежным. Насколько я понимаю, вы пытаетесь контролировать, куда идут события клавиатуры (то есть, в какое окно они идут), основываясь на физической исходной клавиатуре - возможно, было бы лучше вместо фильтрации событий просто вводить их в первую очередь. место.
То есть, зарегистрируйте низкоуровневый хук клавиатуры , который просто отбрасывает все введенные события. Теперь используйте необработанный обработчик событий клавиатуры, чтобы внедрить эмулированные сообщения WM_KEYUP / WM_KEYDOWN в любое окно, которое должно получить их в конце.
В противном случае нам нужно (как-то) синхронизировать потоки событий WM_INPUT и WM_KEY *. Я предполагаю, что вы уже научились обмениваться данными между вашей внедренной DLL-библиотекой подключений и слушателем WM_INPUT в вашем «главном» процессе. Мы начнем с определения мьютекса с готовым ключом. Приложение, обрабатывающее хук WM_KEY *, немедленно получит этот мьютекс перед дальнейшей обработкой, чтобы избежать гонок с другими процессами, которые также могут обрабатывать ключи.
Ваш процесс обработки WM_INPUT может начать запись в кольцевой буфер совместно используемой памяти (синхронизированный с именованным мьютексом) кодов ключей, полученных через WM_INPUT, по порядку. Каждый код ключа должен иметь метку времени; Хуки WM_KEY * будут игнорировать старые коды клавиш. Обработчики WM_KEY * сначала проверяют, соответствует ли их событие самому старому не просроченному событию в буфере; если это так, уведомление должно быть отправлено ведущему процессу, и обработчик выполнит любую обработку, какую пожелает. Нет проблем.
Если в кольцевом буфере нет данных, именованный семафор можно использовать для сна. Счетчик семафора должен быть оптимистичным счетчиком количества записей, оставшихся в кольцевом буфере; получение счетчика дает процессу право и обязанность удалить один элемент из буфера, если таковой имеется, но если буфер пуст, процесс должен отбросить кольцевой мьютекс и вернуться к ожиданию семафора. Затем процедура ловушки может поставить (короткий!) Тайм-аут на ожидание в мьютексе; если время ожидания истекло, ловушка должна считать, что была рассинхронизация, и продолжить нормальную обработку. Может быть хорошей идеей будет отключить хук на короткий промежуток времени, чтобы избежать замедления быстрого набора.
Если перехватчик считывает из кольцевого буфера код клавиши, который не соответствует нажатию клавиши, которой он был отправлен, то где-то произошла рассинхронизация. Обработка этого может зависеть от того, что вы делаете; например, если вы внедряете систему горячих клавиш, одним из подходов будет просто отбросить все необработанные события и превратить ловушку в чистый проход, пока все клавиатуры не будут молчать в течение короткого интервала.
Имейте в виду, что, поскольку вы имеете дело с несинхронизированными потоками, каждый из которых видит свой отдельный фрагмент из нескольких несинхронизированных потоков событий, десинхронизация всегда будет проблемой. Внедрение событий все еще может быть хорошим способом избежать этого, поскольку дает единую точку синхронизации, которая может обеспечить упорядочение событий.