「懸鉤子」的全部文章

勇闖新世界︰ 《 Kernel 4.X 》之整裝蓄勢‧設備管理及應用‧三下

當人們嘗試用 python-evdev 的 uinput 時,也許早已發現那個程式必須冠以 sudo 才能執行?

 

pi@raspberrypi ~ python3 Python 3.2.3 (default, Mar  1 2013, 11:53:50)  [GCC 4.6.3] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> from evdev import uinput, ecodes as e >>> with uinput.UInput() as ui: ...     ui.write(e.EV_KEY, e.KEY_LEFTSHIFT, 1) ...     ui.write(e.EV_KEY, e.KEY_A, 1) ...     ui.syn() ...  Traceback (most recent call last):   File "<stdin>", line 1, in <module>   File "/usr/local/lib/python3.2/dist-packages/evdev/uinput.py", line 64, in __init__     self._verify()   File "/usr/local/lib/python3.2/dist-packages/evdev/uinput.py", line 195, in _verify     raise UInputError(msg.format(self.devnode)) evdev.uinput.UInputError: "/dev/uinput" cannot be opened for writing >>>   pi@raspberrypi ~ sudo python3
Python 3.2.3 (default, Mar  1 2013, 11:53:50) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from evdev import uinput, ecodes as e
>>> with uinput.UInput() as ui:
...     ui.write(e.EV_KEY, e.KEY_LEFTSHIFT, 1)
...     ui.write(e.EV_KEY, e.KEY_A, 1)
...     ui.syn()
... 
>>> 

 

為什麼呢? Linux 是多人多工的作業環境 ,各種裝置設備有著一種分享觀,所以需要管理,以避免系統資源之不當使用。所以即使在只有一人擁有的情況下,那個人也就得要負起管理責任。雖說今天早就是個人電腦的時代,這個『root』與『sudo』問題也爭議多年 。由於『網路資安』的風險越來越高,或許學點正統管理辦法未嘗不是件好事,就讓我們來改善 user pi 的使用權限吧!

 

【/dev/uinput 的原本權限是 root only】

因此只有 super user 可以使用這個裝置

pi@raspberrypi /dev ls uinput* -l crw------T 1 root root 10, 223  8月 18 10:39 uinput </pre>    <span style="color: #808080;"><strong>【創建 udev rule,管理 uinput 裝置】</strong></span>  最簡單的辦法,模仿『輸入裝置』的 udev 規則︰  <span style="color: #ff9900;">/etc/udev/rules.d/99-input.rules </span> <span style="color: #ff9900;">SUBSYSTEM=="input", GROUP="input", MODE="0660"</span>  【參考設定】 <pre class="lang:sh decode:true "># 建立新規則 pi@raspberrypi ~ sudo nano /etc/udev/rules.d/70-uinput.rules 

# 內容一行
KERNEL=="uinput", GROUP="uinput", MODE="0660"

# 建立新群組 group
pi@raspberrypi ~ sudo addgroup uinput  # 將使用者 pi 歸屬到 uinput 群組 pi@raspberrypi ~ sudo adduser pi uinput

# 重新開機,重啟 udev
pi@raspberrypi ~ sudo reboot  # 確認 udev 規則正確執行 pi@raspberrypi ~ sudo rmmod uinput
Error: Module uinput is not currently loaded

pi@raspberrypi ~ sudo modprobe uinput  # 新的權限設定 pi@raspberrypi ~ ls /dev/uinput -l
crw-rw---T 1 root uinput 10, 223  8月 18 10:42 /dev/uinput

 

前面引用的例子,其實有個出處︰

Simulate keystroke in linux with Python

Consider python-uinput and evdev. Example of shift+a with the latter:

from evdev import uinput, ecodes as e

with uinput.UInput() as ui:
    ui.write(e.EV_KEY, e.KEY_LEFTSHIFT, 1)
    ui.write(e.EV_KEY, e.KEY_A, 1)
    ui.syn()
I tried similar code, it is exeuted because I see in system log that a new virtual input device was created but the keystrokes do not appear in X? Any special thing can be done so the keys are received by X server?

 

之所以用這個例子,是希望說明『整體理解』的重要性。比方說,有人在鍵盤上打了一個 A 鍵,假使根本沒有應用程式在讀取鍵盤,將會發生什麼事情呢?這個『模糊』的問題是沒有『正確答案』的 !因為系統『環境設定』之不同,結果可以非常不一樣。因此如果想要『測試』那個程式,也許可以

一、 進入 raspbian 視窗環境,打開 lxterminal ,當作接收端。

二、 使用ssh -l pi 樹莓派 IP 遠端登入,作為程式執行端。

如此將會見到

2015-08-18-105806_659x432_scrot

的也!!

 

於此再舉

gpio-evdev-driver

polls GPIO events on the Raspberry Pi and maps them to keyboard events.

The code was intended to be used with RetroPie: http://blog.petrockblock.com/retropie/ and custom input hardware which is directly hooked up to the GPIO pins of the Pi. Similar projects (also based on uinput, listed below) exist, but none of them worked for my particular configuration so I decided to start a new one.

The code polls for low-active signals! It sets the input pins up with the internat pull-up resistors, so the default state is HIGH. After a pin is connected to GND, an input event is triggered, which fires a keyboard event.

When running the code for the first time, it will ask you to define a keyboard event to be sent for each user action in ACTIONS. The same goes for GPIO events (falling edges). Currently, you revert the configuration by simply deleting the corresponding *.p files. ……

 

這個網頁,給有興趣的讀者。同時附以用之改寫的 PiTFT GPIO 按鍵轉碼鍵盤程式,以為範例︰

 

import RPi.GPIO as GPIO
from time import sleep
import pickle
from os.path import isfile
from evdev import InputDevice, UInput, categorize, ecodes
from sys import stdout

入針 = [17,22,23,27] # pins to be 輪詢ed (all others are ignored)
多少入針 = len(入針)
鍵盤保存檔 = 'keys.p' # key configuration (action -> key)
按鍵保存檔 = 'gpio.p' # gpio configuration (action -> gpio pin)
動作 = ['Menu', 'Up', 'Down', 'ESC'] # list of user 動作 (should be <= 入針)
輪詢時距 = 0.01 # in seconds

# setup input pins to use pull-up resistors
def 設定入針():
        for pin in 入針:
                print("輪詢ing pin %d" % pin)
                GPIO.setup(pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)

