【问题标题】:Capture and interpret XI2 RawKeyPress event with python使用 python 捕获和解释 XI2 RawKeyPress 事件
【发布时间】:2018-01-30 05:35:42
【问题描述】:

自行解决

它作为答案发布在下面。

尝试使用 python xlib 获取 xinput test-xi2 --root 打印的内容。
使用来自 github 的 1.9 版:https://github.com/python-xlib/python-xlib

event._data["data"]aaaaoo 的内容:

a<class 'Xlib.ext.ge.GenericEvent'>(data = b'\t\x00\xa9!v\x17&\x00\x00\x00\t\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', sequence_number = 15, length = 2, evtype = 13, extension = 131, type = 35)
<class 'Xlib.ext.ge.GenericEvent'>(data = b'\x03\x00\xa9!v\x17&\x00\x00\x00\t\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', sequence_number = 15, length = 2, evtype = 13, extension = 131, type = 35)
a<class 'Xlib.ext.ge.GenericEvent'>(data = b"\t\x00A'v\x17&\x00\x00\x00\t\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", sequence_number = 15, length = 2, evtype = 13, extension = 131, type = 35)
<class 'Xlib.ext.ge.GenericEvent'>(data = b"\x03\x00A'v\x17&\x00\x00\x00\t\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", sequence_number = 15, length = 2, evtype = 13, extension = 131, type = 35)
a<class 'Xlib.ext.ge.GenericEvent'>(data = b'\t\x00\xa9Ev\x17&\x00\x00\x00\t\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', sequence_number = 15, length = 2, evtype = 13, extension = 131, type = 35)
<class 'Xlib.ext.ge.GenericEvent'>(data = b'\x03\x00\xa9Ev\x17&\x00\x00\x00\t\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', sequence_number = 15, length = 2, evtype = 13, extension = 131, type = 35)
a<class 'Xlib.ext.ge.GenericEvent'>(data = b"\t\x00\xea\x9dv\x17'\x00\x00\x00\t\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", sequence_number = 15, length = 2, evtype = 13, extension = 131, type = 35)
<class 'Xlib.ext.ge.GenericEvent'>(data = b"\x03\x00\xea\x9dv\x17'\x00\x00\x00\t\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", sequence_number = 15, length = 2, evtype = 13, extension = 131, type = 35)
o<class 'Xlib.ext.ge.GenericEvent'>(data = b"\t\x002\xb4v\x17'\x00\x00\x00\t\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", sequence_number = 15, length = 2, evtype = 13, extension = 131, type = 35)
<class 'Xlib.ext.ge.GenericEvent'>(data = b"\x03\x002\xb4v\x17'\x00\x00\x00\t\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", sequence_number = 15, length = 2, evtype = 13, extension = 131, type = 35)
o<class 'Xlib.ext.ge.GenericEvent'>(data = b"\t\x00\xba\xb8v\x17'\x00\x00\x00\t\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", sequence_number = 15, length = 2, evtype = 13, extension = 131, type = 35)
<class 'Xlib.ext.ge.GenericEvent'>(data = b"\x03\x00\xba\xb8v\x17'\x00\x00\x00\t\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", sequence_number = 15, length = 2, evtype = 13, extension = 131, type = 35)

用于获取上述内容的代码;尽管需要注释掉某些行以重现上述输出。

from Xlib import X, XK, display, error
from Xlib.ext import xinput
from Xlib.protocol import rq
from Xlib import protocol
from Xlib import Xutil



class Test:
    def __init__(self):
        self.dpy_input = display.Display(None)
        #try setting events to capture
        root = self.dpy_input.screen().root
        root.xinput_select_events([(xinput.AllDevices, xinput.RawKeyPressMask)])

        extension_info = self.dpy_input.query_extension('XInputExtension')
        self.xinput_major = extension_info.major_opcode
        self.version_info = self.dpy_input.xinput_query_version()
        print('Found XInput version %u.%u' %(
            self.version_info.major_version,
            self.version_info.major_version,) )

    def run(self):
        while True:
            event = self.dpy_input.next_event()
            if event is None:
                break
            if event.type != self.dpy_input.extension_event.GenericEvent:
                break
            if event.evtype != xinput.RawKeyPress:
                break

            print (event.__class__)
            print(event.__dict__)
            print(event)

            estruct = self.dpy_input.display.event_classes.get(
                rq.byte2int(event._binary) & 0x7f, protocol.event.AnyEvent)
            print(estruct)

            e , d= rq.EventField(None).parse_binary_value(
                event._binary, self.dpy_input.display, None, None)
            print (e)


            e , d= rq.EventField(None).parse_binary_value(
                event._data["data"], self.dpy_input.display, None, None)
            print (e)

            break

if __name__ == "__main__":
    t = Test()
    t.run()

a 按键时的输出:

Found XInput version 2.2
<class 'Xlib.ext.ge.GenericEvent'>
{'_data': {'sequence_number': 15, 'extension': 131, 'length': 2, 'send_event': False, 'data': b'\t\x00\xbf\xbdc\x17&\x00\x00\x00\t\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', 'evtype': 13, 'type': 35}, '_binary': b'#\x83\x0f\x00\x02\x00\x00\x00\r\x00'}
<class 'Xlib.ext.ge.GenericEvent'>(sequence_number = 15, extension = 131, length = 2, data = b'\t\x00\xbf\xbdc\x17&\x00\x00\x00\t\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', evtype = 13, type = 35)
<class 'Xlib.ext.ge.GenericEvent'>
<class 'Xlib.ext.ge.GenericEvent'>(sequence_number = 15, extension = 131, length = 2, data = b'', evtype = 13, type = 35)
aTraceback (most recent call last):
  File "/home/d/PycharmProjects/GUIConfigurator/xi2_test.py", line 54, in <module>
    t.run()
  File "/home/d/PycharmProjects/GUIConfigurator/xi2_test.py", line 47, in run
    event._data["data"], self.dpy_input.display, None, None)
  File "/home/d/PycharmProjects/GUIConfigurator/Xlib/protocol/rq.py", line 859, in parse_binary_value
    return estruct(display = display, binarydata = data[:32]), data[32:]
  File "/home/d/PycharmProjects/GUIConfigurator/Xlib/protocol/rq.py", line 1403, in __init__
    rawdict = 1)
  File "/home/d/PycharmProjects/GUIConfigurator/Xlib/protocol/rq.py", line 1146, in parse_binary
    val = struct.unpack(self.static_codes, data[:self.static_size])
struct.error: unpack requires a bytes object of length 32  

问题

event._data["data"] 中有什么内容,我怎样才能让它可读?

【问题讨论】:

    标签: python x11 hid xlib


    【解决方案1】:

    设法破解 RawKeyPress 事件中的部分二进制数据。
    这个过程相当......不过,我想知道真正的黑客是如何做到这一点的。

    from Xlib import X, XK, display, error
    from Xlib.ext import xinput
    import time
    
    
    class Test:
        def __init__(self):
            self.dpy_input = display.Display(None)
            #try setting events to capture
            root = self.dpy_input.screen().root
            root.xinput_select_events([(xinput.AllMasterDevices, xinput.RawKeyPressMask)])
            extension_info = self.dpy_input.query_extension('XInputExtension')
            self.xinput_major = extension_info.major_opcode
            self.version_info = self.dpy_input.xinput_query_version()
            print('Found XInput version %u.%u' %(
                self.version_info.major_version,
                self.version_info.major_version,) )
    
        def run(self):
            while True:
                event = self.dpy_input.next_event()
                if event is None:
                    break
                if event.type != self.dpy_input.extension_event.GenericEvent:
                    break
                if event.evtype != xinput.RawKeyPress:
                    break
    
                # print (event.__class__)
                # print(event.__dict__)
                print(event)
                b = event._data["data"]
    
                device = b[0:1]
                print("device:%d" % ( int.from_bytes(device,"little")))
                # value at b[1] seems like padding, always 0.
    
                # 7th byte contains x11 keycode
                keycode = b[6]
                print("keycode:"+str(keycode))
    
    
                # Not certain as to what this really is.
                timestamp = b[2:6] # four bytes int
                print('timestamp:'+str(int.from_bytes(timestamp,"little")))
    
                # Not certain as to what this really is.
                valuators = b[7:9] # 2 bytes, short int
                print("valuators:" + str(int.from_bytes(valuators,"little")))
    
                device_id = b[10:11] # 2 bytes, short int
                print("device id:" + str(int.from_bytes(device_id,"little")))
    
    
    if __name__ == "__main__":
        t = Test()
        t.run()
    

    我将 python 脚本输出与 xinput test-xi2 --root 的输出进行了比较,以获得 A 按键。

    Python:

    b'\x03\x00H\x8a\xd9\x1c&\x00\x00\x00\x0c\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
    

    输入:

    EVENT type 14 (RawKeyRelease)
        device: 3 (12)
        detail: 38
        valuators:
    

    现在脚本打印出来了:

    Found XInput version 2.2
    <class 'Xlib.ext.ge.GenericEvent'>(evtype = 13, data = b'\x03\x004=A\x1d&\x00\x00\x00\x0c\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', type = 35, length = 2, extension = 131, sequence_number = 15)
    device:3
    keycode:38
    timestamp:490814772
    valuators:0
    device id:12
    

    虽然它仍然相当不完整,但我必须在这里停下来,因为现在我知道 RawKeyPress 事件没有提供我想要的:隐藏使用 id 或 linux 内核扫描码。

    【讨论】:

    • 要获取 Linux 内核扫描码,您可以使用evdev。这是一个 C API,但我认为还有一个 Python 库
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-07
    • 2010-09-06
    • 2012-09-27
    • 1970-01-01
    相关资源
    最近更新 更多