Add threading, allow mapping events one-to-many

This commit is contained in:
Marc Riera Irigoyen 2022-10-20 00:01:30 +02:00
parent 5052407e53
commit 9712d26508
5 changed files with 77 additions and 25 deletions

View file

@ -55,24 +55,25 @@ class SwitchGamepad(PhysicalGamepad):
# time.sleep(5) # time.sleep(5)
# print("Read from ZKNS-001 correct") # print("Read from ZKNS-001 correct")
# return InputEvent(InputEvent.EventType.PRESS_BUTTON, InputEvent.Button.BUTTON_A) # return InputEvent(InputEvent.EventType.PRESS_BUTTON, InputEvent.Button.BUTTON_A)
print(self.device.active_keys())
select([self.device], [], [], 5) select([self.device], [], [], 5)
try: try:
event = self.device.read_one() event = self.device.read_one()
input_events = []
if event is not None: if event is not None:
if event.type == evdev.ecodes.EV_KEY: if event.type == evdev.ecodes.EV_KEY:
match event.code: match event.code:
case 304: # Y case 304: # Y
return InputEvent(InputEvent.EventType(event.value), InputEvent.Button.BUTTON_A) input_events.append(InputEvent(InputEvent.EventType(event.value), InputEvent.Button.BUTTON_A))
case 305: # B case 305: # B
return InputEvent(InputEvent.EventType(event.value), InputEvent.Button.BUTTON_B) input_events.append(InputEvent(InputEvent.EventType(event.value), InputEvent.Button.BUTTON_B))
case 306: # A case 306: # A
return InputEvent(InputEvent.EventType(event.value), InputEvent.Button.BUTTON_C) input_events.append(InputEvent(InputEvent.EventType(event.value), InputEvent.Button.BUTTON_C))
case 307: # X case 307: # X
return InputEvent(InputEvent.EventType(event.value), InputEvent.Button.BUTTON_D) input_events.append(InputEvent(InputEvent.EventType(event.value), InputEvent.Button.BUTTON_D))
case 312: # MINUS case 312: # MINUS
return InputEvent(InputEvent.EventType(event.value), InputEvent.Button.BUTTON_SELECT) input_events.append(InputEvent(InputEvent.EventType(event.value), InputEvent.Button.BUTTON_SELECT))
case 313: # PLUS case 313: # PLUS
return InputEvent(InputEvent.EventType(event.value), InputEvent.Button.BUTTON_START) input_events.append(InputEvent(InputEvent.EventType(event.value), InputEvent.Button.BUTTON_START))
return input_events
except OSError: except OSError:
return (InputEvent(InputEvent.EventType.ERROR, None)) return [InputEvent(InputEvent.EventType.ERROR, None)]

View file