# 輪詢ing loop
def 輪詢(mapping):
        state = dict(zip(入針,多少入針*[1])) # default pin state (working with low-active signals here)
        uinput = UInput()

        while True:
                for pin in 入針:
                        pval = state[pin] # previous pin state
                        val = GPIO.input(pin) # current pin state

                        # detect edges
                        if not pval and val: # rising edge
                                #print("rising edge at pin %d -> %s up" % (pin,ecodes.KEY[mapping[pin]]))
                                uinput.write(ecodes.EV_KEY, mapping[pin], 0)  # key up
                                uinput.syn()
                        elif pval and not val: # falling edge
                                #print("falling edge at pin %d -> %s down" % (pin, ecodes.KEY[mapping[pin]]))
                                uinput.write(ecodes.EV_KEY, mapping[pin], 1)  # key down
                                uinput.syn()

                        state[pin] = val # update pin state

                sleep(輪詢時距) # wait for next 輪詢ing cycle

# waits for and returns key down event
def wait_key(dev):
        for event in dev.read_loop():
                if event.type == ecodes.EV_KEY and event.value == 1: # key down
                        return event

# waits for falling edge and returns corresponding input pin 
def wait_falling_edge():
        while True:
                for pin in 入針:
                        if GPIO.input(pin) == 0:
                                return pin
        sleep(輪詢時距)

# print() without linebreak
def printf(string):
        stdout.write(string)
        stdout.flush()

# prompts for keyboard events to be sent for each user action (action->key mapping)
def 規劃鍵盤鍵(dev):
        keys = dict()
        for action in 動作:
                printf("press key for %s ... " % action)
                while True:
                        event = wait_key(dev)
                        if event.code not in keys.values():
                                break
                printf("%s\n" % ecodes.KEY[event.code])
                keys[action] = event.code
        return keys

# prompts for GPIO events that should trigger the user 動作 (action->pin mapping)
def 規劃開關鍵():
        gpio = dict()
        for action in 動作:
                printf("press button for %s ... " % action)
                while True:
                        pin = wait_falling_edge()
                        if pin not in gpio.values():
                                break
                printf("%d\n" % pin)
                gpio[action] = pin
        return gpio

# reads action->key mapping from config file, starts configuration if file not yet exists
def read_keys():
        if not isfile(鍵盤保存檔):
                keyboard = InputDevice('/dev/input/event1')
                keys = 規劃鍵盤鍵(keyboard)
                pickle.dump(keys, open(鍵盤保存檔,'wb'))
        else:
                keys = pickle.load(open(鍵盤保存檔, 'rb'))
        return keys

# reads action->pin mapping from config file, starts configuration if file not yet exists
def read_gpio():
        if not isfile(按鍵保存檔):
                gpio = 規劃開關鍵()
                pickle.dump(gpio, open(按鍵保存檔,'wb'))
        else:
                gpio = pickle.load(open(按鍵保存檔, 'rb'))
        return gpio

# creates pin->key mapping for all user 動作
def create_mapping(gpio, keys):
        mapping = dict()
        for action in 動作:
                mapping[gpio[action]] = keys[action]
        return mapping


GPIO.setmode(GPIO.BCM)
設定入針()

keys = read_keys()
gpio = read_gpio()
mapping = create_mapping(gpio, keys)

輪詢(mapping)

 

 

※ 註記︰樹莓派官方板 raspbian 已經將 Kernel 版本更新至 4.1.6 。

 

 

 

 

 

 

 

 

勇闖新世界︰ 《 Kernel 4.X 》之整裝蓄勢‧設備管理及應用‧三上

假使從『裝置的程式介面』 API 來觀察『裝置』是什麼?『裝置』不過就是透過那個『 API 規範』存取的 □□○○!這可引發了一個『大哉問』?如果說某種『物理裝置』事實上沒有連上系統,但是它的『API 介面』卻『存在』且能『運作』,那麼我們『能不能』知道那個『裝置』實際上不存在的呢??這個問題其實比表面深沈 的多,一直延伸到『知識論』的哲學爭議之上。比方說,什麼是『蘋果樹 』?如何判定『某個水果』是『蘋果』?最終總容易落入用『外在屬性』來作『歸類』的事實裡。更不要講過去的『接枝』到現今的『基改』,所作的『跨界』之事!也許當『界線』越來越模糊,『什麼是什麼』的問題終將越來越不清楚的耶!!

這『何謂鴨子』之事也發生在『物件導向』的語言中。維基百科的『鴨子型別』講︰

當看到一隻鳥走起來像鴨子、游泳起來像鴨子、叫起來也像鴨子,那麼這隻鳥就可以被稱為鴨子。

Duck typing

In computer programming with object-oriented programming languages, duck typing is a layer of programming language and design rules on top of typing. Typing is concerned with assigning a type to any object. Duck typing is concerned with establishing the suitability of an object for some purpose. With normal typing, suitability is assumed to be determined by an object’s type only. In duck typing, an object’s suitability is determined by the presence of certain methods and properties (with appropriate meaning), rather than the actual type of the object.

The name of the concept refers to the duck test, attributed to James Whitcomb Riley, which may be phrased as follows:

When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck.[1]

In duck typing, a programmer is only concerned with ensuring that objects behave as demanded of them in a given context, rather than ensuring that they are of a specific type. For example, in a non-duck-typed language, one would create a function that requires that the object passed into it be of type Duck, in order to ensure that that function can then use the object’s walk and quack methods. In a duck-typed language, the function would take an object of any type and simply call its walk and quack methods, producing a run-time error if they are not defined. Instead of specifying types formally, duck typing practices rely on documentation, clear code, and testing to ensure correct use.

───

Criticism

One issue with duck typing is that it forces programmers to have a much wider understanding of the code they are working with at any given time. For instance, in Python, one could easily create a class called Wine, which expects a class implementing the “press” attribute as an ingredient. However, a class called Trousers might also implement the press() method. With duck typing, in order to prevent strange, hard-to-detect errors, the developer needs to be aware of each potential use of the method “press”, even when it’s conceptually unrelated to what they are working on. By way of contrast, in a strongly and statically typed language that uses type hierarchies and parameter type checking, it’s much harder to supply an unexpected object type to a class. For example, in a language like Java, the ambiguity in the above reuse of the method name press() would not be a problem unless one of the two classes was deliberately defined as a child of the other.

Proponents of duck typing, such as Guido van Rossum, argue that the issue is handled by testing, and the necessary knowledge of the codebase required to maintain it.[4][5]

Criticisms around duck typing tend to be special cases of broader points of contention regarding dynamically typed versus statically typed programming language semantics.

 

