Pythonライブラリpynput徹底解説:キーボード&マウス操作を自由自在に操る 🖱️

プログラミング

Pythonを使って、キーボードやマウスの操作を自動化したり、入力を監視したりしたいと考えたことはありませんか? pynputは、まさにそれを実現するための強力なPythonライブラリです。このライブラリを使えば、OSに依存しない形で、キーボード入力のシミュレーションやマウスカーソルの移動、クリック操作などをプログラムから制御できます。 さらに、ユーザーによるキーボードやマウスの入力イベントをリアルタイムで監視することも可能です。 この記事では、pynputの基本的な使い方から、応用的なテクニックまで、具体的なコード例を交えながら詳しく解説していきます。

pynputとは? ✨

pynputは、Pythonでキーボードとマウスの制御監視を行うためのライブラリです。主な特徴は以下の通りです。

  • クロスプラットフォーム対応: Windows, macOS, Linuxなど、主要なOSで同じコードが動作します。OSごとに異なるAPIを意識する必要がなく、開発効率が向上します。
  • キーボード制御: 特定のキーの押下・解放、文字列のタイピングなどをプログラムから実行できます。
  • マウス制御: マウスカーソルの移動、クリック(左、右、中)、ダブルクリック、ドラッグ、スクロールなどを自動化できます。
  • イベント監視 (リスナー): ユーザーがキーボードを打ったり、マウスを操作したりするイベントを検知し、特定の処理を実行させることができます。バックグラウンドでの入力監視も可能です。
  • ホットキー設定: 特定のキーの組み合わせ(例: Ctrl+Shift+A)が押されたときに、指定した関数を実行するグローバルホットキーを設定できます。

これらの機能により、GUIアプリケーションの自動テスト、定型作業の自動化、アクセシビリティツールの開発、ゲームの操作補助(利用規約に注意!)など、幅広い用途での活用が期待できます。 低レベルなOS固有のAPIを直接扱わずに、Pythonのシンプルなコードでこれらの機能を実現できるのが大きな魅力です。😊

インストール方法 💻

pynputのインストールは、Pythonのパッケージ管理ツールであるpipを使って簡単に行えます。ターミナルやコマンドプロンプトを開き、以下のコマンドを実行してください。

pip install pynput

通常、これだけでインストールは完了します。依存関係のあるライブラリも自動的にインストールされます。 特定の環境(特にLinuxやmacOS)では、バックエンドライブラリのインストールや設定、あるいは実行権限が必要になる場合があります。 例えば、Linuxの`uinput`バックエンドを使用するにはroot権限が必要です。また、macOSではセキュリティとプライバシー設定で、実行するターミナルやアプリケーションに対して「アクセシビリティ」や「入力監視」の許可を与える必要がある場合があります。 問題が発生した場合は、公式ドキュメントのPlatform limitationsのセクションなどを確認してください。

インストールが成功したか確認するには、Pythonインタプリタを起動してインポートを試みます。

import pynput

エラーが出なければ、正常にインストールされています。🎉

キーボードの制御 ⌨️

pynputを使えば、キーボードからの入力をシミュレートできます。これには主にpynput.keyboard.Controllerクラスを使用します。

基本的なキー操作

特定のキーを押したり離したりするには、press()メソッドとrelease()メソッドを使います。

from pynput.keyboard import Key, Controller
import time

# Controllerオブジェクトを作成
keyboard = Controller()

# 'A'キーを押す
keyboard.press('a')
# 'A'キーを離す
keyboard.release('a')

time.sleep(0.5) # 少し待機

# Shiftキーを押しながら'b'を押す (大文字のBを入力)
with keyboard.pressed(Key.shift):
    keyboard.press('b')
    keyboard.release('b')

time.sleep(0.5)

# 特殊キー(Enterキー)を押す
keyboard.press(Key.enter)
keyboard.release(Key.enter)

