Как имитировать WM_KEYDOWN, WM_KEY * из обработчика WM_INPUT, зарегистрированного в RIDEV_NOLEGACY? - PullRequest
0 голосов
/ 27 октября 2010

У меня есть система с двумя клавиатурами HID (на самом деле это сканер штрих-кода).

Я зарегистрировался для необработанного ввода с помощью RIDEV_NOLEGACY, чтобы заблокировать создание системой сообщений WM_KEY * для сканера штрих-кода, что также утомительно.блокирует сообщения с другой клавиатуры.

Моя цель - сохранить сообщения WM_ * для любого устройства клавиатуры, которое не является сканером штрих-кода.

По сути, мне нужно либо:

  1. Создайте сообщения WM_ * самостоятельно и отправьте их моему hwnd от wndproc, получившего wm_input

или

  1. Прогноз 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

1 Ответ

2 голосов
/ 27 октября 2010

Это невозможно исправить как есть, вы не можете контролировать состояние клавиатуры.Принимающее приложение будет использовать GetKeyState (), чтобы проверить, не нажата ли клавиша Shift, Ctrl или Alt.SetKeyState () не работает, он только изменяет состояние клавиатуры вашего процесса, а не процесса, который получает сообщения.

Вместо этого используйте SendInput ().Окно в целевом процессе должно иметь фокус.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...