所以,什麼是『電腦滑鼠』的呢?若是以『核心輸入子系統』以及『python-evdev 程式庫』的觀點而言,就是能『產生』某些『事件型別』的東東罷了!

【滑鼠參考說明】

pi@raspberrypi ~ python3 Python 3.2.3 (default, Mar  1 2013, 11:53:50)  [GCC 4.6.3] on linux2 Type "help", "copyright", "credits" or "license" for more information.  >>> from evdev import InputDevice, list_devices  # 取得系統所有的輸入設備 >>> 輸入裝置列 =  [InputDevice(fn) for fn in list_devices()] >>> for 裝置 in 輸入裝置列: ...     print(裝置.fn, 裝置.name, 裝置.phys) ...  /dev/input/event3 Logitech USB Receiver usb-bcm2708_usb-1.5/input1 /dev/input/event2 Logitech USB Receiver usb-bcm2708_usb-1.5/input0 /dev/input/event1 Logitech USB Receiver usb-bcm2708_usb-1.4/input1 /dev/input/event0 Logitech USB Receiver usb-bcm2708_usb-1.4/input0 >>>   # 選擇電腦滑鼠 >>> 裝置 = InputDevice('/dev/input/event2') >>> print(裝置) device /dev/input/event2, name "Logitech USB Receiver", phys "usb-bcm2708_usb-1.5/input0"  # 裝置詳細功能 >>> 裝置.capabilities(verbose=True) {('EV_MSC', 4): [('MSC_SCAN', 4)], ('EV_KEY', 1): [(['BTN_LEFT', 'BTN_MOUSE'], 272), ('BTN_RIGHT', 273), ('BTN_MIDDLE', 274), ('BTN_SIDE', 275), ('BTN_EXTRA', 276), ('BTN_FORWARD', 277), ('BTN_BACK', 278), ('BTN_TASK', 279), ('?', 280), ('?', 281), ('?', 282), ('?', 283), ('?', 284), ('?', 285), ('?', 286), ('?', 287)], ('EV_REL', 2): [('REL_X', 0), ('REL_Y', 1), ('REL_HWHEEL', 6), ('REL_WHEEL', 8)], ('EV_SYN', 0): [('SYN_REPORT', 0), ('SYN_CONFIG', 1), ('SYN_MT_REPORT', 2), ('?', 4)]} >>> from evdev import categorize, ecodes >>>  >>> 裝置.capabilities() {0: [0, 1, 2, 4], 1: [272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287], 2: [0, 1, 6, 8], 4: [4]} >>>   # 電腦滑鼠功能測試 >>> 滑鼠裝置 = 裝置  # 產生相對移動事件 >>> for 事件 in 滑鼠裝置.read_loop(): ...     if 事件.type == ecodes.EV_REL: ...         print(categorize(事件)) ...         print(事件) ...  relative axis event at 1439779280.080989, REL_WHEEL  event at 1439779280.080989, code 08, type 02, val -1 relative axis event at 1439779283.809490, REL_WHEEL  event at 1439779283.809490, code 08, type 02, val 01 relative axis event at 1439779287.810024, REL_X  event at 1439779287.810024, code 00, type 02, val -1 relative axis event at 1439779287.810024, REL_Y  event at 1439779287.810024, code 01, type 02, val 01 relative axis event at 1439779287.954040, REL_X  event at 1439779287.954040, code 00, type 02, val -1 relative axis event at 1439779287.986048, REL_X  event at 1439779287.986048, code 00, type 02, val -1 relative axis event at 1439779288.002045, REL_X  event at 1439779288.002045, code 00, type 02, val -1 relative axis event at 1439779288.018041, REL_X  event at 1439779288.018041, code 00, type 02, val -3 relative axis event at 1439779288.018041, REL_Y  event at 1439779288.018041, code 01, type 02, val 01 relative axis event at 1439779288.034044, REL_X  event at 1439779288.034044, code 00, type 02, val -1 relative axis event at 1439779288.114064, REL_Y  event at 1439779288.114064, code 01, type 02, val 01 relative axis event at 1439779307.764695, REL_X  event at 1439779307.764695, code 00, type 02, val 01 ^CTraceback (most recent call last):   File "<stdin>", line 1, in <module>   File "/usr/local/lib/python3.2/dist-packages/evdev/device.py", line 280, in read_loop     r, w, x = select([self.fd], [], []) KeyboardInterrupt >>>   # 產生按鍵事件 >>> for 事件 in 滑鼠裝置.read_loop(): ...     if 事件.type == ecodes.EV_KEY: ...         print(categorize(事件)) ...         print(事件) ...  key event at 1439779469.418293, 272 (['BTN_LEFT', 'BTN_MOUSE']), down event at 1439779469.418293, code 272, type 01, val 01 key event at 1439779469.626321, 272 (['BTN_LEFT', 'BTN_MOUSE']), up event at 1439779469.626321, code 272, type 01, val 00 key event at 1439779472.474709, 273 (BTN_RIGHT), down event at 1439779472.474709, code 273, type 01, val 01 key event at 1439779472.762738, 273 (BTN_RIGHT), up event at 1439779472.762738, code 273, type 01, val 00 key event at 1439779477.195335, 274 (BTN_MIDDLE), down event at 1439779477.195335, code 274, type 01, val 01 key event at 1439779477.627399, 274 (BTN_MIDDLE), up event at 1439779477.627399, code 274, type 01, val 00 ^CTraceback (most recent call last):   File "<stdin>", line 1, in <module>   File "/usr/local/lib/python3.2/dist-packages/evdev/device.py", line 280, in read_loop     r, w, x = select([self.fd], [], []) KeyboardInterrupt >>>  </pre>    <span style="color: #666699;">因此所謂用『python-evdev』來寫程式,處理的就是『裝置事件』的『解讀』與『產生』而已!!</span>  <span style="color: #666699;">【鍵盤補充範例】</span> <pre class="lang:sh decode:true   ">pi@raspberrypi ~ python3
Python 3.2.3 (default, Mar  1 2013, 11:53:50) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from evdev import InputDevice, list_devices, categorize, ecodes

>>> 鍵盤 = InputDevice('/dev/input/event0')

