0

2 つの HID キーボードを備えたシステムを使用しています (実際には、1 つはバーコード スキャナーです)。

RIDEV_NOLEGACY を使用して raw 入力を登録し、システムがバーコード スキャナー用の WM_KEY* メッセージを作成するのをブロックしました。これにより、面倒なことに他のキーボードからのメッセージもブロックされます。

私の目標は、バーコード スキャナーではないキーボード デバイスの WM_* メッセージを保持することです。

基本的に、次のいずれかが必要です。

  1. 自分で WM_* メッセージを作成し、wm_input を受け取った wndproc から自分の hwnd に投稿します。

また

  1. システムが生成する WM_* メッセージを予測し、それらがバーコード スキャナーからのものである場合は無視します。

2 の実用的な実装を作成しました。これは XP ではうまく機能しますが、Windows 7 では何もブロックできません (実際、win7 では、RIDEV_NOLEGACY フラグがなくても WM_INPUT しか受信していないようです)。

私は現在、間違いなく「より正しい」方法1を試していますが、これを完全に正しく行う方法を見つけることができないようです.

私の環境は PyQt を使用した Python 2.6 です。PyQt によって作成されたウィンドウにメッセージを直接送信しています。win32 イベント フィルターを使用して wndproc にフックしました。


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 で解決できますが、誰かが答えてくれることを期待していました。

In addition, I'm posting these messages back onto PyQt's queue, but the application fails to process them until a real event is sytem generated. That is, If I type a sentence into a text box, nothing shows up until I then move my mouse over the window. The messages seem queued until a real event happens. Any suggestions?


Clarification:

This is a window in my own process, created by PyQt. I have gotten it's hwnd, and hooked the raw input notification up to it. In the window procedure for WM_INPUT on this hwnd, I want to sendmessage to my own hwnd to duplicate the 'legacy' WM_KEY* messages that I previously disabled to filter them. Again, this all happens in my own process, in my own thread.


Update:

Shift state detection simply doesn't work. No matter what, I am getting all capital keys. Any advice?


純粋な 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
4

1 に答える 1

2

これはそのままでは修正できません。キーボードの状態を制御することはできません。受信アプリは GetKeyState() を使用して、Shift、Ctrl、または Alt キーが押されているかどうかを確認します。SetKeyState() は機能しません。メッセージを取得するプロセスではなく、プロセスのキーボード状態のみを変更します。

代わりに SendInput() を使用してください。ターゲット プロセスのウィンドウにフォーカスがある必要があります。

于 2010-10-27T16:32:08.477 に答える