У меня есть система с двумя клавиатурами HID (на самом деле это сканер штрих-кода).
Я зарегистрировался для необработанного ввода с помощью RIDEV_NOLEGACY, чтобы заблокировать создание системой сообщений WM_KEY * для сканера штрих-кода, что также утомительно.блокирует сообщения с другой клавиатуры.
Моя цель - сохранить сообщения WM_ * для любого устройства клавиатуры, которое не является сканером штрих-кода.
По сути, мне нужно либо:
- Создайте сообщения WM_ * самостоятельно и отправьте их моему hwnd от wndproc, получившего wm_input
или
- Прогноз WM_ *сообщения, которые система будет генерировать, и игнорировать их, если они пришли из сканера штрих-кода.
Я создал работающую реализацию 2, которая прекрасно работает на XP, но не может ничего блокировать на Windows 7. (ВНа самом деле, на win7 кажется, что я получаю только WM_INPUT, даже без флага RIDEV_NOLEGACY)
Я сейчас пробую метод 1, который, возможно, «более корректен», но яКажется, я не могу найти способ сделать это полностью правильно.
Моя среда Python 2.6 с использованием PyQt.Я отправляю сообщения непосредственно в окно, созданное PyQt, и подключился к его wndproc с помощью фильтра событий win32.
class wm_lparam(Structure):
_fields_ = [("repeat_count", c_short),
("scancode", c_byte),
("extended_key", c_int, 1),
("reserved", c_int, 4),
("context_code", c_int, 1),
("prev_state", c_int, 1),
("transition_state", c_int, 1),
]
assert sizeof(wm_lparam) == 8, sizeof(wm_lparam)
WM_KEYDOWN = 0x0100
WM_KEYUP = 0x0101
WM_SYSKEYDOWN = 0x0104
WM_SYSKEYUP = 0x0105
ALL_WM_KEYDOWN = (WM_KEYDOWN, WM_SYSKEYDOWN)
ALL_WM_KEYUP = (WM_KEYUP, WM_SYSKEYUP)
VK_SHIFT = 0x10
VK_LSHIFT = 0xA0
VK_RSHIFT = 0xA1
#These values are filled in by my WM_INPUT handler and the RAWINPUT struct
@staticmethod
def _synthesize_wm_legacy(hwnd, wm, vk, scancode, modifider_keys=None):
kbState_old = (c_byte*255)()
kbState = (c_byte*255)()
def keydown(vk):
return bool(user32.GetAsyncKeyState(vk) & 0x8000)
kbState[VK_SHIFT] = 0x80 if keydown(VK_SHIFT) else 0
kbState[VK_LSHIFT] = 0x80 if keydown(VK_SHIFT) else 0
user32.GetKeyboardState(kbState_old)
user32.SetKeyboardState(kbState)
lParam = wm_lparam()
lp = c_uint.from_address(ctypes.addressof(lParam))
lParam.repeat_count = 0
lParam.scancode = scancode
lParam.extended_key = 0
if wm in ALL_WM_KEYDOWN:
lParam.context_code = 0
lParam.prev_state = 0
lParam.transition_state = 0
if wm in ALL_WM_KEYUP:
lParam.repeat_count = 0
lParam.context_code = 0
lParam.prev_state = 1
lParam.transition_state = 1
lp = lp.value
if wm in ALL_WM_KEYUP: #Seems ctypes doesn't like my struct definition.
lp |= 1 << 30
lp |= 1 << 31
log.debug("Posting %s %s %s %08x\n%s"%(hwnd, wm_str(wm), vk, lp, lParam.dump_s()))
user32.SendMessageA(hwnd, wm, vk, lp)
user32.SetKeyboardState(kbState_old)
Этот код работает, но некоторые вещи (например, удержаниеклавиша Shift и т. д.) не удалась.Также очень странным является то, что при использовании SendMessage я набираю буквы в верхнем регистре, но переключение на PostMessage делает их строчными.Вероятно, я могу решить эту проблему с помощью Get / SetKeyState, но я надеялся, что кто-нибудь может дать мне несколько ответов.
Кроме того, я отправляю эти сообщения обратно в очередь PyQt, но приложение не может их обработать до тех пор, поканастоящее событие генерируется системой.То есть, если я введу предложение в текстовое поле, ничего не появится, пока я не наведу курсор мыши на окно.Сообщения кажутся в очереди, пока не произойдет реальное событие.Есть предложения?
Уточнение:
Это окно в моем собственном процессе, созданное PyQt.Я получил его hwnd и подключил к нему необработанное входное уведомление.В оконной процедуре для WM_INPUT на этом hwnd я хочу отправить сообщение на мой собственный hwnd, чтобы продублировать «устаревшие» сообщения WM_KEY *, которые я ранее отключил для их фильтрации.Опять же, все это происходит в моем собственном процессе, в моем собственном потоке.
Обновление:
Определение состояния сдвига просто не работает.Несмотря ни на что, я получаю все прописные ключи.Любой совет?
Мне не удалось решить эту проблему в чистом Win32, и я получил только половину решения, так как я использую PyQt.Если кто-то заинтересован, вот код, который я использую для этой части:
class BarcodeQtEventFiler(QtCore.QObject):
def __init__(self, parent, *args):
self.log = logging.getLogger(__name__ + '.keyevent')
self.app = parent
self.input_to_surpress = list()
super(BarcodeQtEventFiler, self).__init__(parent, *args)
def ignoreKey(self, which):
"""On WM_INPUT from the device, call this with the reported VKey"""
self.input_to_surpress.append(which)
def eventFilter(self, object, event):
if event.type() == QtCore.QEvent.KeyPress:
if self.input_to_surpress:
if event.nativeVirtualKey() in self.input_to_surpress:
z = None
#This loop eats the suppression buffer until the VK pressed is found. Fixes Dupes for WM key up/down, etc.
while z != event.nativeVirtualKey():
z = self.input_to_surpress.pop(0)
self.log.debug("Ate key press %s (%s)", event.key(), event.text())
return True
else:
self.log.debug("Future surpressed input: %s", self.input_to_surpress)
self.log.debug("Allowing key press %s (%s)", event.key(), event.text())
return False