>>> 鍵盤.capabilities(verbose=True)
{('EV_LED', 17): [('LED_NUML', 0), ('LED_CAPSL', 1), ('LED_SCROLLL', 2), ('LED_COMPOSE', 3), ('LED_KANA', 4)], ('EV_MSC', 4): [('MSC_SCAN', 4)], ('EV_KEY', 1): [('KEY_ESC', 1), ('KEY_1', 2), ('KEY_2', 3), ('KEY_3', 4), ('KEY_4', 5), ('KEY_5', 6), ('KEY_6', 7), ('KEY_7', 8), ('KEY_8', 9), ('KEY_9', 10), ('KEY_0', 11), ('KEY_MINUS', 12), ('KEY_EQUAL', 13), ('KEY_BACKSPACE', 14), ('KEY_TAB', 15), ('KEY_Q', 16), ('KEY_W', 17), ('KEY_E', 18), ('KEY_R', 19), ('KEY_T', 20), ('KEY_Y', 21), ('KEY_U', 22), ('KEY_I', 23), ('KEY_O', 24), ('KEY_P', 25), ('KEY_LEFTBRACE', 26), ('KEY_RIGHTBRACE', 27), ('KEY_ENTER', 28), ('KEY_LEFTCTRL', 29), ('KEY_A', 30), ('KEY_S', 31), ('KEY_D', 32), ('KEY_F', 33), ('KEY_G', 34), ('KEY_H', 35), ('KEY_J', 36), ('KEY_K', 37), ('KEY_L', 38), ('KEY_SEMICOLON', 39), ('KEY_APOSTROPHE', 40), ('KEY_GRAVE', 41), ('KEY_LEFTSHIFT', 42), ('KEY_BACKSLASH', 43), ('KEY_Z', 44), ('KEY_X', 45), ('KEY_C', 46), ('KEY_V', 47), ('KEY_B', 48), ('KEY_N', 49), ('KEY_M', 50), ('KEY_COMMA', 51), ('KEY_DOT', 52), ('KEY_SLASH', 53), ('KEY_RIGHTSHIFT', 54), ('KEY_KPASTERISK', 55), ('KEY_LEFTALT', 56), ('KEY_SPACE', 57), ('KEY_CAPSLOCK', 58), ('KEY_F1', 59), ('KEY_F2', 60), ('KEY_F3', 61), ('KEY_F4', 62), ('KEY_F5', 63), ('KEY_F6', 64), ('KEY_F7', 65), ('KEY_F8', 66), ('KEY_F9', 67), ('KEY_F10', 68), ('KEY_NUMLOCK', 69), ('KEY_SCROLLLOCK', 70), ('KEY_KP7', 71), ('KEY_KP8', 72), ('KEY_KP9', 73), ('KEY_KPMINUS', 74), ('KEY_KP4', 75), ('KEY_KP5', 76), ('KEY_KP6', 77), ('KEY_KPPLUS', 78), ('KEY_KP1', 79), ('KEY_KP2', 80), ('KEY_KP3', 81), ('KEY_KP0', 82), ('KEY_KPDOT', 83), ('KEY_ZENKAKUHANKAKU', 85), ('KEY_102ND', 86), ('KEY_F11', 87), ('KEY_F12', 88), ('KEY_RO', 89), ('KEY_KATAKANA', 90), ('KEY_HIRAGANA', 91), ('KEY_HENKAN', 92), ('KEY_KATAKANAHIRAGANA', 93), ('KEY_MUHENKAN', 94), ('KEY_KPJPCOMMA', 95), ('KEY_KPENTER', 96), ('KEY_RIGHTCTRL', 97), ('KEY_KPSLASH', 98), ('KEY_SYSRQ', 99), ('KEY_RIGHTALT', 100), ('KEY_HOME', 102), ('KEY_UP', 103), ('KEY_PAGEUP', 104), ('KEY_LEFT', 105), ('KEY_RIGHT', 106), ('KEY_END', 107), ('KEY_DOWN', 108), ('KEY_PAGEDOWN', 109), ('KEY_INSERT', 110), ('KEY_DELETE', 111), (['KEY_MIN_INTERESTING', 'KEY_MUTE'], 113), ('KEY_VOLUMEDOWN', 114), ('KEY_VOLUMEUP', 115), ('KEY_POWER', 116), ('KEY_KPEQUAL', 117), ('KEY_PAUSE', 119), ('KEY_KPCOMMA', 121), (['KEY_HANGEUL', 'KEY_HANGUEL'], 122), ('KEY_HANJA', 123), ('KEY_YEN', 124), ('KEY_LEFTMETA', 125), ('KEY_RIGHTMETA', 126), ('KEY_COMPOSE', 127), ('KEY_STOP', 128), ('KEY_AGAIN', 129), ('KEY_PROPS', 130), ('KEY_UNDO', 131), ('KEY_FRONT', 132), ('KEY_COPY', 133), ('KEY_OPEN', 134), ('KEY_PASTE', 135), ('KEY_FIND', 136), ('KEY_CUT', 137), ('KEY_HELP', 138), ('KEY_F13', 183), ('KEY_F14', 184), ('KEY_F15', 185), ('KEY_F16', 186), ('KEY_F17', 187), ('KEY_F18', 188), ('KEY_F19', 189), ('KEY_F20', 190), ('KEY_F21', 191), ('KEY_F22', 192), ('KEY_F23', 193), ('KEY_F24', 194), ('KEY_UNKNOWN', 240)], ('EV_SYN', 0): [('SYN_REPORT', 0), ('SYN_CONFIG', 1), ('?', 4), ('?', 17), ('?', 20)]}

>>> 鍵盤.capabilities()
{0: [0, 1, 4, 17, 20], 1: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 113, 114, 115, 116, 117, 119, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 240], 4: [4], 17: [0, 1, 2, 3, 4]}

>>> 鍵盤.leds(verbose=True)
[]

