演示笔Xenta Wireless以及udev、systemd的问题

CPU/显卡/打印机/USB设备等硬件问题
回复
jmxhyz
帖子: 78
注册时间: 2012-02-12 20:44

演示笔Xenta Wireless以及udev、systemd的问题

#1

帖子 jmxhyz » 2015-10-18 17:22

一支用来遥控幻灯演示的USB笔型设备,插入ubuntu系统,无法工作。
参考这个帖子viewtopic.php?f=42&t=387978,设备可以工作了。但无法自动工作。
经过一番研究,克服了好几个问题,总算可以自动工作了。其中涉及的问题,在这里记录一下。

一、确定设备信息。
因演示笔无法从外观上确定型号,在插入USB接口前,先运行udev监视:

代码: 全选

udevadm monitor
插入USB演示笔后,运行lsusb命令,查看识别的信息:
Bus 005 Device 007: ID 1d57:ac01 Xenta Wireless Receiver (Keyboard and Mouse)
根据该设备的id 1d57:ac01检查在系统上的设备名,例如:
UDEV [24945.105402] add /devices/pci0000:00/0000:00:1d.0/usb5/5-1/5-1:1.0/0003:1D57:AC01.0006/hidraw/hidraw0 (hidraw)
然后使用udevadm命令查看设备的属性,用于写udev规则:
(注意在上面的查找结果前加/sys)

代码: 全选

udevadm info -a -p /sys/devices/pci0000:00/0000:00:1d.0/usb5/5-1/5-1:1.0/0003:1D57:AC01.0006/hidraw/hidraw0 (hidraw)
二、根据udev信息,撰写udev规则:
在/etc/udev/rules.d/里面撰写99-wirelesspen.rules规则文件,内容如下:
ACTION=="add", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1d57", MODE="0666", SYMLINK+="wirelesspen", RUN+="/usr/bin/wirelesspen_relay.sh"
保存好规则后,重新加载udev规则,命令:

代码: 全选

sudo udevadm control --reload
上面的规则为设备创建一个固定名字的符号链接wirelesspen,方便后面脚本的读取。设备插入后,运行wirelesspen_relay.sh脚本。
由于udev规则的限制,只能运行短小的、短时间运行的脚本,因此在这里只能放一个小脚本作跳板(relay)。

wirelesspen_relay.sh脚本内容:

代码: 全选

#!/bin/bash
nohup /usr/bin/wirelesspen.py &
exit 0
脚本使用nohup 和 &,让真正的处理演示笔的wirelesspen.py脚本得以脱离udev规则的限制,持续工作。
把wirelesspen_relay.sh脚本放入/usr/bin,并加上运行权限。(也可以把脚本放其他地方,写udev规则时使用全路径即可)

代码: 全选

sudo chmod +x /usr/bin/wirelesspen_relay.sh
三、以上规则和跳板脚本,适用于ubuntu14.04之前的系统。
ubuntu 15.04后,采用systemd来控制udev,上面的方法不能用了。systemd会把所有由udev规则中运行(RUN)起来的脚本统统杀掉。
使用nohup、&、setsid等各种手段都无法摆脱systemd的魔爪。解决方法只能使用systemd的services(服务),感觉是变相强制使用systemd :Sad

使用systemd的ubuntu,把上面的udev规则的RUN改一下:
修改/etc/udev/rules.d/99-wirelesspen.rules规则文件:
ACTION=="add", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="1d57", MODE="0666", SYMLINK+="wirelesspen", RUN+="/bin/systemctl --no-block start wirelesspen.service"
保存好规则后,记得重新加载udev规则,命令:

代码: 全选

sudo udevadm control --reload
然后,注册systemd服务:
撰写服务文件:/etc/systemd/system/wirelesspen.service
[Unit]
Description=Wireless Pen
[Service]
Type=simple
ExecStart=/usr/bin/wirelesspen.py
如果服务运行需要参数之类的,就自行查找有关资料吧。为了简单方便,前面把演示笔链接为wirelesspen,免了很多麻烦了。

保存好服务文件,记得重新加载一下,命令:

代码: 全选

sudo systemctl daemon-reload
四,最后的事情,就是交给/usr/bin/wirelesspen.py来处理了。
上面提到的帖子,用了python的virtkey库,无法在udev中使用,因为udev使用root帐号,没有图形接口。而virtkey必须在图形接口下才能运行。
如何给系统提供虚拟按键?最终选择了另外一个python-evdev库,不再依赖图形接口,稳定提供虚拟键盘鼠标功能。
先安装python-evdev库:

代码: 全选

sudo apt-get install python-evdev
最终脚本/usr/bin/wirelesspen.py:

代码: 全选

#!/usr/bin/python
# coding: utf-8

def main():
    try:
        from evdev import UInput, ecodes as e
        ui = UInput()
    except Exception as e:
        print(str(e))
        exit()

    while True:
        try:
            hidraw = open('/dev/wirelesspen', 'r')
            c = hidraw.read(3)
            if c[2:3]=='N':
                # accepts only KEY_* events by default
                ui.write(e.EV_KEY, e.KEY_PAGEDOWN, 1)  # KEY down
                ui.write(e.EV_KEY, e.KEY_PAGEDOWN, 0)  # KEY up
                ui.syn()
            elif c[2:3]=='K':
                # accepts only KEY_* events by default
                ui.write(e.EV_KEY, e.KEY_PAGEUP, 1)  # KEY down
                ui.write(e.EV_KEY, e.KEY_PAGEUP, 0)  # KEY up
                ui.syn()
        except IOError as ioe:
            print('\n /dev/wirelesspen can not read \n')
            exit()
        except KeyboardInterrupt:
            print('\n KeyboardInterrupt \n')
            exit()
        except Exception as e:
            print(str(e))

if __name__ == "__main__":
    main()
脚本放入/usr/bin,记得一定要加上运行权限:

代码: 全选

sudo chmod +x /usr/bin/wirelesspen.py
当然也可以放在其他地方,但要记住在wirelesspen_relay.sh跳板上,或在 /etc/systemd/system/wirelesspen.service上修改路径,
jmxhyz
帖子: 78
注册时间: 2012-02-12 20:44

Re: 演示笔Xenta Wireless以及udev、systemd的问题

#2

帖子 jmxhyz » 2015-10-18 17:35

有相同设备的:ID 1d57:ac01 Xenta Wireless Receiver (Keyboard and Mouse)

可以下载以下文件安装即可:

代码: 全选

sudo python setup.py
wirelesspen.tar.gz
演示笔安装
(2.58 KiB) 已下载 125 次
回复