用python腳本檢測(cè)熱插拔事件

在 Python 中作彤,檢測(cè)熱插拔事件(例如 USB 設(shè)備插入或移除)可以通過(guò)以下幾種方法實(shí)現(xiàn)覆山。最常用的方式是使用 pyudev 庫(kù)(適用于 Linux 系統(tǒng))來(lái)監(jiān)聽系統(tǒng)設(shè)備的變化俐东。

1脖镀、問(wèn)題背景

用戶正在嘗試使用 Python 來(lái)檢測(cè)鼠標(biāo)和鍵盤事件公给,并在檢測(cè)過(guò)程中容忍熱插拔操作基协。用戶編寫的腳本可以自動(dòng)檢測(cè)運(yùn)行時(shí)環(huán)境中的鍵盤和鼠標(biāo)插件,并輸出所有鍵盤和鼠標(biāo)事件剑按。用戶使用了 evdev 和 pyudev 包來(lái)實(shí)現(xiàn)此功能疾就。腳本大部分都可以正常工作,包括鍵盤和鼠標(biāo)事件檢測(cè)以及插件檢測(cè)艺蝴。然而猬腰,每當(dāng)用戶拔出鼠標(biāo)時(shí),都會(huì)發(fā)生許多奇怪的事情猜敢,導(dǎo)致腳本無(wú)法正常工作姑荷。

(1)每當(dāng)將鼠標(biāo)插入系統(tǒng)時(shí),/dev/input/ 文件夾中都會(huì)生成兩個(gè)文件缩擂,包括 ./mouseX 和 ./eventX鼠冕。用戶嘗試通過(guò) cat 命令查看兩個(gè)源的輸出,發(fā)現(xiàn)確實(shí)有差異撇叁,但我不理解為什么 Linux 會(huì)在 ./eventX 已經(jīng)存在的情況下仍然會(huì)有 ./mouseX。

(2)每當(dāng)用戶拔下鼠標(biāo)時(shí)畦贸,./mouseX 拔下事件會(huì)首先發(fā)生陨闹,但我在 evdev 中沒(méi)有使用它,這會(huì)導(dǎo)致腳本失敗薄坏,因?yàn)?./eventX(腳本中讀取數(shù)據(jù)的位置)也會(huì)同時(shí)拔下趋厉,但我只能在下一輪中檢測(cè)到 ./eventX。我使用了一個(gè)技巧(腳本中的變量 i)來(lái)繞過(guò)這個(gè)問(wèn)題胶坠,但即使我能夠成功刪除鼠標(biāo)設(shè)備君账,select.select() 也會(huì)開始無(wú)限期地讀取輸入,即使我沒(méi)有對(duì)鍵盤輸入任何內(nèi)容沈善。

以下是腳本的內(nèi)容(根據(jù)先前帖子的答案進(jìn)行了修改)乡数,非常感謝您事先的關(guān)注椭蹄!

#!/usr/bin/env python

importpyudev

fromevdevimportInputDevice,list_devices,categorize

fromselectimportselect

context=pyudev.Context()

monitor=pyudev.Monitor.from_netlink(context)

monitor.filter_by(subsystem='input')

monitor.start()

devices=map(InputDevice,list_devices())

dev_paths=[]

finalizers=[]

fordevindevices:

if"keyboard"indev.name.lower():

dev_paths.append(dev.fn)

elif"mouse"indev.name.lower():

dev_paths.append(dev.fn)

devices=map(InputDevice,dev_paths)

devices={dev.fd:devfordevindevices}

devices[monitor.fileno()]=monitor

count=1

whileTrue:

r,w,x=select(devices, [], [])

ifmonitor.fileno()inr:

r.remove(monitor.fileno())

forudeviniter(functools.partial(monitor.poll,0),None):

# we're only interested in devices that have a device node

# (e.g. /dev/input/eventX)

ifnotudev.device_node:

break

# find the device we're interested in and add it to fds

fornamein(i['NAME']foriinudev.ancestorsif'NAME'ini):

# I used a virtual input device for this test - you

# should adapt this to your needs

if'mouse'inname.lower()and'event'inudev.device_node:

ifudev.action=='add':

print('Device added: %s'%udev)

dev=InputDevice(udev.device_node)

devices[dev.fd]=dev

break

ifudev.action=='remove':

print('Device removed: %s'%udev)

finalizers.append(udev.device_node)

break

forpathinfinalizers:

fordevindevices.keys():

ifdev!=monitor.fileno()anddevices[dev].fn==path:

print"delete the device from list"

deldevices[dev]

foriinr:

ifiindevices.keys()andcount!=0:

count=-1