>>> for 事件 in 鍵盤.read_loop():
...     if 事件.type == ecodes.EV_KEY:
...         print(categorize(事件))
...         print(事件)
... 
key event at 1439784566.338788, 20 (KEY_T), down
event at 1439784566.338788, code 20, type 01, val 01
key event at 1439784566.418811, 20 (KEY_T), up
event at 1439784566.418811, code 20, type 01, val 00
key event at 1439784568.283038, 18 (KEY_E), down
event at 1439784568.283038, code 18, type 01, val 01
key event at 1439784568.387043, 18 (KEY_E), up
event at 1439784568.387043, code 18, type 01, val 00
key event at 1439784569.291174, 31 (KEY_S), down
event at 1439784569.291174, code 31, type 01, val 01
key event at 1439784569.395174, 31 (KEY_S), up
event at 1439784569.395174, code 31, type 01, val 00
key event at 1439784569.659215, 20 (KEY_T), down
event at 1439784569.659215, code 20, type 01, val 01
key event at 1439784569.763225, 20 (KEY_T), up
event at 1439784569.763225, code 20, type 01, val 00
key event at 1439784575.187941, 58 (KEY_CAPSLOCK), down
event at 1439784575.187941, code 58, type 01, val 01
key event at 1439784575.291938, 58 (KEY_CAPSLOCK), up
event at 1439784575.291938, code 58, type 01, val 00
key event at 1439784582.908932, 58 (KEY_CAPSLOCK), down
event at 1439784582.908932, code 58, type 01, val 01
key event at 1439784583.044951, 58 (KEY_CAPSLOCK), up
event at 1439784583.044951, code 58, type 01, val 00
key event at 1439784585.613291, 69 (KEY_NUMLOCK), down
event at 1439784585.613291, code 69, type 01, val 01
key event at 1439784585.709302, 69 (KEY_NUMLOCK), up
event at 1439784585.709302, code 69, type 01, val 00
key event at 1439784588.661688, 69 (KEY_NUMLOCK), down
event at 1439784588.661688, code 69, type 01, val 01
key event at 1439784588.765693, 69 (KEY_NUMLOCK), up
event at 1439784588.765693, code 69, type 01, val 00
^CTraceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.2/dist-packages/evdev/device.py", line 280, in read_loop
    r, w, x = select([self.fd], [], [])
KeyboardInterrupt
>>> 

 

 

 

 

 

 

勇闖新世界︰ 《 Kernel 4.X 》之整裝蓄勢‧設備管理及應用‧二下

同樣當我們想應用 python-evdev uinput 程式庫寫作程式,在閱讀 『技術文件 』時,請務須仔細而且確實,千萬不要隨意放過不清楚的『術語』。底下列出相關文檔,方便讀者參考︰

uinput

class evdev.uinput.UInput(events=None, name=’py-evdev-uinput’, vendor=1, product=1, version=1, bustype=3, devnode=’/dev/uinput’)

A userland input device and that can inject input events into the linux input subsystem.

__init__(events=None, name=’py-evdev-uinput’, vendor=1, product=1, version=1, bustype=3, devnode=’/dev/uinput’)

Parameters:
  • events (dictionary of event types mapping to lists of event codes.) – the event types and codes that the uinput device will be able to inject – defaults to all key codes.
  • name – the name of the input device.
  • vendor – vendor identifier.
  • product – product identifier.
  • version – version identifier.
  • bustype – bustype identifier.

Note

If you do not specify any events, the uinput device will be able to inject only KEY_* and BTN_* event codes.

name
Uinput device name.
vendor
Device vendor identifier.
product
Device product identifier.
version
Device version identifier.
bustype
Device bustype – eg. BUS_USB.
devnode
Uinput device node – eg. /dev/uinput/.
fd
Write-only, non-blocking file descriptor to the uinput device node.
device
An InputDevice instance for the fake input device. None if the device cannot be opened for reading and writing.
write_event(event)

Inject an input event into the input subsystem. Events are queued until a synchronization event is received.

Parameters: event – InputEvent instance or an object with an event attribute (KeyEvent, RelEvent etc).

Example:

ev = InputEvent(1334414993, 274296, ecodes.EV_KEY, ecodes.KEY_A, 1)
ui.write_event(ev)
write(etype, code, value)

Inject an input event into the input subsystem. Events are queued until a synchronization event is received.

Parameters:
  • etype – event type (eg. EV_KEY).
  • code – event code (eg. KEY_A).
  • value – event value (eg. 0 1 2 – depends on event type).

Example:

ui.write(e.EV_KEY, e.KEY_A, 1) # key A - down
ui.write(e.EV_KEY, e.KEY_A, 0) # key A - up
syn()

Inject a SYN_REPORT event into the input subsystem. Events queued by write() will be fired. If possible, events will be merged into an ‘atomic’ event.
capabilities(verbose=False, absinfo=True)

See capabilities.

 

【Linux uinput 設備資料結構】

Linux/include/linux/uinput.h

uinput_request

 45 struct uinput_request {
 46         unsigned int            id;
 47         unsigned int            code;   /* UI_FF_UPLOAD, UI_FF_ERASE */
 48 
 49         int                     retval;
 50         struct completion       done;
 51 
 52         union {
 53                 unsigned int    effect_id;
 54                 struct {
 55                         struct ff_effect *effect;
 56                         struct ff_effect *old;
 57                 } upload;
 58         } u;
 59 };

 

uinput_device

 61 struct uinput_device {
 62         struct input_dev        *dev;
 63         struct mutex            mutex;
 64         enum uinput_state       state;
 65         wait_queue_head_t       waitq;
 66         unsigned char           ready;
 67         unsigned char           head;
 68         unsigned char           tail;
 69         struct input_event      buff[UINPUT_BUFFER_SIZE];
 70         unsigned int            ff_effects_max;
 71 
 72         struct uinput_request   *requests[UINPUT_NUM_REQUESTS];
 73         wait_queue_head_t       requests_waitq;
 74         spinlock_t              requests_lock;
 75 };

 

【Linux 輸入設備資料結構】

Linux/include/linux/input.h

121 struct input_dev {
122         const char *name;
123         const char *phys;
124         const char *uniq;
125         struct input_id id;
126 
127         unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)];
128 
129         unsigned long evbit[BITS_TO_LONGS(EV_CNT)];
130         unsigned long keybit[BITS_TO_LONGS(KEY_CNT)];
131         unsigned long relbit[BITS_TO_LONGS(REL_CNT)];
132         unsigned long absbit[BITS_TO_LONGS(ABS_CNT)];
133         unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)];
134         unsigned long ledbit[BITS_TO_LONGS(LED_CNT)];
135         unsigned long sndbit[BITS_TO_LONGS(SND_CNT)];
136         unsigned long ffbit[BITS_TO_LONGS(FF_CNT)];
137         unsigned long swbit[BITS_TO_LONGS(SW_CNT)];
138 
139         unsigned int hint_events_per_packet;
140 
141         unsigned int keycodemax;
142         unsigned int keycodesize;
143         void *keycode;
144 
145         int (*setkeycode)(struct input_dev *dev,
146                           const struct input_keymap_entry *ke,
147                           unsigned int *old_keycode);
148         int (*getkeycode)(struct input_dev *dev,
149                           struct input_keymap_entry *ke);
150 
151         struct ff_device *ff;
152 
153         unsigned int repeat_key;
154         struct timer_list timer;
155 
156         int rep[REP_CNT];
157 
158         struct input_mt *mt;
159 
160         struct input_absinfo *absinfo;
161 
162         unsigned long key[BITS_TO_LONGS(KEY_CNT)];
163         unsigned long led[BITS_TO_LONGS(LED_CNT)];
164         unsigned long snd[BITS_TO_LONGS(SND_CNT)];
165         unsigned long sw[BITS_TO_LONGS(SW_CNT)];
166 
167         int (*open)(struct input_dev *dev);
168         void (*close)(struct input_dev *dev);
169         int (*flush)(struct input_dev *dev, struct file *file);
170         int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
171 
172         struct input_handle __rcu *grab;
173 
174         spinlock_t event_lock;
175         struct mutex mutex;
176 
177         unsigned int users;
178         bool going_away;
179 
180         struct device dev;
181 
182         struct list_head        h_list;
183         struct list_head        node;
184 
185         unsigned int num_vals;
186         unsigned int max_vals;
187         struct input_value *vals;
188 
189         bool devres_managed;
190 };

 