press()release()には、通常の文字キー(’a’, ‘b’, ‘1’など)か、pynput.keyboard.Keyで定義されている特殊キー(Key.shift, Key.ctrl, Key.alt, Key.cmd (macOS), Key.space, Key.enter, Key.tab, 矢印キーなど)を指定します。 with keyboard.pressed(Key.shift):のように書くと、withブロック内では指定したキー(この場合はShift)が押された状態になります。

文字列のタイピング

文字列全体を一度にタイピングさせたい場合は、type()メソッドが便利です。

from pynput.keyboard import Controller
import time

keyboard = Controller()

time.sleep(2) # テキストエディタなどをアクティブにするための待機時間

# 文字列をタイピング
keyboard.type('こんにちは、pynput! これは自動入力です。')
time.sleep(0.5)
keyboard.type('\nHello from pynput!')

type()メソッドは、指定された文字列の各文字に対応するキーの押下と解放を自動的に行います。これにより、まるで人がタイピングしているかのような動作を再現できます。

特殊キー (pynput.keyboard.Key)

pynputでは、ShiftやCtrl、Enterなどの特殊キーはpynput.keyboard.Keyクラスの属性として定義されています。よく使われるものをいくつか紹介します。

属性名 説明
Key.altAltキー (Optionキー on macOS)
Key.alt_l左Altキー
Key.alt_r右Altキー
Key.backspaceBackspaceキー
Key.caps_lockCaps Lockキー
Key.cmdCommandキー (macOS)
Key.cmd_l左Commandキー (macOS)
Key.cmd_r右Commandキー (macOS)
Key.ctrlControlキー
Key.ctrl_l左Controlキー
Key.ctrl_r右Controlキー
Key.deleteDeleteキー
Key.down下矢印キー
Key.endEndキー
Key.enterEnterキー (Returnキー)
Key.escEscapeキー
Key.f1Key.f20ファンクションキー
Key.homeHomeキー
Key.left左矢印キー
Key.page_downPage Downキー
Key.page_upPage Upキー
Key.right右矢印キー
Key.shiftShiftキー
Key.shift_l左Shiftキー
Key.shift_r右Shiftキー
Key.spaceスペースキー
Key.tabTabキー
Key.up上矢印キー
Key.media_play_pauseメディア再生/一時停止キー
Key.media_volume_muteメディア音量ミュートキー
Key.media_volume_downメディア音量ダウンキー
Key.media_volume_upメディア音量アップキー

これらを利用して、ショートカットキー(例: Ctrl+C, Ctrl+V)などもシミュレートできます。

from pynput.keyboard import Key, Controller
import time

keyboard = Controller()

# テキストを選択する動作を想定 (例: Shift + 右矢印)
with keyboard.pressed(Key.shift):
    for _ in range(5):
        keyboard.press(Key.right)
        keyboard.release(Key.right)
        time.sleep(0.1)

time.sleep(0.5)

# コピー (Ctrl+C または Cmd+C)
copy_key = Key.cmd if 'darwin' in __import__('sys').platform else Key.ctrl
with keyboard.pressed(copy_key):
    keyboard.press('c')
    keyboard.release('c')

time.sleep(0.5)

# ペースト (Ctrl+V または Cmd+V)
with keyboard.pressed(copy_key):
    keyboard.press('v')
    keyboard.release('v')

マウスの制御 🖱️

キーボードと同様に、pynputはマウス操作の自動化もサポートしています。pynput.mouse.Controllerクラスを使います。

マウスカーソルの移動

position属性で現在のカーソル位置を取得したり、新しい位置を設定したりできます。move()メソッドで相対的な移動も可能です。

from pynput.mouse import Button, Controller
import time

# Controllerオブジェクトを作成
mouse = Controller()

# 現在のマウスカーソル位置を取得して表示
print(f'現在のカーソル位置: {mouse.position}')

# カーソルを指定した座標(100, 200)に移動
mouse.position = (100, 200)
print(f'移動後のカーソル位置: {mouse.position}')

