Add Qt5 GUI

This commit is contained in:
Marc Riera Irigoyen 2022-10-09 18:25:48 +02:00
parent cc8a271883
commit 0c9428fdd8
6 changed files with 433 additions and 147 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
__pycache__/
*.db

View file

@ -1,151 +1,15 @@
#!/usr/bin/env python #!/usr/bin/env python
from evdev import InputDevice, list_devices, ecodes as e, UInput, AbsInfo import sys
from PyQt5.QtWidgets import QApplication
from gui.main import MainWindow
cap = { class App(QApplication):
e.EV_KEY : [e.BTN_NORTH, e.BTN_SOUTH, e.BTN_EAST, e.BTN_WEST, e.BTN_SELECT, e.BTN_START], def __init__(self, sys_argv):
e.EV_ABS : [(e.ABS_X, AbsInfo(0, 0, 255, 0, 0, 0)), (e.ABS_Y, AbsInfo(0, 0, 255, 0, 0, 0))] super(App, self).__init__(sys_argv)
} self.main_view = MainWindow(None)
self.main_view.show()
# Mapping if __name__ == '__main__':
# A: BTN_EAST app = App(sys.argv)
# B: BTN_SOUTH sys.exit(app.exec_())
# C: BTN_NORTH
# D: BTN_WEST
# SL: BTN_SELECT
# ST: BTN_START
# BRAKE: ABS_X
# POWER: ABS_Y
mascon_switch = None
devices = [InputDevice(path) for path in list_devices()]
for device in devices:
dev_name = [device.info.vendor, device.info.product, device.name]
if dev_name == [0x0f0d, 0x00c1, "One Handle MasCon for Nintendo Switch"]:
mascon_switch = device
break
if mascon_switch is None:
print("No supported controller found.")
exit()
ui = UInput(cap, vendor=0x0AE4, product=0x0003, name='Emulated DGOC-44U')
mascon_switch.grab()
for event in mascon_switch.read_loop():
if event.type == e.EV_KEY:
match event.code:
case 304: # Y
ui.write(e.EV_KEY, e.BTN_EAST, event.value)
ui.syn()
case 305: # B
ui.write(e.EV_KEY, e.BTN_SOUTH, event.value)
ui.syn()
case 306: # A
ui.write(e.EV_KEY, e.BTN_NORTH, event.value)
ui.syn()
case 307: # X
ui.write(e.EV_KEY, e.BTN_WEST, event.value)
ui.syn()
case 312: # MINUS
ui.write(e.EV_KEY, e.BTN_SELECT, event.value)
ui.syn()
case 313: # PLUS
ui.write(e.EV_KEY, e.BTN_START, event.value)
ui.syn()
if event.type == e.EV_ABS and event.code == e.ABS_HAT0X:
match event.value:
case -1: # LEFT
ui.write(e.EV_KEY, e.BTN_SELECT, 1)
ui.write(e.EV_KEY, e.BTN_EAST, 1)
ui.write(e.EV_KEY, e.BTN_NORTH, 0)
ui.syn()
case 1: # RIGHT
ui.write(e.EV_KEY, e.BTN_SELECT, 1)
ui.write(e.EV_KEY, e.BTN_EAST, 0)
ui.write(e.EV_KEY, e.BTN_NORTH, 1)
ui.syn()
case _: # NONE
ui.write(e.EV_KEY, e.BTN_SELECT, 0)
ui.write(e.EV_KEY, e.BTN_EAST, 0)
ui.write(e.EV_KEY, e.BTN_NORTH, 0)
ui.syn()
if event.type == e.EV_ABS and event.code == e.ABS_HAT0Y:
match event.value:
case -1: # UP
ui.write(e.EV_KEY, e.BTN_SELECT, 1)
ui.write(e.EV_KEY, e.BTN_WEST, 1)
ui.write(e.EV_KEY, e.BTN_SOUTH, 0)
ui.syn()
case 1: # DOWN
ui.write(e.EV_KEY, e.BTN_SELECT, 1)
ui.write(e.EV_KEY, e.BTN_WEST, 0)
ui.write(e.EV_KEY, e.BTN_SOUTH, 1)
ui.syn()
case _: # NONE
ui.write(e.EV_KEY, e.BTN_SELECT, 0)
ui.write(e.EV_KEY, e.BTN_WEST, 0)
ui.write(e.EV_KEY, e.BTN_SOUTH, 0)
ui.syn()
if event.type == e.EV_ABS and event.code == e.ABS_Y:
match event.value:
case 0x0: # EMG
ui.write(e.EV_ABS, e.ABS_X, 0xB9)
ui.write(e.EV_ABS, e.ABS_Y, 0x81)
ui.syn()
case 0x5:
ui.write(e.EV_ABS, e.ABS_X, 0xB5)
ui.write(e.EV_ABS, e.ABS_Y, 0x81)
ui.syn()
case 0x13:
ui.write(e.EV_ABS, e.ABS_X, 0xB2)
ui.write(e.EV_ABS, e.ABS_Y, 0x81)
ui.syn()
case 0x20:
ui.write(e.EV_ABS, e.ABS_X, 0xAF)
ui.write(e.EV_ABS, e.ABS_Y, 0x81)
ui.syn()
case 0x2E:
ui.write(e.EV_ABS, e.ABS_X, 0xA8)
ui.write(e.EV_ABS, e.ABS_Y, 0x81)
ui.syn()
case 0x3C:
ui.write(e.EV_ABS, e.ABS_X, 0xA2)
ui.write(e.EV_ABS, e.ABS_Y, 0x81)
ui.syn()
case 0x49:
ui.write(e.EV_ABS, e.ABS_X, 0x9A)
ui.write(e.EV_ABS, e.ABS_Y, 0x81)
ui.syn()
case 0x57:
ui.write(e.EV_ABS, e.ABS_X, 0x94)
ui.write(e.EV_ABS, e.ABS_Y, 0x81)
ui.syn()
case 0x65:
ui.write(e.EV_ABS, e.ABS_X, 0x8A)
ui.write(e.EV_ABS, e.ABS_Y, 0x81)
ui.syn()
case 0x80:
ui.write(e.EV_ABS, e.ABS_X, 0x79)
ui.write(e.EV_ABS, e.ABS_Y, 0x81)
ui.syn()
case 0x9F:
ui.write(e.EV_ABS, e.ABS_X, 0x79)
ui.write(e.EV_ABS, e.ABS_Y, 0x6D)
ui.syn()
case 0xB7:
ui.write(e.EV_ABS, e.ABS_X, 0x79)
ui.write(e.EV_ABS, e.ABS_Y, 0x54)
ui.syn()
case 0xCE:
ui.write(e.EV_ABS, e.ABS_X, 0x79)
ui.write(e.EV_ABS, e.ABS_Y, 0x3F)
ui.syn()
case 0xE6:
ui.write(e.EV_ABS, e.ABS_X, 0x79)
ui.write(e.EV_ABS, e.ABS_Y, 0x21)
ui.syn()
case 0xFF:
ui.write(e.EV_ABS, e.ABS_X, 0x79)
ui.write(e.EV_ABS, e.ABS_Y, 0x00)
ui.syn()