【Linux uinput API】

Linux/include/uapi/linux/uinput.h

input_event

 24 struct input_event {
 25         struct timeval time;
 26         __u16 type;
 27         __u16 code;
 28         __s32 value;
 29 };

 

input_id

 41 struct input_id {
 42         __u16 bustype;
 43         __u16 vendor;
 44         __u16 product;
 45         __u16 version;
 46 };

 

【核心說明文件】

Documentation/input

再經過範例的練習,

【Injecting input events】

>>> from evdev import UInput, ecodes as e

>>> ui = UInput()

>>> # accepts only KEY_* events by default
>>> ui.write(e.EV_KEY, e.KEY_A, 1)  # KEY_A down
>>> ui.write(e.EV_KEY, e.KEY_A, 0)  # KEY_A up
>>> ui.syn()

>>> ui.close()

 

【Injecting events (2)】

>>> ev = InputEvent(1334414993, 274296, ecodes.EV_KEY, ecodes.KEY_A, 1)
>>> with UInput() as ui:
...    ui.write_event(ev)
...    ui.syn()

 

【Specifying uinput device options】

>>> from evdev import UInput, AbsInfo, ecodes as e

>>> cap = {
...     e.EV_KEY : [e.KEY_A, e.KEY_B],
...     e.EV_ABS : [
...         (e.ABS_X, AbsInfo(value=0, min=0, max=255,
...                           fuzz=0, flat=0, resolution=0)),
...         (e.ABS_Y, AbsInfo(0, 0, 255, 0, 0, 0)),
...         (e.ABS_MT_POSITION_X, (0, 255, 128, 0)) ]
... }

>>> ui = UInput(cap, name='example-device', version=0x3)
>>> print(ui)
name "example-device", bus "BUS_USB", vendor "0001", product "0001", version "0003"
event types: EV_KEY EV_ABS EV_SYN

>>> print(ui.capabilities())
{0: [0, 1, 3],
 1: [30, 48],
 3: [(0,  AbsInfo(value=0, min=0, max=0,   fuzz=255, flat=0, resolution=0)),
     (1,  AbsInfo(value=0, min=0, max=0,   fuzz=255, flat=0, resolution=0)),
     (53, AbsInfo(value=0, min=0, max=255, fuzz=128, flat=0, resolution=0))]}

>>> # move mouse cursor
>>> ui.write(e.EV_ABS, e.ABS_X, 20)
>>> ui.write(e.EV_ABS, e.ABS_Y, 20)
>>> ui.syn()


 

,或將能對『核心輸入子系統』以及『python-evdev 程式庫』多些了解的乎!?

 

 

 

 

 

 

 

 

勇闖新世界︰ 《 Kernel 4.X 》之整裝蓄勢‧設備管理及應用‧二中

當我們閱讀『技術文件』時,為什麼老覺得咬文嚼字,難以下咽的呢?這是因為『技術文件』之『術語』定義,必要的『精確性』 ── 精準且正確 ── 使然。比方說, CPU 的『存取單位』是一個『模糊』的名詞。因為『資料匯流排』 data bus 有多少『位元』的寬度,決定了那個 CPU 資料『存取單位』的大小。更不要說還有那『位元組』 byte 排序問題,因此不同種類的 CPU ,就有了『位元組序』 Endianness 的『大‧小』之區分。再加上許多『技術文件』通常用於整個『事物族系』,散布於『技術文件』的『不同部份』 ,很容易導致了『不知全盤』就『難知其一』的現象。舉例來講,什麼是『輸入事件』 input event ?假使我們查詢『 input_event 』名稱在 Kernel 4.1.X 中使用之『交互參考』,恐怕會暈頭轉向的吧!如果對『輸入裝置』這個子系統多些了解之後,也許從下面的資料『樣板結構』,就能知道梗概的了︰

Linux/include/uapi/linux/input.h
20 /*
21 * The event structure itself
22 */
23
24 struct input_event {
25 struct timeval time;
26 __u16 type;
27 __u16 code;
28 __s32 value;
29 };
30

這裡『__u16』和『__s32』都是指『位元』之大小,假使想更清楚知道這個『資料結構』大小及意義,還得先知道『__kernel_time_t』與『__kernel_suseconds_t』之大小及意義!!

Linux/include/uapi/linux/time.h
14
15 struct timeval {
16 __kernel_time_t tv_sec; /* seconds */
17 __kernel_suseconds_t tv_usec; /* microseconds */
18 };
19

這也就是一般 kernel 裝置『驅動程式』學習的為難處。因此若想『學習』 PiTFT 的『觸控輸入』,用

