需要注册全局热键。例如,f4
和f8
。使用键盘库,当第一个回调没有返回时,下一个不会调用。
换句话说,像这样的日志
pressed f4
end for f4
pressed f8
end for f8
但我想喜欢这个
pressed f4
pressed f8
end for f4
end for f8
演示代码
# pip install keyboard
from keyboard import add_hotkey, wait
from time import sleep
def on_callback(key):
print('pressed', key)
sleep(5) # emulate long run task
print('end for', key)
add_hotkey("f4", lambda: on_callback("f4"))
add_hotkey("f8", lambda: on_callback("f8"))
wait('esc')
我尝试使用asyncio
,但没有任何改变
pressed f4
end for f4
pressed f8
end for f8
from keyboard import add_hotkey, wait
import asyncio
async def on_callback(key):
print('pressed', key)
await asyncio.sleep(5) # emulate long run task
print('end for', key)
add_hotkey("f4", lambda: asyncio.run(on_callback("f4")))
add_hotkey("f8", lambda: asyncio.run(on_callback("f8")))
wait('esc')
更新 1
键盘库的开发人员建议使用call_later
为每个函数创建新线程的函数,callback
它的工作原理和我想要的一样。
但是有没有办法在同一个线程中完成这样的任务(使用asyncio
)?我没有成功。
# example with 'call_later' function
from keyboard import add_hotkey, wait, call_later
from time import sleep
def on_callback(key):
print('pressed', key)
sleep(5) # emulate long run task
print('end for', key)
add_hotkey("f4", lambda: call_later(on_callback, args=("f4",)))
add_hotkey("f8", lambda: call_later(on_callback, args=("f8",)))
wait('esc')
更新 2
现在它看起来像下面(github上的完整代码)。我似乎为了等待http请求而创建新线程是太繁重的操作。因此我想在当前线程中使用 asyncio 并同时继续处理其他热键。
from googleapiclient.discovery import build
from os import getenv
from settings import get_settings
from loguru import logger
import keyboard
class ScriptService():
def __init__(self):
# ...
self._script = AppsScript(id)
self._hotkeys = values["hotkeys"]
def _register_hotkeys(self):
self._add_hotkey(self._hotkeys["reload"], self._on_reload)
for item in self._hotkeys["goofy"]:
k, f = item["keys"], item["function"]
self._add_hotkey(k, self._on_callback, args=(f, k))
def _add_hotkey(self, keys, callback, args=()):
# lambda bug: https://github.com/boppreh/keyboard/issues/493
keyboard.add_hotkey(keys, lambda: keyboard.call_later(callback, args))
def _on_callback(self, function, keys):
response = self._script.run(function)
class AppsScript():
def __init__(self, id: str):
self._name = getenv("API_SERVICE_NAME")
self._version = getenv("API_VERSION")
self._id = id
def run(self, function: str):
body = {"function": function}
with build(self._name, self._version, credentials=get_credentials()) as service:
# http request
return service.scripts().run(scriptId=self._id, body=body).execute()