Pynput не работает, если я запускаю демон с помощью launchctl на macOS - PullRequest
0 голосов
/ 22 марта 2019

Я использую launchctl для запуска демона моего кода py:

launchctl load -w com.bruce2.PicUploaderHelper.plist

Затем я ps aux | grep testpynput, демон был запущен:

root             65334   0.1  0.2  4350320  37596   ??  Ss    2:52   0:00.44 /usr/local/Cellar/python/3.7.2/Frameworks/Python.framework/Versions/3.7/Resources/Python.app/Contents/MacOS/Python /Users/bruce/PicUploaderHelper-macOS/testpynput.py /Users/bruce/PicUploaderHelper-macOS/config2.json

Однако привязка клавиш не работает, но если я использую точно такой же код в iTerm2 (терминальное приложение на macOS), он работает, я имею в виду, что я непосредственно выполняю следующий код в iTerm2:

/usr/local/Cellar/python/3.7.2/Frameworks/Python.framework/Versions/3.7/Resources/Python.app/Contents/MacOS/Python /Users/bruce/PicUploaderHelper-macOS/testpynput.py /Users/bruce/PicUploaderHelper-macOS/config2.json
pynput

execute command directly

Я понимаю, что у macOS есть некоторые ограничения ограничения для macOS , по сути, я сначала не добавил iTerm2 в System PreferencesSecurity & PrivacyAccessibility, он даже не работаетЯ выполняю testpynput.py непосредственно на iTerm2, но после добавления iTerm2 к Accessibility этот способ работает нормально: mac-Accessibility

Поэтому я поставил

/usr/local/Cellar/python/3.7.2/Frameworks/Python.framework/Versions/3.7/Resources/Python.app

или

/usr/local/Cellar/python/3.7.2/Frameworks/Python.framework/Versions/3.7/Resources/Python.app/Contents/MacOS/Python

в Систему System PreferencesSecurity & PrivacyAccessibility, это так же, как я установил iTerm2 в право доступа ?, но ни один из двух вариантов не работает.

Итак, вы, ребята, знаете, как я могу решить эту проблему?

Я поставлю свой код здесь:

testpynput.py:

#!/usr/bin/env /usr/local/bin/python3

from pynput import keyboard
from PIL import ImageGrab
import os
import logging
import json
import subprocess
import sys

# The currently active modifiers
current = set()


def read_config():
    """ Read config from config.json """
    config_file = '/etc/PicUploaderHelper-macOS/config.json'
    if len(sys.argv) == 2:
        config_file = sys.argv[1]

    f = open(config_file, 'r')
    text = f.read()
    f.close()
    return json.loads(text)


# Read config from config.json
config = read_config()

if config['debug'] == 1:
    log_dir = "/var/log"
    logging.basicConfig(filename=(log_dir + "/key_log.txt"), level=logging.DEBUG, format='%(asctime)s: %(message)s')


def get_key_combination():
    """ Get key combinations from config """
    tmp_list = []
    key_combinations = config['key_combinations']

    for items in key_combinations:
        s = set()
        for item in items:
            if len(item) == 1:
                ele = keyboard.KeyCode(char=item)
            else:
                ele = getattr(keyboard.Key, item)
            s.add(ele)
        tmp_list.append(s)
    return tmp_list


def send_notification(notification_type=''):
    """ Send notification with applescript """
    if notification_type == "":
        notification_type = 'success'

    notification = config['notification'][notification_type]
    title = notification['title']
    subtitle = notification['subtitle']
    message = notification['message']

    notification_script = 'display notification "'+message+'" with title "'+title+'" subtitle "'+subtitle+'"'
    applescript_command = "osascript -e '"+notification_script+"'"

    # Execute shell by python
    subprocess.Popen(applescript_command, shell=True)


def get_image_from_clipboard():
    """" Get image from clipboard """
    # Pull image from clipboard
    img_obj = ImageGrab.grabclipboard()

    if img_obj is None:
        return '';
    else:
        # Define temp dir
        tmp_dir = '/var/tmp'

        # Get image type from config
        img_type = config['img_type']

        # Tmp image path
        tmp_img = tmp_dir+'/.screenshot_upload_tmp.'+img_type.lower()

        # Save the image as jpg to disk
        img_obj.save(tmp_img, img_type.upper())
        return tmp_img


def upload_image():
    """ Upload image to remote server by running shell command """
    tmp_img = get_image_from_clipboard()

    if tmp_img != '':

        # Here goes the upload code, I currently use print instead
        print('Uploading image...')

        # Send macOS notification
        send_notification()
    else:
        send_notification('no_image')


COMBINATIONS = []
COMBINATIONS = get_key_combination()


def on_press(key):
    """ Listen button press event  """
    if config['debug'] == 1:
        logging.info(str(key))
    if any([key in COMBO for COMBO in COMBINATIONS]):
        current.add(key)
        if any(all(k in current for k in COMBO) for COMBO in COMBINATIONS):
            upload_image()


def on_release(key):
    """ Listen button release event """
    if any([key in COMBO for COMBO in COMBINATIONS]):
        current.remove(key)


with keyboard.Listener(on_press=on_press, on_release=on_release) as listener:
    """ start a keyboard listener """
    listener.join()

config2.json:

{
    "img_type": "JPEG",
    "notification": {
        "success": {
            "title": "Upload image succeed",
            "subtitle": "",
            "message": "Markdown link is copied to the cliboard, you can paste now!"
        },
        "no_image": {
            "title": "No image detected",
            "subtitle": "",
            "message": "No image was detected in the clipboard, please take a screenshot first!"
        }
    },
    "key_combinations": [
        ["alt", "shift", "u"],
        ["alt", "shift", "U"]
    ],
    "debug": 1
}

com.bruce2.PicUploaderHelper.plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>KeepAlive</key>
  <true/>
  <key>Label</key>
  <string>com.bruce2.PicUploaderHelper</string>
  <key>Program</key>
  <string>/Users/bruce/PicUploaderHelper-macOS/testpynput.py</string>
  <key>ProgramArguments</key>
  <array>
    <string>/Users/bruce/PicUploaderHelper-macOS/testpynput.py</string>
    <string>/Users/bruce/PicUploaderHelper-macOS/config2.json</string>
  </array>
  <key>RunAtLoad</key>
  <true/>
  <key>WorkingDirectory</key>
  <string>/Users/bruce/PicUploaderHelper-macOS</string>
  <key>StandardErrorPath</key>
  <string>/Users/bruce/PicUploaderHelper-macOS/testpynput.log</string>
  <key>StandardOutPath</key>
  <string>/Users/bruce/PicUploaderHelper-macOS/testpynput.log</string>
</dict>
</plist>

введите com.bruce2.PicUploaderHelper.plist в /Library/LaunchAgents, убедитесь, что вам нужно установить для его владельца значение root:wheel

-rw-r--r--  1 root  wheel   894B  3 22 14:41 com.bruce2.PicUploaderHelper.plist

Затем запустите с привилегиями sudo или root:

sudo launchctl load -w com.bruce2.PicUploaderHelper.plist

Это код в файле: PicUploaderHelper-macOS.zip

Python2.7 тоже самое, я пробовал.

macOS: 10.14.1 (18B75)
python2: Python 2.7.15
python3: Python 3.7.2
iTerm2: 3.2.7

...