如果我在macOS上通过launchctl启动守护进程,则Pynput无法正常工作

时间:2019-03-22 09:41:40

标签: python macos pynput launchctl

我使用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 limitations的局限性,事实上,我最初并未将iTerm2添加到System PreferencesSecurity & PrivacyAccessibility中,即使我直接在iTerm2上执行testpynput.py也不起作用,但是在将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

0 个答案:

没有答案