17
gui/main.py Executable file
View file

@ -0,0 +1,17 @@
import sys
from PyQt5 import uic
from PyQt5.QtWidgets import QMainWindow
from gui.main_ui import Ui_MainWindow
class MainWindow(QMainWindow):
def __init__(self, main_controller):
super().__init__()
self._main_controller = main_controller
self._gui = Ui_MainWindow()
self._gui.setupUi(self)
self._gui.pushButton_emulatedControllerStart.clicked.connect(self.startPressed)
def startPressed(self):
self._gui.statusbar.showMessage("Hello!")

100
gui/main_ui.py Normal file
View file

@ -0,0 +1,100 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'ui/main_ui.ui'
#
# Created by: PyQt5 UI code generator 5.15.7
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(MainWindow.sizePolicy().hasHeightForWidth())
MainWindow.setSizePolicy(sizePolicy)
MainWindow.setMinimumSize(QtCore.QSize(800, 600))
MainWindow.setMaximumSize(QtCore.QSize(800, 600))
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
self.gridLayout.setContentsMargins(9, 9, 9, 9)
self.gridLayout.setObjectName("gridLayout")
self.verticalLayout = QtWidgets.QVBoxLayout()
self.verticalLayout.setObjectName("verticalLayout")
self.groupBox_physicalControllers = QtWidgets.QGroupBox(self.centralwidget)
self.groupBox_physicalControllers.setObjectName("groupBox_physicalControllers")
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.groupBox_physicalControllers)
self.verticalLayout_2.setObjectName("verticalLayout_2")
self.tableWidget_physicalControllerList = QtWidgets.QTableWidget(self.groupBox_physicalControllers)
self.tableWidget_physicalControllerList.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
self.tableWidget_physicalControllerList.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
self.tableWidget_physicalControllerList.setObjectName("tableWidget_physicalControllerList")
self.tableWidget_physicalControllerList.setColumnCount(3)
self.tableWidget_physicalControllerList.setRowCount(0)
item = QtWidgets.QTableWidgetItem()
self.tableWidget_physicalControllerList.setHorizontalHeaderItem(0, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget_physicalControllerList.setHorizontalHeaderItem(1, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget_physicalControllerList.setHorizontalHeaderItem(2, item)
self.tableWidget_physicalControllerList.horizontalHeader().setStretchLastSection(True)
self.verticalLayout_2.addWidget(self.tableWidget_physicalControllerList)
self.verticalLayout.addWidget(self.groupBox_physicalControllers)
self.groupBox_emulatedController = QtWidgets.QGroupBox(self.centralwidget)
self.groupBox_emulatedController.setObjectName("groupBox_emulatedController")
self.horizontalLayout = QtWidgets.QHBoxLayout(self.groupBox_emulatedController)
self.horizontalLayout.setObjectName("horizontalLayout")
self.label_emulatedControllerModel = QtWidgets.QLabel(self.groupBox_emulatedController)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.label_emulatedControllerModel.sizePolicy().hasHeightForWidth())
self.label_emulatedControllerModel.setSizePolicy(sizePolicy)
self.label_emulatedControllerModel.setObjectName("label_emulatedControllerModel")
self.horizontalLayout.addWidget(self.label_emulatedControllerModel)
self.comboBox_emulatedControllerModel = QtWidgets.QComboBox(self.groupBox_emulatedController)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.comboBox_emulatedControllerModel.sizePolicy().hasHeightForWidth())
self.comboBox_emulatedControllerModel.setSizePolicy(sizePolicy)
self.comboBox_emulatedControllerModel.setObjectName("comboBox_emulatedControllerModel")
self.comboBox_emulatedControllerModel.addItem("")
self.horizontalLayout.addWidget(self.comboBox_emulatedControllerModel)
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.horizontalLayout.addItem(spacerItem)
self.pushButton_emulatedControllerStart = QtWidgets.QPushButton(self.groupBox_emulatedController)
self.pushButton_emulatedControllerStart.setObjectName("pushButton_emulatedControllerStart")
self.horizontalLayout.addWidget(self.pushButton_emulatedControllerStart)
self.verticalLayout.addWidget(self.groupBox_emulatedController)
self.gridLayout.addLayout(self.verticalLayout, 0, 0, 1, 1)
MainWindow.setCentralWidget(self.centralwidget)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "Densha de GO! Controller Converter"))
self.groupBox_physicalControllers.setTitle(_translate("MainWindow", "Physical controllers"))
item = self.tableWidget_physicalControllerList.horizontalHeaderItem(0)
item.setText(_translate("MainWindow", "Name"))
item = self.tableWidget_physicalControllerList.horizontalHeaderItem(1)
item.setText(_translate("MainWindow", "ID"))
item = self.tableWidget_physicalControllerList.horizontalHeaderItem(2)
item.setText(_translate("MainWindow", "Status"))
self.groupBox_emulatedController.setTitle(_translate("MainWindow", "Emulated controller"))
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"))

