python監聽、操作鍵盤鼠標庫pynput詳細教程


§ 0.0.0 前言

監聽、操作鼠標、鍵盤是實現自動化的捷徑,比如我實現自動化簽到用到了模擬鍵盤操作。

pynput是監聽、操控鼠標和鍵盤的跨平台第三方python庫。
你可以通過pip insnall pynput來安裝。安裝時會自動下載依賴庫。

pypi鏈接在此。

接下來我會按
“鼠標按鍵”“監聽鼠標”“控制鼠標”,“鍵盤按鍵”“監聽鍵盤”“控制鍵盤”
的順序介紹它的用法。



  • 以下為正文。


§1.0.0 鼠標按鍵

鼠標的按鍵在pynput.mouse.Button中,
liftrightmiddle還有unknown四種。

每一個按鍵都有兩個有意義的屬性:namevalue
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里,有leftrightmiddle
還有可選參數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,提供參數dxdy

例:

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鍵,但別的呢?

最后

這份算是最全的了。原創不易,純手打。

轉載請注明作者和鏈接哦。

感謝閱讀!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM