mirror of
https://github.com/marcriera/ddgo-converter.git
synced 2025-04-19 18:39:29 +02:00
Add Qt5 GUI
This commit is contained in:
parent
cc8a271883
commit
0c9428fdd8
6 changed files with 433 additions and 147 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
__pycache__/
|
||||||
|
*.db
|
|
@ -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
17
gui/main.py
Executable 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
100
gui/main_ui.py
Normal 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
152
gui/main_ui.ui
Normal 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
151
handlers/gamepad.py
Executable 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()
|
Loading…
Add table
Reference in a new issue