foreventindevices[i].read():

count=count+1

print(categorize(event))

2、解決方案

答案1:

mouseX 和 eventX 之間的區(qū)別在于净赴,一般來(lái)說(shuō)绳矩,eventX 是 evdev 設(shè)備,而 mouseX 是“傳統(tǒng)”設(shè)備(例如玖翅,不支持各種 evdev ioctl)翼馆。

我不知道你發(fā)布的代碼出了什么問(wèn)題,但這里有一個(gè)代碼片段可以解決這個(gè)問(wèn)題金度。

#!/usr/bin/env python

importpyudev

importevdev

importselect

importsys

importfunctools

importerrno

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

defpred(d):

return"keyboard"ind.name.lower()or"mouse"ind.name.lower()

# Populate the "active devices" map, mapping from /dev/input/eventXX to

# InputDevice

devices={}

fordinmap(evdev.InputDevice,evdev.list_devices()):

ifpred(d):

printd

devices[d.fn]=d

# "Special" monitor device

devices['monitor']=monitor

whileTrue:

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.

forudeviniter(functools.partial(monitor.poll,0),None):

ifnotudev.device_node:break

ifudev.action=='add':

ifudev.device_nodenotindevices:

print"Device added: %s"%udev

try:

devices[udev.device_node]=evdev.InputDevice(udev.device_node)

exceptIOError,e:

# udev reports MORE devices than are accessible from

# evdev; a simple way to check is see if the devinfo

# ioctl fails

ife.errno!=errno.ENOTTY:raise

pass

elifudev.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.

ifudev.device_nodeindevices:

print"Device removed (udev): %s"%devices[udev.device_node]

deldevices[udev.device_node]

forrinrs:

# You can't read from a monitor

ifr.fileno()==monitor.fileno():continue

ifr.fnnotindevices:continue

# Select will immediately return an fd for read if it will

# ENODEV.? So be sure to handle that.

try:

foreventinr.read():

pass

printevdev.categorize(event)

exceptIOError,e:

ife.errno!=errno.ENODEV:raise

print"Device removed: %s"%r

deldevices[r.fn]

然后你可以用類似的方式來(lái)監(jiān)聽事件应媚。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市猜极,隨后出現(xiàn)的幾起案子中姜,更是在濱河造成了極大的恐慌,老刑警劉巖魔吐,帶你破解...
    沈念sama閱讀 219,270評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件扎筒,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡酬姆,警方通過(guò)查閱死者的電腦和手機(jī)嗜桌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)辞色,“玉大人骨宠,你說(shuō)我怎么就攤上這事∠嗦” “怎么了层亿?”我有些...
    開封第一講書人閱讀 165,630評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)立美。 經(jīng)常有香客問(wèn)我匿又,道長(zhǎng),這世上最難降的妖魔是什么建蹄? 我笑而不...
    開封第一講書人閱讀 58,906評(píng)論 1 295
  • 正文 為了忘掉前任碌更,我火速辦了婚禮,結(jié)果婚禮上洞慎,老公的妹妹穿的比我還像新娘痛单。我一直安慰自己,他們只是感情好劲腿,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,928評(píng)論 6 392
  • 文/花漫 我一把揭開白布旭绒。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪挥吵。 梳的紋絲不亂的頭發(fā)上重父,一...
    開封第一講書人閱讀 51,718評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音蔫劣,去河邊找鬼坪郭。 笑死,一個(gè)胖子當(dāng)著我的面吹牛脉幢,可吹牛的內(nèi)容都是我干的歪沃。 我是一名探鬼主播,決...
    沈念sama閱讀 40,442評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼嫌松,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼沪曙!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起萎羔,我...
    開封第一講書人閱讀 39,345評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤液走,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后贾陷,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體缘眶,經(jīng)...
    沈念sama閱讀 45,802評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,984評(píng)論 3 337
  • 正文 我和宋清朗相戀三年髓废,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了巷懈。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,117評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡慌洪,死狀恐怖顶燕,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情冈爹,我是刑警寧澤涌攻,帶...
    沈念sama閱讀 35,810評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站频伤,受9級(jí)特大地震影響恳谎,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜憋肖,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,462評(píng)論 3 331
  • 文/蒙蒙 一因痛、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧瞬哼,春花似錦婚肆、人聲如沸租副。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至结胀,卻和暖如春赞咙,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背糟港。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工攀操, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人秸抚。 一個(gè)月前我還...
    沈念sama閱讀 48,377評(píng)論 3 373
  • 正文 我出身青樓速和,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親剥汤。 傳聞我的和親對(duì)象是個(gè)殘疾皇子颠放,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,060評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容