@ -1,6 +1,7 @@
import sys import sys
from PyQt5.QtCore import Qt from PyQt5.QtCore import Qt, QTimer
from PyQt5.QtWidgets import QMainWindow, QTableWidgetItem, QHeaderView from PyQt5.QtWidgets import QMainWindow, QTableWidgetItem, QHeaderView
import threading
from gui.main_ui import Ui_MainWindow from gui.main_ui import Ui_MainWindow
import gamepads.physical as gamepad_physical import gamepads.physical as gamepad_physical
import gamepads.emulated as gamepad_emulated import gamepads.emulated as gamepad_emulated
@ -13,6 +14,8 @@ class MainWindow(QMainWindow):
self._gamepad_handler = gamepad_handler self._gamepad_handler = gamepad_handler
self._gui = Ui_MainWindow() self._gui = Ui_MainWindow()
self._gui.setupUi(self) self._gui.setupUi(self)
self._emuthread = None
self._emuthread_stop = threading.Event()
self.gamepad_model = GamepadModel(self._gamepad_handler.find_gamepads()) self.gamepad_model = GamepadModel(self._gamepad_handler.find_gamepads())
self._gui.tableView_physicalControllerList.setModel(self.gamepad_model) self._gui.tableView_physicalControllerList.setModel(self.gamepad_model)
@ -24,11 +27,18 @@ class MainWindow(QMainWindow):
self._gui.pushButton_physicalControllerRefresh.clicked.connect(self.controller_list_refresh) self._gui.pushButton_physicalControllerRefresh.clicked.connect(self.controller_list_refresh)
self._gui.pushButton_emulatedControllerStart.clicked.connect(self.controller_emulator_start) self._gui.pushButton_emulatedControllerStart.clicked.connect(self.controller_emulator_start)
self._gui.pushButton_emulatedControllerStop.clicked.connect(self.controller_emulator_stop)
self._gui.pushButton_emulatedControllerStop.setVisible(False)
def closeEvent(self, event):
self._emuthread_stop.set()
def controller_list_refresh(self): def controller_list_refresh(self):
self.gamepad_model.beginResetModel() self.gamepad_model.beginResetModel()
self.gamepad_model.gamepads = self._gamepad_handler.find_gamepads() self.gamepad_model.gamepads = self._gamepad_handler.find_gamepads()
self.gamepad_model.endResetModel() self.gamepad_model.endResetModel()
self.controller_list_selection_changed()
def controller_list_selection_changed(self): def controller_list_selection_changed(self):
enabled = False enabled = False
@ -37,10 +47,41 @@ class MainWindow(QMainWindow):
enabled = True enabled = True
self._gui.pushButton_emulatedControllerStart.setEnabled(enabled) self._gui.pushButton_emulatedControllerStart.setEnabled(enabled)
def lock_interface(self,):
self._gui.pushButton_emulatedControllerStart.setVisible(False)
self._gui.pushButton_emulatedControllerStop.setVisible(True)
self._gui.tableView_physicalControllerList.setEnabled(False)
self._gui.pushButton_physicalControllerRefresh.setEnabled(False)
self._gui.pushButton_physicalControllerConfig.setEnabled(False)
self._gui.comboBox_emulatedControllerModel.setEnabled(False)
def unlock_interface(self,):
self._gui.pushButton_emulatedControllerStart.setVisible(True)
self._gui.pushButton_emulatedControllerStop.setVisible(False)
self._gui.tableView_physicalControllerList.setEnabled(True)
self._gui.pushButton_physicalControllerRefresh.setEnabled(True)
self._gui.pushButton_physicalControllerConfig.setEnabled(True)
self._gui.comboBox_emulatedControllerModel.setEnabled(True)
def controller_emulator_start(self): def controller_emulator_start(self):
self._gui.pushButton_emulatedControllerStart.setEnabled(False) self.lock_interface()
self._gui.statusbar.showMessage("Gamepad emulator running...")
rows = self._gui.tableView_physicalControllerList.selectionModel().selectedRows() rows = self._gui.tableView_physicalControllerList.selectionModel().selectedRows()
if rows: if rows:
gamepad = self.gamepad_model.gamepads[rows[0].row()] gamepad = self.gamepad_model.gamepads[rows[0].row()]
emulated_gamepad = gamepad_emulated.PC2HandleGamepad() emulated_gamepad = gamepad_emulated.PC2HandleGamepad()
self._gamepad_handler.start_gamepad_emulator(gamepad, emulated_gamepad) self._emuthread = threading.Thread(target=self._gamepad_handler.run_gamepad_emulator, args=(gamepad, emulated_gamepad, self._emuthread_stop))
self._emuthread.start()
def controller_emulator_stop(self):
self._gui.statusbar.showMessage("Stopping gamepad emulator...")
self._emuthread_stop.set()
self._emuthread.join(timeout=0.05)
if self._emuthread.is_alive():
QTimer.singleShot(50, self.controller_emulator_stop)
return
self._emuthread_stop.clear()
self.unlock_interface()
self.controller_list_refresh()
self._gui.statusbar.showMessage("Gamepad emulator stopped successfully!", 5000)

View file

