目的是读取多个游戏手柄的输入并在Python中处理它。我正在使用evdev library。
根据文档,假设使用给定的设备对象dev
,可以使用功能dev.read_loop()
轻松读取Gamepad发送的事件。此函数调用返回调试器告知的generator object
。然后,可以使用一个简单的for
循环来迭代生成器。它将一直阻塞,直到发生新事件,然后使用在for循环中使用的任何代码处理该事件。
现在,我想使用一个自定义类将事件“流”捆绑到多个游戏手柄上(这更像为它们分配ID,跟踪断开连接等),这就是我的问题所在。 我找不到一种方法来创建这样的生成器,该生成器将所有游戏手柄的事件组合在一起。游戏手柄对象在列表中给出。
提供的示例代码尝试模仿所需的行为,但失败。构造函数将打印所有可用的设备,然后对其进行初始化。方法global_generator()
是我解决此问题的方法。问题是,外部for循环for device in self.__gamepads
永远不会进行,因为第一个生成器是无限的,因此将始终且仅转发来自第一个控制器的事件。我尝试使用itertools.chain()
,但是它们有同样的问题,因为第一个生成器永远不会结束。所以我想要的基本上是:“一旦这n个生成器之一产生结果,就进一步产生它(并因此将它们组合)”。由于无法同时循环我的设备(即它们的生成器)的问题,我拥有的所有想法(例如创建队列或其他任何东西)总是会停止。
我在文档中看到了该部分,其中显示了如何从多个设备读取信息。问题是他们总是打印结果,但没有显示如何以我想要的方式传递结果。
import hardware.ControllerHandler as ch
controller_handler = ch.ControllerHandler()
global_generator = controller_handler.global_generator()
for event in global_generator:
#event = ce.ControllerEvent(event)
print(event)
import evdev
from evdev import InputDevice
import asyncio
class ControllerHandler:
def __init__(self):
print(evdev.list_devices())
self.__gamepads = list(map(InputDevice, evdev.list_devices()))
@property
def gamepads(self):
return self.__gamepads
@property
def count(self):
return len(self.__gamepads)
async def global_generator(self):
for device in self.__gamepads:
async for event in device.async_read_loop():
yield event
因此,预期结果是生成器返回任何基础事件,而不仅仅是第一个游戏手柄上的事件。
答案 0 :(得分:3)
您可以使用aiostream
库合并多个异步生成器:
async def global_generator(self):
loops = [device.async_read_loop() for device in self.__gamepads]
async with aiostream.stream.merge(*loops).stream() as merged:
async for event in merged:
yield event
如果您不希望依赖aiostream
,请参阅this answer,以获取有关如何使用纯异步来合并流的说明。
请注意,由于生成的生成器是异步的,因此您需要在协程内部使用async for
对其进行迭代。