152
gui/main_ui.ui Normal file
View file

@ -0,0 +1,152 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>800</width>
<height>600</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>800</width>
<height>600</height>
</size>
</property>
<property name="windowTitle">
<string>Densha de GO! Controller Converter</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>9</number>
</property>
<property name="topMargin">
<number>9</number>
</property>
<property name="rightMargin">
<number>9</number>
</property>
<property name="bottomMargin">
<number>9</number>
</property>
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="groupBox_physicalControllers">
<property name="title">
<string>Physical controllers</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QTableWidget" name="tableWidget_physicalControllerList">
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
<column>
<property name="text">
<string>Name</string>
</property>
</column>
<column>
<property name="text">
<string>ID</string>
</property>
</column>
<column>
<property name="text">
<string>Status</string>
</property>
</column>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_emulatedController">
<property name="title">
<string>Emulated controller</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label_emulatedControllerModel">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Model</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBox_emulatedControllerModel">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<item>
<property name="text">
<string>Two-handle controller for PC (DGOC-44U)</string>
</property>
</item>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="pushButton_emulatedControllerStart">
<property name="text">
<string>Start</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>

151
handlers/gamepad.py Executable file
View file

@ -0,0 +1,151 @@
#!/usr/bin/env python
from evdev import InputDevice, list_devices, ecodes as e, UInput, AbsInfo
cap = {
e.EV_KEY : [e.BTN_NORTH, e.BTN_SOUTH, e.BTN_EAST, e.BTN_WEST, e.BTN_SELECT, e.BTN_START],
e.EV_ABS : [(e.ABS_X, AbsInfo(0, 0, 255, 0, 0, 0)), (e.ABS_Y, AbsInfo(0, 0, 255, 0, 0, 0))]
}
# Mapping
# A: BTN_EAST
# B: BTN_SOUTH
# C: BTN_NORTH
# D: BTN_WEST
# SL: BTN_SELECT
# ST: BTN_START
# BRAKE: ABS_X
# POWER: ABS_Y
mascon_switch = None
devices = [InputDevice(path) for path in list_devices()]
for device in devices:
dev_name = [device.info.vendor, device.info.product, device.name]
if dev_name == [0x0f0d, 0x00c1, "One Handle MasCon for Nintendo Switch"]:
mascon_switch = device
break
if mascon_switch is None:
print("No supported controller found.")
exit()
ui = UInput(cap, vendor=0x0AE4, product=0x0003, name='Emulated DGOC-44U')
mascon_switch.grab()
for event in mascon_switch.read_loop():
if event.type == e.EV_KEY:
match event.code:
case 304: # Y
ui.write(e.EV_KEY, e.BTN_EAST, event.value)
ui.syn()
case 305: # B
ui.write(e.EV_KEY, e.BTN_SOUTH, event.value)
ui.syn()
case 306: # A
ui.write(e.EV_KEY, e.BTN_NORTH, event.value)
ui.syn()
case 307: # X
ui.write(e.EV_KEY, e.BTN_WEST, event.value)
ui.syn()
case 312: # MINUS
ui.write(e.EV_KEY, e.BTN_SELECT, event.value)
ui.syn()
case 313: # PLUS
ui.write(e.EV_KEY, e.BTN_START, event.value)
ui.syn()
if event.type == e.EV_ABS and event.code == e.ABS_HAT0X:
match event.value:
case -1: # LEFT
ui.write(e.EV_KEY, e.BTN_SELECT, 1)
ui.write(e.EV_KEY, e.BTN_EAST, 1)
ui.write(e.EV_KEY, e.BTN_NORTH, 0)
ui.syn()
case 1: # RIGHT
ui.write(e.EV_KEY, e.BTN_SELECT, 1)
ui.write(e.EV_KEY, e.BTN_EAST, 0)
ui.write(e.EV_KEY, e.BTN_NORTH, 1)
ui.syn()
case _: # NONE
ui.write(e.EV_KEY, e.BTN_SELECT, 0)
ui.write(e.EV_KEY, e.BTN_EAST, 0)
ui.write(e.EV_KEY, e.BTN_NORTH, 0)
ui.syn()
if event.type == e.EV_ABS and event.code == e.ABS_HAT0Y:
match event.value:
case -1: # UP
ui.write(e.EV_KEY, e.BTN_SELECT, 1)
ui.write(e.EV_KEY, e.BTN_WEST, 1)
ui.write(e.EV_KEY, e.BTN_SOUTH, 0)
ui.syn()
case 1: # DOWN
ui.write(e.EV_KEY, e.BTN_SELECT, 1)
ui.write(e.EV_KEY, e.BTN_WEST, 0)
ui.write(e.EV_KEY, e.BTN_SOUTH, 1)
ui.syn()
case _: # NONE
ui.write(e.EV_KEY, e.BTN_SELECT, 0)
ui.write(e.EV_KEY, e.BTN_WEST, 0)
ui.write(e.EV_KEY, e.BTN_SOUTH, 0)
ui.syn()
if event.type == e.EV_ABS and event.code == e.ABS_Y:
match event.value:
case 0x0: # EMG
ui.write(e.EV_ABS, e.ABS_X, 0xB9)
ui.write(e.EV_ABS, e.ABS_Y, 0x81)
ui.syn()
case 0x5:
ui.write(e.EV_ABS, e.ABS_X, 0xB5)
ui.write(e.EV_ABS, e.ABS_Y, 0x81)
ui.syn()
case 0x13:
ui.write(e.EV_ABS, e.ABS_X, 0xB2)
ui.write(e.EV_ABS, e.ABS_Y, 0x81)
ui.syn()
case 0x20:
ui.write(e.EV_ABS, e.ABS_X, 0xAF)
ui.write(e.EV_ABS, e.ABS_Y, 0x81)
ui.syn()
case 0x2E:
ui.write(e.EV_ABS, e.ABS_X, 0xA8)
ui.write(e.EV_ABS, e.ABS_Y, 0x81)
ui.syn()
case 0x3C:
ui.write(e.EV_ABS, e.ABS_X, 0xA2)
ui.write(e.EV_ABS, e.ABS_Y, 0x81)
ui.syn()
case 0x49:
ui.write(e.EV_ABS, e.ABS_X, 0x9A)
ui.write(e.EV_ABS, e.ABS_Y, 0x81)
ui.syn()
case 0x57:
ui.write(e.EV_ABS, e.ABS_X, 0x94)
ui.write(e.EV_ABS, e.ABS_Y, 0x81)
ui.syn()
case 0x65:
ui.write(e.EV_ABS, e.ABS_X, 0x8A)
ui.write(e.EV_ABS, e.ABS_Y, 0x81)
ui.syn()
case 0x80:
ui.write(e.EV_ABS, e.ABS_X, 0x79)
ui.write(e.EV_ABS, e.ABS_Y, 0x81)
ui.syn()
case 0x9F:
ui.write(e.EV_ABS, e.ABS_X, 0x79)
ui.write(e.EV_ABS, e.ABS_Y, 0x6D)
ui.syn()
case 0xB7:
ui.write(e.EV_ABS, e.ABS_X, 0x79)
ui.write(e.EV_ABS, e.ABS_Y, 0x54)
ui.syn()
case 0xCE:
ui.write(e.EV_ABS, e.ABS_X, 0x79)
ui.write(e.EV_ABS, e.ABS_Y, 0x3F)
ui.syn()
case 0xE6:
ui.write(e.EV_ABS, e.ABS_X, 0x79)
ui.write(e.EV_ABS, e.ABS_Y, 0x21)
ui.syn()
case 0xFF:
ui.write(e.EV_ABS, e.ABS_X, 0x79)
ui.write(e.EV_ABS, e.ABS_Y, 0x00)
ui.syn()