time.sleep(1)

# 現在位置から相対的に移動 (右に50, 下に30)
mouse.move(50, 30)
print(f'相対移動後のカーソル位置: {mouse.position}')

座標は通常、画面の左上隅を(0, 0)とするピクセル単位で指定します。

クリックとスクロール

press(), release()メソッドでボタンの押下・解放、click()メソッドでクリック(指定回数可能)、scroll()メソッドでスクロールができます。

from pynput.mouse import Button, Controller
import time

mouse = Controller()

# 左ボタンをクリック (押してすぐ離す)
print("左クリックを実行します")
mouse.press(Button.left)
mouse.release(Button.left)

time.sleep(1)

# 右ボタンをダブルクリック
print("右ダブルクリックを実行します")
mouse.click(Button.right, 2) # 第2引数でクリック回数を指定

time.sleep(1)

# 下方向にスクロール (垂直方向に2ステップ)
print("下にスクロールします")
# scroll(dx, dy): dxは水平方向、dyは垂直方向のスクロール量
mouse.scroll(0, 2)

time.sleep(1)

# 上方向にスクロール (垂直方向に-3ステップ)
print("上にスクロールします")
mouse.scroll(0, -3)

# ドラッグ操作の例 (左ボタンを押しながら移動)
print("ドラッグ操作を実行します")
mouse.position = (300, 300) # 開始位置
time.sleep(0.5)
mouse.press(Button.left) # 左ボタンを押す
time.sleep(0.1)
mouse.move(100, 50) # 移動
time.sleep(0.1)
mouse.release(Button.left) # 左ボタンを離す
print("ドラッグ操作完了")

マウスボタンはpynput.mouse.Buttonで定義されており、Button.left, Button.right, Button.middleなどが利用できます。 scroll()の引数はプラットフォームや設定によって挙動が異なる場合がありますが、一般的には正の値が下または右方向、負の値が上または左方向のスクロールに対応します。

pynputのもう一つの強力な機能は、キーボードやマウスのイベントを監視する「リスナー」です。これにより、ユーザーの入力をリアルタイムで検知し、それに応じた処理を実行できます。リスナーは別スレッドで動作します。

pynput.keyboard.Listenerクラスを使用します。キーが押されたとき、離されたときに呼び出されるコールバック関数を指定します。

from pynput import keyboard

def on_press(key):
    try:
        # 通常のキーの場合、文字を表示
        print(f'キー {key.char} が押されました')
    except AttributeError:
        # 特殊キーの場合、キーの名前を表示
        print(f'特殊キー {key} が押されました')

def on_release(key):
    print(f'キー {key} が離されました')
    # Escキーが離されたらリスナーを停止
    if key == keyboard.Key.esc:
        print('リスナーを停止します...')
        return False # Falseを返すとリスナーが停止する

# リスナーインスタンスを作成し、コールバック関数を登録
# with文を使うと、ブロック終了時に自動的にjoin()が呼ばれる
with keyboard.Listener(on_press=on_press, on_release=on_release) as listener:
    print("キーボードリスナーを開始しました。Escキーで終了します。")
    listener.join() # リスナーが停止するまで待機

print("リスナーが終了しました。")

on_pressコールバック関数は、押されたキーを表すオブジェクトを引数として受け取ります。通常の文字キーの場合はkey.char属性で文字を取得できますが、特殊キーの場合はAttributeErrorが発生するため、try-exceptで処理を分けています。 on_releaseコールバック関数も同様に、離されたキーオブジェクトを受け取ります。 コールバック関数内でFalseを返すか、StopExceptionを送出する、あるいは別の場所からlistener.stop()を呼び出すことで、リスナーを停止できます。 リスナーはバックグラウンドスレッドで動作するため、メインスレッドが終了しないようにlistener.join()で待機する必要があります。with構文を使うとこの辺りの管理が楽になります。

