0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Mac対応】pynputでマウスのサイドボタンを入力する

Last updated at Posted at 2024-11-17

イベント発火のみで、入力の検出はできていません

結論

from pynput.mouse import Button
from pynput.mouse._darwin import _button_value
from enum import Enum

class Buttons(Enum):
    left = Button.left.value
    right = Button.right.value
    middle = Button.middle.value
    x1 = _button_value("kCGEventOther", 3) # ここ重要
    x2 = _button_value("kCGEventOther", 4) # ここ重要

使い方

from pynput.mouse import Controller

controller = Controller()

controller.click(Buttons.x1) # 第4ボタン
controller.click(Buttons.x2) # 第5ボタン

システム設定からアクセシビリティにアプリを追加するのを忘れないようにしましょう。

はじめに

pynputを使ってマウスのサイドボタンを入力させる場合、Windowsでは以下のように書くことができます。

from pynput.mouse import Button, Controller

controller = Controller()

controller.click(Button.x1) # 第4ボタン
controller.click(Button.x2) # 第5ボタン

しかしMacではAttributeErrorとなってしまいます。

AttributeError: type object 'Button' has no attribute 'x1'

これは、pynputがMacのサイドボタンに対応していないためです。

辿り着いた経緯

pynputの内部コードを覗いてみます。

pynput/mouse/_darwin.py
...

def _button_value(base_name, mouse_button):
    ...
    return (
        tuple(
            getattr(Quartz, '%sMouse%s' % (base_name, name))
            for name in ('Down', 'Up', 'Dragged')),
        mouse_button)

        
class Button(enum.Enum):
    """The various buttons.
    """
    unknown = None
    left = _button_value('kCGEventLeft', 0)
    middle = _button_value('kCGEventOther', 2)
    right = _button_value('kCGEventRight', 1)

...

kCGEventというキーワードが出てきたので調べてみると、Apple Developerのサイトがヒットしました。

case otherMouseDown
  Specifies a mouse down event with one of buttons 2-31.
case otherMouseUp
  Specifies a mouse up event with one of buttons 2-31.
case otherMouseDragged
  Specifies a mouse drag event with one of buttons 2-31 down.

どうやらボタン2〜31は全てkCGEventOtherとして括られるようです。
ボタン0が左クリック、ボタン1が右クリックで、ボタン2がミドルクリック(マウスホイール)だとすると、サイドボタンは3と4である可能性が高そうです。

2〜31のkCGEventOtherを実行して検証してみます。

from pynput.mouse import Controller, Button
from pynput.mouse._darwin import _button_value
from time import sleep
from enum import Enum

addition = {}
for i in range(2, 32):
    button = _button_value("kCGEventOther", i)
    addition[f"button{i}"] = button
# Enumの拡張については下を参考
# https://zenn.dev/yuji38kwmt/articles/63cda54021ecf3
tmp = {e.name: e.value for e in Button} | addition
buttons = Enum("buttons", tmp)

sleep(5) # この間にブラウザなど、サイドボタンの動きがわかるアプリにフォーカスする

controller = Controller()
for i in range(2, 32):
    controller.click(buttons[f"button{i}"])
    print(f"Clicked button {i}")
    sleep(3)

検証の結果、button3の時に「戻る」、button4の時に「進む」が実行されました。

終わりに

Windows / Mac両対応のコード

from pynput.mouse import Button as bt
from enum import Enum
import platform

system = platform.system()

class Button(Enum):
    if system == "Windows":
        left = bt.left.value
        right = bt.right.value
        middle = bt.middle.value
        x1 = bt.x1.value
        x2 = bt.x2.value
    elif system == "Darwin":
        from pynput.mouse._darwin import _button_value
        left = bt.left.value
        right = bt.right.value
        middle = bt.middle.value
        x1 = _button_value("kCGEventOther", 3)
        x2 = _button_value("kCGEventOther", 4)
    elif system == "Linux":
        pass # 検証環境をサッと用意できなかったので割愛

または

from pynput.mouse import Button
import sys

if sys.platform == "darwin":
    from pynput.mouse._darwin import _button_value
    from enum import Enum
    Button = Enum("Button", {e.name: e.value for e in Button} | {"x1": _button_value("kCGEventOther", 3), "x2": _button_value("kCGEventOther", 4)})

検証

from pynput.mouse import Controller
from time import sleep

controller = Controller()

sleep(5)

controller.click(Button.x1, 1)
sleep(3)
controller.click(Button.x2, 1)
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?