@ -70,8 +70,8 @@ class Ui_MainWindow(object):
sizePolicy.setVerticalStretch(0) sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.comboBox_emulatedControllerModel.sizePolicy().hasHeightForWidth()) sizePolicy.setHeightForWidth(self.comboBox_emulatedControllerModel.sizePolicy().hasHeightForWidth())
self.comboBox_emulatedControllerModel.setSizePolicy(sizePolicy) self.comboBox_emulatedControllerModel.setSizePolicy(sizePolicy)
self.comboBox_emulatedControllerModel.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToContents)
self.comboBox_emulatedControllerModel.setObjectName("comboBox_emulatedControllerModel") self.comboBox_emulatedControllerModel.setObjectName("comboBox_emulatedControllerModel")
self.comboBox_emulatedControllerModel.addItem("")
self.horizontalLayout.addWidget(self.comboBox_emulatedControllerModel) self.horizontalLayout.addWidget(self.comboBox_emulatedControllerModel)
spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem1) self.horizontalLayout.addItem(spacerItem1)
@ -79,6 +79,9 @@ class Ui_MainWindow(object):
self.pushButton_emulatedControllerStart.setEnabled(False) self.pushButton_emulatedControllerStart.setEnabled(False)
self.pushButton_emulatedControllerStart.setObjectName("pushButton_emulatedControllerStart") self.pushButton_emulatedControllerStart.setObjectName("pushButton_emulatedControllerStart")
self.horizontalLayout.addWidget(self.pushButton_emulatedControllerStart) self.horizontalLayout.addWidget(self.pushButton_emulatedControllerStart)
self.pushButton_emulatedControllerStop = QtWidgets.QPushButton(self.groupBox_emulatedController)
self.pushButton_emulatedControllerStop.setObjectName("pushButton_emulatedControllerStop")
self.horizontalLayout.addWidget(self.pushButton_emulatedControllerStop)
self.verticalLayout_main.addWidget(self.groupBox_emulatedController) self.verticalLayout_main.addWidget(self.groupBox_emulatedController)
self.gridLayout.addLayout(self.verticalLayout_main, 0, 0, 1, 1) self.gridLayout.addLayout(self.verticalLayout_main, 0, 0, 1, 1)
MainWindow.setCentralWidget(self.centralwidget) MainWindow.setCentralWidget(self.centralwidget)
@ -97,5 +100,5 @@ class Ui_MainWindow(object):
self.pushButton_physicalControllerConfig.setText(_translate("MainWindow", "Configuration")) self.pushButton_physicalControllerConfig.setText(_translate("MainWindow", "Configuration"))
self.groupBox_emulatedController.setTitle(_translate("MainWindow", "Emulated controller")) self.groupBox_emulatedController.setTitle(_translate("MainWindow", "Emulated controller"))
self.label_emulatedControllerModel.setText(_translate("MainWindow", "Model")) self.label_emulatedControllerModel.setText(_translate("MainWindow", "Model"))
self.comboBox_emulatedControllerModel.setItemText(0, _translate("MainWindow", "Two-handle controller for PC (DGOC-44U)"))
self.pushButton_emulatedControllerStart.setText(_translate("MainWindow", "Start")) self.pushButton_emulatedControllerStart.setText(_translate("MainWindow", "Start"))
self.pushButton_emulatedControllerStop.setText(_translate("MainWindow", "Stop"))

View file

@ -130,11 +130,9 @@
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<item> <property name="sizeAdjustPolicy">
<property name="text"> <enum>QComboBox::AdjustToContents</enum>
<string>Two-handle controller for PC (DGOC-44U)</string> </property>
</property>
</item>
</widget> </widget>
</item> </item>
<item> <item>
@ -160,6 +158,13 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QPushButton" name="pushButton_emulatedControllerStop">
<property name="text">
<string>Stop</string>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>

View file

@ -1,4 +1,5 @@
from evdev import InputDevice, list_devices, ecodes as e, UInput, AbsInfo from evdev import InputDevice, list_devices, ecodes as e, UInput, AbsInfo
import threading
import events.input as input_events import events.input as input_events
import gamepads.physical as gamepad_physical import gamepads.physical as gamepad_physical
import gamepads.emulated as gamepad_emulated import gamepads.emulated as gamepad_emulated
@ -15,13 +16,14 @@ class GamepadHandler:
gamepads.append(gamepad_physical.create_gamepad(0x0f0d, 0x00c1, "Test gamepad")) gamepads.append(gamepad_physical.create_gamepad(0x0f0d, 0x00c1, "Test gamepad"))
return gamepads return gamepads
def start_gamepad_emulator(gamepad, emulated_gamepad): def run_gamepad_emulator(gamepad, emulated_gamepad, stop_event):
while True: while not stop_event.is_set():
event = gamepad.read_input() events = gamepad.read_input()
if event is not None: if events is not None:
if event.type == input_events.InputEvent.EventType.ERROR: for event in events:
break if event.type == input_events.InputEvent.EventType.ERROR:
emulated_gamepad.write_input(event) break
emulated_gamepad.write_input(event)
""" cap = { """ cap = {