pi@raspberrypi ~ cat /dev/input/touchscreen | hexdump  0000000 d1b1 55ce d28c 000e 0003 0000 082a 0000 0000010 d1b1 55ce d28c 000e 0003 0001 0819 0000 0000020 d1b1 55ce d28c 000e 0003 0018 0060 0000 0000030 d1b1 55ce d28c 000e 0001 014a 0001 0000 0000040 d1b1 55ce d28c 000e 0000 0000 0000 0000 0000050 d1b2 55ce 17ad 0000 0003 0000 0864 0000 0000060 d1b2 55ce 17ad 0000 0003 0001 0876 0000 0000070 d1b2 55ce 17ad 0000 0000 0000 0000 0000 0000080 d1b2 55ce 362d 0000 0003 0000 084e 0000 0000090 d1b2 55ce 362d 0000 0003 0001 086d 0000 00000a0 d1b2 55ce 362d 0000 0003 0018 0061 0000 00000b0 d1b2 55ce 362d 0000 0000 0000 0000 0000 00000c0 d1b2 55ce 4f44 0000 0003 0000 0849 0000 00000d0 d1b2 55ce 4f44 0000 0003 0001 086b 0000 00000e0 d1b2 55ce 4f44 0000 0003 0018 0067 0000 00000f0 d1b2 55ce 4f44 0000 0000 0000 0000 0000 0000100 d1b2 55ce 9c93 0000 0003 0018 0000 0000 0000110 d1b2 55ce 9c93 0000 0001 014a 0000 0000 0000120 d1b2 55ce 9c93 0000 0000 0000 0000 0000 </pre>    <span style="color: #808000;">雖有困難,確非『難以理解』的事。或用</span> <pre class="lang:sh decode:true ">pi@raspberrypi ~ evtest /dev/input/touchscreen 
Input driver version is 1.0.1
Input device ID: bus 0x18 vendor 0x0 product 0x0 version 0x0
Input device name: "stmpe-ts"
Supported events:
  Event type 0 (EV_SYN)
  Event type 1 (EV_KEY)
    Event code 330 (BTN_TOUCH)
  Event type 3 (EV_ABS)
    Event code 0 (ABS_X)
      Value   1851
      Min        0
      Max     4095
    Event code 1 (ABS_Y)
      Value   2714
      Min        0
      Max     4095
    Event code 24 (ABS_PRESSURE)
      Value      0
      Min        0
      Max      255
Properties:
Testing ... (interrupt to exit)
Event: time 1439617362.428940, type 3 (EV_ABS), code 0 (ABS_X), value 2413
Event: time 1439617362.428940, type 3 (EV_ABS), code 1 (ABS_Y), value 2222
Event: time 1439617362.428940, type 3 (EV_ABS), code 24 (ABS_PRESSURE), value 93
Event: time 1439617362.428940, type 1 (EV_KEY), code 330 (BTN_TOUCH), value 1
Event: time 1439617362.428940, -------------- SYN_REPORT ------------
Event: time 1439617362.435368, type 3 (EV_ABS), code 0 (ABS_X), value 2482
Event: time 1439617362.435368, type 3 (EV_ABS), code 1 (ABS_Y), value 2238
Event: time 1439617362.435368, type 3 (EV_ABS), code 24 (ABS_PRESSURE), value 100
Event: time 1439617362.435368, -------------- SYN_REPORT ------------
Event: time 1439617362.441796, type 3 (EV_ABS), code 0 (ABS_X), value 2484
Event: time 1439617362.441796, type 3 (EV_ABS), code 1 (ABS_Y), value 2249
Event: time 1439617362.441796, type 3 (EV_ABS), code 24 (ABS_PRESSURE), value 97
Event: time 1439617362.441796, -------------- SYN_REPORT ------------
Event: time 1439617362.448270, type 3 (EV_ABS), code 0 (ABS_X), value 2550
Event: time 1439617362.448270, type 3 (EV_ABS), code 1 (ABS_Y), value 2256
Event: time 1439617362.448270, type 3 (EV_ABS), code 24 (ABS_PRESSURE), value 98
Event: time 1439617362.448270, -------------- SYN_REPORT ------------
Event: time 1439617362.454676, type 3 (EV_ABS), code 0 (ABS_X), value 2561
Event: time 1439617362.454676, type 3 (EV_ABS), code 1 (ABS_Y), value 2258
Event: time 1439617362.454676, type 3 (EV_ABS), code 24 (ABS_PRESSURE), value 96
Event: time 1439617362.454676, -------------- SYN_REPORT ------------
Event: time 1439617362.461091, type 3 (EV_ABS), code 0 (ABS_X), value 2555
Event: time 1439617362.461091, type 3 (EV_ABS), code 24 (ABS_PRESSURE), value 97
Event: time 1439617362.461091, -------------- SYN_REPORT ------------
Event: time 1439617362.483105, type 3 (EV_ABS), code 0 (ABS_X), value 2536
Event: time 1439617362.483105, type 3 (EV_ABS), code 1 (ABS_Y), value 2259
Event: time 1439617362.483105, type 3 (EV_ABS), code 24 (ABS_PRESSURE), value 101
Event: time 1439617362.483105, -------------- SYN_REPORT ------------
Event: time 1439617362.554620, type 3 (EV_ABS), code 24 (ABS_PRESSURE), value 0
Event: time 1439617362.554620, type 1 (EV_KEY), code 330 (BTN_TOUCH), value 0
Event: time 1439617362.554620, -------------- SYN_REPORT ------------

 

看似易讀,總『留有疑惑』,終究有賴於『整體了解』的耶??此正是研讀『高階程式庫』,更需要小心之處︰

events

This module provides the InputEvent class, which closely resembles the input_event struct defined in linux/input.h:

struct input_event {
    struct timeval time;
    __u16 type;
    __u16 code;
    __s32 value;
};

This module also defines several InputEvent sub-classes that know more about the different types of events (key, abs, rel etc). The event_factory dictionary maps event types to these classes.

Assuming you use the evdev.util.categorize() function to categorize events according to their type, adding or replacing a class for a specific event type becomes a matter of modifying event_factory.

All classes in this module have reasonable str() and repr() methods:

>>> print(event)
event at 1337197425.477827, code 04, type 04, val 458792
>>> print(repr(event))
InputEvent(1337197425L, 477827L, 4, 4, 458792L)

>>> print(key_event)
key event at 1337197425.477835, 28 (KEY_ENTER), up
>>> print(repr(key_event))
KeyEvent(InputEvent(1337197425L, 477835L, 1, 28, 0L))

 

,一旦『望文生義』常是『囫圇吞棗』之結果??所以請對眾多之『術語』務必清楚明白,這才是應用真實的基礎也!!

能夠嘗試『解讀』他人來源碼,或正是『寫程式』之基本功乎!?