注意: キーボードリスナーは、ユーザーが入力するすべての情報を取得できてしまうため、悪意を持って使用されるとキーロガーとなり、プライバシー侵害やセキュリティリスクにつながります。作成したプログラムの取り扱いには十分注意し、倫理的な範囲で使用してください。特に、他人のコンピュータで無断で使用することは絶対に避けてください。macOSなどでは、セキュリティ上の理由から、リスナーの実行に特別な許可が必要になる場合があります。

pynput.mouse.Listenerクラスを使用します。マウスカーソルが移動したとき、クリックされたとき、スクロールされたときに呼び出されるコールバック関数を指定します。

from pynput import mouse

def on_move(x, y):
    # print(f'マウスカーソルが ({x}, {y}) に移動しました') # 移動イベントは大量に発生するのでコメントアウト
    pass

def on_click(x, y, button, pressed):
    action = '押されました' if pressed else '離されました'
    print(f'{button} ボタンが ({x}, {y}) で {action}')
    # 右クリックが離されたらリスナーを停止
    if button == mouse.Button.right and not pressed:
        print('リスナーを停止します...')
        return False # Falseを返すとリスナーが停止

def on_scroll(x, y, dx, dy):
    direction = '下' if dy < 0 else '上' if dy > 0 else '右' if dx > 0 else '左'
    print(f'({x}, {y}) で {direction} へスクロールしました (dx={dx}, dy={dy})')

# リスナーインスタンスを作成し、コールバック関数を登録
with mouse.Listener(on_move=on_move, on_click=on_click, on_scroll=on_scroll) as listener:
    print("マウスリスナーを開始しました。右クリックで終了します。")
    listener.join() # リスナーが停止するまで待機

print("リスナーが終了しました。")

on_clickコールバックは、クリック位置(x, y)、ボタンの種類(Buttonオブジェクト)、押されたか離されたか(pressed, boolean)を受け取ります。 on_scrollコールバックは、スクロールが発生した位置(x, y)と、水平方向(dx)および垂直方向(dy)のスクロール量を受け取ります。 キーボードリスナーと同様に、コールバックからFalseを返すかStopExceptionを送出、またはlistener.stop()を呼び出すことで停止できます。

キーボードとマウスの両方のイベントを同時に監視したい場合は、それぞれのリスナーを別々に起動します。threadingモジュールなどを活用すると管理しやすくなりますが、単純に両方のwith文を開始するだけでも可能です。

from pynput import keyboard, mouse
import threading
import time

# 停止要求を管理するためのフラグ
stop_event = threading.Event()

def on_press_kb(key):
    try:
        print(f'キーボード: {key.char} が押されました')
    except AttributeError:
        print(f'キーボード: 特殊キー {key} が押されました')
        # F12キーで停止
        if key == keyboard.Key.f12:
            print("F12キーが押されたため、両方のリスナーを停止します...")
            stop_event.set() # 停止フラグをセット
            return False # キーボードリスナーを停止

def on_click_mouse(x, y, button, pressed):
    action = '押されました' if pressed else '離されました'
    print(f'マウス: {button} が ({x}, {y}) で {action}')
    if stop_event.is_set(): # 停止フラグが立っていたらマウスリスナーも停止
        return False

# キーボードリスナーを別スレッドで開始する関数
def keyboard_listener_thread():
    with keyboard.Listener(on_press=on_press_kb) as k_listener:
        print("キーボードリスナー スレッド開始 (F12で終了)")
        k_listener.join()
    print("キーボードリスナー スレッド終了")

# マウスリスナーを別スレッドで開始する関数
def mouse_listener_thread():
    with mouse.Listener(on_click=on_click_mouse) as m_listener:
        print("マウスリスナー スレッド開始 (F12で終了)")
        m_listener.join()
    print("マウスリスナー スレッド終了")


