§ 0.0.0 前言
監聽、操作滑鼠、鍵盤是實作自動化的捷徑,比如我實作自動化簽到用到了模擬鍵盤操作,
pynput是監聽、操控滑鼠和鍵盤的跨平臺第三方python庫,
你可以通過pip insnall pynput來安裝,安裝時會自動下載依賴庫,
pypi鏈接在此,
接下來我會按
“滑鼠按鍵”“監聽滑鼠”“控制滑鼠”,“鍵盤按鍵”“監聽鍵盤”“控制鍵盤”
的順序介紹它的用法,
- 以下為正文,
§1.0.0 滑鼠按鍵
滑鼠的按鍵在pynput.mouse.Button中,
有lift、right、middle還有unknown四種,
每一個按鍵都有兩個有意義的屬性:name和value,
name是該按鍵的名稱,比如 Button.left.name == 'left';
value是記錄上一次點擊位置的元組,
§1.1.0 監聽滑鼠
有兩種方法,一種是函式式、非阻塞型,另一種是陳述句式、阻塞型,
先說第一種,這種是常見的教程所說的方法,
§1.1.1 pynput.mouse.Listener
以下是官網的說明示例:
import pynput, time
def on_move(x, y):
print('Pointer moved to {0}'.format((x, y)))
def on_click(x, y, button, pressed):
print('{0} at {1}'.format(
'Pressed' if pressed else 'Released',
(x, y)))
if not pressed:
# Stop listener
return False
def on_scroll(x, y, dx, dy):
print('Scrolled {0} at {1}'.format(
'down' if dy < 0 else 'up',
(x, y)))
# Collect events until released
with pynput.mouse.Listener(
on_move=on_move,
on_click=on_click,
on_scroll=on_scroll) as listener:
listener.join()
運行這段代碼時,移動滑鼠會顯示其坐標,
按下滑鼠按鍵并松開后,程式結束,
- 當三個函式任意一個回傳
False((還有就是釋放Exception或繼承自Exception的例外)時,就會結束行程, - 可以用
listener.start()和listener.stop()代替with陳述句,
§1.1.2 pynput.mouse.Events
個人認為,這個方法比上一個更直觀,
import pynput
with pynput.mouse.Events() as event:
for i in event:
#迭代用法,
if isinstance(i, pynput.mouse.Events.Move):
#滑鼠移動事件,
print(i.x, i.y)
#不要直接列印`i`,模塊這里有問題,會報錯,
elif isinstance(i, pynput.mouse.Events.Click):
#滑鼠點擊事件,
print(i.x, i.y, i.button, i.pressed)
#這個i.button就是上文所說的“滑鼠按鍵”中的一個,用is陳述句判斷即可,
elif isinstance(i, pynput.mouse.Events.Scroll):
#滑鼠滾輪,
print(i.x, i.y, i.dx, i.dy)
break
i = event.get(1)
#另一種用法,
#默認值是None,
#這個`1`就是最長等待時間,超過這個時間沒有事件,
#就會報錯,錯誤型別是queue模塊的Empty,而非TimeoutError,
§1.2.0 控制滑鼠
- § 1.2.1
先執行pynput.mouse.Controller()獲取控制元件,
以下方法都是該控制元件的所屬方法,
如下:
import pynput
ctr = pynput.mouse.Controller()
- § 1.2.2
動態屬性position回傳滑鼠位置坐標的元組(像這樣: (x, y) ),
通過定義來改變滑鼠位置,比如ctr.position = (500, 500),
- § 1.2.3
當然,也有move方法,用于移動滑鼠,
用法是ctr.move(dx, dy),
- § 1.2.4
使用方法click進行模擬點擊,需提供點擊的按鈕,
按鈕在pynput.mouse.Button里,有left、right和middle,
還有可選引數count,是點擊次數,默認為1,
示例:
import pynput
ctr = pynput.mouse.Controller()
ctr.click(pynput.mouse.Button.left)
#左鍵單擊,
ctr.click(pynput.mouse.Button.left, 2)
#左鍵雙擊,
ctr.click(pynput.mouse.Button.right)
#右鍵單擊,
- § 1.2.5
使用press(button)按下button鍵;
方法release(button)釋放鍵,如果操作時按鍵并沒有被按下,也不會報錯,
示例:
import pynput
ctr = pynput.mouse.Controller()
ctr.press(pynput.mouse.Button.left)
#按下左鍵,
ctr.move(50, 0)
#右移50單位,
ctr.move(0, 50)
#下移50單位,
ctr.release(pynput.mouse.Button.left)
#釋放左鍵,
- § 1.2.6
模擬滾輪,使用的方法是scroll,提供引數dx和dy,
例:
import pynput
ctr = pynput.mouse.Controller()
ctr.scroll(0, 50)
#向上滾動50單位,
ctr.scroll(0, -50)
#向下滾動50單位,
- 以上是滑鼠操作,
- 以下是鍵盤操作,
§ 2.0.0 鍵盤按鍵
鍵盤的按鍵獲取比滑鼠的麻煩些,但是沒有滑鼠用得多,
因此我先說給常用的使用方法,再說獲取,
§ 2.0.1 使用方法
首先,當獲取事件后,要判斷按鍵是“特殊按鍵”還是“普通按鍵”,
需判斷其是否具有name屬性,有則是特殊按鍵,
這個屬性記錄屬性的名稱,比如ctrl對應著'ctrl'、'ctrl_l'或是'ctrl_r',
普通按鍵中,取而代之的是.char,
注:大寫字母與小寫字母有不同的按鍵,
還有其他功能,這里就不多說了,
§ 2.0.2 獲取
首先,特殊按鍵在pynput.keyboard.Key“模塊”中可以直接找到,
比如ctrl對應pynput.keyboard.Key.ctrl還有.ctrl_l以及.ctrl_r,
然后,普通按鍵可以通過pynput.keyboard.KeyCode.from_char取得(特殊按鍵不可以,使用時會出現ArgumentError),
如a可以運行pynput.keyboard.KeyCode.from_char('a')獲得,
二者都可以用pynput.keyboard.KeyCode.from_vk通過按鍵的映射碼取得,
§ 2.1.0 監聽鍵盤
主要有兩種方法,類似于滑鼠的,我的講述順序同前文,
還有一種是對Listener的封裝,用于快捷鍵,我放在最后一個說,
§ 2.1.1 pynput.keyboard.Listener
注:如果你只想關注個別按鍵而非所有事件,可以使用
GlobalHotKeys,我會在后文說,
官網示例:
from pynput import keyboard
def on_press(key):
'按下按鍵時執行,'
try:
print('alphanumeric key {0} pressed'.format(
key.char))
except AttributeError:
print('special key {0} pressed'.format(
key))
#通過屬性判斷按鍵型別,
def on_release(key):
'松開按鍵時執行,'
print('{0} released'.format(
key))
if key == keyboard.Key.esc:
# Stop listener
return False
# Collect events until released
with keyboard.Listener(
on_press=on_press,
on_release=on_release) as listener:
listener.join()
- 當兩個函式中任意一個回傳
False(還有就是釋放Exception或繼承自Exception的例外)時,就會結束行程, - 可以用
listener.start()和listener.stop()代替with陳述句,
§ 2.1.2 pynput.keyboard.Events
import pynput
with pynput.keyboard.Events() as event:
for i in event:
#迭代用法,
key_event = i
break
key_event = event.get()
#get用法,
#可以提供一個實數作為最長等待時間(單位秒),超過這個時間沒有事件,
#就會報錯,錯誤型別是queue模塊的Empty,而非TimeoutError,
#判斷事件情況:
if isinstance(key_event, pynput.keyboard.Events.Press):
print('按下按鍵', end = '')
elif isinstance(key_event, pynput.keyboard.Events.Release):
print('松開按鍵', end = '')
#判斷按鍵:
#*這個事件的`key`屬性*對應才是*Listener方法獲得的按鍵`'key'`*,
try:
print(key_event.key.name)
except AttributeError:
#說明這個是普通按鍵,
print(key_event.key.char)
else:
#兩種判斷方式,第一種是我自創的,第二種是官網上的,
if (key_event.key.name).startswith('ctrl'):
#通過名稱判斷,
print('發生了ctrl鍵事件,')
elif key_event.key is pynput.keyboard.Key.esc:
print('發生了esc鍵事件,')
§ 2.1.3 pynput.keyboard.GlobalHotKeys
(還有'pynput.keyboard.HotKey'可以實作相似功能,但很麻煩)
官網示例,esc那個是我寫的,
from pynput import keyboard
def on_activate_h():
print('<ctrl>+<alt>+h pressed')
def on_activate_i():
print('<ctrl>+<alt>+i pressed')
def esc():
print('<esc> pressed')
return False
def esc_shift():
print('<esc>+<shift> pressed')
raise Exception
with keyboard.GlobalHotKeys({
'<ctrl>+<alt>+h': on_activate_h,
'<ctrl>+<alt>+i': on_activate_i,
'<esc>': esc,
'<esc>+<shift>': esc_shift}) as h:
h.join()
當按下esc鍵時,函式被觸發,但運行未停止,
觀察原始碼,發現雖然該類繼承自Listener,但會對執行的函式有封裝,封裝后只回傳None,
所以無法通過return False結束行程,
設定單個普通按鍵(比如“a”)也是可以的,
不能分辨按鍵順序如“<ctrl>+a”與“a+<ctrl>”,
§ 2.2.0 控制鍵盤
- § 2.2.1
先獲取控制元件 :ctr = pynput.keyboard.Controller(),
以下所說的方法均是指該控制元件的方法,
- § 2.2.2
通過方法press來按下按鍵,
你需要提供一個“長度為1的字符”或是“前文所說的按鍵物件”,
溫馨提示,此方法測驗有風險,如果發現電腦打字、操作例外,
很可能是因為模擬按下了某個鍵未松開,
可以重啟控制臺或電腦,
- § 2.2.3
通過release釋放按鍵,
和press方法一樣,需要提供一個“長度為1的字符”或是“前文所說的按鍵物件”,
示例:
'''
這段程式會按“下ctrl+shilf+s”快捷鍵,停頓3秒后按下esc鍵,
簡單模擬了“另存為”操作,
'''
import pynput, time
ctr = pynput.keyboard.Controller()
ctr.press(pynput.keyboard.KeyCode.from_vk(17))
#通過按鍵的映射碼 按下ctrl鍵,
ctr.press(pynput.keyboard.Key.shift)
#通過按鍵物件 按下shift鍵,
ctr.press('s')
#通過長度為1的字符 按下s鍵,
#掃尾,釋放剛才按下的鍵,后面我會說更簡單、優雅的辦法,
ctr.release(pynput.keyboard.Key.ctrl)
ctr.release(pynput.keyboard.Key.shift)
ctr.release('s')
time.sleep(0.3)
ctr.press(pynput.keyboard.Key.esc)
ctr.release(pynput.keyboard.Key.esc)
- § 2.2.4
pressed方法就是我說的“更簡單、優雅”的方法,
使用時提供要按下的鍵,再用with陳述句“封裝”上,
效果是進入陳述句塊時順序按下提供按鍵,退出陳述句塊時逆序釋放按鍵,
如下:
import pynput, time
ctr = pynput.keyboard.Controller()
with ctr.pressed(
pynput.keyboard.Key.ctrl,
pynput.keyboard.Key.shift,
's'):
pass
time.sleep(0.3)
with ctr.pressed(pynput.keyboard.Key.esc):
pass
- § 2.2.5
type在英語中除了“型別”還有“打字”之意,
該方法接收字串,然后打出每個字符,
據測驗,向它提供一個“按鍵串列”也可以正常使用,
例:
import pynput
ctr = pynput.keyboard.Controller()
ctr.type('Hello world!')
ctr.type([pynput.keyboard.Key.esc])
#按下esc再松開,
- 以上是正文,
一些建議
該模塊滑鼠、鍵盤的監聽操作均由多執行緒實作,
所以,可以利用多執行緒共享記憶體的特征編程;二要注意不要頻繁啟動監聽,這樣對系統開支極大,
還有就是對滑鼠位置監聽要求不是很高時(比如實時向用戶顯示滑鼠位置),可以每次回圈sleep一下,
如果向Listener提供的函式會執行很久(比如含有sleep),會導致電腦變卡,
閑談
之前和別人聊天,他說他在不需要時把電腦的麥拔下來、攝像頭擋上,
我說用Fn快捷鍵禁掉麥克風更方便,
現在想想,黑客可以通過模擬按鍵解禁麥克風啊,
雖然這個模塊沒有Fn鍵,但別的呢?
最后
這份算是最全的了,原創不易,純手打,
轉載請注明作者和鏈接哦,
感謝閱讀!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/145723.html
標籤:Python