pi@raspberrypi ~ $ python3
Python 3.2.3 (default, Mar  1 2013, 11:53:50) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from evdev import InputDevice, list_devices, categorize, ecodes
>>> devices = [InputDevice(fn) for fn in list_devices()]
>>> for dev in devices:
...     print(dev.fn, dev.name, dev.phys)
... 
/dev/input/event2 Gwell HicHan RF-Dongle usb-3f980000.usb-1.2/input1
/dev/input/event1 Gwell HicHan RF-Dongle usb-3f980000.usb-1.2/input0
/dev/input/event0 stmpe-ts stmpe-ts/input0
>>> 
>>> dev = InputDevice('/dev/input/event0')
>>> print(dev)
device /dev/input/event0, name "stmpe-ts", phys "stmpe-ts/input0"
>>> 
>>> dev.capabilities()
{0: [0, 1, 3], 1: [330], 3: [(0, AbsInfo(value=2212, min=0, max=4095, fuzz=0, flat=0, resolution=0)), (1, AbsInfo(value=2904, min=0, max=4095, fuzz=0, flat=0, resolution=0)), (24, AbsInfo(value=0, min=0, max=255, fuzz=0, flat=0, resolution=0))]}
>>> 
>>> dev.capabilities(verbose=True)
{('EV_KEY', 1): [('BTN_TOUCH', 330)], ('EV_ABS', 3): [(('ABS_X', 0), AbsInfo(value=2212, min=0, max=4095, fuzz=0, flat=0, resolution=0)), (('ABS_Y', 1), AbsInfo(value=2904, min=0, max=4095, fuzz=0, flat=0, resolution=0)), (('ABS_PRESSURE', 24), AbsInfo(value=0, min=0, max=255, fuzz=0, flat=0, resolution=0))], ('EV_SYN', 0): [('SYN_REPORT', 0), ('SYN_CONFIG', 1), ('SYN_DROPPED', 3)]}
>>> 
>>> for event in dev.read_loop():
...     if event.type == ecodes.EV_ABS:
...         print(categorize(event))
... 
absolute axis event at 1439627454.210421, ABS_X 
absolute axis event at 1439627454.210421, ABS_Y 
absolute axis event at 1439627454.210421, ABS_PRESSURE 
absolute axis event at 1439627454.241907, ABS_X 
absolute axis event at 1439627454.241907, ABS_Y 
absolute axis event at 1439627454.241907, ABS_PRESSURE 
absolute axis event at 1439627454.257593, ABS_X 
absolute axis event at 1439627454.257593, ABS_Y 
absolute axis event at 1439627454.257593, ABS_PRESSURE 
absolute axis event at 1439627454.264023, ABS_X 
absolute axis event at 1439627454.264023, ABS_Y 
absolute axis event at 1439627454.264023, ABS_PRESSURE 
absolute axis event at 1439627454.270441, ABS_X 
absolute axis event at 1439627454.270441, ABS_Y 
absolute axis event at 1439627454.270441, ABS_PRESSURE 
absolute axis event at 1439627454.276901, ABS_X 
absolute axis event at 1439627454.276901, ABS_Y 
absolute axis event at 1439627454.276901, ABS_PRESSURE 
absolute axis event at 1439627454.380102, ABS_PRESSURE 

 

 

 

 

 

 

 

 

勇闖新世界︰ 《 Kernel 4.X 》之整裝蓄勢‧設備管理及應用‧二上

就讓我們從 freedesktop.org 的 libevdev 之說明開始︰

libevdev  1.4.3
A wrapper library for evdev devices

libevdev is a library for handling evdev kernel devices. It abstracts the evdev ioctls through type-safe interfaces and provides functions to change the appearance of the device.

Development of libevdev is discussed on input-tools@lists.freedesktop.org Please submit patches, questions or general comments there.

Handling events and SYN_DROPPED

libevdev provides an interface for handling events, including most notably SYN_DROPPED events. SYN_DROPPED events are sent by the kernel when the process does not read events fast enough and the kernel is forced to drop some events. This causes the device to get out of sync with the process’ view of it. libevdev handles this by telling the caller that a SYN_DROPPED has been received and that the state of the device is different to what is to be expected. It then provides the delta between the previous state and the actual state of the device as a set of events. See libevdev_next_event() and SYN_DROPPED handling for more information on how SYN_DROPPED is handled.

Signal safety

libevdev is signal-safe for the majority of its operations, i.e. many of its functions are safe to be called from within a signal handler. Check the API documentation to make sure, unless explicitly stated a call is not signal safe.

Device handling

A libevdev context is valid for a given file descriptor and its duration. Closing the file descriptor will not destroy the libevdev device but libevdev will not be able to read further events.

libevdev does not attempt duplicate detection. Initializing two libevdev devices for the same fd is valid and behaves the same as for two different devices.

libevdev does not handle the file descriptors directly, it merely uses them. The caller is responsible for opening the file descriptors, setting them to O_NONBLOCK and handling permissions.

Where does libevdev sit?

libevdev is essentially a read(2) on steroids for /dev/input/eventX devices. It sits below the process that handles input events, in between the kernel and that process. In the simplest case, e.g. an evtest-like tool the stack would look like this:

 kernel → libevdev → evtest

For X.Org input modules, the stack would look like this:

 kernel → libevdev → xf86-input-evdev → X server → X client

For Weston/Wayland, the stack would look like this:

 kernel → libevdev → Weston → Wayland client

libevdev does not have knowledge of X clients or Wayland clients, it is too low in the stack. ……

 

這個 C 語言的程式庫,提供了核心 evdev 模組與使用者空間程式的界面。然而 python-evdev 不只提供了 evdev 模組的程式界面,

evdev 0.5.0

Bindings to the Linux input handling subsystem

This package provides bindings to the generic input event interface in Linux. The evdev interface serves the purpose of passing events generated in the kernel directly to userspace through character devices that are typically located in /dev/input/.

This package also comes with bindings to uinput, the userspace input subsystem. Uinput allows userspace programs to create and handle input devices that can inject events directly into the input subsystem.

Documentation:
http://python-evdev.readthedocs.org/en/latest/
Development:
https://github.com/gvalkov/python-evdev
Package:
http://pypi.python.org/pypi/evdev
Changelog:
http://python-evdev.readthedocs.org/en/latest/changelog.html

 

還提供了 linux uinput 輸入子系統界面。

Linux/include/uapi/linux/uinput.h

1 /*
2 * User level driver support for input subsystem
3 *
4 * Heavily based on evdev.c by Vojtech Pavlik
5 *

───

Getting started with uinput: the user level input subsystem

uinput is a linux kernel module that allows to handle the input subsystem from user land. It can be used to create and to handle input devices from an application. It creates a character device in /dev/input directory. The device is a virtual interface, it doesn’t belong to a physical device.

In this document, we will see how to create a such input device and how it can be used. ……

 

這不僅開啟了用派生寫作輸入裝置『驅動程式』之大門,還打開了創造『虛擬裝置』的一扇窗。

我們的旅程也從這個軟體的安裝展開了︰

sudo pip-3.2 install evdev

【python-evdev 參考資料】

完整範例

API 參考