# 各リスナーを別々のスレッドで起動
kb_thread = threading.Thread(target=keyboard_listener_thread, daemon=True)
mouse_thread = threading.Thread(target=mouse_listener_thread, daemon=True)

kb_thread.start()
mouse_thread.start()

# メインスレッドは停止イベントが発生するまで待機するか、他の処理を行う
# ここでは単純に待機する例
try:
    # stop_eventがセットされるか、KeyboardInterrupt(Ctrl+C)が発生するまで待つ
    while not stop_event.wait(timeout=1): # タイムアウト付きで待機し、中断可能にする
        pass
except KeyboardInterrupt:
    print("\nCtrl+Cが押されました。リスナーを停止します。")
    stop_event.set() # 念のため停止フラグをセット

# スレッドが終了するのを待つ(必要であれば)
# kb_thread.join()
# mouse_thread.join()

print("メインプログラム終了")

この例では、threading.Eventを使って、一方のリスナー(ここではキーボードリスナーでF12キーを検知)からもう一方のリスナーとメインスレッドに停止を通知する仕組みを実装しています。各リスナーをデーモンスレッド (daemon=True) として起動すると、メインスレッドが終了したときに自動的に終了させることができます。

応用的な使い方と注意点 💡

グローバルホットキー

特定のキーの組み合わせが押されたときにアクションを実行したい場合、pynput.keyboard.GlobalHotKeysを使うと便利です。これはリスナーの一種ですが、ホットキー専用に設計されています。

from pynput import keyboard

def on_activate_h():
    print('ホットキー <ctrl>+<alt>+h が押されました!')

def on_activate_x():
    print('ホットキー <ctrl>+<alt>+x が押されました!リスナーを終了します。')
    # ここでリスナーを停止
    return False

# ホットキーと対応する関数を辞書で定義
# キーの組み合わせは '+' で連結した文字列で指定
hotkeys_mapping = {
        '<ctrl>+<alt>+h': on_activate_h,
        '<ctrl>+<alt>+x': on_activate_x
}

# グローバルホットキーリスナーを作成して開始
with keyboard.GlobalHotKeys(hotkeys_mapping) as h_listener:
    print("ホットキーリスナーを開始しました。")
    print("Ctrl+Alt+H または Ctrl+Alt+X を押してみてください。")
    h_listener.join()

print("ホットキーリスナーが終了しました。")

キーの組み合わせは、'<ctrl>+<alt>+h'のように、修飾キー(<ctrl>, <alt>, <shift>, <cmd>)と通常のキー文字を+でつないだ文字列で指定します。特殊キー(Enter, Spaceなど)も<enter>, <space>のように指定できます。 コールバック関数でFalseを返すと、そのホットキーリスナーが停止します。

プラットフォーム固有の注意点

  • macOS: 近年のmacOSでは、セキュリティ強化のため、キーボードイベントの監視(リスナー)には特別な許可が必要です。「システム環境設定」>「セキュリティとプライバシー」>「プライバシー」タブの「アクセシビリティ」や「入力監視」の項目で、スクリプトを実行するターミナルやアプリケーション(パッケージ化した場合)を許可リストに追加する必要があります。許可がない場合、リスナーは動作しないか、一部のキーしか検知できないことがあります。
  • Linux: デフォルトではXorgバックエンドが使われますが、DISPLAY環境変数が設定されている必要があります。SSH経由などで実行する場合は注意が必要です。また、Wayland環境下では、Xwayland経由で動作しますが、監視できるのはXwayland上で動作しているアプリケーションのイベントのみに限られる場合があります。root権限があれば、キーボード専用の`uinput`バックエンドも利用できます。
  • Windows: 他のプロセスから送信された仮想的なキーイベント(他の自動化ツールによる入力など)は、pynputのリスナーで受信できない場合があります。ただし、pynput自身が生成したイベントは、同一プロセス内のリスナーには正しくディスパッチされます。

これらの制限については、pynputの公式ドキュメントにある “Platform limitations” のセクションに詳細が記載されています。

