【问题标题】:python script to detect hot-plug event检测热插拔事件的python脚本
【发布时间】:2014-05-05 21:35:06
【问题描述】:

我正在尝试使用 python 来检测鼠标和键盘事件,并在检测过程中容忍热插拔操作。我编写这个脚本来在运行时自动检测键盘和鼠标插件并输出所有的键盘和鼠标事件。我使用 evdev 和 pyudev 包来实现这个功能。我的脚本大部分都在工作,包括键盘和鼠标事件检测以及插件检测。但是,每当我拔掉鼠标时,就会发生许多奇怪的事情,我的脚本无法正常工作。我在这里有几个困惑。

(1) 当鼠标插入系统时,/dev/input/ 文件夹中会生成两个文件,分别是./mouseX 和./eventX。我尝试 cat 查看来自两个源的输出,确实存在差异,但我不明白为什么即使 ./eventX 已经存在,linux 也会有 ./mouseX?

(2) 每当我拔下鼠标时,./mouseX unplug 事件首先出现,我没有在 evdev 中使用它,这导致脚本失败,因为 ./eventX( 我在其中读取数据script) 被同时拔掉,但我只能在下一轮检测到 ./eventX。我使用了一个技巧(脚本中的变量 i)来绕过这个问题,但是即使我可以成功删除鼠标设备,即使我没有在键盘上键入任何内容,select.select() 也会开始无休止的输入读取。

脚本如下(根据previous post的回答修改),先感谢您的关注!

#!/usr/bin/env python

import pyudev
from evdev import InputDevice, list_devices, categorize
from select import select

context = pyudev.Context()
monitor = pyudev.Monitor.from_netlink(context)
monitor.filter_by(subsystem='input')
monitor.start()

devices = map(InputDevice, list_devices())
dev_paths = []
finalizers = []

for dev in devices:
    if "keyboard" in dev.name.lower():
        dev_paths.append(dev.fn)
    elif "mouse" in dev.name.lower():
        dev_paths.append(dev.fn)

devices = map(InputDevice, dev_paths)
devices = {dev.fd : dev for dev in devices}
devices[monitor.fileno()] = monitor
count = 1

while True:
    r, w, x = select(devices, [], [])

    if monitor.fileno() in r:
        r.remove(monitor.fileno())

        for udev in iter(functools.partial(monitor.poll, 0), None):
            # we're only interested in devices that have a device node
            # (e.g. /dev/input/eventX)
            if not udev.device_node:
                break

            # find the device we're interested in and add it to fds
            for name in (i['NAME'] for i in udev.ancestors if 'NAME' in i):
                # I used a virtual input device for this test - you
                # should adapt this to your needs
                if 'mouse' in name.lower() and 'event' in udev.device_node:
                    if udev.action == 'add':
                        print('Device added: %s' % udev)
                        dev = InputDevice(udev.device_node)
                        devices[dev.fd] = dev
                        break
                    if udev.action == 'remove':
                        print('Device removed: %s' % udev)
                        finalizers.append(udev.device_node)
                        break


    for path in finalizers:
        for dev in devices.keys():
            if dev != monitor.fileno() and devices[dev].fn == path:
                print "delete the device from list"
                del devices[dev]

    for i in r:
        if i in devices.keys() and count != 0:
            count = -1
            for event in devices[i].read():
                count = count + 1
                print(categorize(event))

【问题讨论】:

    标签: python linux events keyboard


    【解决方案1】:

    mouseX 和 eventX 之间的区别,一般来说,eventX 是 evdev 设备,而 mouseX 是“传统”设备(例如,不支持各种 evdev ioctl。)

    我不知道您发布的代码有什么问题,但这里有一个代码 sn-p 可以做正确的事情。

    #!/usr/bin/env python
    
    import pyudev
    import evdev
    import select
    import sys
    import functools
    import errno
    
    context = pyudev.Context()
    monitor = pyudev.Monitor.from_netlink(context)
    monitor.filter_by(subsystem='input')
    # NB: Start monitoring BEFORE we query evdev initially, so that if
    # there is a plugin after we evdev.list_devices() we'll pick it up
    monitor.start()
    
    # Modify this predicate function for whatever you want to match against
    def pred(d):
        return "keyboard" in d.name.lower() or "mouse" in d.name.lower()
    
    # Populate the "active devices" map, mapping from /dev/input/eventXX to
    # InputDevice
    devices = {}
    for d in map(evdev.InputDevice, evdev.list_devices()):
        if pred(d):
            print d
            devices[d.fn] = d
    
    # "Special" monitor device
    devices['monitor'] = monitor
    
    while True:
        rs, _, _ = select.select(devices.values(), [], [])
        # Unconditionally ping monitor; if this is spurious this
        # will no-op because we pass a zero timeout.  Note that
        # it takes some time for udev events to get to us.
        for udev in iter(functools.partial(monitor.poll, 0), None):
            if not udev.device_node: break
            if udev.action == 'add':
                if udev.device_node not in devices:
                    print "Device added: %s" % udev
                    try:
                        devices[udev.device_node] = evdev.InputDevice(udev.device_node)
                    except IOError, e:
                        # udev reports MORE devices than are accessible from
                        # evdev; a simple way to check is see if the devinfo
                        # ioctl fails
                        if e.errno != errno.ENOTTY: raise
                        pass
            elif udev.action == 'remove':
                # NB: This code path isn't exercised very frequently,
                # because select() will trigger a read immediately when file
                # descriptor goes away, whereas the udev event takes some
                # time to propagate to us.
                if udev.device_node in devices:
                    print "Device removed (udev): %s" % devices[udev.device_node]
                    del devices[udev.device_node]
        for r in rs:
            # You can't read from a monitor
            if r.fileno() == monitor.fileno(): continue
            if r.fn not in devices: continue
            # Select will immediately return an fd for read if it will
            # ENODEV.  So be sure to handle that.
            try:
                for event in r.read():
                    pass
                    print evdev.categorize(event)
            except IOError, e:
                if e.errno != errno.ENODEV: raise
                print "Device removed: %s" % r
                del devices[r.fn]
    

    【讨论】:

      猜你喜欢
      • 2017-05-25
      • 1970-01-01
      • 2011-10-08
      • 1970-01-01
      • 2017-03-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多