我使用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
我意识到macOS有macOS limitations的局限性,事实上,我最初并未将iTerm2添加到System Preferences
→Security & Privacy
→Accessibility
中,即使我直接在iTerm2上执行testpynput.py
也不起作用,但是在将iTerm2添加到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 Preferences
→Security & Privacy
→Accessibility
,这就像我将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