リスナーの再起動とエラーハンドリング

pynputのリスナークラス(keyboard.Listener, mouse.Listener, keyboard.GlobalHotKeys)は、一度stop()メソッドが呼ばれるか、コールバックがFalseを返して停止すると、再起動することはできません。これは、リスナーが内部的にthreading.Threadを継承しており、スレッドは一度停止すると再利用できないためです。 もし、イベントの監視を一時停止・再開したい場合は、リスナー内部でフラグを管理し、フラグが有効なときだけ処理を行うようにするか、監視を再開する際に新しいリスナーインスタンスを作成する必要があります。

また、リスナーのコールバック関数内で未処理の例外が発生すると、そのリスナーは停止してしまいます。長時間安定して動作させる必要がある場合は、コールバック関数内で適切にtry...exceptブロックを使い、エラーハンドリングを行うことが重要です。

from pynput import keyboard
import time

is_listening_active = True # 監視を有効にするかどうかのフラグ

def on_press_safe(key):
    global is_listening_active
    try:
        if not is_listening_active:
            # print("監視が無効なため、処理をスキップします。")
            pass # フラグが無効なら何もしない

        elif key == keyboard.Key.f1:
            is_listening_active = not is_listening_active # F1キーで監視の有効/無効を切り替え
            status = "有効" if is_listening_active else "無効"
            print(f"\n--- 監視を {status} にしました ---")

        elif is_listening_active: # 監視が有効な場合のみ処理
            if hasattr(key, 'char') and key.char:
                 print(f'キー {key.char} を処理しました', end=', ')
            else:
                 print(f'特殊キー {key} を処理しました', end=', ')

        # Escキーで終了
        if key == keyboard.Key.esc:
            print("\nEscキーが押されたため、リスナーを停止します。")
            return False

    except Exception as e:
        print(f"\n--- コールバック内でエラーが発生しました: {e} ---")
        # ここでエラーログを記録するなどの処理を追加できる
        # リスナー自体は停止させずに継続させる(場合による)
        pass

with keyboard.Listener(on_press=on_press_safe) as listener:
    print("リスナーを開始しました。F1で監視の有効/無効切り替え、Escで終了。")
    listener.join()

print("リスナーが終了しました。")

非同期処理との連携

pynputのリスナーはブロッキングする(join()で待機する)ため、他のGUIフレームワーク(Tkinter, PyQt, Kivyなど)のメインループや、asyncioなどの非同期処理と組み合わせる際には工夫が必要です。 単純な解決策は、リスナーを別スレッドで起動し、メインスレッドはGUIのメインループや非同期イベントループを実行することです。上記「キーボードとマウスの同時監視」の例のように、threadingモジュールを使うのが一般的です。

まとめ 🚀

pynputは、Pythonでキーボードとマウスの制御・監視を行うための非常に強力で柔軟なライブラリです。クロスプラットフォーム対応であり、比較的シンプルなAPIで複雑な操作を実現できます。

  • 制御 (Controller): キー入力のシミュレート、マウスカーソルの移動、クリック、スクロールなどを自動化できます。
  • 監視 (Listener): ユーザーのキーボード・マウス入力をリアルタイムで検知し、特定の処理をトリガーできます。
  • ホットキー: 特定のキー組み合わせで関数を呼び出すグローバルホットキーを簡単に設定できます。

GUIテストの自動化、作業効率化のためのマクロ作成、アクセシビリティ支援ツールの開発など、アイデア次第で様々な応用が可能です。ただし、特にリスナー機能はユーザーの入力をすべて取得できるため、プライバシーとセキュリティに十分配慮し、倫理的に利用することが非常に重要です。

この記事が、pynputを使った開発の一助となれば幸いです。ぜひ、このライブラリを活用して、あなたのPythonプロジェクトの可能性を広げてください!🥳

コメント

タイトルとURLをコピーしました