Merge pull request #4530 from Morph1984/mjolnir-p1
Project Mjölnir: Part 1 - Input Rewrite
							
								
								
									
										25
									
								
								dist/icons/controller/controller.qrc
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,25 @@
 | 
			
		||||
<RCC>
 | 
			
		||||
  <qresource prefix="controller">
 | 
			
		||||
    <file alias="dual_joycon">dual_joycon.png</file>
 | 
			
		||||
    <file alias="dual_joycon_dark">dual_joycon_dark.png</file>
 | 
			
		||||
    <file alias="dual_joycon_midnight">dual_joycon_midnight.png</file>
 | 
			
		||||
    <file alias="handheld">handheld.png</file>
 | 
			
		||||
    <file alias="handheld_dark">handheld_dark.png</file>
 | 
			
		||||
    <file alias="handheld_midnight">handheld_midnight.png</file>
 | 
			
		||||
    <file alias="pro_controller">pro_controller.png</file>
 | 
			
		||||
    <file alias="pro_controller_dark">pro_controller_dark.png</file>
 | 
			
		||||
    <file alias="pro_controller_midnight">pro_controller_midnight.png</file>
 | 
			
		||||
    <file alias="single_joycon_left">single_joycon_left.png</file>
 | 
			
		||||
    <file alias="single_joycon_left_dark">single_joycon_left_dark.png</file>
 | 
			
		||||
    <file alias="single_joycon_left_midnight">single_joycon_left_midnight.png</file>
 | 
			
		||||
    <file alias="single_joycon_right">single_joycon_right.png</file>
 | 
			
		||||
    <file alias="single_joycon_right_dark">single_joycon_right_dark.png</file>
 | 
			
		||||
    <file alias="single_joycon_right_midnight">single_joycon_right_midnight.png</file>
 | 
			
		||||
    <file alias="single_joycon_left_vertical">single_joycon_left_vertical.png</file>
 | 
			
		||||
    <file alias="single_joycon_left_vertical_dark">single_joycon_left_vertical_dark.png</file>
 | 
			
		||||
    <file alias="single_joycon_left_vertical_midnight">single_joycon_left_vertical_midnight.png</file>
 | 
			
		||||
    <file alias="single_joycon_right_vertical">single_joycon_right_vertical.png</file>
 | 
			
		||||
    <file alias="single_joycon_right_vertical_dark">single_joycon_right_vertical_dark.png</file>
 | 
			
		||||
    <file alias="single_joycon_right_vertical_midnight">single_joycon_right_vertical_midnight.png</file>
 | 
			
		||||
  </qresource>
 | 
			
		||||
</RCC>
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/dual_joycon.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 36 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/dual_joycon_dark.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 35 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/dual_joycon_midnight.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 34 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/handheld.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 14 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/handheld_dark.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 13 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/handheld_midnight.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 13 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/pro_controller.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 36 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/pro_controller_dark.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 34 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/pro_controller_midnight.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 35 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/single_joycon_left.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 25 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/single_joycon_left_dark.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 25 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/single_joycon_left_midnight.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 24 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/single_joycon_left_vertical.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 24 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/single_joycon_left_vertical_dark.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 24 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/single_joycon_left_vertical_midnight.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 23 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/single_joycon_right.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 28 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/single_joycon_right_dark.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 28 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/single_joycon_right_midnight.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 26 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/single_joycon_right_vertical.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 27 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/single_joycon_right_vertical_dark.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 27 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/single_joycon_right_vertical_midnight.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 26 KiB  | 
							
								
								
									
										3
									
								
								dist/license.md
									
									
									
									
										vendored
									
									
								
							
							
						
						@ -5,6 +5,7 @@ Icon Name | License | Origin/Author
 | 
			
		||||
qt_themes/default/icons/16x16/checked.png | CC BY-ND 3.0 | https://icons8.com
 | 
			
		||||
qt_themes/default/icons/16x16/failed.png | CC BY-ND 3.0 | https://icons8.com
 | 
			
		||||
qt_themes/default/icons/16x16/lock.png | CC BY-ND 3.0 | https://icons8.com
 | 
			
		||||
qt_themes/default/icons/16x16/view-refresh.png | Apache 2.0 | https://material.io
 | 
			
		||||
qt_themes/default/icons/256x256/plus_folder.png | CC BY-ND 3.0 | https://icons8.com
 | 
			
		||||
qt_themes/default/icons/48x48/bad_folder.png | CC BY-ND 3.0 | https://icons8.com
 | 
			
		||||
qt_themes/default/icons/48x48/chip.png | CC BY-ND 3.0 | https://icons8.com
 | 
			
		||||
@ -12,6 +13,7 @@ qt_themes/default/icons/48x48/folder.png | CC BY-ND 3.0 | https://icons8.com
 | 
			
		||||
qt_themes/default/icons/48x48/plus.png | CC0 1.0 | Designed by BreadFish64 from the Citra team
 | 
			
		||||
qt_themes/default/icons/48x48/sd_card.png | CC BY-ND 3.0 | https://icons8.com
 | 
			
		||||
qt_themes/qdarkstyle/icons/16x16/lock.png | CC BY-ND 3.0 | https://icons8.com
 | 
			
		||||
qt_themes/qdarkstyle/icons/16x16/view-refresh.png | Apache 2.0 | https://material.io
 | 
			
		||||
qt_themes/qdarkstyle/icons/256x256/plus_folder.png | CC BY-ND 3.0 | https://icons8.com
 | 
			
		||||
qt_themes/qdarkstyle/icons/48x48/bad_folder.png | CC BY-ND 3.0 | https://icons8.com
 | 
			
		||||
qt_themes/qdarkstyle/icons/48x48/chip.png | CC BY-ND 3.0 | https://icons8.com
 | 
			
		||||
@ -19,6 +21,7 @@ qt_themes/qdarkstyle/icons/48x48/folder.png | CC BY-ND 3.0 | https://icons8.com
 | 
			
		||||
qt_themes/qdarkstyle/icons/48x48/plus.png | CC0 1.0 | Designed by BreadFish64 from the Citra team
 | 
			
		||||
qt_themes/qdarkstyle/icons/48x48/sd_card.png | CC BY-ND 3.0 | https://icons8.com
 | 
			
		||||
qt_themes/colorful/icons/16x16/lock.png | CC BY-ND 3.0 | https://icons8.com
 | 
			
		||||
qt_themes/colorful/icons/16x16/view-refresh.png | Apache 2.0 | https://material.io
 | 
			
		||||
qt_themes/colorful/icons/256x256/plus_folder.png | CC BY-ND 3.0 | https://icons8.com
 | 
			
		||||
qt_themes/colorful/icons/48x48/bad_folder.png | CC BY-ND 3.0 | https://icons8.com
 | 
			
		||||
qt_themes/colorful/icons/48x48/chip.png | CC BY-ND 3.0 | https://icons8.com
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								dist/qt_themes/colorful_dark/icons/16x16/refresh.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 362 B  | 
							
								
								
									
										
											BIN
										
									
								
								dist/qt_themes/colorful_dark/icons/16x16/view-refresh.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 362 B  | 
							
								
								
									
										1
									
								
								dist/qt_themes/colorful_dark/style.qrc
									
									
									
									
										vendored
									
									
								
							
							
						
						@ -2,6 +2,7 @@
 | 
			
		||||
    <qresource prefix="icons/colorful_dark">
 | 
			
		||||
        <file alias="index.theme">icons/index.theme</file>
 | 
			
		||||
        <file alias="16x16/lock.png">icons/16x16/lock.png</file>
 | 
			
		||||
        <file alias="16x16/view-refresh.png">icons/16x16/view-refresh.png</file>
 | 
			
		||||
        <file alias="48x48/bad_folder.png">../colorful/icons/48x48/bad_folder.png</file>
 | 
			
		||||
        <file alias="48x48/chip.png">../colorful/icons/48x48/chip.png</file>
 | 
			
		||||
        <file alias="48x48/folder.png">../colorful/icons/48x48/folder.png</file>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								dist/qt_themes/colorful_midnight_blue/icons/16x16/refresh.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 362 B  | 
							
								
								
									
										
											BIN
										
									
								
								dist/qt_themes/colorful_midnight_blue/icons/16x16/view-refresh.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 362 B  | 
@ -2,6 +2,7 @@
 | 
			
		||||
    <qresource prefix="icons/colorful_midnight_blue">
 | 
			
		||||
        <file alias="index.theme">icons/index.theme</file>
 | 
			
		||||
        <file alias="16x16/lock.png">icons/16x16/lock.png</file>
 | 
			
		||||
        <file alias="16x16/view-refresh.png">icons/16x16/view-refresh.png</file>
 | 
			
		||||
        <file alias="48x48/bad_folder.png">../colorful/icons/48x48/bad_folder.png</file>
 | 
			
		||||
        <file alias="48x48/chip.png">../colorful/icons/48x48/chip.png</file>
 | 
			
		||||
        <file alias="48x48/folder.png">../colorful/icons/48x48/folder.png</file>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								dist/qt_themes/default/default.qrc
									
									
									
									
										vendored
									
									
								
							
							
						
						@ -4,6 +4,7 @@
 | 
			
		||||
        <file alias="16x16/checked.png">icons/16x16/checked.png</file>
 | 
			
		||||
        <file alias="16x16/failed.png">icons/16x16/failed.png</file>
 | 
			
		||||
        <file alias="16x16/lock.png">icons/16x16/lock.png</file>
 | 
			
		||||
        <file alias="16x16/view-refresh.png">icons/16x16/view-refresh.png</file>
 | 
			
		||||
        <file alias="48x48/bad_folder.png">icons/48x48/bad_folder.png</file>
 | 
			
		||||
        <file alias="48x48/chip.png">icons/48x48/chip.png</file>
 | 
			
		||||
        <file alias="48x48/folder.png">icons/48x48/folder.png</file>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								dist/qt_themes/default/icons/16x16/refresh.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 349 B  | 
							
								
								
									
										
											BIN
										
									
								
								dist/qt_themes/default/icons/16x16/view-refresh.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 349 B  | 
							
								
								
									
										62
									
								
								dist/qt_themes/default/style.qss
									
									
									
									
										vendored
									
									
								
							
							
						
						@ -30,6 +30,66 @@ QPushButton#RendererStatusBarButton:checked {
 | 
			
		||||
    color: #e85c00;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QPushButton#RendererStatusBarButton:!checked{
 | 
			
		||||
QPushButton#RendererStatusBarButton:!checked {
 | 
			
		||||
    color: #0066ff;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QPushButton#buttonRefreshDevices {
 | 
			
		||||
    min-width: 20px;
 | 
			
		||||
    min-height: 20px;
 | 
			
		||||
    max-width: 20px;
 | 
			
		||||
    max-height: 20px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QCheckBox#checkboxPlayer1Connected,
 | 
			
		||||
QCheckBox#checkboxPlayer2Connected,
 | 
			
		||||
QCheckBox#checkboxPlayer3Connected,
 | 
			
		||||
QCheckBox#checkboxPlayer4Connected,
 | 
			
		||||
QCheckBox#checkboxPlayer5Connected,
 | 
			
		||||
QCheckBox#checkboxPlayer6Connected,
 | 
			
		||||
QCheckBox#checkboxPlayer7Connected,
 | 
			
		||||
QCheckBox#checkboxPlayer8Connected {
 | 
			
		||||
    spacing: 0px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QCheckBox#checkboxPlayer1Connected::indicator,
 | 
			
		||||
QCheckBox#checkboxPlayer2Connected::indicator,
 | 
			
		||||
QCheckBox#checkboxPlayer3Connected::indicator,
 | 
			
		||||
QCheckBox#checkboxPlayer4Connected::indicator,
 | 
			
		||||
QCheckBox#checkboxPlayer5Connected::indicator,
 | 
			
		||||
QCheckBox#checkboxPlayer6Connected::indicator,
 | 
			
		||||
QCheckBox#checkboxPlayer7Connected::indicator,
 | 
			
		||||
QCheckBox#checkboxPlayer8Connected::indicator {
 | 
			
		||||
    width: 14px;
 | 
			
		||||
    height: 14px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QCheckBox#checkboxPlayer1Connected::indicator:checked,
 | 
			
		||||
QCheckBox#checkboxPlayer2Connected::indicator:checked,
 | 
			
		||||
QCheckBox#checkboxPlayer3Connected::indicator:checked,
 | 
			
		||||
QCheckBox#checkboxPlayer4Connected::indicator:checked,
 | 
			
		||||
QCheckBox#checkboxPlayer5Connected::indicator:checked,
 | 
			
		||||
QCheckBox#checkboxPlayer6Connected::indicator:checked,
 | 
			
		||||
QCheckBox#checkboxPlayer7Connected::indicator:checked,
 | 
			
		||||
QCheckBox#checkboxPlayer8Connected::indicator:checked,
 | 
			
		||||
QGroupBox#groupConnectedController::indicator:checked {
 | 
			
		||||
    border-radius: 2px;
 | 
			
		||||
    border: 1px solid black;
 | 
			
		||||
    background: #39ff14;
 | 
			
		||||
    image: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QCheckBox#checkboxPlayer1Connected::indicator:unchecked,
 | 
			
		||||
QCheckBox#checkboxPlayer2Connected::indicator:unchecked,
 | 
			
		||||
QCheckBox#checkboxPlayer3Connected::indicator:unchecked,
 | 
			
		||||
QCheckBox#checkboxPlayer4Connected::indicator:unchecked,
 | 
			
		||||
QCheckBox#checkboxPlayer5Connected::indicator:unchecked,
 | 
			
		||||
QCheckBox#checkboxPlayer6Connected::indicator:unchecked,
 | 
			
		||||
QCheckBox#checkboxPlayer7Connected::indicator:unchecked,
 | 
			
		||||
QCheckBox#checkboxPlayer8Connected::indicator:unchecked,
 | 
			
		||||
QGroupBox#groupConnectedController::indicator:unchecked {
 | 
			
		||||
    border-radius: 2px;
 | 
			
		||||
    border: 1px solid black;
 | 
			
		||||
    background: transparent;
 | 
			
		||||
    image: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								dist/qt_themes/qdarkstyle/icons/16x16/refresh.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 362 B  | 
							
								
								
									
										
											BIN
										
									
								
								dist/qt_themes/qdarkstyle/icons/16x16/view-refresh.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 362 B  | 
							
								
								
									
										1
									
								
								dist/qt_themes/qdarkstyle/style.qrc
									
									
									
									
										vendored
									
									
								
							
							
						
						@ -2,6 +2,7 @@
 | 
			
		||||
  <qresource prefix="icons/qdarkstyle">
 | 
			
		||||
    <file alias="index.theme">icons/index.theme</file>
 | 
			
		||||
    <file alias="16x16/lock.png">icons/16x16/lock.png</file>
 | 
			
		||||
    <file alias="16x16/view-refresh.png">icons/16x16/view-refresh.png</file>
 | 
			
		||||
    <file alias="48x48/bad_folder.png">icons/48x48/bad_folder.png</file>
 | 
			
		||||
    <file alias="48x48/chip.png">icons/48x48/chip.png</file>
 | 
			
		||||
    <file alias="48x48/folder.png">icons/48x48/folder.png</file>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										105
									
								
								dist/qt_themes/qdarkstyle/style.qss
									
									
									
									
										vendored
									
									
								
							
							
						
						@ -40,8 +40,8 @@ QCheckBox:disabled {
 | 
			
		||||
 | 
			
		||||
QCheckBox::indicator,
 | 
			
		||||
QGroupBox::indicator {
 | 
			
		||||
    width: 18px;
 | 
			
		||||
    height: 18px;
 | 
			
		||||
    width: 16px;
 | 
			
		||||
    height: 16px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QGroupBox::indicator {
 | 
			
		||||
@ -1237,6 +1237,7 @@ QPlainTextEdit:disabled {
 | 
			
		||||
    background-color: #2b2e31;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
QPushButton#TogglableStatusBarButton {
 | 
			
		||||
    min-width: 0px;
 | 
			
		||||
    color: #656565;
 | 
			
		||||
@ -1271,6 +1272,102 @@ QPushButton#RendererStatusBarButton:checked {
 | 
			
		||||
    color: #e85c00;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QPushButton#RendererStatusBarButton:!checked{
 | 
			
		||||
   color: #00ccdd;
 | 
			
		||||
QPushButton#RendererStatusBarButton:!checked {
 | 
			
		||||
    color: #00ccdd;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QPushButton#buttonRefreshDevices {
 | 
			
		||||
    min-width: 24px;
 | 
			
		||||
    min-height: 24px;
 | 
			
		||||
    max-width: 24px;
 | 
			
		||||
    max-height: 24px;
 | 
			
		||||
    padding: 0px 0px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QCheckBox#checkboxPlayer1Connected,
 | 
			
		||||
QCheckBox#checkboxPlayer2Connected,
 | 
			
		||||
QCheckBox#checkboxPlayer3Connected,
 | 
			
		||||
QCheckBox#checkboxPlayer4Connected,
 | 
			
		||||
QCheckBox#checkboxPlayer5Connected,
 | 
			
		||||
QCheckBox#checkboxPlayer6Connected,
 | 
			
		||||
QCheckBox#checkboxPlayer7Connected,
 | 
			
		||||
QCheckBox#checkboxPlayer8Connected {
 | 
			
		||||
    spacing: 0px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QCheckBox#checkboxPlayer1Connected::indicator,
 | 
			
		||||
QCheckBox#checkboxPlayer2Connected::indicator,
 | 
			
		||||
QCheckBox#checkboxPlayer3Connected::indicator,
 | 
			
		||||
QCheckBox#checkboxPlayer4Connected::indicator,
 | 
			
		||||
QCheckBox#checkboxPlayer5Connected::indicator,
 | 
			
		||||
QCheckBox#checkboxPlayer6Connected::indicator,
 | 
			
		||||
QCheckBox#checkboxPlayer7Connected::indicator,
 | 
			
		||||
QCheckBox#checkboxPlayer8Connected::indicator {
 | 
			
		||||
    width: 14px;
 | 
			
		||||
    height: 14px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QCheckBox#checkboxPlayer1Connected::indicator:checked,
 | 
			
		||||
QCheckBox#checkboxPlayer2Connected::indicator:checked,
 | 
			
		||||
QCheckBox#checkboxPlayer3Connected::indicator:checked,
 | 
			
		||||
QCheckBox#checkboxPlayer4Connected::indicator:checked,
 | 
			
		||||
QCheckBox#checkboxPlayer5Connected::indicator:checked,
 | 
			
		||||
QCheckBox#checkboxPlayer6Connected::indicator:checked,
 | 
			
		||||
QCheckBox#checkboxPlayer7Connected::indicator:checked,
 | 
			
		||||
QCheckBox#checkboxPlayer8Connected::indicator:checked,
 | 
			
		||||
QGroupBox#groupConnectedController::indicator:checked {
 | 
			
		||||
    border-radius: 2px;
 | 
			
		||||
    border: 1px solid #929192;
 | 
			
		||||
    background: #39ff14;
 | 
			
		||||
    image: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QCheckBox#checkboxPlayer1Connected::indicator:unchecked,
 | 
			
		||||
QCheckBox#checkboxPlayer2Connected::indicator:unchecked,
 | 
			
		||||
QCheckBox#checkboxPlayer3Connected::indicator:unchecked,
 | 
			
		||||
QCheckBox#checkboxPlayer4Connected::indicator:unchecked,
 | 
			
		||||
QCheckBox#checkboxPlayer5Connected::indicator:unchecked,
 | 
			
		||||
QCheckBox#checkboxPlayer6Connected::indicator:unchecked,
 | 
			
		||||
QCheckBox#checkboxPlayer7Connected::indicator:unchecked,
 | 
			
		||||
QCheckBox#checkboxPlayer8Connected::indicator:unchecked,
 | 
			
		||||
QGroupBox#groupConnectedController::indicator:unchecked {
 | 
			
		||||
    border-radius: 2px;
 | 
			
		||||
    border: 1px solid #929192;
 | 
			
		||||
    background: transparent;
 | 
			
		||||
    image: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QSpinBox#spinboxLStickRange,
 | 
			
		||||
QSpinBox#spinboxRStickRange {
 | 
			
		||||
    padding: 4px 0px 5px 0px;
 | 
			
		||||
    min-width: 63px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QSpinBox#vibrationSpin {
 | 
			
		||||
    padding: 4px 0px 5px 0px;
 | 
			
		||||
    min-width: 63px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QSpinBox#spinboxLStickRange:up-button,
 | 
			
		||||
QSpinBox#spinboxRStickRange:up-button,
 | 
			
		||||
QSpinBox#vibrationSpin:up-button {
 | 
			
		||||
    left: -2px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QSpinBox#spinboxLStickRange:down-button,
 | 
			
		||||
QSpinBox#spinboxRStickRange:down-button,
 | 
			
		||||
QSpinBox#vibrationSpin:down-button {
 | 
			
		||||
    right: -1px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QGroupBox#motionGroup::indicator,
 | 
			
		||||
QGroupBox#vibrationGroup::indicator {
 | 
			
		||||
    margin-left: 0px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QGroupBox#motionGroup::title,
 | 
			
		||||
QGroupBox#vibrationGroup::title {
 | 
			
		||||
	spacing: 2px;
 | 
			
		||||
	padding-left: 1px;
 | 
			
		||||
	padding-right: 1px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								dist/qt_themes/qdarkstyle_midnight_blue/icons/16x16/refresh.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 362 B  | 
							
								
								
									
										
											BIN
										
									
								
								dist/qt_themes/qdarkstyle_midnight_blue/icons/16x16/view-refresh.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 362 B  | 
@ -2,6 +2,7 @@
 | 
			
		||||
  <qresource prefix="icons/qdarkstyle_midnight_blue">
 | 
			
		||||
    <file alias="index.theme">icons/index.theme</file>
 | 
			
		||||
    <file alias="16x16/lock.png">icons/16x16/lock.png</file>
 | 
			
		||||
    <file alias="16x16/view-refresh.png">icons/16x16/view-refresh.png</file>
 | 
			
		||||
    <file alias="48x48/bad_folder.png">icons/48x48/bad_folder.png</file>
 | 
			
		||||
    <file alias="48x48/chip.png">icons/48x48/chip.png</file>
 | 
			
		||||
    <file alias="48x48/folder.png">icons/48x48/folder.png</file>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										248
									
								
								dist/qt_themes/qdarkstyle_midnight_blue/style.qss
									
									
									
									
										vendored
									
									
								
							
							
						
						@ -138,8 +138,6 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qstatusbar
 | 
			
		||||
 | 
			
		||||
--------------------------------------------------------------------------- */
 | 
			
		||||
QStatusBar {
 | 
			
		||||
  border: 1px solid #32414B;
 | 
			
		||||
  /* Fixes Spyder #9120, #9121 */
 | 
			
		||||
  background: #32414B;
 | 
			
		||||
  /* Fixes #205, white vertical borders separating items */
 | 
			
		||||
}
 | 
			
		||||
@ -161,6 +159,7 @@ QStatusBar QToolTip {
 | 
			
		||||
QStatusBar QLabel {
 | 
			
		||||
  /* Fixes Spyder #9120, #9121 */
 | 
			
		||||
  background: transparent;
 | 
			
		||||
  padding: 0px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* QCheckBox --------------------------------------------------------------
 | 
			
		||||
@ -236,21 +235,19 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qgroupbox
 | 
			
		||||
 | 
			
		||||
--------------------------------------------------------------------------- */
 | 
			
		||||
QGroupBox {
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
  border: 1px solid #32414B;
 | 
			
		||||
  border-radius: 4px;
 | 
			
		||||
  padding: 4px;
 | 
			
		||||
  margin-top: 16px;
 | 
			
		||||
    font-weight: bold;
 | 
			
		||||
    border: 1px solid #32414B;
 | 
			
		||||
    border-radius: 4px;
 | 
			
		||||
    margin-top: 12px;
 | 
			
		||||
    padding: 4px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QGroupBox::title {
 | 
			
		||||
  subcontrol-origin: margin;
 | 
			
		||||
  subcontrol-position: top left;
 | 
			
		||||
  left: 3px;
 | 
			
		||||
  padding-left: 3px;
 | 
			
		||||
  padding-right: 5px;
 | 
			
		||||
  padding-top: 8px;
 | 
			
		||||
  padding-bottom: 16px;
 | 
			
		||||
    subcontrol-origin: margin;
 | 
			
		||||
    subcontrol-position: top left;
 | 
			
		||||
    padding-left: 3px;
 | 
			
		||||
    padding-right: 5px;
 | 
			
		||||
    padding-top: 4px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QGroupBox::indicator {
 | 
			
		||||
@ -367,28 +364,19 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmenubar
 | 
			
		||||
--------------------------------------------------------------------------- */
 | 
			
		||||
QMenuBar {
 | 
			
		||||
  background-color: #32414B;
 | 
			
		||||
  padding: 2px;
 | 
			
		||||
  border: 1px solid #19232D;
 | 
			
		||||
  color: #F0F0F0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QMenuBar:focus {
 | 
			
		||||
  border: 1px solid #148CD2;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QMenuBar::item {
 | 
			
		||||
  background: transparent;
 | 
			
		||||
  padding: 4px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QMenuBar::item:selected {
 | 
			
		||||
  padding: 4px;
 | 
			
		||||
  background: transparent;
 | 
			
		||||
  border: 0px solid #32414B;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QMenuBar::item:pressed {
 | 
			
		||||
  padding: 4px;
 | 
			
		||||
  border: 0px solid #32414B;
 | 
			
		||||
  background-color: #148CD2;
 | 
			
		||||
  color: #F0F0F0;
 | 
			
		||||
@ -396,6 +384,7 @@ QMenuBar::item:pressed {
 | 
			
		||||
  padding-bottom: 0px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* QMenu ------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmenu
 | 
			
		||||
@ -482,7 +471,7 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcombobox
 | 
			
		||||
 | 
			
		||||
--------------------------------------------------------------------------- */
 | 
			
		||||
QAbstractItemView {
 | 
			
		||||
  alternate-background-color: #19232D;
 | 
			
		||||
  alternate-background-color: #1f2933;
 | 
			
		||||
  color: #F0F0F0;
 | 
			
		||||
  border: 1px solid #32414B;
 | 
			
		||||
  border-radius: 4px;
 | 
			
		||||
@ -501,13 +490,13 @@ QAbstractScrollArea {
 | 
			
		||||
  background-color: #19232D;
 | 
			
		||||
  border: 1px solid #32414B;
 | 
			
		||||
  border-radius: 4px;
 | 
			
		||||
  padding: 2px;
 | 
			
		||||
  /* fix #159 */
 | 
			
		||||
  min-height: 1.25em;
 | 
			
		||||
  /* fix #159 */
 | 
			
		||||
  color: #F0F0F0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
QAbstractScrollArea:disabled {
 | 
			
		||||
  color: #787878;
 | 
			
		||||
}
 | 
			
		||||
@ -807,20 +796,22 @@ QAbstractSpinBox {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QAbstractSpinBox:up-button {
 | 
			
		||||
  background-color: transparent #19232D;
 | 
			
		||||
  background-color: #505F69;
 | 
			
		||||
  subcontrol-origin: border;
 | 
			
		||||
  subcontrol-position: top right;
 | 
			
		||||
  border-left: 1px solid #32414B;
 | 
			
		||||
  border-bottom: 1px solid #32414B;
 | 
			
		||||
  border-top: 1px solid #32414B;
 | 
			
		||||
  border-right: 1px solid #32414B;
 | 
			
		||||
  border-top-right-radius: 4px;
 | 
			
		||||
  border-top-left-radius: 0;
 | 
			
		||||
  border-bottom-left-radius: 0;
 | 
			
		||||
  margin: 1px;
 | 
			
		||||
  margin: 0px;
 | 
			
		||||
  width: 12px;
 | 
			
		||||
  margin-bottom: -1px;
 | 
			
		||||
  margin-bottom: 0px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QAbstractSpinBox::up-arrow, QAbstractSpinBox::up-arrow:disabled, QAbstractSpinBox::up-arrow:off {
 | 
			
		||||
  image: url(":/qss_icons/rc/arrow_up_disabled.png");
 | 
			
		||||
  image: url(":/qss_icons/rc/up_arrow.png");
 | 
			
		||||
  height: 8px;
 | 
			
		||||
  width: 8px;
 | 
			
		||||
}
 | 
			
		||||
@ -830,20 +821,23 @@ QAbstractSpinBox::up-arrow:hover {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QAbstractSpinBox:down-button {
 | 
			
		||||
  background-color: transparent #19232D;
 | 
			
		||||
  background-color: #505F69;
 | 
			
		||||
  subcontrol-origin: border;
 | 
			
		||||
  subcontrol-position: bottom right;
 | 
			
		||||
  border-left: 1px solid #32414B;
 | 
			
		||||
  border-right: 1px solid #32414B;
 | 
			
		||||
  border-bottom: 1px solid #32414B;
 | 
			
		||||
  border-top: 1px solid #32414B;
 | 
			
		||||
  border-top-left-radius: 0;
 | 
			
		||||
  border-bottom-left-radius: 0;
 | 
			
		||||
  margin: 1px;
 | 
			
		||||
  border-bottom-right-radius: 4px;
 | 
			
		||||
  margin: 0px;
 | 
			
		||||
  width: 12px;
 | 
			
		||||
  margin-top: -1px;
 | 
			
		||||
  margin-top: 0px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QAbstractSpinBox::down-arrow, QAbstractSpinBox::down-arrow:disabled, QAbstractSpinBox::down-arrow:off {
 | 
			
		||||
  image: url(":/qss_icons/rc/arrow_down_disabled.png");
 | 
			
		||||
  image: url(":/qss_icons/rc/down_arrow.png");
 | 
			
		||||
  height: 8px;
 | 
			
		||||
  width: 8px;
 | 
			
		||||
}
 | 
			
		||||
@ -1199,6 +1193,7 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcombobox
 | 
			
		||||
 | 
			
		||||
--------------------------------------------------------------------------- */
 | 
			
		||||
QComboBox {
 | 
			
		||||
  background-color: #0f1922;
 | 
			
		||||
  border: 1px solid #32414B;
 | 
			
		||||
  border-radius: 4px;
 | 
			
		||||
  selection-background-color: #1464A0;
 | 
			
		||||
@ -1216,7 +1211,7 @@ QComboBox {
 | 
			
		||||
QComboBox QAbstractItemView {
 | 
			
		||||
  border: 1px solid #32414B;
 | 
			
		||||
  border-radius: 0;
 | 
			
		||||
  background-color: #19232D;
 | 
			
		||||
  background-color: #0f1922;
 | 
			
		||||
  selection-background-color: #1464A0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1285,7 +1280,12 @@ QComboBox::drop-down {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QComboBox::down-arrow {
 | 
			
		||||
  image: url(":/qss_icons/rc/arrow_down_disabled.png");
 | 
			
		||||
  image: url(":/qss_icons/rc/down_arrow.png");
 | 
			
		||||
  background-color: #505F69;
 | 
			
		||||
  padding: 6px 2px;
 | 
			
		||||
  border: 1px solid #32414B;
 | 
			
		||||
  border-top-right-radius: 4px;
 | 
			
		||||
  border-bottom-right-radius: 4px;
 | 
			
		||||
  height: 8px;
 | 
			
		||||
  width: 8px;
 | 
			
		||||
}
 | 
			
		||||
@ -1559,12 +1559,12 @@ QTabBar::tab:right:!selected {
 | 
			
		||||
QTabBar::tab:top {
 | 
			
		||||
  background-color: #32414B;
 | 
			
		||||
  color: #F0F0F0;
 | 
			
		||||
  min-width: 36px;
 | 
			
		||||
  margin-left: 2px;
 | 
			
		||||
  padding-left: 4px;
 | 
			
		||||
  padding-right: 4px;
 | 
			
		||||
  padding-left: 8px;
 | 
			
		||||
  padding-right: 8px;
 | 
			
		||||
  padding-top: 2px;
 | 
			
		||||
  padding-bottom: 2px;
 | 
			
		||||
  min-width: 5px;
 | 
			
		||||
  border-bottom: 3px solid #32414B;
 | 
			
		||||
  border-top-left-radius: 3px;
 | 
			
		||||
  border-top-right-radius: 3px;
 | 
			
		||||
@ -1588,16 +1588,16 @@ QTabBar::tab:top:!selected:hover {
 | 
			
		||||
 | 
			
		||||
QTabBar::tab:bottom {
 | 
			
		||||
  color: #F0F0F0;
 | 
			
		||||
  min-width: 36px;
 | 
			
		||||
  border-top: 3px solid #32414B;
 | 
			
		||||
  background-color: #32414B;
 | 
			
		||||
  margin-left: 2px;
 | 
			
		||||
  padding-left: 4px;
 | 
			
		||||
  padding-right: 4px;
 | 
			
		||||
  padding-left: 8px;
 | 
			
		||||
  padding-right: 8px;
 | 
			
		||||
  padding-top: 2px;
 | 
			
		||||
  padding-bottom: 2px;
 | 
			
		||||
  border-bottom-left-radius: 3px;
 | 
			
		||||
  border-bottom-right-radius: 3px;
 | 
			
		||||
  min-width: 5px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QTabBar::tab:bottom:selected {
 | 
			
		||||
@ -1752,21 +1752,6 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qlistview
 | 
			
		||||
https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtableview
 | 
			
		||||
 | 
			
		||||
--------------------------------------------------------------------------- */
 | 
			
		||||
QTreeView:branch:selected, QTreeView:branch:hover {
 | 
			
		||||
  background: url(":/qss_icons/rc/transparent.png");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QTreeView:branch:has-siblings:!adjoins-item {
 | 
			
		||||
  border-image: url(":/qss_icons/rc/branch_line.png") 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QTreeView:branch:has-siblings:adjoins-item {
 | 
			
		||||
  border-image: url(":/qss_icons/rc/branch_more.png") 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QTreeView:branch:!has-children:!has-siblings:adjoins-item {
 | 
			
		||||
  border-image: url(":/qss_icons/rc/branch_end.png") 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QTreeView:branch:has-children:!has-siblings:closed, QTreeView:branch:closed:has-children:has-siblings {
 | 
			
		||||
  border-image: none;
 | 
			
		||||
@ -1900,21 +1885,21 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qheaderview
 | 
			
		||||
 | 
			
		||||
--------------------------------------------------------------------------- */
 | 
			
		||||
QHeaderView {
 | 
			
		||||
  background-color: #32414B;
 | 
			
		||||
  border: 0px transparent #32414B;
 | 
			
		||||
  background-color: #19232D;
 | 
			
		||||
  border: 0px transparent #19232D;
 | 
			
		||||
  padding: 0px;
 | 
			
		||||
  margin: 0px;
 | 
			
		||||
  border-radius: 0px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QHeaderView:disabled {
 | 
			
		||||
  background-color: #32414B;
 | 
			
		||||
  border: 1px transparent #32414B;
 | 
			
		||||
  background-color: #19232D;
 | 
			
		||||
  border: 1px transparent #19232D;
 | 
			
		||||
  padding: 2px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QHeaderView::section {
 | 
			
		||||
  background-color: #32414B;
 | 
			
		||||
  background-color: #19232D;
 | 
			
		||||
  color: #F0F0F0;
 | 
			
		||||
  padding: 2px;
 | 
			
		||||
  border-radius: 0px;
 | 
			
		||||
@ -1934,11 +1919,11 @@ QHeaderView::section:checked:disabled {
 | 
			
		||||
QHeaderView::section::horizontal {
 | 
			
		||||
  padding-left: 4px;
 | 
			
		||||
  padding-right: 4px;
 | 
			
		||||
  border-left: 1px solid #19232D;
 | 
			
		||||
  border-left: 1px solid #32414B;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QHeaderView::section::horizontal::first, QHeaderView::section::horizontal::only-one {
 | 
			
		||||
  border-left: 1px solid #32414B;
 | 
			
		||||
  border-left: 1px solid #19232D;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QHeaderView::section::horizontal:disabled {
 | 
			
		||||
@ -1948,7 +1933,7 @@ QHeaderView::section::horizontal:disabled {
 | 
			
		||||
QHeaderView::section::vertical {
 | 
			
		||||
  padding-left: 4px;
 | 
			
		||||
  padding-right: 4px;
 | 
			
		||||
  border-top: 1px solid #19232D;
 | 
			
		||||
  border-top: 1px solid #32414B;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QHeaderView::section::vertical::first, QHeaderView::section::vertical::only-one {
 | 
			
		||||
@ -1962,7 +1947,7 @@ QHeaderView::section::vertical:disabled {
 | 
			
		||||
QHeaderView::down-arrow {
 | 
			
		||||
  /* Those settings (border/width/height/background-color) solve bug */
 | 
			
		||||
  /* transparent arrow background and size */
 | 
			
		||||
  background-color: #32414B;
 | 
			
		||||
  background-color: #19232D;
 | 
			
		||||
  border: none;
 | 
			
		||||
  height: 12px;
 | 
			
		||||
  width: 12px;
 | 
			
		||||
@ -1972,7 +1957,7 @@ QHeaderView::down-arrow {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QHeaderView::up-arrow {
 | 
			
		||||
  background-color: #32414B;
 | 
			
		||||
  background-color: #19232D;
 | 
			
		||||
  border: none;
 | 
			
		||||
  height: 12px;
 | 
			
		||||
  width: 12px;
 | 
			
		||||
@ -2172,3 +2157,132 @@ PlotWidget {
 | 
			
		||||
  /* Fix cut labels in plots #134 */
 | 
			
		||||
  padding: 0px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
QPushButton#TogglableStatusBarButton {
 | 
			
		||||
  min-width: 0px;
 | 
			
		||||
  color: #656565;
 | 
			
		||||
  border: 1px solid transparent;
 | 
			
		||||
  background-color: transparent;
 | 
			
		||||
  padding: 0px 3px 0px 3px;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QPushButton#TogglableStatusBarButton:checked {
 | 
			
		||||
  color: #ffffff;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QPushButton#TogglableStatusBarButton:hover {
 | 
			
		||||
  border: 1px solid #76797C;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QPushButton#RendererStatusBarButton {
 | 
			
		||||
  min-width: 0px;
 | 
			
		||||
  color: #656565;
 | 
			
		||||
  border: 1px solid transparent;
 | 
			
		||||
  background-color: transparent;
 | 
			
		||||
  padding: 0px 3px 0px 3px;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QPushButton#RendererStatusBarButton:hover {
 | 
			
		||||
  border: 1px solid #76797C;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QPushButton#RendererStatusBarButton:checked {
 | 
			
		||||
  color: #e85c00;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QPushButton#RendererStatusBarButton:!checked {
 | 
			
		||||
  color: #00ccdd;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QPushButton#buttonRefreshDevices {
 | 
			
		||||
  min-width: 20px;
 | 
			
		||||
  min-height: 20px;
 | 
			
		||||
  max-width: 20px;
 | 
			
		||||
  max-height: 20px;
 | 
			
		||||
  padding: 0px 0px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
QCheckBox#checkboxPlayer1Connected,
 | 
			
		||||
QCheckBox#checkboxPlayer2Connected,
 | 
			
		||||
QCheckBox#checkboxPlayer3Connected,
 | 
			
		||||
QCheckBox#checkboxPlayer4Connected,
 | 
			
		||||
QCheckBox#checkboxPlayer5Connected,
 | 
			
		||||
QCheckBox#checkboxPlayer6Connected,
 | 
			
		||||
QCheckBox#checkboxPlayer7Connected,
 | 
			
		||||
QCheckBox#checkboxPlayer8Connected {
 | 
			
		||||
  spacing: 0px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QCheckBox#checkboxPlayer1Connected::indicator,
 | 
			
		||||
QCheckBox#checkboxPlayer2Connected::indicator,
 | 
			
		||||
QCheckBox#checkboxPlayer3Connected::indicator,
 | 
			
		||||
QCheckBox#checkboxPlayer4Connected::indicator,
 | 
			
		||||
QCheckBox#checkboxPlayer5Connected::indicator,
 | 
			
		||||
QCheckBox#checkboxPlayer6Connected::indicator,
 | 
			
		||||
QCheckBox#checkboxPlayer7Connected::indicator,
 | 
			
		||||
QCheckBox#checkboxPlayer8Connected::indicator {
 | 
			
		||||
  width: 14px;
 | 
			
		||||
  height: 14px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QCheckBox#checkboxPlayer1Connected::indicator:checked,
 | 
			
		||||
QCheckBox#checkboxPlayer2Connected::indicator:checked,
 | 
			
		||||
QCheckBox#checkboxPlayer3Connected::indicator:checked,
 | 
			
		||||
QCheckBox#checkboxPlayer4Connected::indicator:checked,
 | 
			
		||||
QCheckBox#checkboxPlayer5Connected::indicator:checked,
 | 
			
		||||
QCheckBox#checkboxPlayer6Connected::indicator:checked,
 | 
			
		||||
QCheckBox#checkboxPlayer7Connected::indicator:checked,
 | 
			
		||||
QCheckBox#checkboxPlayer8Connected::indicator:checked,
 | 
			
		||||
QGroupBox#groupConnectedController::indicator:checked {
 | 
			
		||||
  border-radius: 2px;
 | 
			
		||||
  border: 1px solid #929192;
 | 
			
		||||
  background: #39ff14;
 | 
			
		||||
  image: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QCheckBox#checkboxPlayer1Connected::indicator:unchecked,
 | 
			
		||||
QCheckBox#checkboxPlayer2Connected::indicator:unchecked,
 | 
			
		||||
QCheckBox#checkboxPlayer3Connected::indicator:unchecked,
 | 
			
		||||
QCheckBox#checkboxPlayer4Connected::indicator:unchecked,
 | 
			
		||||
QCheckBox#checkboxPlayer5Connected::indicator:unchecked,
 | 
			
		||||
QCheckBox#checkboxPlayer6Connected::indicator:unchecked,
 | 
			
		||||
QCheckBox#checkboxPlayer7Connected::indicator:unchecked,
 | 
			
		||||
QCheckBox#checkboxPlayer8Connected::indicator:unchecked,
 | 
			
		||||
QGroupBox#groupConnectedController::indicator:unchecked {
 | 
			
		||||
  border-radius: 2px;
 | 
			
		||||
  border: 1px solid #929192;
 | 
			
		||||
  background: transparent;
 | 
			
		||||
  image: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QSpinBox#spinboxLStickRange,
 | 
			
		||||
QSpinBox#spinboxRStickRange {
 | 
			
		||||
  min-width: 38px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QGroupBox#motionGroup::indicator,
 | 
			
		||||
QGroupBox#vibrationGroup::indicator {
 | 
			
		||||
  margin-left: 0px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QGroupBox#motionGroup::title,
 | 
			
		||||
QGroupBox#vibrationGroup::title {
 | 
			
		||||
spacing: 2px;
 | 
			
		||||
  padding-left: 1px;
 | 
			
		||||
  padding-right: 1px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QListWidget#selectorList {
 | 
			
		||||
  background-color: #0f1922;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QSpinBox,
 | 
			
		||||
QLineEdit,
 | 
			
		||||
QTreeView#hotkey_list,
 | 
			
		||||
QScrollArea#scrollArea QTreeView {
 | 
			
		||||
  background-color: #0f1922;
 | 
			
		||||
}
 | 
			
		||||
@ -19,7 +19,7 @@ public:
 | 
			
		||||
    explicit ParamPackage(const std::string& serialized);
 | 
			
		||||
    ParamPackage(std::initializer_list<DataType::value_type> list);
 | 
			
		||||
    ParamPackage(const ParamPackage& other) = default;
 | 
			
		||||
    ParamPackage(ParamPackage&& other) = default;
 | 
			
		||||
    ParamPackage(ParamPackage&& other) noexcept = default;
 | 
			
		||||
 | 
			
		||||
    ParamPackage& operator=(const ParamPackage& other) = default;
 | 
			
		||||
    ParamPackage& operator=(ParamPackage&& other) = default;
 | 
			
		||||
 | 
			
		||||
@ -24,6 +24,7 @@ constexpr s32 HID_JOYSTICK_MAX = 0x7fff;
 | 
			
		||||
constexpr std::size_t NPAD_OFFSET = 0x9A00;
 | 
			
		||||
constexpr u32 BATTERY_FULL = 2;
 | 
			
		||||
constexpr u32 MAX_NPAD_ID = 7;
 | 
			
		||||
constexpr std::size_t HANDHELD_INDEX = 8;
 | 
			
		||||
constexpr std::array<u32, 10> npad_id_list{
 | 
			
		||||
    0, 1, 2, 3, 4, 5, 6, 7, NPAD_HANDHELD, NPAD_UNKNOWN,
 | 
			
		||||
};
 | 
			
		||||
@ -33,19 +34,41 @@ enum class JoystickId : std::size_t {
 | 
			
		||||
    Joystick_Right,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static Controller_NPad::NPadControllerType MapSettingsTypeToNPad(Settings::ControllerType type) {
 | 
			
		||||
Controller_NPad::NPadControllerType Controller_NPad::MapSettingsTypeToNPad(
 | 
			
		||||
    Settings::ControllerType type) {
 | 
			
		||||
    switch (type) {
 | 
			
		||||
    case Settings::ControllerType::ProController:
 | 
			
		||||
        return Controller_NPad::NPadControllerType::ProController;
 | 
			
		||||
    case Settings::ControllerType::DualJoycon:
 | 
			
		||||
        return Controller_NPad::NPadControllerType::JoyDual;
 | 
			
		||||
        return NPadControllerType::ProController;
 | 
			
		||||
    case Settings::ControllerType::DualJoyconDetached:
 | 
			
		||||
        return NPadControllerType::JoyDual;
 | 
			
		||||
    case Settings::ControllerType::LeftJoycon:
 | 
			
		||||
        return Controller_NPad::NPadControllerType::JoyLeft;
 | 
			
		||||
        return NPadControllerType::JoyLeft;
 | 
			
		||||
    case Settings::ControllerType::RightJoycon:
 | 
			
		||||
        return Controller_NPad::NPadControllerType::JoyRight;
 | 
			
		||||
        return NPadControllerType::JoyRight;
 | 
			
		||||
    case Settings::ControllerType::Handheld:
 | 
			
		||||
        return NPadControllerType::Handheld;
 | 
			
		||||
    default:
 | 
			
		||||
        UNREACHABLE();
 | 
			
		||||
        return Controller_NPad::NPadControllerType::JoyDual;
 | 
			
		||||
        return NPadControllerType::ProController;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Settings::ControllerType Controller_NPad::MapNPadToSettingsType(
 | 
			
		||||
    Controller_NPad::NPadControllerType type) {
 | 
			
		||||
    switch (type) {
 | 
			
		||||
    case NPadControllerType::ProController:
 | 
			
		||||
        return Settings::ControllerType::ProController;
 | 
			
		||||
    case NPadControllerType::JoyDual:
 | 
			
		||||
        return Settings::ControllerType::DualJoyconDetached;
 | 
			
		||||
    case NPadControllerType::JoyLeft:
 | 
			
		||||
        return Settings::ControllerType::LeftJoycon;
 | 
			
		||||
    case NPadControllerType::JoyRight:
 | 
			
		||||
        return Settings::ControllerType::RightJoycon;
 | 
			
		||||
    case NPadControllerType::Handheld:
 | 
			
		||||
        return Settings::ControllerType::Handheld;
 | 
			
		||||
    default:
 | 
			
		||||
        UNREACHABLE();
 | 
			
		||||
        return Settings::ControllerType::ProController;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -60,9 +83,9 @@ std::size_t Controller_NPad::NPadIdToIndex(u32 npad_id) {
 | 
			
		||||
    case 6:
 | 
			
		||||
    case 7:
 | 
			
		||||
        return npad_id;
 | 
			
		||||
    case 8:
 | 
			
		||||
    case HANDHELD_INDEX:
 | 
			
		||||
    case NPAD_HANDHELD:
 | 
			
		||||
        return 8;
 | 
			
		||||
        return HANDHELD_INDEX;
 | 
			
		||||
    case 9:
 | 
			
		||||
    case NPAD_UNKNOWN:
 | 
			
		||||
        return 9;
 | 
			
		||||
@ -83,7 +106,7 @@ u32 Controller_NPad::IndexToNPad(std::size_t index) {
 | 
			
		||||
    case 6:
 | 
			
		||||
    case 7:
 | 
			
		||||
        return static_cast<u32>(index);
 | 
			
		||||
    case 8:
 | 
			
		||||
    case HANDHELD_INDEX:
 | 
			
		||||
        return NPAD_HANDHELD;
 | 
			
		||||
    case 9:
 | 
			
		||||
        return NPAD_UNKNOWN;
 | 
			
		||||
@ -96,25 +119,35 @@ u32 Controller_NPad::IndexToNPad(std::size_t index) {
 | 
			
		||||
Controller_NPad::Controller_NPad(Core::System& system) : ControllerBase(system), system(system) {}
 | 
			
		||||
Controller_NPad::~Controller_NPad() = default;
 | 
			
		||||
 | 
			
		||||
void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) {
 | 
			
		||||
void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {
 | 
			
		||||
    const auto controller_type = connected_controllers[controller_idx].type;
 | 
			
		||||
    auto& controller = shared_memory_entries[controller_idx];
 | 
			
		||||
    if (controller_type == NPadControllerType::None) {
 | 
			
		||||
        styleset_changed_events[controller_idx].writable->Signal();
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    controller.joy_styles.raw = 0; // Zero out
 | 
			
		||||
    controller.device_type.raw = 0;
 | 
			
		||||
    controller.properties.raw = 0;
 | 
			
		||||
    switch (controller_type) {
 | 
			
		||||
    case NPadControllerType::None:
 | 
			
		||||
        UNREACHABLE();
 | 
			
		||||
        break;
 | 
			
		||||
    case NPadControllerType::Handheld:
 | 
			
		||||
        controller.joy_styles.handheld.Assign(1);
 | 
			
		||||
        controller.device_type.handheld.Assign(1);
 | 
			
		||||
        controller.pad_assignment = NPadAssignments::Dual;
 | 
			
		||||
    case NPadControllerType::ProController:
 | 
			
		||||
        controller.joy_styles.pro_controller.Assign(1);
 | 
			
		||||
        controller.device_type.pro_controller.Assign(1);
 | 
			
		||||
        controller.properties.is_vertical.Assign(1);
 | 
			
		||||
        controller.properties.use_plus.Assign(1);
 | 
			
		||||
        controller.properties.use_minus.Assign(1);
 | 
			
		||||
        controller.pad_assignment = NPadAssignments::Single;
 | 
			
		||||
        break;
 | 
			
		||||
    case NPadControllerType::Handheld:
 | 
			
		||||
        controller.joy_styles.handheld.Assign(1);
 | 
			
		||||
        controller.device_type.handheld.Assign(1);
 | 
			
		||||
        controller.properties.is_vertical.Assign(1);
 | 
			
		||||
        controller.properties.use_plus.Assign(1);
 | 
			
		||||
        controller.properties.use_minus.Assign(1);
 | 
			
		||||
        controller.pad_assignment = NPadAssignments::Dual;
 | 
			
		||||
        break;
 | 
			
		||||
    case NPadControllerType::JoyDual:
 | 
			
		||||
        controller.joy_styles.joycon_dual.Assign(1);
 | 
			
		||||
@ -144,14 +177,6 @@ void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) {
 | 
			
		||||
        controller.device_type.pokeball.Assign(1);
 | 
			
		||||
        controller.pad_assignment = NPadAssignments::Single;
 | 
			
		||||
        break;
 | 
			
		||||
    case NPadControllerType::ProController:
 | 
			
		||||
        controller.joy_styles.pro_controller.Assign(1);
 | 
			
		||||
        controller.device_type.pro_controller.Assign(1);
 | 
			
		||||
        controller.properties.is_vertical.Assign(1);
 | 
			
		||||
        controller.properties.use_plus.Assign(1);
 | 
			
		||||
        controller.properties.use_minus.Assign(1);
 | 
			
		||||
        controller.pad_assignment = NPadAssignments::Single;
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    controller.single_color_error = ColorReadError::ReadOk;
 | 
			
		||||
@ -192,36 +217,25 @@ void Controller_NPad::OnInit() {
 | 
			
		||||
        style.pokeball.Assign(1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::transform(
 | 
			
		||||
        Settings::values.players.begin(), Settings::values.players.end(),
 | 
			
		||||
        connected_controllers.begin(), [](const Settings::PlayerInput& player) {
 | 
			
		||||
            return ControllerHolder{MapSettingsTypeToNPad(player.type), player.connected};
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
    std::stable_partition(connected_controllers.begin(), connected_controllers.begin() + 8,
 | 
			
		||||
                          [](const ControllerHolder& holder) { return holder.is_connected; });
 | 
			
		||||
    std::transform(Settings::values.players.begin(), Settings::values.players.end(),
 | 
			
		||||
                   connected_controllers.begin(), [](const Settings::PlayerInput& player) {
 | 
			
		||||
                       return ControllerHolder{MapSettingsTypeToNPad(player.controller_type),
 | 
			
		||||
                                               player.connected};
 | 
			
		||||
                   });
 | 
			
		||||
 | 
			
		||||
    // Account for handheld
 | 
			
		||||
    if (connected_controllers[8].is_connected)
 | 
			
		||||
        connected_controllers[8].type = NPadControllerType::Handheld;
 | 
			
		||||
    if (connected_controllers[HANDHELD_INDEX].is_connected) {
 | 
			
		||||
        connected_controllers[HANDHELD_INDEX].type = NPadControllerType::Handheld;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    supported_npad_id_types.resize(npad_id_list.size());
 | 
			
		||||
    std::memcpy(supported_npad_id_types.data(), npad_id_list.data(),
 | 
			
		||||
                npad_id_list.size() * sizeof(u32));
 | 
			
		||||
 | 
			
		||||
    // Add a default dual joycon controller if none are present.
 | 
			
		||||
    if (std::none_of(connected_controllers.begin(), connected_controllers.end(),
 | 
			
		||||
                     [](const ControllerHolder& controller) { return controller.is_connected; })) {
 | 
			
		||||
        supported_npad_id_types.resize(npad_id_list.size());
 | 
			
		||||
        std::memcpy(supported_npad_id_types.data(), npad_id_list.data(),
 | 
			
		||||
                    npad_id_list.size() * sizeof(u32));
 | 
			
		||||
        AddNewController(NPadControllerType::JoyDual);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (std::size_t i = 0; i < connected_controllers.size(); ++i) {
 | 
			
		||||
        const auto& controller = connected_controllers[i];
 | 
			
		||||
        if (controller.is_connected) {
 | 
			
		||||
            AddNewControllerAt(controller.type, IndexToNPad(i));
 | 
			
		||||
            AddNewControllerAt(controller.type, i);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -309,8 +323,9 @@ void Controller_NPad::RequestPadStateUpdate(u32 npad_id) {
 | 
			
		||||
 | 
			
		||||
void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
 | 
			
		||||
                               std::size_t data_len) {
 | 
			
		||||
    if (!IsControllerActivated())
 | 
			
		||||
    if (!IsControllerActivated()) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    for (std::size_t i = 0; i < shared_memory_entries.size(); i++) {
 | 
			
		||||
        auto& npad = shared_memory_entries[i];
 | 
			
		||||
        const std::array<NPadGeneric*, 7> controller_npads{&npad.main_controller_states,
 | 
			
		||||
@ -360,13 +375,25 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
 | 
			
		||||
        auto& libnx_entry = npad.libnx.npad[npad.libnx.common.last_entry_index];
 | 
			
		||||
 | 
			
		||||
        libnx_entry.connection_status.raw = 0;
 | 
			
		||||
        libnx_entry.connection_status.IsConnected.Assign(1);
 | 
			
		||||
 | 
			
		||||
        switch (controller_type) {
 | 
			
		||||
        case NPadControllerType::None:
 | 
			
		||||
            UNREACHABLE();
 | 
			
		||||
            break;
 | 
			
		||||
        case NPadControllerType::ProController:
 | 
			
		||||
            main_controller.connection_status.raw = 0;
 | 
			
		||||
            main_controller.connection_status.IsConnected.Assign(1);
 | 
			
		||||
            main_controller.connection_status.IsWired.Assign(1);
 | 
			
		||||
            main_controller.pad.pad_states.raw = pad_state.pad_states.raw;
 | 
			
		||||
            main_controller.pad.l_stick = pad_state.l_stick;
 | 
			
		||||
            main_controller.pad.r_stick = pad_state.r_stick;
 | 
			
		||||
 | 
			
		||||
            libnx_entry.connection_status.IsWired.Assign(1);
 | 
			
		||||
            break;
 | 
			
		||||
        case NPadControllerType::Handheld:
 | 
			
		||||
            handheld_entry.connection_status.raw = 0;
 | 
			
		||||
            handheld_entry.connection_status.IsConnected.Assign(1);
 | 
			
		||||
            handheld_entry.connection_status.IsWired.Assign(1);
 | 
			
		||||
            handheld_entry.connection_status.IsLeftJoyConnected.Assign(1);
 | 
			
		||||
            handheld_entry.connection_status.IsRightJoyConnected.Assign(1);
 | 
			
		||||
@ -375,57 +402,52 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
 | 
			
		||||
            handheld_entry.pad.pad_states.raw = pad_state.pad_states.raw;
 | 
			
		||||
            handheld_entry.pad.l_stick = pad_state.l_stick;
 | 
			
		||||
            handheld_entry.pad.r_stick = pad_state.r_stick;
 | 
			
		||||
 | 
			
		||||
            libnx_entry.connection_status.IsWired.Assign(1);
 | 
			
		||||
            libnx_entry.connection_status.IsLeftJoyConnected.Assign(1);
 | 
			
		||||
            libnx_entry.connection_status.IsRightJoyConnected.Assign(1);
 | 
			
		||||
            libnx_entry.connection_status.IsLeftJoyWired.Assign(1);
 | 
			
		||||
            libnx_entry.connection_status.IsRightJoyWired.Assign(1);
 | 
			
		||||
            break;
 | 
			
		||||
        case NPadControllerType::JoyDual:
 | 
			
		||||
            dual_entry.connection_status.raw = 0;
 | 
			
		||||
 | 
			
		||||
            dual_entry.connection_status.IsConnected.Assign(1);
 | 
			
		||||
            dual_entry.connection_status.IsLeftJoyConnected.Assign(1);
 | 
			
		||||
            dual_entry.connection_status.IsRightJoyConnected.Assign(1);
 | 
			
		||||
            dual_entry.connection_status.IsConnected.Assign(1);
 | 
			
		||||
 | 
			
		||||
            libnx_entry.connection_status.IsLeftJoyConnected.Assign(1);
 | 
			
		||||
            libnx_entry.connection_status.IsRightJoyConnected.Assign(1);
 | 
			
		||||
            libnx_entry.connection_status.IsConnected.Assign(1);
 | 
			
		||||
 | 
			
		||||
            dual_entry.pad.pad_states.raw = pad_state.pad_states.raw;
 | 
			
		||||
            dual_entry.pad.l_stick = pad_state.l_stick;
 | 
			
		||||
            dual_entry.pad.r_stick = pad_state.r_stick;
 | 
			
		||||
 | 
			
		||||
            libnx_entry.connection_status.IsLeftJoyConnected.Assign(1);
 | 
			
		||||
            libnx_entry.connection_status.IsRightJoyConnected.Assign(1);
 | 
			
		||||
            break;
 | 
			
		||||
        case NPadControllerType::JoyLeft:
 | 
			
		||||
            left_entry.connection_status.raw = 0;
 | 
			
		||||
 | 
			
		||||
            left_entry.connection_status.IsConnected.Assign(1);
 | 
			
		||||
            left_entry.connection_status.IsLeftJoyConnected.Assign(1);
 | 
			
		||||
            left_entry.pad.pad_states.raw = pad_state.pad_states.raw;
 | 
			
		||||
            left_entry.pad.l_stick = pad_state.l_stick;
 | 
			
		||||
            left_entry.pad.r_stick = pad_state.r_stick;
 | 
			
		||||
 | 
			
		||||
            libnx_entry.connection_status.IsLeftJoyConnected.Assign(1);
 | 
			
		||||
            break;
 | 
			
		||||
        case NPadControllerType::JoyRight:
 | 
			
		||||
            right_entry.connection_status.raw = 0;
 | 
			
		||||
 | 
			
		||||
            right_entry.connection_status.IsConnected.Assign(1);
 | 
			
		||||
            right_entry.connection_status.IsRightJoyConnected.Assign(1);
 | 
			
		||||
            right_entry.pad.pad_states.raw = pad_state.pad_states.raw;
 | 
			
		||||
            right_entry.pad.l_stick = pad_state.l_stick;
 | 
			
		||||
            right_entry.pad.r_stick = pad_state.r_stick;
 | 
			
		||||
 | 
			
		||||
            libnx_entry.connection_status.IsRightJoyConnected.Assign(1);
 | 
			
		||||
            break;
 | 
			
		||||
        case NPadControllerType::Pokeball:
 | 
			
		||||
            pokeball_entry.connection_status.raw = 0;
 | 
			
		||||
 | 
			
		||||
            pokeball_entry.connection_status.IsConnected.Assign(1);
 | 
			
		||||
            pokeball_entry.connection_status.IsWired.Assign(1);
 | 
			
		||||
 | 
			
		||||
            pokeball_entry.pad.pad_states.raw = pad_state.pad_states.raw;
 | 
			
		||||
            pokeball_entry.pad.l_stick = pad_state.l_stick;
 | 
			
		||||
            pokeball_entry.pad.r_stick = pad_state.r_stick;
 | 
			
		||||
            break;
 | 
			
		||||
        case NPadControllerType::ProController:
 | 
			
		||||
            main_controller.connection_status.raw = 0;
 | 
			
		||||
 | 
			
		||||
            main_controller.connection_status.IsConnected.Assign(1);
 | 
			
		||||
            main_controller.connection_status.IsWired.Assign(1);
 | 
			
		||||
            main_controller.pad.pad_states.raw = pad_state.pad_states.raw;
 | 
			
		||||
            main_controller.pad.l_stick = pad_state.l_stick;
 | 
			
		||||
            main_controller.pad.r_stick = pad_state.r_stick;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // LibNX exclusively uses this section, so we always update it since LibNX doesn't activate
 | 
			
		||||
@ -453,26 +475,6 @@ void Controller_NPad::SetSupportedNPadIdTypes(u8* data, std::size_t length) {
 | 
			
		||||
    supported_npad_id_types.clear();
 | 
			
		||||
    supported_npad_id_types.resize(length / sizeof(u32));
 | 
			
		||||
    std::memcpy(supported_npad_id_types.data(), data, length);
 | 
			
		||||
    for (std::size_t i = 0; i < connected_controllers.size(); i++) {
 | 
			
		||||
        auto& controller = connected_controllers[i];
 | 
			
		||||
        if (!controller.is_connected) {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
        const auto requested_controller =
 | 
			
		||||
            i <= MAX_NPAD_ID ? MapSettingsTypeToNPad(Settings::values.players[i].type)
 | 
			
		||||
                             : NPadControllerType::Handheld;
 | 
			
		||||
        if (!IsControllerSupported(requested_controller)) {
 | 
			
		||||
            const auto is_handheld = requested_controller == NPadControllerType::Handheld;
 | 
			
		||||
            if (is_handheld) {
 | 
			
		||||
                controller.type = NPadControllerType::None;
 | 
			
		||||
                controller.is_connected = false;
 | 
			
		||||
                AddNewController(requested_controller);
 | 
			
		||||
            } else {
 | 
			
		||||
                controller.type = requested_controller;
 | 
			
		||||
                InitNewlyAddedControler(i);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Controller_NPad::GetSupportedNpadIdTypes(u32* data, std::size_t max_length) {
 | 
			
		||||
@ -504,7 +506,7 @@ void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids,
 | 
			
		||||
                                        const std::vector<Vibration>& vibrations) {
 | 
			
		||||
    LOG_DEBUG(Service_HID, "(STUBBED) called");
 | 
			
		||||
 | 
			
		||||
    if (!can_controllers_vibrate) {
 | 
			
		||||
    if (!Settings::values.vibration_enabled || !can_controllers_vibrate) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    for (std::size_t i = 0; i < controller_ids.size(); i++) {
 | 
			
		||||
@ -517,8 +519,6 @@ void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::shared_ptr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent(u32 npad_id) const {
 | 
			
		||||
    // TODO(ogniK): Figure out the best time to signal this event. This event seems that it should
 | 
			
		||||
    // be signalled at least once, and signaled after a new controller is connected?
 | 
			
		||||
    const auto& styleset_event = styleset_changed_events[NPadIdToIndex(npad_id)];
 | 
			
		||||
    return styleset_event.readable;
 | 
			
		||||
}
 | 
			
		||||
@ -527,43 +527,43 @@ Controller_NPad::Vibration Controller_NPad::GetLastVibration() const {
 | 
			
		||||
    return last_processed_vibration;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Controller_NPad::AddNewController(NPadControllerType controller) {
 | 
			
		||||
    controller = DecideBestController(controller);
 | 
			
		||||
    if (controller == NPadControllerType::Handheld) {
 | 
			
		||||
        connected_controllers[8] = {controller, true};
 | 
			
		||||
        InitNewlyAddedControler(8);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    const auto pos =
 | 
			
		||||
        std::find_if(connected_controllers.begin(), connected_controllers.end() - 2,
 | 
			
		||||
                     [](const ControllerHolder& holder) { return !holder.is_connected; });
 | 
			
		||||
    if (pos == connected_controllers.end() - 2) {
 | 
			
		||||
        LOG_ERROR(Service_HID, "Cannot connect any more controllers!");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    const auto controller_id = std::distance(connected_controllers.begin(), pos);
 | 
			
		||||
    connected_controllers[controller_id] = {controller, true};
 | 
			
		||||
    InitNewlyAddedControler(controller_id);
 | 
			
		||||
void Controller_NPad::AddNewControllerAt(NPadControllerType controller, std::size_t npad_index) {
 | 
			
		||||
    UpdateControllerAt(controller, npad_index, true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Controller_NPad::AddNewControllerAt(NPadControllerType controller, u32 npad_id) {
 | 
			
		||||
    controller = DecideBestController(controller);
 | 
			
		||||
    if (controller == NPadControllerType::Handheld) {
 | 
			
		||||
        connected_controllers[NPadIdToIndex(NPAD_HANDHELD)] = {controller, true};
 | 
			
		||||
        InitNewlyAddedControler(NPadIdToIndex(NPAD_HANDHELD));
 | 
			
		||||
void Controller_NPad::UpdateControllerAt(NPadControllerType controller, std::size_t npad_index,
 | 
			
		||||
                                         bool connected) {
 | 
			
		||||
    if (!connected) {
 | 
			
		||||
        DisconnectNPad(IndexToNPad(npad_index));
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    connected_controllers[NPadIdToIndex(npad_id)] = {controller, true};
 | 
			
		||||
    InitNewlyAddedControler(NPadIdToIndex(npad_id));
 | 
			
		||||
}
 | 
			
		||||
    if (controller == NPadControllerType::Handheld) {
 | 
			
		||||
        Settings::values.players[HANDHELD_INDEX].controller_type =
 | 
			
		||||
            MapNPadToSettingsType(controller);
 | 
			
		||||
        Settings::values.players[HANDHELD_INDEX].connected = true;
 | 
			
		||||
        connected_controllers[HANDHELD_INDEX] = {controller, true};
 | 
			
		||||
        InitNewlyAddedController(HANDHELD_INDEX);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
void Controller_NPad::ConnectNPad(u32 npad_id) {
 | 
			
		||||
    connected_controllers[NPadIdToIndex(npad_id)].is_connected = true;
 | 
			
		||||
    Settings::values.players[npad_index].controller_type = MapNPadToSettingsType(controller);
 | 
			
		||||
    Settings::values.players[npad_index].connected = true;
 | 
			
		||||
    connected_controllers[npad_index] = {controller, true};
 | 
			
		||||
    InitNewlyAddedController(npad_index);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Controller_NPad::DisconnectNPad(u32 npad_id) {
 | 
			
		||||
    connected_controllers[NPadIdToIndex(npad_id)].is_connected = false;
 | 
			
		||||
    const auto npad_index = NPadIdToIndex(npad_id);
 | 
			
		||||
    connected_controllers[npad_index].is_connected = false;
 | 
			
		||||
    Settings::values.players[npad_index].connected = false;
 | 
			
		||||
 | 
			
		||||
    auto& controller = shared_memory_entries[npad_index];
 | 
			
		||||
    controller.joy_styles.raw = 0; // Zero out
 | 
			
		||||
    controller.device_type.raw = 0;
 | 
			
		||||
    controller.properties.raw = 0;
 | 
			
		||||
 | 
			
		||||
    styleset_changed_events[npad_index].writable->Signal();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Controller_NPad::SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode) {
 | 
			
		||||
@ -599,8 +599,8 @@ bool Controller_NPad::SwapNpadAssignment(u32 npad_id_1, u32 npad_id_2) {
 | 
			
		||||
 | 
			
		||||
    std::swap(connected_controllers[npad_index_1].type, connected_controllers[npad_index_2].type);
 | 
			
		||||
 | 
			
		||||
    InitNewlyAddedControler(npad_index_1);
 | 
			
		||||
    InitNewlyAddedControler(npad_index_2);
 | 
			
		||||
    AddNewControllerAt(connected_controllers[npad_index_1].type, npad_index_1);
 | 
			
		||||
    AddNewControllerAt(connected_controllers[npad_index_2].type, npad_index_2);
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
@ -614,11 +614,11 @@ Controller_NPad::LedPattern Controller_NPad::GetLedPattern(u32 npad_id) {
 | 
			
		||||
    case 0:
 | 
			
		||||
        return LedPattern{1, 0, 0, 0};
 | 
			
		||||
    case 1:
 | 
			
		||||
        return LedPattern{0, 1, 0, 0};
 | 
			
		||||
        return LedPattern{1, 1, 0, 0};
 | 
			
		||||
    case 2:
 | 
			
		||||
        return LedPattern{0, 0, 1, 0};
 | 
			
		||||
        return LedPattern{1, 1, 1, 0};
 | 
			
		||||
    case 3:
 | 
			
		||||
        return LedPattern{0, 0, 0, 1};
 | 
			
		||||
        return LedPattern{1, 1, 1, 1};
 | 
			
		||||
    case 4:
 | 
			
		||||
        return LedPattern{1, 0, 0, 1};
 | 
			
		||||
    case 5:
 | 
			
		||||
@ -628,7 +628,6 @@ Controller_NPad::LedPattern Controller_NPad::GetLedPattern(u32 npad_id) {
 | 
			
		||||
    case 7:
 | 
			
		||||
        return LedPattern{0, 1, 1, 0};
 | 
			
		||||
    default:
 | 
			
		||||
        UNIMPLEMENTED_MSG("Unhandled npad_id {}", npad_id);
 | 
			
		||||
        return LedPattern{0, 0, 0, 0};
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -118,10 +118,11 @@ public:
 | 
			
		||||
    std::shared_ptr<Kernel::ReadableEvent> GetStyleSetChangedEvent(u32 npad_id) const;
 | 
			
		||||
    Vibration GetLastVibration() const;
 | 
			
		||||
 | 
			
		||||
    void AddNewController(NPadControllerType controller);
 | 
			
		||||
    void AddNewControllerAt(NPadControllerType controller, u32 npad_id);
 | 
			
		||||
    // Adds a new controller at an index.
 | 
			
		||||
    void AddNewControllerAt(NPadControllerType controller, std::size_t npad_index);
 | 
			
		||||
    // Adds a new controller at an index with connection status.
 | 
			
		||||
    void UpdateControllerAt(NPadControllerType controller, std::size_t npad_index, bool connected);
 | 
			
		||||
 | 
			
		||||
    void ConnectNPad(u32 npad_id);
 | 
			
		||||
    void DisconnectNPad(u32 npad_id);
 | 
			
		||||
    void SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode);
 | 
			
		||||
    GyroscopeZeroDriftMode GetGyroscopeZeroDriftMode() const;
 | 
			
		||||
@ -141,6 +142,8 @@ public:
 | 
			
		||||
    // Specifically for cheat engine and other features.
 | 
			
		||||
    u32 GetAndResetPressState();
 | 
			
		||||
 | 
			
		||||
    static Controller_NPad::NPadControllerType MapSettingsTypeToNPad(Settings::ControllerType type);
 | 
			
		||||
    static Settings::ControllerType MapNPadToSettingsType(Controller_NPad::NPadControllerType type);
 | 
			
		||||
    static std::size_t NPadIdToIndex(u32 npad_id);
 | 
			
		||||
    static u32 IndexToNPad(std::size_t index);
 | 
			
		||||
 | 
			
		||||
@ -309,7 +312,7 @@ private:
 | 
			
		||||
        bool is_connected;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    void InitNewlyAddedControler(std::size_t controller_idx);
 | 
			
		||||
    void InitNewlyAddedController(std::size_t controller_idx);
 | 
			
		||||
    bool IsControllerSupported(NPadControllerType controller) const;
 | 
			
		||||
    NPadControllerType DecideBestController(NPadControllerType priority) const;
 | 
			
		||||
    void RequestPadStateUpdate(u32 npad_id);
 | 
			
		||||
 | 
			
		||||
@ -38,11 +38,9 @@
 | 
			
		||||
namespace Service::HID {
 | 
			
		||||
 | 
			
		||||
// Updating period for each HID device.
 | 
			
		||||
// TODO(ogniK): Find actual polling rate of hid
 | 
			
		||||
constexpr auto pad_update_ns = std::chrono::nanoseconds{1000000000 / 66};
 | 
			
		||||
[[maybe_unused]] constexpr auto accelerometer_update_ns =
 | 
			
		||||
    std::chrono::nanoseconds{1000000000 / 100};
 | 
			
		||||
[[maybe_unused]] constexpr auto gyroscope_update_ticks = std::chrono::nanoseconds{1000000000 / 100};
 | 
			
		||||
// HID is polled every 15ms, this value was derived from
 | 
			
		||||
// https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering#joy-con-status-data-packet
 | 
			
		||||
constexpr auto pad_update_ns = std::chrono::nanoseconds{15 * 1000 * 1000}; // (15ms, 66.6Hz)
 | 
			
		||||
constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000;
 | 
			
		||||
 | 
			
		||||
IAppletResource::IAppletResource(Core::System& system)
 | 
			
		||||
@ -845,8 +843,7 @@ void Hid::CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
void Hid::PermitVibration(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
    IPC::RequestParser rp{ctx};
 | 
			
		||||
    const auto can_vibrate{rp.Pop<bool>()};
 | 
			
		||||
    applet_resource->GetController<Controller_NPad>(HidController::NPad)
 | 
			
		||||
        .SetVibrationEnabled(can_vibrate);
 | 
			
		||||
    Settings::values.vibration_enabled = can_vibrate;
 | 
			
		||||
 | 
			
		||||
    LOG_DEBUG(Service_HID, "called, can_vibrate={}", can_vibrate);
 | 
			
		||||
 | 
			
		||||
@ -859,8 +856,7 @@ void Hid::IsVibrationPermitted(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
 | 
			
		||||
    IPC::ResponseBuilder rb{ctx, 3};
 | 
			
		||||
    rb.Push(RESULT_SUCCESS);
 | 
			
		||||
    rb.Push(
 | 
			
		||||
        applet_resource->GetController<Controller_NPad>(HidController::NPad).IsVibrationEnabled());
 | 
			
		||||
    rb.Push(Settings::values.vibration_enabled);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Hid::ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
 | 
			
		||||
 | 
			
		||||
@ -13,56 +13,6 @@
 | 
			
		||||
 | 
			
		||||
namespace Settings {
 | 
			
		||||
 | 
			
		||||
namespace NativeButton {
 | 
			
		||||
const std::array<const char*, NumButtons> mapping = {{
 | 
			
		||||
    "button_a",
 | 
			
		||||
    "button_b",
 | 
			
		||||
    "button_x",
 | 
			
		||||
    "button_y",
 | 
			
		||||
    "button_lstick",
 | 
			
		||||
    "button_rstick",
 | 
			
		||||
    "button_l",
 | 
			
		||||
    "button_r",
 | 
			
		||||
    "button_zl",
 | 
			
		||||
    "button_zr",
 | 
			
		||||
    "button_plus",
 | 
			
		||||
    "button_minus",
 | 
			
		||||
    "button_dleft",
 | 
			
		||||
    "button_dup",
 | 
			
		||||
    "button_dright",
 | 
			
		||||
    "button_ddown",
 | 
			
		||||
    "button_lstick_left",
 | 
			
		||||
    "button_lstick_up",
 | 
			
		||||
    "button_lstick_right",
 | 
			
		||||
    "button_lstick_down",
 | 
			
		||||
    "button_rstick_left",
 | 
			
		||||
    "button_rstick_up",
 | 
			
		||||
    "button_rstick_right",
 | 
			
		||||
    "button_rstick_down",
 | 
			
		||||
    "button_sl",
 | 
			
		||||
    "button_sr",
 | 
			
		||||
    "button_home",
 | 
			
		||||
    "button_screenshot",
 | 
			
		||||
}};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace NativeAnalog {
 | 
			
		||||
const std::array<const char*, NumAnalogs> mapping = {{
 | 
			
		||||
    "lstick",
 | 
			
		||||
    "rstick",
 | 
			
		||||
}};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace NativeMouseButton {
 | 
			
		||||
const std::array<const char*, NumMouseButtons> mapping = {{
 | 
			
		||||
    "left",
 | 
			
		||||
    "right",
 | 
			
		||||
    "middle",
 | 
			
		||||
    "forward",
 | 
			
		||||
    "back",
 | 
			
		||||
}};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Values values = {};
 | 
			
		||||
bool configuring_global = true;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -12,340 +12,10 @@
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "input_common/settings.h"
 | 
			
		||||
 | 
			
		||||
namespace Settings {
 | 
			
		||||
 | 
			
		||||
namespace NativeButton {
 | 
			
		||||
enum Values {
 | 
			
		||||
    A,
 | 
			
		||||
    B,
 | 
			
		||||
    X,
 | 
			
		||||
    Y,
 | 
			
		||||
    LStick,
 | 
			
		||||
    RStick,
 | 
			
		||||
    L,
 | 
			
		||||
    R,
 | 
			
		||||
    ZL,
 | 
			
		||||
    ZR,
 | 
			
		||||
    Plus,
 | 
			
		||||
    Minus,
 | 
			
		||||
 | 
			
		||||
    DLeft,
 | 
			
		||||
    DUp,
 | 
			
		||||
    DRight,
 | 
			
		||||
    DDown,
 | 
			
		||||
 | 
			
		||||
    LStick_Left,
 | 
			
		||||
    LStick_Up,
 | 
			
		||||
    LStick_Right,
 | 
			
		||||
    LStick_Down,
 | 
			
		||||
 | 
			
		||||
    RStick_Left,
 | 
			
		||||
    RStick_Up,
 | 
			
		||||
    RStick_Right,
 | 
			
		||||
    RStick_Down,
 | 
			
		||||
 | 
			
		||||
    SL,
 | 
			
		||||
    SR,
 | 
			
		||||
 | 
			
		||||
    Home,
 | 
			
		||||
    Screenshot,
 | 
			
		||||
 | 
			
		||||
    NumButtons,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
constexpr int BUTTON_HID_BEGIN = A;
 | 
			
		||||
constexpr int BUTTON_NS_BEGIN = Home;
 | 
			
		||||
 | 
			
		||||
constexpr int BUTTON_HID_END = BUTTON_NS_BEGIN;
 | 
			
		||||
constexpr int BUTTON_NS_END = NumButtons;
 | 
			
		||||
 | 
			
		||||
constexpr int NUM_BUTTONS_HID = BUTTON_HID_END - BUTTON_HID_BEGIN;
 | 
			
		||||
constexpr int NUM_BUTTONS_NS = BUTTON_NS_END - BUTTON_NS_BEGIN;
 | 
			
		||||
 | 
			
		||||
extern const std::array<const char*, NumButtons> mapping;
 | 
			
		||||
 | 
			
		||||
} // namespace NativeButton
 | 
			
		||||
 | 
			
		||||
namespace NativeAnalog {
 | 
			
		||||
enum Values {
 | 
			
		||||
    LStick,
 | 
			
		||||
    RStick,
 | 
			
		||||
 | 
			
		||||
    NumAnalogs,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
constexpr int STICK_HID_BEGIN = LStick;
 | 
			
		||||
constexpr int STICK_HID_END = NumAnalogs;
 | 
			
		||||
constexpr int NUM_STICKS_HID = NumAnalogs;
 | 
			
		||||
 | 
			
		||||
extern const std::array<const char*, NumAnalogs> mapping;
 | 
			
		||||
} // namespace NativeAnalog
 | 
			
		||||
 | 
			
		||||
namespace NativeMouseButton {
 | 
			
		||||
enum Values {
 | 
			
		||||
    Left,
 | 
			
		||||
    Right,
 | 
			
		||||
    Middle,
 | 
			
		||||
    Forward,
 | 
			
		||||
    Back,
 | 
			
		||||
 | 
			
		||||
    NumMouseButtons,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
constexpr int MOUSE_HID_BEGIN = Left;
 | 
			
		||||
constexpr int MOUSE_HID_END = NumMouseButtons;
 | 
			
		||||
constexpr int NUM_MOUSE_HID = NumMouseButtons;
 | 
			
		||||
 | 
			
		||||
extern const std::array<const char*, NumMouseButtons> mapping;
 | 
			
		||||
} // namespace NativeMouseButton
 | 
			
		||||
 | 
			
		||||
namespace NativeKeyboard {
 | 
			
		||||
enum Keys {
 | 
			
		||||
    None,
 | 
			
		||||
    Error,
 | 
			
		||||
 | 
			
		||||
    A = 4,
 | 
			
		||||
    B,
 | 
			
		||||
    C,
 | 
			
		||||
    D,
 | 
			
		||||
    E,
 | 
			
		||||
    F,
 | 
			
		||||
    G,
 | 
			
		||||
    H,
 | 
			
		||||
    I,
 | 
			
		||||
    J,
 | 
			
		||||
    K,
 | 
			
		||||
    L,
 | 
			
		||||
    M,
 | 
			
		||||
    N,
 | 
			
		||||
    O,
 | 
			
		||||
    P,
 | 
			
		||||
    Q,
 | 
			
		||||
    R,
 | 
			
		||||
    S,
 | 
			
		||||
    T,
 | 
			
		||||
    U,
 | 
			
		||||
    V,
 | 
			
		||||
    W,
 | 
			
		||||
    X,
 | 
			
		||||
    Y,
 | 
			
		||||
    Z,
 | 
			
		||||
    N1,
 | 
			
		||||
    N2,
 | 
			
		||||
    N3,
 | 
			
		||||
    N4,
 | 
			
		||||
    N5,
 | 
			
		||||
    N6,
 | 
			
		||||
    N7,
 | 
			
		||||
    N8,
 | 
			
		||||
    N9,
 | 
			
		||||
    N0,
 | 
			
		||||
    Enter,
 | 
			
		||||
    Escape,
 | 
			
		||||
    Backspace,
 | 
			
		||||
    Tab,
 | 
			
		||||
    Space,
 | 
			
		||||
    Minus,
 | 
			
		||||
    Equal,
 | 
			
		||||
    LeftBrace,
 | 
			
		||||
    RightBrace,
 | 
			
		||||
    Backslash,
 | 
			
		||||
    Tilde,
 | 
			
		||||
    Semicolon,
 | 
			
		||||
    Apostrophe,
 | 
			
		||||
    Grave,
 | 
			
		||||
    Comma,
 | 
			
		||||
    Dot,
 | 
			
		||||
    Slash,
 | 
			
		||||
    CapsLockKey,
 | 
			
		||||
 | 
			
		||||
    F1,
 | 
			
		||||
    F2,
 | 
			
		||||
    F3,
 | 
			
		||||
    F4,
 | 
			
		||||
    F5,
 | 
			
		||||
    F6,
 | 
			
		||||
    F7,
 | 
			
		||||
    F8,
 | 
			
		||||
    F9,
 | 
			
		||||
    F10,
 | 
			
		||||
    F11,
 | 
			
		||||
    F12,
 | 
			
		||||
 | 
			
		||||
    SystemRequest,
 | 
			
		||||
    ScrollLockKey,
 | 
			
		||||
    Pause,
 | 
			
		||||
    Insert,
 | 
			
		||||
    Home,
 | 
			
		||||
    PageUp,
 | 
			
		||||
    Delete,
 | 
			
		||||
    End,
 | 
			
		||||
    PageDown,
 | 
			
		||||
    Right,
 | 
			
		||||
    Left,
 | 
			
		||||
    Down,
 | 
			
		||||
    Up,
 | 
			
		||||
 | 
			
		||||
    NumLockKey,
 | 
			
		||||
    KPSlash,
 | 
			
		||||
    KPAsterisk,
 | 
			
		||||
    KPMinus,
 | 
			
		||||
    KPPlus,
 | 
			
		||||
    KPEnter,
 | 
			
		||||
    KP1,
 | 
			
		||||
    KP2,
 | 
			
		||||
    KP3,
 | 
			
		||||
    KP4,
 | 
			
		||||
    KP5,
 | 
			
		||||
    KP6,
 | 
			
		||||
    KP7,
 | 
			
		||||
    KP8,
 | 
			
		||||
    KP9,
 | 
			
		||||
    KP0,
 | 
			
		||||
    KPDot,
 | 
			
		||||
 | 
			
		||||
    Key102,
 | 
			
		||||
    Compose,
 | 
			
		||||
    Power,
 | 
			
		||||
    KPEqual,
 | 
			
		||||
 | 
			
		||||
    F13,
 | 
			
		||||
    F14,
 | 
			
		||||
    F15,
 | 
			
		||||
    F16,
 | 
			
		||||
    F17,
 | 
			
		||||
    F18,
 | 
			
		||||
    F19,
 | 
			
		||||
    F20,
 | 
			
		||||
    F21,
 | 
			
		||||
    F22,
 | 
			
		||||
    F23,
 | 
			
		||||
    F24,
 | 
			
		||||
 | 
			
		||||
    Open,
 | 
			
		||||
    Help,
 | 
			
		||||
    Properties,
 | 
			
		||||
    Front,
 | 
			
		||||
    Stop,
 | 
			
		||||
    Repeat,
 | 
			
		||||
    Undo,
 | 
			
		||||
    Cut,
 | 
			
		||||
    Copy,
 | 
			
		||||
    Paste,
 | 
			
		||||
    Find,
 | 
			
		||||
    Mute,
 | 
			
		||||
    VolumeUp,
 | 
			
		||||
    VolumeDown,
 | 
			
		||||
    CapsLockActive,
 | 
			
		||||
    NumLockActive,
 | 
			
		||||
    ScrollLockActive,
 | 
			
		||||
    KPComma,
 | 
			
		||||
 | 
			
		||||
    KPLeftParenthesis,
 | 
			
		||||
    KPRightParenthesis,
 | 
			
		||||
 | 
			
		||||
    LeftControlKey = 0xE0,
 | 
			
		||||
    LeftShiftKey,
 | 
			
		||||
    LeftAltKey,
 | 
			
		||||
    LeftMetaKey,
 | 
			
		||||
    RightControlKey,
 | 
			
		||||
    RightShiftKey,
 | 
			
		||||
    RightAltKey,
 | 
			
		||||
    RightMetaKey,
 | 
			
		||||
 | 
			
		||||
    MediaPlayPause,
 | 
			
		||||
    MediaStopCD,
 | 
			
		||||
    MediaPrevious,
 | 
			
		||||
    MediaNext,
 | 
			
		||||
    MediaEject,
 | 
			
		||||
    MediaVolumeUp,
 | 
			
		||||
    MediaVolumeDown,
 | 
			
		||||
    MediaMute,
 | 
			
		||||
    MediaWebsite,
 | 
			
		||||
    MediaBack,
 | 
			
		||||
    MediaForward,
 | 
			
		||||
    MediaStop,
 | 
			
		||||
    MediaFind,
 | 
			
		||||
    MediaScrollUp,
 | 
			
		||||
    MediaScrollDown,
 | 
			
		||||
    MediaEdit,
 | 
			
		||||
    MediaSleep,
 | 
			
		||||
    MediaCoffee,
 | 
			
		||||
    MediaRefresh,
 | 
			
		||||
    MediaCalculator,
 | 
			
		||||
 | 
			
		||||
    NumKeyboardKeys,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static_assert(NumKeyboardKeys == 0xFC, "Incorrect number of keyboard keys.");
 | 
			
		||||
 | 
			
		||||
enum Modifiers {
 | 
			
		||||
    LeftControl,
 | 
			
		||||
    LeftShift,
 | 
			
		||||
    LeftAlt,
 | 
			
		||||
    LeftMeta,
 | 
			
		||||
    RightControl,
 | 
			
		||||
    RightShift,
 | 
			
		||||
    RightAlt,
 | 
			
		||||
    RightMeta,
 | 
			
		||||
    CapsLock,
 | 
			
		||||
    ScrollLock,
 | 
			
		||||
    NumLock,
 | 
			
		||||
 | 
			
		||||
    NumKeyboardMods,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
constexpr int KEYBOARD_KEYS_HID_BEGIN = None;
 | 
			
		||||
constexpr int KEYBOARD_KEYS_HID_END = NumKeyboardKeys;
 | 
			
		||||
constexpr int NUM_KEYBOARD_KEYS_HID = NumKeyboardKeys;
 | 
			
		||||
 | 
			
		||||
constexpr int KEYBOARD_MODS_HID_BEGIN = LeftControl;
 | 
			
		||||
constexpr int KEYBOARD_MODS_HID_END = NumKeyboardMods;
 | 
			
		||||
constexpr int NUM_KEYBOARD_MODS_HID = NumKeyboardMods;
 | 
			
		||||
 | 
			
		||||
} // namespace NativeKeyboard
 | 
			
		||||
 | 
			
		||||
using ButtonsRaw = std::array<std::string, NativeButton::NumButtons>;
 | 
			
		||||
using AnalogsRaw = std::array<std::string, NativeAnalog::NumAnalogs>;
 | 
			
		||||
using MouseButtonsRaw = std::array<std::string, NativeMouseButton::NumMouseButtons>;
 | 
			
		||||
using KeyboardKeysRaw = std::array<std::string, NativeKeyboard::NumKeyboardKeys>;
 | 
			
		||||
using KeyboardModsRaw = std::array<std::string, NativeKeyboard::NumKeyboardMods>;
 | 
			
		||||
 | 
			
		||||
constexpr u32 JOYCON_BODY_NEON_RED = 0xFF3C28;
 | 
			
		||||
constexpr u32 JOYCON_BUTTONS_NEON_RED = 0x1E0A0A;
 | 
			
		||||
constexpr u32 JOYCON_BODY_NEON_BLUE = 0x0AB9E6;
 | 
			
		||||
constexpr u32 JOYCON_BUTTONS_NEON_BLUE = 0x001E1E;
 | 
			
		||||
 | 
			
		||||
enum class ControllerType {
 | 
			
		||||
    ProController,
 | 
			
		||||
    DualJoycon,
 | 
			
		||||
    RightJoycon,
 | 
			
		||||
    LeftJoycon,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct PlayerInput {
 | 
			
		||||
    bool connected;
 | 
			
		||||
    ControllerType type;
 | 
			
		||||
    ButtonsRaw buttons;
 | 
			
		||||
    AnalogsRaw analogs;
 | 
			
		||||
 | 
			
		||||
    u32 body_color_right;
 | 
			
		||||
    u32 button_color_right;
 | 
			
		||||
    u32 body_color_left;
 | 
			
		||||
    u32 button_color_left;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct TouchscreenInput {
 | 
			
		||||
    bool enabled;
 | 
			
		||||
    std::string device;
 | 
			
		||||
 | 
			
		||||
    u32 finger;
 | 
			
		||||
    u32 diameter_x;
 | 
			
		||||
    u32 diameter_y;
 | 
			
		||||
    u32 rotation_angle;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class RendererBackend {
 | 
			
		||||
    OpenGL = 0,
 | 
			
		||||
    Vulkan = 1,
 | 
			
		||||
@ -461,6 +131,8 @@ struct Values {
 | 
			
		||||
    // Controls
 | 
			
		||||
    std::array<PlayerInput, 10> players;
 | 
			
		||||
 | 
			
		||||
    bool use_docked_mode;
 | 
			
		||||
 | 
			
		||||
    bool mouse_enabled;
 | 
			
		||||
    std::string mouse_device;
 | 
			
		||||
    MouseButtonsRaw mouse_buttons;
 | 
			
		||||
@ -474,14 +146,15 @@ struct Values {
 | 
			
		||||
    AnalogsRaw debug_pad_analogs;
 | 
			
		||||
 | 
			
		||||
    std::string motion_device;
 | 
			
		||||
 | 
			
		||||
    bool vibration_enabled;
 | 
			
		||||
 | 
			
		||||
    TouchscreenInput touchscreen;
 | 
			
		||||
    std::atomic_bool is_device_reload_pending{true};
 | 
			
		||||
    std::string udp_input_address;
 | 
			
		||||
    u16 udp_input_port;
 | 
			
		||||
    u8 udp_pad_index;
 | 
			
		||||
 | 
			
		||||
    bool use_docked_mode;
 | 
			
		||||
 | 
			
		||||
    // Data Storage
 | 
			
		||||
    bool use_virtual_sd;
 | 
			
		||||
    bool gamecard_inserted;
 | 
			
		||||
 | 
			
		||||
@ -7,6 +7,8 @@ add_library(input_common STATIC
 | 
			
		||||
    main.h
 | 
			
		||||
    motion_emu.cpp
 | 
			
		||||
    motion_emu.h
 | 
			
		||||
    settings.cpp
 | 
			
		||||
    settings.h
 | 
			
		||||
    gcadapter/gc_adapter.cpp
 | 
			
		||||
    gcadapter/gc_adapter.h
 | 
			
		||||
    gcadapter/gc_poller.cpp
 | 
			
		||||
 | 
			
		||||
@ -191,7 +191,7 @@ public:
 | 
			
		||||
 | 
			
		||||
    bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override {
 | 
			
		||||
        const auto [x, y] = GetStatus();
 | 
			
		||||
        const float directional_deadzone = 0.4f;
 | 
			
		||||
        const float directional_deadzone = 0.5f;
 | 
			
		||||
        switch (direction) {
 | 
			
		||||
        case Input::AnalogDirection::RIGHT:
 | 
			
		||||
            return x > directional_deadzone;
 | 
			
		||||
@ -232,7 +232,7 @@ std::unique_ptr<Input::AnalogDevice> GCAnalogFactory::Create(const Common::Param
 | 
			
		||||
    const int port = params.Get("port", 0);
 | 
			
		||||
    const int axis_x = params.Get("axis_x", 0);
 | 
			
		||||
    const int axis_y = params.Get("axis_y", 1);
 | 
			
		||||
    const float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, .99f);
 | 
			
		||||
    const float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f);
 | 
			
		||||
    const float range = std::clamp(params.Get("range", 1.0f), 0.50f, 1.50f);
 | 
			
		||||
 | 
			
		||||
    return std::make_unique<GCAnalog>(port, axis_x, axis_y, deadzone, adapter.get(), range);
 | 
			
		||||
 | 
			
		||||
@ -44,7 +44,6 @@ void Init() {
 | 
			
		||||
#ifdef HAVE_SDL2
 | 
			
		||||
    sdl = SDL::Init();
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    udp = CemuhookUDP::Init();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -103,6 +102,56 @@ std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left,
 | 
			
		||||
    return circle_pad_param.Serialize();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::vector<Common::ParamPackage> GetInputDevices() {
 | 
			
		||||
    std::vector<Common::ParamPackage> devices = {
 | 
			
		||||
        Common::ParamPackage{{"display", "Any"}, {"class", "any"}},
 | 
			
		||||
        Common::ParamPackage{{"display", "Keyboard/Mouse"}, {"class", "key"}},
 | 
			
		||||
    };
 | 
			
		||||
#ifdef HAVE_SDL2
 | 
			
		||||
    auto sdl_devices = sdl->GetInputDevices();
 | 
			
		||||
    devices.insert(devices.end(), sdl_devices.begin(), sdl_devices.end());
 | 
			
		||||
#endif
 | 
			
		||||
    auto udp_devices = udp->GetInputDevices();
 | 
			
		||||
    devices.insert(devices.end(), udp_devices.begin(), udp_devices.end());
 | 
			
		||||
    return devices;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::unordered_map<Settings::NativeButton::Values, Common::ParamPackage> GetButtonMappingForDevice(
 | 
			
		||||
    const Common::ParamPackage& params) {
 | 
			
		||||
    std::unordered_map<Settings::NativeButton::Values, Common::ParamPackage> mappings;
 | 
			
		||||
    if (!params.Has("class") || params.Get("class", "") == "any") {
 | 
			
		||||
        return {};
 | 
			
		||||
    }
 | 
			
		||||
    if (params.Get("class", "") == "key") {
 | 
			
		||||
        // TODO consider returning the SDL key codes for the default keybindings
 | 
			
		||||
        return {};
 | 
			
		||||
    }
 | 
			
		||||
#ifdef HAVE_SDL2
 | 
			
		||||
    if (params.Get("class", "") == "sdl") {
 | 
			
		||||
        return sdl->GetButtonMappingForDevice(params);
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
    return {};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::unordered_map<Settings::NativeAnalog::Values, Common::ParamPackage> GetAnalogMappingForDevice(
 | 
			
		||||
    const Common::ParamPackage& params) {
 | 
			
		||||
    std::unordered_map<Settings::NativeAnalog::Values, Common::ParamPackage> mappings;
 | 
			
		||||
    if (!params.Has("class") || params.Get("class", "") == "any") {
 | 
			
		||||
        return {};
 | 
			
		||||
    }
 | 
			
		||||
    if (params.Get("class", "") == "key") {
 | 
			
		||||
        // TODO consider returning the SDL key codes for the default keybindings
 | 
			
		||||
        return {};
 | 
			
		||||
    }
 | 
			
		||||
#ifdef HAVE_SDL2
 | 
			
		||||
    if (params.Get("class", "") == "sdl") {
 | 
			
		||||
        return sdl->GetAnalogMappingForDevice(params);
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
    return {};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace Polling {
 | 
			
		||||
 | 
			
		||||
std::vector<std::unique_ptr<DevicePoller>> GetPollers(DeviceType type) {
 | 
			
		||||
 | 
			
		||||
@ -6,8 +6,10 @@
 | 
			
		||||
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include "input_common/gcadapter/gc_poller.h"
 | 
			
		||||
#include "input_common/settings.h"
 | 
			
		||||
 | 
			
		||||
namespace Common {
 | 
			
		||||
class ParamPackage;
 | 
			
		||||
@ -42,9 +44,27 @@ std::string GenerateKeyboardParam(int key_code);
 | 
			
		||||
std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left, int key_right,
 | 
			
		||||
                                        int key_modifier, float modifier_scale);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Return a list of available input devices that this Factory can create a new device with.
 | 
			
		||||
 * Each returned Parampackage should have a `display` field used for display, a class field for
 | 
			
		||||
 * backends to determine if this backend is meant to service the request and any other information
 | 
			
		||||
 * needed to identify this in the backend later.
 | 
			
		||||
 */
 | 
			
		||||
std::vector<Common::ParamPackage> GetInputDevices();
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Given a ParamPackage for a Device returned from `GetInputDevices`, attempt to get the default
 | 
			
		||||
 * mapping for the device. This is currently only implemented for the sdl backend devices.
 | 
			
		||||
 */
 | 
			
		||||
using ButtonMapping = std::unordered_map<Settings::NativeButton::Values, Common::ParamPackage>;
 | 
			
		||||
using AnalogMapping = std::unordered_map<Settings::NativeAnalog::Values, Common::ParamPackage>;
 | 
			
		||||
 | 
			
		||||
ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage&);
 | 
			
		||||
AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage&);
 | 
			
		||||
 | 
			
		||||
namespace Polling {
 | 
			
		||||
 | 
			
		||||
enum class DeviceType { Button, Analog };
 | 
			
		||||
enum class DeviceType { Button, AnalogPreferred };
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * A class that can be used to get inputs from an input device like controllers without having to
 | 
			
		||||
@ -54,7 +74,9 @@ class DevicePoller {
 | 
			
		||||
public:
 | 
			
		||||
    virtual ~DevicePoller() = default;
 | 
			
		||||
    /// Setup and start polling for inputs, should be called before GetNextInput
 | 
			
		||||
    virtual void Start() = 0;
 | 
			
		||||
    /// If a device_id is provided, events should be filtered to only include events from this
 | 
			
		||||
    /// device id
 | 
			
		||||
    virtual void Start(const std::string& device_id = "") = 0;
 | 
			
		||||
    /// Stop polling
 | 
			
		||||
    virtual void Stop() = 0;
 | 
			
		||||
    /**
 | 
			
		||||
 | 
			
		||||
@ -6,6 +6,7 @@
 | 
			
		||||
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include "common/param_package.h"
 | 
			
		||||
#include "input_common/main.h"
 | 
			
		||||
 | 
			
		||||
namespace InputCommon::Polling {
 | 
			
		||||
@ -22,14 +23,24 @@ public:
 | 
			
		||||
    /// Unregisters SDL device factories and shut them down.
 | 
			
		||||
    virtual ~State() = default;
 | 
			
		||||
 | 
			
		||||
    virtual Pollers GetPollers(Polling::DeviceType type) = 0;
 | 
			
		||||
    virtual Pollers GetPollers(Polling::DeviceType type) {
 | 
			
		||||
        return {};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    virtual std::vector<Common::ParamPackage> GetInputDevices() {
 | 
			
		||||
        return {};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    virtual ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage&) {
 | 
			
		||||
        return {};
 | 
			
		||||
    }
 | 
			
		||||
    virtual AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage&) {
 | 
			
		||||
        return {};
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class NullState : public State {
 | 
			
		||||
public:
 | 
			
		||||
    Pollers GetPollers(Polling::DeviceType type) override {
 | 
			
		||||
        return {};
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
std::unique_ptr<State> Init();
 | 
			
		||||
 | 
			
		||||
@ -7,6 +7,8 @@
 | 
			
		||||
#include <cmath>
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <mutex>
 | 
			
		||||
#include <optional>
 | 
			
		||||
#include <sstream>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <thread>
 | 
			
		||||
#include <tuple>
 | 
			
		||||
@ -23,7 +25,8 @@
 | 
			
		||||
 | 
			
		||||
namespace InputCommon::SDL {
 | 
			
		||||
 | 
			
		||||
static std::string GetGUID(SDL_Joystick* joystick) {
 | 
			
		||||
namespace {
 | 
			
		||||
std::string GetGUID(SDL_Joystick* joystick) {
 | 
			
		||||
    const SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
 | 
			
		||||
    char guid_str[33];
 | 
			
		||||
    SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str));
 | 
			
		||||
@ -31,7 +34,8 @@ static std::string GetGUID(SDL_Joystick* joystick) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Creates a ParamPackage from an SDL_Event that can directly be used to create a ButtonDevice
 | 
			
		||||
static Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event);
 | 
			
		||||
Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event);
 | 
			
		||||
} // Anonymous namespace
 | 
			
		||||
 | 
			
		||||
static int SDLEventWatcher(void* user_data, SDL_Event* event) {
 | 
			
		||||
    auto* const sdl_state = static_cast<SDLState*>(user_data);
 | 
			
		||||
@ -48,8 +52,10 @@ static int SDLEventWatcher(void* user_data, SDL_Event* event) {
 | 
			
		||||
 | 
			
		||||
class SDLJoystick {
 | 
			
		||||
public:
 | 
			
		||||
    SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick)
 | 
			
		||||
        : guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose} {}
 | 
			
		||||
    SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick,
 | 
			
		||||
                SDL_GameController* gamecontroller)
 | 
			
		||||
        : guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose},
 | 
			
		||||
          sdl_controller{gamecontroller, &SDL_GameControllerClose} {}
 | 
			
		||||
 | 
			
		||||
    void SetButton(int button, bool value) {
 | 
			
		||||
        std::lock_guard lock{mutex};
 | 
			
		||||
@ -115,10 +121,15 @@ public:
 | 
			
		||||
        return sdl_joystick.get();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void SetSDLJoystick(SDL_Joystick* joystick) {
 | 
			
		||||
    void SetSDLJoystick(SDL_Joystick* joystick, SDL_GameController* controller) {
 | 
			
		||||
        sdl_controller.reset(controller);
 | 
			
		||||
        sdl_joystick.reset(joystick);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    SDL_GameController* GetSDLGameController() const {
 | 
			
		||||
        return sdl_controller.get();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    struct State {
 | 
			
		||||
        std::unordered_map<int, bool> buttons;
 | 
			
		||||
@ -128,6 +139,7 @@ private:
 | 
			
		||||
    std::string guid;
 | 
			
		||||
    int port;
 | 
			
		||||
    std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick;
 | 
			
		||||
    std::unique_ptr<SDL_GameController, decltype(&SDL_GameControllerClose)> sdl_controller;
 | 
			
		||||
    mutable std::mutex mutex;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -136,18 +148,19 @@ std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickByGUID(const std::string& g
 | 
			
		||||
    const auto it = joystick_map.find(guid);
 | 
			
		||||
    if (it != joystick_map.end()) {
 | 
			
		||||
        while (it->second.size() <= static_cast<std::size_t>(port)) {
 | 
			
		||||
            auto joystick =
 | 
			
		||||
                std::make_shared<SDLJoystick>(guid, static_cast<int>(it->second.size()), nullptr);
 | 
			
		||||
            auto joystick = std::make_shared<SDLJoystick>(guid, static_cast<int>(it->second.size()),
 | 
			
		||||
                                                          nullptr, nullptr);
 | 
			
		||||
            it->second.emplace_back(std::move(joystick));
 | 
			
		||||
        }
 | 
			
		||||
        return it->second[port];
 | 
			
		||||
    }
 | 
			
		||||
    auto joystick = std::make_shared<SDLJoystick>(guid, 0, nullptr);
 | 
			
		||||
    auto joystick = std::make_shared<SDLJoystick>(guid, 0, nullptr, nullptr);
 | 
			
		||||
    return joystick_map[guid].emplace_back(std::move(joystick));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) {
 | 
			
		||||
    auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id);
 | 
			
		||||
    auto sdl_controller = SDL_GameControllerFromInstanceID(sdl_id);
 | 
			
		||||
    const std::string guid = GetGUID(sdl_joystick);
 | 
			
		||||
 | 
			
		||||
    std::lock_guard lock{joystick_map_mutex};
 | 
			
		||||
@ -171,23 +184,27 @@ std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickBySDLID(SDL_JoystickID sdl_
 | 
			
		||||
                                             });
 | 
			
		||||
        if (nullptr_it != map_it->second.end()) {
 | 
			
		||||
            // ... and map it
 | 
			
		||||
            (*nullptr_it)->SetSDLJoystick(sdl_joystick);
 | 
			
		||||
            (*nullptr_it)->SetSDLJoystick(sdl_joystick, sdl_controller);
 | 
			
		||||
            return *nullptr_it;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // There is no SDLJoystick without a mapped SDL_Joystick
 | 
			
		||||
        // Create a new SDLJoystick
 | 
			
		||||
        const int port = static_cast<int>(map_it->second.size());
 | 
			
		||||
        auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick);
 | 
			
		||||
        auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick, sdl_controller);
 | 
			
		||||
        return map_it->second.emplace_back(std::move(joystick));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick);
 | 
			
		||||
    auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick, sdl_controller);
 | 
			
		||||
    return joystick_map[guid].emplace_back(std::move(joystick));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SDLState::InitJoystick(int joystick_index) {
 | 
			
		||||
    SDL_Joystick* sdl_joystick = SDL_JoystickOpen(joystick_index);
 | 
			
		||||
    SDL_GameController* sdl_gamecontroller = nullptr;
 | 
			
		||||
    if (SDL_IsGameController(joystick_index)) {
 | 
			
		||||
        sdl_gamecontroller = SDL_GameControllerOpen(joystick_index);
 | 
			
		||||
    }
 | 
			
		||||
    if (!sdl_joystick) {
 | 
			
		||||
        LOG_ERROR(Input, "failed to open joystick {}", joystick_index);
 | 
			
		||||
        return;
 | 
			
		||||
@ -196,7 +213,7 @@ void SDLState::InitJoystick(int joystick_index) {
 | 
			
		||||
 | 
			
		||||
    std::lock_guard lock{joystick_map_mutex};
 | 
			
		||||
    if (joystick_map.find(guid) == joystick_map.end()) {
 | 
			
		||||
        auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick);
 | 
			
		||||
        auto joystick = std::make_shared<SDLJoystick>(guid, 0, sdl_joystick, sdl_gamecontroller);
 | 
			
		||||
        joystick_map[guid].emplace_back(std::move(joystick));
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
@ -205,11 +222,11 @@ void SDLState::InitJoystick(int joystick_index) {
 | 
			
		||||
        joystick_guid_list.begin(), joystick_guid_list.end(),
 | 
			
		||||
        [](const std::shared_ptr<SDLJoystick>& joystick) { return !joystick->GetSDLJoystick(); });
 | 
			
		||||
    if (it != joystick_guid_list.end()) {
 | 
			
		||||
        (*it)->SetSDLJoystick(sdl_joystick);
 | 
			
		||||
        (*it)->SetSDLJoystick(sdl_joystick, sdl_gamecontroller);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    const int port = static_cast<int>(joystick_guid_list.size());
 | 
			
		||||
    auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick);
 | 
			
		||||
    auto joystick = std::make_shared<SDLJoystick>(guid, port, sdl_joystick, sdl_gamecontroller);
 | 
			
		||||
    joystick_guid_list.emplace_back(std::move(joystick));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -231,7 +248,7 @@ void SDLState::CloseJoystick(SDL_Joystick* sdl_joystick) {
 | 
			
		||||
 | 
			
		||||
    // Destruct SDL_Joystick outside the lock guard because SDL can internally call the
 | 
			
		||||
    // event callback which locks the mutex again.
 | 
			
		||||
    joystick->SetSDLJoystick(nullptr);
 | 
			
		||||
    joystick->SetSDLJoystick(nullptr, nullptr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SDLState::HandleGameControllerEvent(const SDL_Event& event) {
 | 
			
		||||
@ -346,7 +363,7 @@ public:
 | 
			
		||||
 | 
			
		||||
    bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override {
 | 
			
		||||
        const auto [x, y] = GetStatus();
 | 
			
		||||
        const float directional_deadzone = 0.4f;
 | 
			
		||||
        const float directional_deadzone = 0.5f;
 | 
			
		||||
        switch (direction) {
 | 
			
		||||
        case Input::AnalogDirection::RIGHT:
 | 
			
		||||
            return x > directional_deadzone;
 | 
			
		||||
@ -460,7 +477,7 @@ public:
 | 
			
		||||
        const int port = params.Get("port", 0);
 | 
			
		||||
        const int axis_x = params.Get("axis_x", 0);
 | 
			
		||||
        const int axis_y = params.Get("axis_y", 1);
 | 
			
		||||
        const float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, .99f);
 | 
			
		||||
        const float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f);
 | 
			
		||||
        const float range = std::clamp(params.Get("range", 1.0f), 0.50f, 1.50f);
 | 
			
		||||
        auto joystick = state.GetSDLJoystickByGUID(guid, port);
 | 
			
		||||
 | 
			
		||||
@ -476,8 +493,10 @@ private:
 | 
			
		||||
 | 
			
		||||
SDLState::SDLState() {
 | 
			
		||||
    using namespace Input;
 | 
			
		||||
    RegisterFactory<ButtonDevice>("sdl", std::make_shared<SDLButtonFactory>(*this));
 | 
			
		||||
    RegisterFactory<AnalogDevice>("sdl", std::make_shared<SDLAnalogFactory>(*this));
 | 
			
		||||
    analog_factory = std::make_shared<SDLAnalogFactory>(*this);
 | 
			
		||||
    button_factory = std::make_shared<SDLButtonFactory>(*this);
 | 
			
		||||
    RegisterFactory<AnalogDevice>("sdl", analog_factory);
 | 
			
		||||
    RegisterFactory<ButtonDevice>("sdl", button_factory);
 | 
			
		||||
 | 
			
		||||
    // If the frontend is going to manage the event loop, then we dont start one here
 | 
			
		||||
    start_thread = !SDL_WasInit(SDL_INIT_JOYSTICK);
 | 
			
		||||
@ -485,6 +504,7 @@ SDLState::SDLState() {
 | 
			
		||||
        LOG_CRITICAL(Input, "SDL_Init(SDL_INIT_JOYSTICK) failed with: {}", SDL_GetError());
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    has_gamecontroller = SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER);
 | 
			
		||||
    if (SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1") == SDL_FALSE) {
 | 
			
		||||
        LOG_ERROR(Input, "Failed to set hint for background events with: {}", SDL_GetError());
 | 
			
		||||
    }
 | 
			
		||||
@ -497,7 +517,7 @@ SDLState::SDLState() {
 | 
			
		||||
            using namespace std::chrono_literals;
 | 
			
		||||
            while (initialized) {
 | 
			
		||||
                SDL_PumpEvents();
 | 
			
		||||
                std::this_thread::sleep_for(10ms);
 | 
			
		||||
                std::this_thread::sleep_for(5ms);
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
@ -523,65 +543,221 @@ SDLState::~SDLState() {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) {
 | 
			
		||||
    Common::ParamPackage params({{"engine", "sdl"}});
 | 
			
		||||
std::vector<Common::ParamPackage> SDLState::GetInputDevices() {
 | 
			
		||||
    std::scoped_lock lock(joystick_map_mutex);
 | 
			
		||||
    std::vector<Common::ParamPackage> devices;
 | 
			
		||||
    for (const auto& [key, value] : joystick_map) {
 | 
			
		||||
        for (const auto& joystick : value) {
 | 
			
		||||
            auto joy = joystick->GetSDLJoystick();
 | 
			
		||||
            if (auto controller = joystick->GetSDLGameController()) {
 | 
			
		||||
                std::string name =
 | 
			
		||||
                    fmt::format("{} {}", SDL_GameControllerName(controller), joystick->GetPort());
 | 
			
		||||
                devices.emplace_back(Common::ParamPackage{
 | 
			
		||||
                    {"class", "sdl"},
 | 
			
		||||
                    {"display", std::move(name)},
 | 
			
		||||
                    {"guid", joystick->GetGUID()},
 | 
			
		||||
                    {"port", std::to_string(joystick->GetPort())},
 | 
			
		||||
                });
 | 
			
		||||
            } else if (joy) {
 | 
			
		||||
                std::string name = fmt::format("{} {}", SDL_JoystickName(joy), joystick->GetPort());
 | 
			
		||||
                devices.emplace_back(Common::ParamPackage{
 | 
			
		||||
                    {"class", "sdl"},
 | 
			
		||||
                    {"display", std::move(name)},
 | 
			
		||||
                    {"guid", joystick->GetGUID()},
 | 
			
		||||
                    {"port", std::to_string(joystick->GetPort())},
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return devices;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    switch (event.type) {
 | 
			
		||||
    case SDL_JOYAXISMOTION: {
 | 
			
		||||
        const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
 | 
			
		||||
        params.Set("port", joystick->GetPort());
 | 
			
		||||
        params.Set("guid", joystick->GetGUID());
 | 
			
		||||
        params.Set("axis", event.jaxis.axis);
 | 
			
		||||
        if (event.jaxis.value > 0) {
 | 
			
		||||
            params.Set("direction", "+");
 | 
			
		||||
            params.Set("threshold", "0.5");
 | 
			
		||||
        } else {
 | 
			
		||||
            params.Set("direction", "-");
 | 
			
		||||
            params.Set("threshold", "-0.5");
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    case SDL_JOYBUTTONUP: {
 | 
			
		||||
        const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which);
 | 
			
		||||
        params.Set("port", joystick->GetPort());
 | 
			
		||||
        params.Set("guid", joystick->GetGUID());
 | 
			
		||||
        params.Set("button", event.jbutton.button);
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    case SDL_JOYHATMOTION: {
 | 
			
		||||
        const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which);
 | 
			
		||||
        params.Set("port", joystick->GetPort());
 | 
			
		||||
        params.Set("guid", joystick->GetGUID());
 | 
			
		||||
        params.Set("hat", event.jhat.hat);
 | 
			
		||||
        switch (event.jhat.value) {
 | 
			
		||||
        case SDL_HAT_UP:
 | 
			
		||||
            params.Set("direction", "up");
 | 
			
		||||
            break;
 | 
			
		||||
        case SDL_HAT_DOWN:
 | 
			
		||||
            params.Set("direction", "down");
 | 
			
		||||
            break;
 | 
			
		||||
        case SDL_HAT_LEFT:
 | 
			
		||||
            params.Set("direction", "left");
 | 
			
		||||
            break;
 | 
			
		||||
        case SDL_HAT_RIGHT:
 | 
			
		||||
            params.Set("direction", "right");
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            return {};
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
namespace {
 | 
			
		||||
Common::ParamPackage BuildAnalogParamPackageForButton(int port, std::string guid, u8 axis,
 | 
			
		||||
                                                      float value = 0.1) {
 | 
			
		||||
    Common::ParamPackage params({{"engine", "sdl"}});
 | 
			
		||||
    params.Set("port", port);
 | 
			
		||||
    params.Set("guid", guid);
 | 
			
		||||
    params.Set("axis", axis);
 | 
			
		||||
    if (value > 0) {
 | 
			
		||||
        params.Set("direction", "+");
 | 
			
		||||
        params.Set("threshold", "0.5");
 | 
			
		||||
    } else {
 | 
			
		||||
        params.Set("direction", "-");
 | 
			
		||||
        params.Set("threshold", "-0.5");
 | 
			
		||||
    }
 | 
			
		||||
    return params;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace Polling {
 | 
			
		||||
Common::ParamPackage BuildButtonParamPackageForButton(int port, std::string guid, u8 button) {
 | 
			
		||||
    Common::ParamPackage params({{"engine", "sdl"}});
 | 
			
		||||
    params.Set("port", port);
 | 
			
		||||
    params.Set("guid", guid);
 | 
			
		||||
    params.Set("button", button);
 | 
			
		||||
    return params;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Common::ParamPackage BuildHatParamPackageForButton(int port, std::string guid, u8 hat, u8 value) {
 | 
			
		||||
    Common::ParamPackage params({{"engine", "sdl"}});
 | 
			
		||||
 | 
			
		||||
    params.Set("port", port);
 | 
			
		||||
    params.Set("guid", guid);
 | 
			
		||||
    params.Set("hat", hat);
 | 
			
		||||
    switch (value) {
 | 
			
		||||
    case SDL_HAT_UP:
 | 
			
		||||
        params.Set("direction", "up");
 | 
			
		||||
        break;
 | 
			
		||||
    case SDL_HAT_DOWN:
 | 
			
		||||
        params.Set("direction", "down");
 | 
			
		||||
        break;
 | 
			
		||||
    case SDL_HAT_LEFT:
 | 
			
		||||
        params.Set("direction", "left");
 | 
			
		||||
        break;
 | 
			
		||||
    case SDL_HAT_RIGHT:
 | 
			
		||||
        params.Set("direction", "right");
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
        return {};
 | 
			
		||||
    }
 | 
			
		||||
    return params;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) {
 | 
			
		||||
    switch (event.type) {
 | 
			
		||||
    case SDL_JOYAXISMOTION: {
 | 
			
		||||
        const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
 | 
			
		||||
        return BuildAnalogParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
 | 
			
		||||
                                                event.jaxis.axis, event.jaxis.value);
 | 
			
		||||
    }
 | 
			
		||||
    case SDL_JOYBUTTONUP: {
 | 
			
		||||
        const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which);
 | 
			
		||||
        return BuildButtonParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
 | 
			
		||||
                                                event.jbutton.button);
 | 
			
		||||
    }
 | 
			
		||||
    case SDL_JOYHATMOTION: {
 | 
			
		||||
        const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which);
 | 
			
		||||
        return BuildHatParamPackageForButton(joystick->GetPort(), joystick->GetGUID(),
 | 
			
		||||
                                             event.jhat.hat, event.jhat.value);
 | 
			
		||||
    }
 | 
			
		||||
    }
 | 
			
		||||
    return {};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Common::ParamPackage BuildParamPackageForBinding(int port, const std::string& guid,
 | 
			
		||||
                                                 const SDL_GameControllerButtonBind& binding) {
 | 
			
		||||
    switch (binding.bindType) {
 | 
			
		||||
    case SDL_CONTROLLER_BINDTYPE_AXIS:
 | 
			
		||||
        return BuildAnalogParamPackageForButton(port, guid, binding.value.axis);
 | 
			
		||||
    case SDL_CONTROLLER_BINDTYPE_BUTTON:
 | 
			
		||||
        return BuildButtonParamPackageForButton(port, guid, binding.value.button);
 | 
			
		||||
    case SDL_CONTROLLER_BINDTYPE_HAT:
 | 
			
		||||
        return BuildHatParamPackageForButton(port, guid, binding.value.hat.hat,
 | 
			
		||||
                                             binding.value.hat.hat_mask);
 | 
			
		||||
    }
 | 
			
		||||
    return {};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Common::ParamPackage BuildParamPackageForAnalog(int port, const std::string& guid, int axis_x,
 | 
			
		||||
                                                int axis_y) {
 | 
			
		||||
    Common::ParamPackage params;
 | 
			
		||||
    params.Set("engine", "sdl");
 | 
			
		||||
    params.Set("port", port);
 | 
			
		||||
    params.Set("guid", guid);
 | 
			
		||||
    params.Set("axis_x", axis_x);
 | 
			
		||||
    params.Set("axis_y", axis_y);
 | 
			
		||||
    return params;
 | 
			
		||||
}
 | 
			
		||||
} // Anonymous namespace
 | 
			
		||||
 | 
			
		||||
ButtonMapping SDLState::GetButtonMappingForDevice(const Common::ParamPackage& params) {
 | 
			
		||||
    // This list is missing ZL/ZR since those are not considered buttons in SDL GameController.
 | 
			
		||||
    // We will add those afterwards
 | 
			
		||||
    // This list also excludes Screenshot since theres not really a mapping for that
 | 
			
		||||
    std::unordered_map<Settings::NativeButton::Values, SDL_GameControllerButton>
 | 
			
		||||
        switch_to_sdl_button = {
 | 
			
		||||
            {Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_B},
 | 
			
		||||
            {Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_A},
 | 
			
		||||
            {Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_Y},
 | 
			
		||||
            {Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_X},
 | 
			
		||||
            {Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK},
 | 
			
		||||
            {Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK},
 | 
			
		||||
            {Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
 | 
			
		||||
            {Settings::NativeButton::R, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
 | 
			
		||||
            {Settings::NativeButton::Plus, SDL_CONTROLLER_BUTTON_START},
 | 
			
		||||
            {Settings::NativeButton::Minus, SDL_CONTROLLER_BUTTON_BACK},
 | 
			
		||||
            {Settings::NativeButton::DLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT},
 | 
			
		||||
            {Settings::NativeButton::DUp, SDL_CONTROLLER_BUTTON_DPAD_UP},
 | 
			
		||||
            {Settings::NativeButton::DRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT},
 | 
			
		||||
            {Settings::NativeButton::DDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN},
 | 
			
		||||
            {Settings::NativeButton::SL, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
 | 
			
		||||
            {Settings::NativeButton::SR, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
 | 
			
		||||
            {Settings::NativeButton::Home, SDL_CONTROLLER_BUTTON_GUIDE},
 | 
			
		||||
        };
 | 
			
		||||
    if (!params.Has("guid") || !params.Has("port")) {
 | 
			
		||||
        return {};
 | 
			
		||||
    }
 | 
			
		||||
    const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
 | 
			
		||||
    auto controller = joystick->GetSDLGameController();
 | 
			
		||||
    if (!controller) {
 | 
			
		||||
        return {};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ButtonMapping mapping{};
 | 
			
		||||
    for (const auto& [switch_button, sdl_button] : switch_to_sdl_button) {
 | 
			
		||||
        const auto& binding = SDL_GameControllerGetBindForButton(controller, sdl_button);
 | 
			
		||||
        mapping[switch_button] =
 | 
			
		||||
            BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Add the missing bindings for ZL/ZR
 | 
			
		||||
    std::unordered_map<Settings::NativeButton::Values, SDL_GameControllerAxis> switch_to_sdl_axis =
 | 
			
		||||
        {
 | 
			
		||||
            {Settings::NativeButton::ZL, SDL_CONTROLLER_AXIS_TRIGGERLEFT},
 | 
			
		||||
            {Settings::NativeButton::ZR, SDL_CONTROLLER_AXIS_TRIGGERRIGHT},
 | 
			
		||||
        };
 | 
			
		||||
    for (const auto& [switch_button, sdl_axis] : switch_to_sdl_axis) {
 | 
			
		||||
        const auto& binding = SDL_GameControllerGetBindForAxis(controller, sdl_axis);
 | 
			
		||||
        mapping[switch_button] =
 | 
			
		||||
            BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return mapping;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AnalogMapping SDLState::GetAnalogMappingForDevice(const Common::ParamPackage& params) {
 | 
			
		||||
    if (!params.Has("guid") || !params.Has("port")) {
 | 
			
		||||
        return {};
 | 
			
		||||
    }
 | 
			
		||||
    const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
 | 
			
		||||
    auto controller = joystick->GetSDLGameController();
 | 
			
		||||
    if (!controller) {
 | 
			
		||||
        return {};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    AnalogMapping mapping = {};
 | 
			
		||||
    const auto& binding_left_x =
 | 
			
		||||
        SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX);
 | 
			
		||||
    const auto& binding_left_y =
 | 
			
		||||
        SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY);
 | 
			
		||||
    mapping[Settings::NativeAnalog::LStick] =
 | 
			
		||||
        BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
 | 
			
		||||
                                   binding_left_x.value.axis, binding_left_y.value.axis);
 | 
			
		||||
    const auto& binding_right_x =
 | 
			
		||||
        SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX);
 | 
			
		||||
    const auto& binding_right_y =
 | 
			
		||||
        SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY);
 | 
			
		||||
    mapping[Settings::NativeAnalog::RStick] =
 | 
			
		||||
        BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
 | 
			
		||||
                                   binding_right_x.value.axis, binding_right_y.value.axis);
 | 
			
		||||
    return mapping;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace Polling {
 | 
			
		||||
class SDLPoller : public InputCommon::Polling::DevicePoller {
 | 
			
		||||
public:
 | 
			
		||||
    explicit SDLPoller(SDLState& state_) : state(state_) {}
 | 
			
		||||
 | 
			
		||||
    void Start() override {
 | 
			
		||||
    void Start(const std::string& device_id) override {
 | 
			
		||||
        state.event_queue.Clear();
 | 
			
		||||
        state.polling = true;
 | 
			
		||||
    }
 | 
			
		||||
@ -601,71 +777,106 @@ public:
 | 
			
		||||
    Common::ParamPackage GetNextInput() override {
 | 
			
		||||
        SDL_Event event;
 | 
			
		||||
        while (state.event_queue.Pop(event)) {
 | 
			
		||||
            switch (event.type) {
 | 
			
		||||
            case SDL_JOYAXISMOTION:
 | 
			
		||||
                if (std::abs(event.jaxis.value / 32767.0) < 0.5) {
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                [[fallthrough]];
 | 
			
		||||
            case SDL_JOYBUTTONUP:
 | 
			
		||||
            case SDL_JOYHATMOTION:
 | 
			
		||||
                return SDLEventToButtonParamPackage(state, event);
 | 
			
		||||
            const auto package = FromEvent(event);
 | 
			
		||||
            if (package) {
 | 
			
		||||
                return *package;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return {};
 | 
			
		||||
    }
 | 
			
		||||
    std::optional<Common::ParamPackage> FromEvent(const SDL_Event& event) {
 | 
			
		||||
        switch (event.type) {
 | 
			
		||||
        case SDL_JOYAXISMOTION:
 | 
			
		||||
            if (std::abs(event.jaxis.value / 32767.0) < 0.5) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            [[fallthrough]];
 | 
			
		||||
        case SDL_JOYBUTTONUP:
 | 
			
		||||
        case SDL_JOYHATMOTION:
 | 
			
		||||
            return {SDLEventToButtonParamPackage(state, event)};
 | 
			
		||||
        }
 | 
			
		||||
        return {};
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class SDLAnalogPoller final : public SDLPoller {
 | 
			
		||||
/**
 | 
			
		||||
 * Attempts to match the press to a controller joy axis (left/right stick) and if a match
 | 
			
		||||
 * isn't found, checks if the event matches anything from SDLButtonPoller and uses that
 | 
			
		||||
 * instead
 | 
			
		||||
 */
 | 
			
		||||
class SDLAnalogPreferredPoller final : public SDLPoller {
 | 
			
		||||
public:
 | 
			
		||||
    explicit SDLAnalogPoller(SDLState& state_) : SDLPoller(state_) {}
 | 
			
		||||
 | 
			
		||||
    void Start() override {
 | 
			
		||||
        SDLPoller::Start();
 | 
			
		||||
    explicit SDLAnalogPreferredPoller(SDLState& state_)
 | 
			
		||||
        : SDLPoller(state_), button_poller(state_) {}
 | 
			
		||||
 | 
			
		||||
    void Start(const std::string& device_id) override {
 | 
			
		||||
        SDLPoller::Start(device_id);
 | 
			
		||||
        // Load the game controller
 | 
			
		||||
        // Reset stored axes
 | 
			
		||||
        analog_x_axis = -1;
 | 
			
		||||
        analog_y_axis = -1;
 | 
			
		||||
        analog_axes_joystick = -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Common::ParamPackage GetNextInput() override {
 | 
			
		||||
        SDL_Event event;
 | 
			
		||||
        while (state.event_queue.Pop(event)) {
 | 
			
		||||
            if (event.type != SDL_JOYAXISMOTION || std::abs(event.jaxis.value / 32767.0) < 0.5) {
 | 
			
		||||
            // Filter out axis events that are below a threshold
 | 
			
		||||
            if (event.type == SDL_JOYAXISMOTION && std::abs(event.jaxis.value / 32767.0) < 0.5) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            // An analog device needs two axes, so we need to store the axis for later and wait for
 | 
			
		||||
            // a second SDL event. The axes also must be from the same joystick.
 | 
			
		||||
            const int axis = event.jaxis.axis;
 | 
			
		||||
            if (analog_x_axis == -1) {
 | 
			
		||||
                analog_x_axis = axis;
 | 
			
		||||
                analog_axes_joystick = event.jaxis.which;
 | 
			
		||||
            } else if (analog_y_axis == -1 && analog_x_axis != axis &&
 | 
			
		||||
                       analog_axes_joystick == event.jaxis.which) {
 | 
			
		||||
                analog_y_axis = axis;
 | 
			
		||||
            // Simplify controller config by testing if game controller support is enabled.
 | 
			
		||||
            if (event.type == SDL_JOYAXISMOTION) {
 | 
			
		||||
                const auto axis = event.jaxis.axis;
 | 
			
		||||
                const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
 | 
			
		||||
                const auto controller = joystick->GetSDLGameController();
 | 
			
		||||
                if (controller) {
 | 
			
		||||
                    const auto axis_left_x =
 | 
			
		||||
                        SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX)
 | 
			
		||||
                            .value.axis;
 | 
			
		||||
                    const auto axis_left_y =
 | 
			
		||||
                        SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY)
 | 
			
		||||
                            .value.axis;
 | 
			
		||||
                    const auto axis_right_x =
 | 
			
		||||
                        SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX)
 | 
			
		||||
                            .value.axis;
 | 
			
		||||
                    const auto axis_right_y =
 | 
			
		||||
                        SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY)
 | 
			
		||||
                            .value.axis;
 | 
			
		||||
 | 
			
		||||
                    if (axis == axis_left_x || axis == axis_left_y) {
 | 
			
		||||
                        analog_x_axis = axis_left_x;
 | 
			
		||||
                        analog_y_axis = axis_left_y;
 | 
			
		||||
                        break;
 | 
			
		||||
                    } else if (axis == axis_right_x || axis == axis_right_y) {
 | 
			
		||||
                        analog_x_axis = axis_right_x;
 | 
			
		||||
                        analog_y_axis = axis_right_y;
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // If the press wasn't accepted as a joy axis, check for a button press
 | 
			
		||||
            auto button_press = button_poller.FromEvent(event);
 | 
			
		||||
            if (button_press) {
 | 
			
		||||
                return *button_press;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        Common::ParamPackage params;
 | 
			
		||||
 | 
			
		||||
        if (analog_x_axis != -1 && analog_y_axis != -1) {
 | 
			
		||||
            const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which);
 | 
			
		||||
            params.Set("engine", "sdl");
 | 
			
		||||
            params.Set("port", joystick->GetPort());
 | 
			
		||||
            params.Set("guid", joystick->GetGUID());
 | 
			
		||||
            params.Set("axis_x", analog_x_axis);
 | 
			
		||||
            params.Set("axis_y", analog_y_axis);
 | 
			
		||||
            auto params = BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
 | 
			
		||||
                                                     analog_x_axis, analog_y_axis);
 | 
			
		||||
            analog_x_axis = -1;
 | 
			
		||||
            analog_y_axis = -1;
 | 
			
		||||
            analog_axes_joystick = -1;
 | 
			
		||||
            return params;
 | 
			
		||||
        }
 | 
			
		||||
        return params;
 | 
			
		||||
        return {};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    int analog_x_axis = -1;
 | 
			
		||||
    int analog_y_axis = -1;
 | 
			
		||||
    SDL_JoystickID analog_axes_joystick = -1;
 | 
			
		||||
    SDLButtonPoller button_poller;
 | 
			
		||||
};
 | 
			
		||||
} // namespace Polling
 | 
			
		||||
 | 
			
		||||
@ -673,8 +884,8 @@ SDLState::Pollers SDLState::GetPollers(InputCommon::Polling::DeviceType type) {
 | 
			
		||||
    Pollers pollers;
 | 
			
		||||
 | 
			
		||||
    switch (type) {
 | 
			
		||||
    case InputCommon::Polling::DeviceType::Analog:
 | 
			
		||||
        pollers.emplace_back(std::make_unique<Polling::SDLAnalogPoller>(*this));
 | 
			
		||||
    case InputCommon::Polling::DeviceType::AnalogPreferred:
 | 
			
		||||
        pollers.emplace_back(std::make_unique<Polling::SDLAnalogPreferredPoller>(*this));
 | 
			
		||||
        break;
 | 
			
		||||
    case InputCommon::Polling::DeviceType::Button:
 | 
			
		||||
        pollers.emplace_back(std::make_unique<Polling::SDLButtonPoller>(*this));
 | 
			
		||||
 | 
			
		||||
@ -50,6 +50,11 @@ public:
 | 
			
		||||
    std::atomic<bool> polling = false;
 | 
			
		||||
    Common::SPSCQueue<SDL_Event> event_queue;
 | 
			
		||||
 | 
			
		||||
    std::vector<Common::ParamPackage> GetInputDevices() override;
 | 
			
		||||
 | 
			
		||||
    ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) override;
 | 
			
		||||
    AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void InitJoystick(int joystick_index);
 | 
			
		||||
    void CloseJoystick(SDL_Joystick* sdl_joystick);
 | 
			
		||||
@ -57,6 +62,9 @@ private:
 | 
			
		||||
    /// Needs to be called before SDL_QuitSubSystem.
 | 
			
		||||
    void CloseJoysticks();
 | 
			
		||||
 | 
			
		||||
    // Set to true if SDL supports game controller subsystem
 | 
			
		||||
    bool has_gamecontroller = false;
 | 
			
		||||
 | 
			
		||||
    /// Map of GUID of a list of corresponding virtual Joysticks
 | 
			
		||||
    std::unordered_map<std::string, std::vector<std::shared_ptr<SDLJoystick>>> joystick_map;
 | 
			
		||||
    std::mutex joystick_map_mutex;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										33
									
								
								src/input_common/settings.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,33 @@
 | 
			
		||||
// Copyright 2020 yuzu Emulator Project
 | 
			
		||||
// Licensed under GPLv2 or any later version
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#include "input_common/settings.h"
 | 
			
		||||
 | 
			
		||||
namespace Settings {
 | 
			
		||||
namespace NativeButton {
 | 
			
		||||
const std::array<const char*, NumButtons> mapping = {{
 | 
			
		||||
    "button_a",      "button_b",     "button_x",     "button_y",    "button_lstick",
 | 
			
		||||
    "button_rstick", "button_l",     "button_r",     "button_zl",   "button_zr",
 | 
			
		||||
    "button_plus",   "button_minus", "button_dleft", "button_dup",  "button_dright",
 | 
			
		||||
    "button_ddown",  "button_sl",    "button_sr",    "button_home", "button_screenshot",
 | 
			
		||||
}};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace NativeAnalog {
 | 
			
		||||
const std::array<const char*, NumAnalogs> mapping = {{
 | 
			
		||||
    "lstick",
 | 
			
		||||
    "rstick",
 | 
			
		||||
}};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace NativeMouseButton {
 | 
			
		||||
const std::array<const char*, NumMouseButtons> mapping = {{
 | 
			
		||||
    "left",
 | 
			
		||||
    "right",
 | 
			
		||||
    "middle",
 | 
			
		||||
    "forward",
 | 
			
		||||
    "back",
 | 
			
		||||
}};
 | 
			
		||||
}
 | 
			
		||||
} // namespace Settings
 | 
			
		||||
							
								
								
									
										335
									
								
								src/input_common/settings.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,335 @@
 | 
			
		||||
// Copyright 2020 yuzu Emulator Project
 | 
			
		||||
// Licensed under GPLv2 or any later version
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
 | 
			
		||||
namespace Settings {
 | 
			
		||||
namespace NativeButton {
 | 
			
		||||
enum Values {
 | 
			
		||||
    A,
 | 
			
		||||
    B,
 | 
			
		||||
    X,
 | 
			
		||||
    Y,
 | 
			
		||||
    LStick,
 | 
			
		||||
    RStick,
 | 
			
		||||
    L,
 | 
			
		||||
    R,
 | 
			
		||||
    ZL,
 | 
			
		||||
    ZR,
 | 
			
		||||
    Plus,
 | 
			
		||||
    Minus,
 | 
			
		||||
 | 
			
		||||
    DLeft,
 | 
			
		||||
    DUp,
 | 
			
		||||
    DRight,
 | 
			
		||||
    DDown,
 | 
			
		||||
 | 
			
		||||
    SL,
 | 
			
		||||
    SR,
 | 
			
		||||
 | 
			
		||||
    Home,
 | 
			
		||||
    Screenshot,
 | 
			
		||||
 | 
			
		||||
    NumButtons,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
constexpr int BUTTON_HID_BEGIN = A;
 | 
			
		||||
constexpr int BUTTON_NS_BEGIN = Home;
 | 
			
		||||
 | 
			
		||||
constexpr int BUTTON_HID_END = BUTTON_NS_BEGIN;
 | 
			
		||||
constexpr int BUTTON_NS_END = NumButtons;
 | 
			
		||||
 | 
			
		||||
constexpr int NUM_BUTTONS_HID = BUTTON_HID_END - BUTTON_HID_BEGIN;
 | 
			
		||||
constexpr int NUM_BUTTONS_NS = BUTTON_NS_END - BUTTON_NS_BEGIN;
 | 
			
		||||
 | 
			
		||||
extern const std::array<const char*, NumButtons> mapping;
 | 
			
		||||
 | 
			
		||||
} // namespace NativeButton
 | 
			
		||||
 | 
			
		||||
namespace NativeAnalog {
 | 
			
		||||
enum Values {
 | 
			
		||||
    LStick,
 | 
			
		||||
    RStick,
 | 
			
		||||
 | 
			
		||||
    NumAnalogs,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
constexpr int STICK_HID_BEGIN = LStick;
 | 
			
		||||
constexpr int STICK_HID_END = NumAnalogs;
 | 
			
		||||
constexpr int NUM_STICKS_HID = NumAnalogs;
 | 
			
		||||
 | 
			
		||||
extern const std::array<const char*, NumAnalogs> mapping;
 | 
			
		||||
} // namespace NativeAnalog
 | 
			
		||||
 | 
			
		||||
namespace NativeMouseButton {
 | 
			
		||||
enum Values {
 | 
			
		||||
    Left,
 | 
			
		||||
    Right,
 | 
			
		||||
    Middle,
 | 
			
		||||
    Forward,
 | 
			
		||||
    Back,
 | 
			
		||||
 | 
			
		||||
    NumMouseButtons,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
constexpr int MOUSE_HID_BEGIN = Left;
 | 
			
		||||
constexpr int MOUSE_HID_END = NumMouseButtons;
 | 
			
		||||
constexpr int NUM_MOUSE_HID = NumMouseButtons;
 | 
			
		||||
 | 
			
		||||
extern const std::array<const char*, NumMouseButtons> mapping;
 | 
			
		||||
} // namespace NativeMouseButton
 | 
			
		||||
 | 
			
		||||
namespace NativeKeyboard {
 | 
			
		||||
enum Keys {
 | 
			
		||||
    None,
 | 
			
		||||
    Error,
 | 
			
		||||
 | 
			
		||||
    A = 4,
 | 
			
		||||
    B,
 | 
			
		||||
    C,
 | 
			
		||||
    D,
 | 
			
		||||
    E,
 | 
			
		||||
    F,
 | 
			
		||||
    G,
 | 
			
		||||
    H,
 | 
			
		||||
    I,
 | 
			
		||||
    J,
 | 
			
		||||
    K,
 | 
			
		||||
    L,
 | 
			
		||||
    M,
 | 
			
		||||
    N,
 | 
			
		||||
    O,
 | 
			
		||||
    P,
 | 
			
		||||
    Q,
 | 
			
		||||
    R,
 | 
			
		||||
    S,
 | 
			
		||||
    T,
 | 
			
		||||
    U,
 | 
			
		||||
    V,
 | 
			
		||||
    W,
 | 
			
		||||
    X,
 | 
			
		||||
    Y,
 | 
			
		||||
    Z,
 | 
			
		||||
    N1,
 | 
			
		||||
    N2,
 | 
			
		||||
    N3,
 | 
			
		||||
    N4,
 | 
			
		||||
    N5,
 | 
			
		||||
    N6,
 | 
			
		||||
    N7,
 | 
			
		||||
    N8,
 | 
			
		||||
    N9,
 | 
			
		||||
    N0,
 | 
			
		||||
    Enter,
 | 
			
		||||
    Escape,
 | 
			
		||||
    Backspace,
 | 
			
		||||
    Tab,
 | 
			
		||||
    Space,
 | 
			
		||||
    Minus,
 | 
			
		||||
    Equal,
 | 
			
		||||
    LeftBrace,
 | 
			
		||||
    RightBrace,
 | 
			
		||||
    Backslash,
 | 
			
		||||
    Tilde,
 | 
			
		||||
    Semicolon,
 | 
			
		||||
    Apostrophe,
 | 
			
		||||
    Grave,
 | 
			
		||||
    Comma,
 | 
			
		||||
    Dot,
 | 
			
		||||
    Slash,
 | 
			
		||||
    CapsLockKey,
 | 
			
		||||
 | 
			
		||||
    F1,
 | 
			
		||||
    F2,
 | 
			
		||||
    F3,
 | 
			
		||||
    F4,
 | 
			
		||||
    F5,
 | 
			
		||||
    F6,
 | 
			
		||||
    F7,
 | 
			
		||||
    F8,
 | 
			
		||||
    F9,
 | 
			
		||||
    F10,
 | 
			
		||||
    F11,
 | 
			
		||||
    F12,
 | 
			
		||||
 | 
			
		||||
    SystemRequest,
 | 
			
		||||
    ScrollLockKey,
 | 
			
		||||
    Pause,
 | 
			
		||||
    Insert,
 | 
			
		||||
    Home,
 | 
			
		||||
    PageUp,
 | 
			
		||||
    Delete,
 | 
			
		||||
    End,
 | 
			
		||||
    PageDown,
 | 
			
		||||
    Right,
 | 
			
		||||
    Left,
 | 
			
		||||
    Down,
 | 
			
		||||
    Up,
 | 
			
		||||
 | 
			
		||||
    NumLockKey,
 | 
			
		||||
    KPSlash,
 | 
			
		||||
    KPAsterisk,
 | 
			
		||||
    KPMinus,
 | 
			
		||||
    KPPlus,
 | 
			
		||||
    KPEnter,
 | 
			
		||||
    KP1,
 | 
			
		||||
    KP2,
 | 
			
		||||
    KP3,
 | 
			
		||||
    KP4,
 | 
			
		||||
    KP5,
 | 
			
		||||
    KP6,
 | 
			
		||||
    KP7,
 | 
			
		||||
    KP8,
 | 
			
		||||
    KP9,
 | 
			
		||||
    KP0,
 | 
			
		||||
    KPDot,
 | 
			
		||||
 | 
			
		||||
    Key102,
 | 
			
		||||
    Compose,
 | 
			
		||||
    Power,
 | 
			
		||||
    KPEqual,
 | 
			
		||||
 | 
			
		||||
    F13,
 | 
			
		||||
    F14,
 | 
			
		||||
    F15,
 | 
			
		||||
    F16,
 | 
			
		||||
    F17,
 | 
			
		||||
    F18,
 | 
			
		||||
    F19,
 | 
			
		||||
    F20,
 | 
			
		||||
    F21,
 | 
			
		||||
    F22,
 | 
			
		||||
    F23,
 | 
			
		||||
    F24,
 | 
			
		||||
 | 
			
		||||
    Open,
 | 
			
		||||
    Help,
 | 
			
		||||
    Properties,
 | 
			
		||||
    Front,
 | 
			
		||||
    Stop,
 | 
			
		||||
    Repeat,
 | 
			
		||||
    Undo,
 | 
			
		||||
    Cut,
 | 
			
		||||
    Copy,
 | 
			
		||||
    Paste,
 | 
			
		||||
    Find,
 | 
			
		||||
    Mute,
 | 
			
		||||
    VolumeUp,
 | 
			
		||||
    VolumeDown,
 | 
			
		||||
    CapsLockActive,
 | 
			
		||||
    NumLockActive,
 | 
			
		||||
    ScrollLockActive,
 | 
			
		||||
    KPComma,
 | 
			
		||||
 | 
			
		||||
    KPLeftParenthesis,
 | 
			
		||||
    KPRightParenthesis,
 | 
			
		||||
 | 
			
		||||
    LeftControlKey = 0xE0,
 | 
			
		||||
    LeftShiftKey,
 | 
			
		||||
    LeftAltKey,
 | 
			
		||||
    LeftMetaKey,
 | 
			
		||||
    RightControlKey,
 | 
			
		||||
    RightShiftKey,
 | 
			
		||||
    RightAltKey,
 | 
			
		||||
    RightMetaKey,
 | 
			
		||||
 | 
			
		||||
    MediaPlayPause,
 | 
			
		||||
    MediaStopCD,
 | 
			
		||||
    MediaPrevious,
 | 
			
		||||
    MediaNext,
 | 
			
		||||
    MediaEject,
 | 
			
		||||
    MediaVolumeUp,
 | 
			
		||||
    MediaVolumeDown,
 | 
			
		||||
    MediaMute,
 | 
			
		||||
    MediaWebsite,
 | 
			
		||||
    MediaBack,
 | 
			
		||||
    MediaForward,
 | 
			
		||||
    MediaStop,
 | 
			
		||||
    MediaFind,
 | 
			
		||||
    MediaScrollUp,
 | 
			
		||||
    MediaScrollDown,
 | 
			
		||||
    MediaEdit,
 | 
			
		||||
    MediaSleep,
 | 
			
		||||
    MediaCoffee,
 | 
			
		||||
    MediaRefresh,
 | 
			
		||||
    MediaCalculator,
 | 
			
		||||
 | 
			
		||||
    NumKeyboardKeys,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static_assert(NumKeyboardKeys == 0xFC, "Incorrect number of keyboard keys.");
 | 
			
		||||
 | 
			
		||||
enum Modifiers {
 | 
			
		||||
    LeftControl,
 | 
			
		||||
    LeftShift,
 | 
			
		||||
    LeftAlt,
 | 
			
		||||
    LeftMeta,
 | 
			
		||||
    RightControl,
 | 
			
		||||
    RightShift,
 | 
			
		||||
    RightAlt,
 | 
			
		||||
    RightMeta,
 | 
			
		||||
    CapsLock,
 | 
			
		||||
    ScrollLock,
 | 
			
		||||
    NumLock,
 | 
			
		||||
 | 
			
		||||
    NumKeyboardMods,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
constexpr int KEYBOARD_KEYS_HID_BEGIN = None;
 | 
			
		||||
constexpr int KEYBOARD_KEYS_HID_END = NumKeyboardKeys;
 | 
			
		||||
constexpr int NUM_KEYBOARD_KEYS_HID = NumKeyboardKeys;
 | 
			
		||||
 | 
			
		||||
constexpr int KEYBOARD_MODS_HID_BEGIN = LeftControl;
 | 
			
		||||
constexpr int KEYBOARD_MODS_HID_END = NumKeyboardMods;
 | 
			
		||||
constexpr int NUM_KEYBOARD_MODS_HID = NumKeyboardMods;
 | 
			
		||||
 | 
			
		||||
} // namespace NativeKeyboard
 | 
			
		||||
 | 
			
		||||
using ButtonsRaw = std::array<std::string, NativeButton::NumButtons>;
 | 
			
		||||
using AnalogsRaw = std::array<std::string, NativeAnalog::NumAnalogs>;
 | 
			
		||||
using MouseButtonsRaw = std::array<std::string, NativeMouseButton::NumMouseButtons>;
 | 
			
		||||
using KeyboardKeysRaw = std::array<std::string, NativeKeyboard::NumKeyboardKeys>;
 | 
			
		||||
using KeyboardModsRaw = std::array<std::string, NativeKeyboard::NumKeyboardMods>;
 | 
			
		||||
 | 
			
		||||
constexpr u32 JOYCON_BODY_NEON_RED = 0xFF3C28;
 | 
			
		||||
constexpr u32 JOYCON_BUTTONS_NEON_RED = 0x1E0A0A;
 | 
			
		||||
constexpr u32 JOYCON_BODY_NEON_BLUE = 0x0AB9E6;
 | 
			
		||||
constexpr u32 JOYCON_BUTTONS_NEON_BLUE = 0x001E1E;
 | 
			
		||||
 | 
			
		||||
enum class ControllerType {
 | 
			
		||||
    ProController,
 | 
			
		||||
    DualJoyconDetached,
 | 
			
		||||
    LeftJoycon,
 | 
			
		||||
    RightJoycon,
 | 
			
		||||
    Handheld,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct PlayerInput {
 | 
			
		||||
    bool connected;
 | 
			
		||||
    ControllerType controller_type;
 | 
			
		||||
    ButtonsRaw buttons;
 | 
			
		||||
    AnalogsRaw analogs;
 | 
			
		||||
    std::string lstick_mod;
 | 
			
		||||
    std::string rstick_mod;
 | 
			
		||||
 | 
			
		||||
    u32 body_color_left;
 | 
			
		||||
    u32 body_color_right;
 | 
			
		||||
    u32 button_color_left;
 | 
			
		||||
    u32 button_color_right;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct TouchscreenInput {
 | 
			
		||||
    bool enabled;
 | 
			
		||||
    std::string device;
 | 
			
		||||
 | 
			
		||||
    u32 finger;
 | 
			
		||||
    u32 diameter_x;
 | 
			
		||||
    u32 diameter_y;
 | 
			
		||||
    u32 rotation_angle;
 | 
			
		||||
};
 | 
			
		||||
} // namespace Settings
 | 
			
		||||
@ -77,10 +77,11 @@ State::State() {
 | 
			
		||||
        std::make_unique<Client>(status, Settings::values.udp_input_address,
 | 
			
		||||
                                 Settings::values.udp_input_port, Settings::values.udp_pad_index);
 | 
			
		||||
 | 
			
		||||
    Input::RegisterFactory<Input::TouchDevice>("cemuhookudp",
 | 
			
		||||
                                               std::make_shared<UDPTouchFactory>(status));
 | 
			
		||||
    Input::RegisterFactory<Input::MotionDevice>("cemuhookudp",
 | 
			
		||||
                                                std::make_shared<UDPMotionFactory>(status));
 | 
			
		||||
    motion_factory = std::make_shared<UDPMotionFactory>(status);
 | 
			
		||||
    touch_factory = std::make_shared<UDPTouchFactory>(status);
 | 
			
		||||
 | 
			
		||||
    Input::RegisterFactory<Input::MotionDevice>("cemuhookudp", motion_factory);
 | 
			
		||||
    Input::RegisterFactory<Input::TouchDevice>("cemuhookudp", touch_factory);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
State::~State() {
 | 
			
		||||
@ -88,6 +89,11 @@ State::~State() {
 | 
			
		||||
    Input::UnregisterFactory<Input::MotionDevice>("cemuhookudp");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::vector<Common::ParamPackage> State::GetInputDevices() const {
 | 
			
		||||
    // TODO support binding udp devices
 | 
			
		||||
    return {};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void State::ReloadUDPClient() {
 | 
			
		||||
    client->ReloadSocket(Settings::values.udp_input_address, Settings::values.udp_input_port,
 | 
			
		||||
                         Settings::values.udp_pad_index);
 | 
			
		||||
 | 
			
		||||
@ -5,19 +5,26 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include "common/param_package.h"
 | 
			
		||||
 | 
			
		||||
namespace InputCommon::CemuhookUDP {
 | 
			
		||||
 | 
			
		||||
class Client;
 | 
			
		||||
class UDPMotionFactory;
 | 
			
		||||
class UDPTouchFactory;
 | 
			
		||||
 | 
			
		||||
class State {
 | 
			
		||||
public:
 | 
			
		||||
    State();
 | 
			
		||||
    ~State();
 | 
			
		||||
    void ReloadUDPClient();
 | 
			
		||||
    std::vector<Common::ParamPackage> GetInputDevices() const;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    std::unique_ptr<Client> client;
 | 
			
		||||
    std::shared_ptr<UDPMotionFactory> motion_factory;
 | 
			
		||||
    std::shared_ptr<UDPTouchFactory> touch_factory;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
std::unique_ptr<State> Init();
 | 
			
		||||
 | 
			
		||||
@ -39,6 +39,9 @@ add_executable(yuzu
 | 
			
		||||
    configuration/configure_debug.cpp
 | 
			
		||||
    configuration/configure_debug.h
 | 
			
		||||
    configuration/configure_debug.ui
 | 
			
		||||
    configuration/configure_debug_controller.cpp
 | 
			
		||||
    configuration/configure_debug_controller.h
 | 
			
		||||
    configuration/configure_debug_controller.ui
 | 
			
		||||
    configuration/configure_dialog.cpp
 | 
			
		||||
    configuration/configure_dialog.h
 | 
			
		||||
    configuration/configure_filesystem.cpp
 | 
			
		||||
@ -62,9 +65,9 @@ add_executable(yuzu
 | 
			
		||||
    configuration/configure_input_player.cpp
 | 
			
		||||
    configuration/configure_input_player.h
 | 
			
		||||
    configuration/configure_input_player.ui
 | 
			
		||||
    configuration/configure_input_simple.cpp
 | 
			
		||||
    configuration/configure_input_simple.h
 | 
			
		||||
    configuration/configure_input_simple.ui
 | 
			
		||||
    configuration/configure_input_advanced.cpp
 | 
			
		||||
    configuration/configure_input_advanced.h
 | 
			
		||||
    configuration/configure_input_advanced.ui
 | 
			
		||||
    configuration/configure_mouse_advanced.cpp
 | 
			
		||||
    configuration/configure_mouse_advanced.h
 | 
			
		||||
    configuration/configure_mouse_advanced.ui
 | 
			
		||||
 | 
			
		||||
@ -6,7 +6,6 @@
 | 
			
		||||
#include <QKeySequence>
 | 
			
		||||
#include <QSettings>
 | 
			
		||||
#include "common/file_util.h"
 | 
			
		||||
#include "configure_input_simple.h"
 | 
			
		||||
#include "core/hle/service/acc/profile_manager.h"
 | 
			
		||||
#include "core/hle/service/hid/controllers/npad.h"
 | 
			
		||||
#include "input_common/main.h"
 | 
			
		||||
@ -32,29 +31,29 @@ Config::~Config() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const std::array<int, Settings::NativeButton::NumButtons> Config::default_buttons = {
 | 
			
		||||
    Qt::Key_A, Qt::Key_S, Qt::Key_Z,    Qt::Key_X,  Qt::Key_3,     Qt::Key_4,    Qt::Key_Q,
 | 
			
		||||
    Qt::Key_W, Qt::Key_1, Qt::Key_2,    Qt::Key_N,  Qt::Key_M,     Qt::Key_F,    Qt::Key_T,
 | 
			
		||||
    Qt::Key_H, Qt::Key_G, Qt::Key_Left, Qt::Key_Up, Qt::Key_Right, Qt::Key_Down, Qt::Key_J,
 | 
			
		||||
    Qt::Key_I, Qt::Key_L, Qt::Key_K,    Qt::Key_D,  Qt::Key_C,     Qt::Key_B,    Qt::Key_V,
 | 
			
		||||
    Qt::Key_A, Qt::Key_S, Qt::Key_Z, Qt::Key_X, Qt::Key_3, Qt::Key_4, Qt::Key_Q,
 | 
			
		||||
    Qt::Key_W, Qt::Key_1, Qt::Key_2, Qt::Key_N, Qt::Key_M, Qt::Key_F, Qt::Key_T,
 | 
			
		||||
    Qt::Key_H, Qt::Key_G, Qt::Key_D, Qt::Key_C, Qt::Key_B, Qt::Key_V,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs> Config::default_analogs{{
 | 
			
		||||
const std::array<std::array<int, 4>, Settings::NativeAnalog::NumAnalogs> Config::default_analogs{{
 | 
			
		||||
    {
 | 
			
		||||
        Qt::Key_Up,
 | 
			
		||||
        Qt::Key_Down,
 | 
			
		||||
        Qt::Key_Left,
 | 
			
		||||
        Qt::Key_Right,
 | 
			
		||||
        Qt::Key_E,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
        Qt::Key_I,
 | 
			
		||||
        Qt::Key_K,
 | 
			
		||||
        Qt::Key_J,
 | 
			
		||||
        Qt::Key_L,
 | 
			
		||||
        Qt::Key_R,
 | 
			
		||||
    },
 | 
			
		||||
}};
 | 
			
		||||
 | 
			
		||||
const int Config::default_lstick_mod = Qt::Key_E;
 | 
			
		||||
const int Config::default_rstick_mod = Qt::Key_R;
 | 
			
		||||
 | 
			
		||||
const std::array<int, Settings::NativeMouseButton::NumMouseButtons> Config::default_mouse_buttons =
 | 
			
		||||
    {
 | 
			
		||||
        Qt::Key_BracketLeft, Qt::Key_BracketRight, Qt::Key_Apostrophe, Qt::Key_Minus, Qt::Key_Equal,
 | 
			
		||||
@ -243,10 +242,10 @@ void Config::ReadPlayerValues() {
 | 
			
		||||
        player.connected =
 | 
			
		||||
            ReadSetting(QStringLiteral("player_%1_connected").arg(p), false).toBool();
 | 
			
		||||
 | 
			
		||||
        player.type = static_cast<Settings::ControllerType>(
 | 
			
		||||
        player.controller_type = static_cast<Settings::ControllerType>(
 | 
			
		||||
            qt_config
 | 
			
		||||
                ->value(QStringLiteral("player_%1_type").arg(p),
 | 
			
		||||
                        static_cast<u8>(Settings::ControllerType::DualJoycon))
 | 
			
		||||
                        static_cast<u8>(Settings::ControllerType::ProController))
 | 
			
		||||
                .toUInt());
 | 
			
		||||
 | 
			
		||||
        player.body_color_left = qt_config
 | 
			
		||||
@ -300,12 +299,6 @@ void Config::ReadPlayerValues() {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::stable_partition(
 | 
			
		||||
        Settings::values.players.begin(),
 | 
			
		||||
        Settings::values.players.begin() +
 | 
			
		||||
            Service::HID::Controller_NPad::NPadIdToIndex(Service::HID::NPAD_HANDHELD),
 | 
			
		||||
        [](const auto& player) { return player.connected; });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Config::ReadDebugValues() {
 | 
			
		||||
@ -397,13 +390,6 @@ void Config::ReadTouchscreenValues() {
 | 
			
		||||
        ReadSetting(QStringLiteral("touchscreen_diameter_y"), 15).toUInt();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Config::ApplyDefaultProfileIfInputInvalid() {
 | 
			
		||||
    if (!std::any_of(Settings::values.players.begin(), Settings::values.players.end(),
 | 
			
		||||
                     [](const Settings::PlayerInput& in) { return in.connected; })) {
 | 
			
		||||
        ApplyInputProfileConfiguration(UISettings::values.profile_index);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Config::ReadAudioValues() {
 | 
			
		||||
    qt_config->beginGroup(QStringLiteral("Audio"));
 | 
			
		||||
 | 
			
		||||
@ -433,6 +419,8 @@ void Config::ReadControlValues() {
 | 
			
		||||
    ReadMouseValues();
 | 
			
		||||
    ReadTouchscreenValues();
 | 
			
		||||
 | 
			
		||||
    Settings::values.vibration_enabled =
 | 
			
		||||
        ReadSetting(QStringLiteral("vibration_enabled"), true).toBool();
 | 
			
		||||
    Settings::values.motion_device =
 | 
			
		||||
        ReadSetting(QStringLiteral("motion_device"),
 | 
			
		||||
                    QStringLiteral("engine:motion_emu,update_period:100,sensitivity:0.01"))
 | 
			
		||||
@ -501,7 +489,7 @@ void Config::ReadDataStorageValues() {
 | 
			
		||||
    Settings::values.gamecard_current_game =
 | 
			
		||||
        ReadSetting(QStringLiteral("gamecard_current_game"), false).toBool();
 | 
			
		||||
    Settings::values.gamecard_path =
 | 
			
		||||
        ReadSetting(QStringLiteral("gamecard_path"), QStringLiteral("")).toString().toStdString();
 | 
			
		||||
        ReadSetting(QStringLiteral("gamecard_path"), QString{}).toString().toStdString();
 | 
			
		||||
 | 
			
		||||
    qt_config->endGroup();
 | 
			
		||||
}
 | 
			
		||||
@ -515,7 +503,7 @@ void Config::ReadDebuggingValues() {
 | 
			
		||||
    Settings::values.use_gdbstub = ReadSetting(QStringLiteral("use_gdbstub"), false).toBool();
 | 
			
		||||
    Settings::values.gdbstub_port = ReadSetting(QStringLiteral("gdbstub_port"), 24689).toInt();
 | 
			
		||||
    Settings::values.program_args =
 | 
			
		||||
        ReadSetting(QStringLiteral("program_args"), QStringLiteral("")).toString().toStdString();
 | 
			
		||||
        ReadSetting(QStringLiteral("program_args"), QString{}).toString().toStdString();
 | 
			
		||||
    Settings::values.dump_exefs = ReadSetting(QStringLiteral("dump_exefs"), false).toBool();
 | 
			
		||||
    Settings::values.dump_nso = ReadSetting(QStringLiteral("dump_nso"), false).toBool();
 | 
			
		||||
    Settings::values.reporting_services =
 | 
			
		||||
@ -548,8 +536,7 @@ void Config::ReadDisabledAddOnValues() {
 | 
			
		||||
        const auto d_size = qt_config->beginReadArray(QStringLiteral("disabled"));
 | 
			
		||||
        for (int j = 0; j < d_size; ++j) {
 | 
			
		||||
            qt_config->setArrayIndex(j);
 | 
			
		||||
            out.push_back(
 | 
			
		||||
                ReadSetting(QStringLiteral("d"), QStringLiteral("")).toString().toStdString());
 | 
			
		||||
            out.push_back(ReadSetting(QStringLiteral("d"), QString{}).toString().toStdString());
 | 
			
		||||
        }
 | 
			
		||||
        qt_config->endArray();
 | 
			
		||||
        Settings::values.disabled_addons.insert_or_assign(title_id, out);
 | 
			
		||||
@ -788,14 +775,11 @@ void Config::ReadUIValues() {
 | 
			
		||||
    UISettings::values.first_start = ReadSetting(QStringLiteral("firstStart"), true).toBool();
 | 
			
		||||
    UISettings::values.callout_flags = ReadSetting(QStringLiteral("calloutFlags"), 0).toUInt();
 | 
			
		||||
    UISettings::values.show_console = ReadSetting(QStringLiteral("showConsole"), false).toBool();
 | 
			
		||||
    UISettings::values.profile_index = ReadSetting(QStringLiteral("profileIndex"), 0).toUInt();
 | 
			
		||||
    UISettings::values.pause_when_in_background =
 | 
			
		||||
        ReadSetting(QStringLiteral("pauseWhenInBackground"), false).toBool();
 | 
			
		||||
    UISettings::values.hide_mouse =
 | 
			
		||||
        ReadSetting(QStringLiteral("hideInactiveMouse"), false).toBool();
 | 
			
		||||
 | 
			
		||||
    ApplyDefaultProfileIfInputInvalid();
 | 
			
		||||
 | 
			
		||||
    qt_config->endGroup();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -869,8 +853,9 @@ void Config::SavePlayerValues() {
 | 
			
		||||
        const auto& player = Settings::values.players[p];
 | 
			
		||||
 | 
			
		||||
        WriteSetting(QStringLiteral("player_%1_connected").arg(p), player.connected, false);
 | 
			
		||||
        WriteSetting(QStringLiteral("player_%1_type").arg(p), static_cast<u8>(player.type),
 | 
			
		||||
                     static_cast<u8>(Settings::ControllerType::DualJoycon));
 | 
			
		||||
        WriteSetting(QStringLiteral("player_%1_type").arg(p),
 | 
			
		||||
                     static_cast<u8>(player.controller_type),
 | 
			
		||||
                     static_cast<u8>(Settings::ControllerType::ProController));
 | 
			
		||||
 | 
			
		||||
        WriteSetting(QStringLiteral("player_%1_body_color_left").arg(p), player.body_color_left,
 | 
			
		||||
                     Settings::JOYCON_BODY_NEON_BLUE);
 | 
			
		||||
@ -990,6 +975,7 @@ void Config::SaveControlValues() {
 | 
			
		||||
    SaveMouseValues();
 | 
			
		||||
    SaveTouchscreenValues();
 | 
			
		||||
 | 
			
		||||
    WriteSetting(QStringLiteral("vibration_enabled"), Settings::values.vibration_enabled, true);
 | 
			
		||||
    WriteSetting(QStringLiteral("motion_device"),
 | 
			
		||||
                 QString::fromStdString(Settings::values.motion_device),
 | 
			
		||||
                 QStringLiteral("engine:motion_emu,update_period:100,sensitivity:0.01"));
 | 
			
		||||
@ -1036,7 +1022,7 @@ void Config::SaveDataStorageValues() {
 | 
			
		||||
    WriteSetting(QStringLiteral("gamecard_current_game"), Settings::values.gamecard_current_game,
 | 
			
		||||
                 false);
 | 
			
		||||
    WriteSetting(QStringLiteral("gamecard_path"),
 | 
			
		||||
                 QString::fromStdString(Settings::values.gamecard_path), QStringLiteral(""));
 | 
			
		||||
                 QString::fromStdString(Settings::values.gamecard_path), QString{});
 | 
			
		||||
 | 
			
		||||
    qt_config->endGroup();
 | 
			
		||||
}
 | 
			
		||||
@ -1049,7 +1035,7 @@ void Config::SaveDebuggingValues() {
 | 
			
		||||
    WriteSetting(QStringLiteral("use_gdbstub"), Settings::values.use_gdbstub, false);
 | 
			
		||||
    WriteSetting(QStringLiteral("gdbstub_port"), Settings::values.gdbstub_port, 24689);
 | 
			
		||||
    WriteSetting(QStringLiteral("program_args"),
 | 
			
		||||
                 QString::fromStdString(Settings::values.program_args), QStringLiteral(""));
 | 
			
		||||
                 QString::fromStdString(Settings::values.program_args), QString{});
 | 
			
		||||
    WriteSetting(QStringLiteral("dump_exefs"), Settings::values.dump_exefs, false);
 | 
			
		||||
    WriteSetting(QStringLiteral("dump_nso"), Settings::values.dump_nso, false);
 | 
			
		||||
    WriteSetting(QStringLiteral("quest_flag"), Settings::values.quest_flag, false);
 | 
			
		||||
@ -1076,8 +1062,7 @@ void Config::SaveDisabledAddOnValues() {
 | 
			
		||||
        qt_config->beginWriteArray(QStringLiteral("disabled"));
 | 
			
		||||
        for (std::size_t j = 0; j < elem.second.size(); ++j) {
 | 
			
		||||
            qt_config->setArrayIndex(static_cast<int>(j));
 | 
			
		||||
            WriteSetting(QStringLiteral("d"), QString::fromStdString(elem.second[j]),
 | 
			
		||||
                         QStringLiteral(""));
 | 
			
		||||
            WriteSetting(QStringLiteral("d"), QString::fromStdString(elem.second[j]), QString{});
 | 
			
		||||
        }
 | 
			
		||||
        qt_config->endArray();
 | 
			
		||||
        ++i;
 | 
			
		||||
@ -1266,7 +1251,6 @@ void Config::SaveUIValues() {
 | 
			
		||||
    WriteSetting(QStringLiteral("firstStart"), UISettings::values.first_start, true);
 | 
			
		||||
    WriteSetting(QStringLiteral("calloutFlags"), UISettings::values.callout_flags, 0);
 | 
			
		||||
    WriteSetting(QStringLiteral("showConsole"), UISettings::values.show_console, false);
 | 
			
		||||
    WriteSetting(QStringLiteral("profileIndex"), UISettings::values.profile_index, 0);
 | 
			
		||||
    WriteSetting(QStringLiteral("pauseWhenInBackground"),
 | 
			
		||||
                 UISettings::values.pause_when_in_background, false);
 | 
			
		||||
    WriteSetting(QStringLiteral("hideInactiveMouse"), UISettings::values.hide_mouse, false);
 | 
			
		||||
 | 
			
		||||
@ -23,7 +23,9 @@ public:
 | 
			
		||||
    void Save();
 | 
			
		||||
 | 
			
		||||
    static const std::array<int, Settings::NativeButton::NumButtons> default_buttons;
 | 
			
		||||
    static const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs> default_analogs;
 | 
			
		||||
    static const std::array<std::array<int, 4>, Settings::NativeAnalog::NumAnalogs> default_analogs;
 | 
			
		||||
    static const int default_lstick_mod;
 | 
			
		||||
    static const int default_rstick_mod;
 | 
			
		||||
    static const std::array<int, Settings::NativeMouseButton::NumMouseButtons>
 | 
			
		||||
        default_mouse_buttons;
 | 
			
		||||
    static const std::array<int, Settings::NativeKeyboard::NumKeyboardKeys> default_keyboard_keys;
 | 
			
		||||
@ -37,7 +39,6 @@ private:
 | 
			
		||||
    void ReadKeyboardValues();
 | 
			
		||||
    void ReadMouseValues();
 | 
			
		||||
    void ReadTouchscreenValues();
 | 
			
		||||
    void ApplyDefaultProfileIfInputInvalid();
 | 
			
		||||
 | 
			
		||||
    // Read functions bases off the respective config section names.
 | 
			
		||||
    void ReadAudioValues();
 | 
			
		||||
 | 
			
		||||
@ -6,7 +6,7 @@
 | 
			
		||||
   <rect>
 | 
			
		||||
    <x>0</x>
 | 
			
		||||
    <y>0</y>
 | 
			
		||||
    <width>382</width>
 | 
			
		||||
    <width>650</width>
 | 
			
		||||
    <height>650</height>
 | 
			
		||||
   </rect>
 | 
			
		||||
  </property>
 | 
			
		||||
@ -26,13 +26,13 @@
 | 
			
		||||
      <widget class="QListWidget" name="selectorList">
 | 
			
		||||
       <property name="minimumSize">
 | 
			
		||||
        <size>
 | 
			
		||||
         <width>150</width>
 | 
			
		||||
         <width>120</width>
 | 
			
		||||
         <height>0</height>
 | 
			
		||||
        </size>
 | 
			
		||||
       </property>
 | 
			
		||||
       <property name="maximumSize">
 | 
			
		||||
        <size>
 | 
			
		||||
         <width>150</width>
 | 
			
		||||
         <width>120</width>
 | 
			
		||||
         <height>16777215</height>
 | 
			
		||||
        </size>
 | 
			
		||||
       </property>
 | 
			
		||||
@ -44,76 +44,121 @@
 | 
			
		||||
        <number>0</number>
 | 
			
		||||
       </property>
 | 
			
		||||
       <widget class="ConfigureGeneral" name="generalTab">
 | 
			
		||||
        <property name="accessibleName">
 | 
			
		||||
         <string>General</string>
 | 
			
		||||
        </property>
 | 
			
		||||
        <attribute name="title">
 | 
			
		||||
         <string>General</string>
 | 
			
		||||
        </attribute>
 | 
			
		||||
       </widget>
 | 
			
		||||
       <widget class="ConfigureUi" name="uiTab">
 | 
			
		||||
        <property name="accessibleName">
 | 
			
		||||
         <string>UI</string>
 | 
			
		||||
        </property>
 | 
			
		||||
        <attribute name="title">
 | 
			
		||||
         <string>Game List</string>
 | 
			
		||||
        </attribute>
 | 
			
		||||
       </widget>
 | 
			
		||||
       <widget class="ConfigureSystem" name="systemTab">
 | 
			
		||||
        <property name="accessibleName">
 | 
			
		||||
         <string>System</string>
 | 
			
		||||
        </property>
 | 
			
		||||
        <attribute name="title">
 | 
			
		||||
         <string>System</string>
 | 
			
		||||
        </attribute>
 | 
			
		||||
       </widget>
 | 
			
		||||
       <widget class="ConfigureProfileManager" name="profileManagerTab">
 | 
			
		||||
        <property name="accessibleName">
 | 
			
		||||
         <string>Profiles</string>
 | 
			
		||||
        </property>
 | 
			
		||||
        <attribute name="title">
 | 
			
		||||
         <string>Profiles</string>
 | 
			
		||||
        </attribute>
 | 
			
		||||
       </widget>
 | 
			
		||||
       <widget class="ConfigureFilesystem" name="filesystemTab">
 | 
			
		||||
        <property name="accessibleName">
 | 
			
		||||
         <string>Filesystem</string>
 | 
			
		||||
        </property>
 | 
			
		||||
        <attribute name="title">
 | 
			
		||||
         <string>Filesystem</string>
 | 
			
		||||
        </attribute>
 | 
			
		||||
       </widget>
 | 
			
		||||
       <widget class="ConfigureInputSimple" name="inputTab">
 | 
			
		||||
       <widget class="ConfigureInput" name="inputTab">
 | 
			
		||||
        <property name="accessibleName">
 | 
			
		||||
         <string>Controls</string>
 | 
			
		||||
        </property>
 | 
			
		||||
        <attribute name="title">
 | 
			
		||||
         <string>Input</string>
 | 
			
		||||
         <string>Controls</string>
 | 
			
		||||
        </attribute>
 | 
			
		||||
       </widget>
 | 
			
		||||
       <widget class="ConfigureHotkeys" name="hotkeysTab">
 | 
			
		||||
        <property name="accessibleName">
 | 
			
		||||
         <string>Hotkeys</string>
 | 
			
		||||
        </property>
 | 
			
		||||
        <attribute name="title">
 | 
			
		||||
         <string>Hotkeys</string>
 | 
			
		||||
        </attribute>
 | 
			
		||||
       </widget>
 | 
			
		||||
       <widget class="ConfigureCpu" name="cpuTab">
 | 
			
		||||
        <property name="accessibleName">
 | 
			
		||||
         <string>CPU</string>
 | 
			
		||||
        </property>
 | 
			
		||||
        <attribute name="title">
 | 
			
		||||
         <string>CPU</string>
 | 
			
		||||
        </attribute>
 | 
			
		||||
       </widget>
 | 
			
		||||
       <widget class="ConfigureCpuDebug" name="cpuDebugTab">
 | 
			
		||||
        <property name="accessibleName">
 | 
			
		||||
         <string>Debug</string>
 | 
			
		||||
        </property>
 | 
			
		||||
        <attribute name="title">
 | 
			
		||||
         <string>Debug</string>
 | 
			
		||||
        </attribute>
 | 
			
		||||
       </widget>
 | 
			
		||||
       <widget class="ConfigureGraphics" name="graphicsTab">
 | 
			
		||||
        <property name="accessibleName">
 | 
			
		||||
         <string>Graphics</string>
 | 
			
		||||
        </property>
 | 
			
		||||
        <attribute name="title">
 | 
			
		||||
         <string>Graphics</string>
 | 
			
		||||
        </attribute>
 | 
			
		||||
       </widget>
 | 
			
		||||
       <widget class="ConfigureGraphicsAdvanced" name="graphicsAdvancedTab">
 | 
			
		||||
        <property name="accessibleName">
 | 
			
		||||
         <string>Advanced</string>
 | 
			
		||||
        </property>
 | 
			
		||||
        <attribute name="title">
 | 
			
		||||
         <string>GraphicsAdvanced</string>
 | 
			
		||||
        </attribute>
 | 
			
		||||
       </widget>
 | 
			
		||||
       <widget class="ConfigureAudio" name="audioTab">
 | 
			
		||||
        <property name="accessibleName">
 | 
			
		||||
         <string>Audio</string>
 | 
			
		||||
        </property>
 | 
			
		||||
        <attribute name="title">
 | 
			
		||||
         <string>Audio</string>
 | 
			
		||||
        </attribute>
 | 
			
		||||
       </widget>
 | 
			
		||||
       <widget class="ConfigureDebug" name="debugTab">
 | 
			
		||||
        <property name="accessibleName">
 | 
			
		||||
         <string>Debug</string>
 | 
			
		||||
        </property>
 | 
			
		||||
        <attribute name="title">
 | 
			
		||||
         <string>Debug</string>
 | 
			
		||||
        </attribute>
 | 
			
		||||
       </widget>
 | 
			
		||||
       <widget class="ConfigureWeb" name="webTab">
 | 
			
		||||
        <property name="accessibleName">
 | 
			
		||||
         <string>Web</string>
 | 
			
		||||
        </property>
 | 
			
		||||
        <attribute name="title">
 | 
			
		||||
         <string>Web</string>
 | 
			
		||||
        </attribute>
 | 
			
		||||
       </widget>
 | 
			
		||||
       <widget class="ConfigureService" name="serviceTab">
 | 
			
		||||
        <property name="accessibleName">
 | 
			
		||||
         <string>Services</string>
 | 
			
		||||
        </property>
 | 
			
		||||
        <attribute name="title">
 | 
			
		||||
         <string>Services</string>
 | 
			
		||||
        </attribute>
 | 
			
		||||
@ -205,9 +250,9 @@
 | 
			
		||||
   <container>1</container>
 | 
			
		||||
  </customwidget>
 | 
			
		||||
  <customwidget>
 | 
			
		||||
   <class>ConfigureInputSimple</class>
 | 
			
		||||
   <class>ConfigureInput</class>
 | 
			
		||||
   <extends>QWidget</extends>
 | 
			
		||||
   <header>configuration/configure_input_simple.h</header>
 | 
			
		||||
   <header>configuration/configure_input.h</header>
 | 
			
		||||
   <container>1</container>
 | 
			
		||||
  </customwidget>
 | 
			
		||||
  <customwidget>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										39
									
								
								src/yuzu/configuration/configure_debug_controller.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,39 @@
 | 
			
		||||
// Copyright 2020 yuzu Emulator Project
 | 
			
		||||
// Licensed under GPLv2 or any later version
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#include "ui_configure_debug_controller.h"
 | 
			
		||||
#include "yuzu/configuration/configure_debug_controller.h"
 | 
			
		||||
 | 
			
		||||
ConfigureDebugController::ConfigureDebugController(QWidget* parent)
 | 
			
		||||
    : QDialog(parent), ui(std::make_unique<Ui::ConfigureDebugController>()),
 | 
			
		||||
      debug_controller(new ConfigureInputPlayer(this, 9, nullptr, true)) {
 | 
			
		||||
    ui->setupUi(this);
 | 
			
		||||
 | 
			
		||||
    ui->controllerLayout->addWidget(debug_controller);
 | 
			
		||||
 | 
			
		||||
    connect(ui->clear_all_button, &QPushButton::clicked, this,
 | 
			
		||||
            [this] { debug_controller->ClearAll(); });
 | 
			
		||||
    connect(ui->restore_defaults_button, &QPushButton::clicked, this,
 | 
			
		||||
            [this] { debug_controller->RestoreDefaults(); });
 | 
			
		||||
 | 
			
		||||
    RetranslateUI();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ConfigureDebugController::~ConfigureDebugController() = default;
 | 
			
		||||
 | 
			
		||||
void ConfigureDebugController::ApplyConfiguration() {
 | 
			
		||||
    debug_controller->ApplyConfiguration();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ConfigureDebugController::changeEvent(QEvent* event) {
 | 
			
		||||
    if (event->type() == QEvent::LanguageChange) {
 | 
			
		||||
        RetranslateUI();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    QDialog::changeEvent(event);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ConfigureDebugController::RetranslateUI() {
 | 
			
		||||
    ui->retranslateUi(this);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										33
									
								
								src/yuzu/configuration/configure_debug_controller.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,33 @@
 | 
			
		||||
// Copyright 2020 yuzu Emulator Project
 | 
			
		||||
// Licensed under GPLv2 or any later version
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <QDialog>
 | 
			
		||||
#include "yuzu/configuration/configure_input_player.h"
 | 
			
		||||
 | 
			
		||||
class QPushButton;
 | 
			
		||||
 | 
			
		||||
namespace Ui {
 | 
			
		||||
class ConfigureDebugController;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class ConfigureDebugController : public QDialog {
 | 
			
		||||
    Q_OBJECT
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    explicit ConfigureDebugController(QWidget* parent);
 | 
			
		||||
    ~ConfigureDebugController() override;
 | 
			
		||||
 | 
			
		||||
    void ApplyConfiguration();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void changeEvent(QEvent* event) override;
 | 
			
		||||
    void RetranslateUI();
 | 
			
		||||
 | 
			
		||||
    std::unique_ptr<Ui::ConfigureDebugController> ui;
 | 
			
		||||
 | 
			
		||||
    ConfigureInputPlayer* debug_controller;
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										97
									
								
								src/yuzu/configuration/configure_debug_controller.ui
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,97 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<ui version="4.0">
 | 
			
		||||
 <class>ConfigureDebugController</class>
 | 
			
		||||
 <widget class="QDialog" name="ConfigureDebugController">
 | 
			
		||||
  <property name="geometry">
 | 
			
		||||
   <rect>
 | 
			
		||||
    <x>0</x>
 | 
			
		||||
    <y>0</y>
 | 
			
		||||
    <width>780</width>
 | 
			
		||||
    <height>500</height>
 | 
			
		||||
   </rect>
 | 
			
		||||
  </property>
 | 
			
		||||
  <property name="windowTitle">
 | 
			
		||||
   <string>Configure Debug Controller</string>
 | 
			
		||||
  </property>
 | 
			
		||||
  <layout class="QVBoxLayout" name="verticalLayout">
 | 
			
		||||
   <property name="spacing">
 | 
			
		||||
    <number>2</number>
 | 
			
		||||
   </property>
 | 
			
		||||
   <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>
 | 
			
		||||
    <layout class="QHBoxLayout" name="controllerLayout"/>
 | 
			
		||||
   </item>
 | 
			
		||||
   <item>
 | 
			
		||||
    <layout class="QHBoxLayout" name="horizontalLayout">
 | 
			
		||||
     <item>
 | 
			
		||||
      <widget class="QPushButton" name="clear_all_button">
 | 
			
		||||
       <property name="text">
 | 
			
		||||
        <string>Clear</string>
 | 
			
		||||
       </property>
 | 
			
		||||
      </widget>
 | 
			
		||||
     </item>
 | 
			
		||||
     <item>
 | 
			
		||||
      <widget class="QPushButton" name="restore_defaults_button">
 | 
			
		||||
       <property name="text">
 | 
			
		||||
        <string>Defaults</string>
 | 
			
		||||
       </property>
 | 
			
		||||
      </widget>
 | 
			
		||||
     </item>
 | 
			
		||||
     <item>
 | 
			
		||||
      <widget class="QDialogButtonBox" name="buttonBox">
 | 
			
		||||
       <property name="standardButtons">
 | 
			
		||||
        <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
 | 
			
		||||
       </property>
 | 
			
		||||
      </widget>
 | 
			
		||||
     </item>
 | 
			
		||||
    </layout>
 | 
			
		||||
   </item>
 | 
			
		||||
  </layout>
 | 
			
		||||
 </widget>
 | 
			
		||||
 <resources/>
 | 
			
		||||
 <connections>
 | 
			
		||||
  <connection>
 | 
			
		||||
   <sender>buttonBox</sender>
 | 
			
		||||
   <signal>accepted()</signal>
 | 
			
		||||
   <receiver>ConfigureDebugController</receiver>
 | 
			
		||||
   <slot>accept()</slot>
 | 
			
		||||
   <hints>
 | 
			
		||||
    <hint type="sourcelabel">
 | 
			
		||||
     <x>140</x>
 | 
			
		||||
     <y>318</y>
 | 
			
		||||
    </hint>
 | 
			
		||||
    <hint type="destinationlabel">
 | 
			
		||||
     <x>140</x>
 | 
			
		||||
     <y>169</y>
 | 
			
		||||
    </hint>
 | 
			
		||||
   </hints>
 | 
			
		||||
  </connection>
 | 
			
		||||
  <connection>
 | 
			
		||||
   <sender>buttonBox</sender>
 | 
			
		||||
   <signal>rejected()</signal>
 | 
			
		||||
   <receiver>ConfigureDebugController</receiver>
 | 
			
		||||
   <slot>reject()</slot>
 | 
			
		||||
   <hints>
 | 
			
		||||
    <hint type="sourcelabel">
 | 
			
		||||
     <x>140</x>
 | 
			
		||||
     <y>318</y>
 | 
			
		||||
    </hint>
 | 
			
		||||
    <hint type="destinationlabel">
 | 
			
		||||
     <x>140</x>
 | 
			
		||||
     <y>169</y>
 | 
			
		||||
    </hint>
 | 
			
		||||
   </hints>
 | 
			
		||||
  </connection>
 | 
			
		||||
 </connections>
 | 
			
		||||
</ui>
 | 
			
		||||
@ -80,12 +80,12 @@ Q_DECLARE_METATYPE(QList<QWidget*>);
 | 
			
		||||
 | 
			
		||||
void ConfigureDialog::PopulateSelectionList() {
 | 
			
		||||
    const std::array<std::pair<QString, QList<QWidget*>>, 6> items{
 | 
			
		||||
        {{tr("General"), {ui->generalTab, ui->webTab, ui->debugTab, ui->uiTab}},
 | 
			
		||||
        {{tr("General"), {ui->generalTab, ui->hotkeysTab, ui->uiTab, ui->webTab, ui->debugTab}},
 | 
			
		||||
         {tr("System"), {ui->systemTab, ui->profileManagerTab, ui->serviceTab, ui->filesystemTab}},
 | 
			
		||||
         {tr("CPU"), {ui->cpuTab, ui->cpuDebugTab}},
 | 
			
		||||
         {tr("Graphics"), {ui->graphicsTab, ui->graphicsAdvancedTab}},
 | 
			
		||||
         {tr("Audio"), {ui->audioTab}},
 | 
			
		||||
         {tr("Controls"), {ui->inputTab, ui->hotkeysTab}}},
 | 
			
		||||
         {tr("Controls"), ui->inputTab->GetSubTabs()}},
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    [[maybe_unused]] const QSignalBlocker blocker(ui->selectorList);
 | 
			
		||||
@ -117,7 +117,7 @@ void ConfigureDialog::UpdateVisibleTabs() {
 | 
			
		||||
        {ui->generalTab, tr("General")},
 | 
			
		||||
        {ui->systemTab, tr("System")},
 | 
			
		||||
        {ui->profileManagerTab, tr("Profiles")},
 | 
			
		||||
        {ui->inputTab, tr("Input")},
 | 
			
		||||
        {ui->inputTab, tr("Controls")},
 | 
			
		||||
        {ui->hotkeysTab, tr("Hotkeys")},
 | 
			
		||||
        {ui->cpuTab, tr("CPU")},
 | 
			
		||||
        {ui->cpuDebugTab, tr("Debug")},
 | 
			
		||||
@ -138,6 +138,6 @@ void ConfigureDialog::UpdateVisibleTabs() {
 | 
			
		||||
    const QList<QWidget*> tabs = qvariant_cast<QList<QWidget*>>(items[0]->data(Qt::UserRole));
 | 
			
		||||
 | 
			
		||||
    for (const auto tab : tabs) {
 | 
			
		||||
        ui->tabWidget->addTab(tab, widgets.at(tab));
 | 
			
		||||
        ui->tabWidget->addTab(tab, tab->accessibleName());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -8,18 +8,32 @@
 | 
			
		||||
#include <QSignalBlocker>
 | 
			
		||||
#include <QTimer>
 | 
			
		||||
 | 
			
		||||
#include "configuration/configure_touchscreen_advanced.h"
 | 
			
		||||
#include "core/core.h"
 | 
			
		||||
#include "core/hle/service/am/am.h"
 | 
			
		||||
#include "core/hle/service/am/applet_ae.h"
 | 
			
		||||
#include "core/hle/service/am/applet_oe.h"
 | 
			
		||||
#include "core/hle/service/hid/controllers/npad.h"
 | 
			
		||||
#include "core/hle/service/sm/sm.h"
 | 
			
		||||
#include "ui_configure_input.h"
 | 
			
		||||
#include "ui_configure_input_advanced.h"
 | 
			
		||||
#include "ui_configure_input_player.h"
 | 
			
		||||
#include "yuzu/configuration/configure_debug_controller.h"
 | 
			
		||||
#include "yuzu/configuration/configure_input.h"
 | 
			
		||||
#include "yuzu/configuration/configure_input_advanced.h"
 | 
			
		||||
#include "yuzu/configuration/configure_input_player.h"
 | 
			
		||||
#include "yuzu/configuration/configure_mouse_advanced.h"
 | 
			
		||||
#include "yuzu/configuration/configure_touchscreen_advanced.h"
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
template <typename Dialog, typename... Args>
 | 
			
		||||
void CallConfigureDialog(ConfigureInput& parent, Args&&... args) {
 | 
			
		||||
    Dialog dialog(&parent, std::forward<Args>(args)...);
 | 
			
		||||
 | 
			
		||||
    const auto res = dialog.exec();
 | 
			
		||||
    if (res == QDialog::Accepted) {
 | 
			
		||||
        dialog.ApplyConfiguration();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
} // Anonymous namespace
 | 
			
		||||
 | 
			
		||||
void OnDockedModeChanged(bool last_state, bool new_state) {
 | 
			
		||||
    if (last_state == new_state) {
 | 
			
		||||
@ -48,97 +62,94 @@ void OnDockedModeChanged(bool last_state, bool new_state) {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
template <typename Dialog, typename... Args>
 | 
			
		||||
void CallConfigureDialog(ConfigureInput& parent, Args&&... args) {
 | 
			
		||||
    parent.ApplyConfiguration();
 | 
			
		||||
    Dialog dialog(&parent, std::forward<Args>(args)...);
 | 
			
		||||
 | 
			
		||||
    const auto res = dialog.exec();
 | 
			
		||||
    if (res == QDialog::Accepted) {
 | 
			
		||||
        dialog.ApplyConfiguration();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
} // Anonymous namespace
 | 
			
		||||
 | 
			
		||||
ConfigureInput::ConfigureInput(QWidget* parent)
 | 
			
		||||
    : QDialog(parent), ui(std::make_unique<Ui::ConfigureInput>()) {
 | 
			
		||||
    : QWidget(parent), ui(std::make_unique<Ui::ConfigureInput>()) {
 | 
			
		||||
    ui->setupUi(this);
 | 
			
		||||
 | 
			
		||||
    players_controller = {
 | 
			
		||||
        ui->player1_combobox, ui->player2_combobox, ui->player3_combobox, ui->player4_combobox,
 | 
			
		||||
        ui->player5_combobox, ui->player6_combobox, ui->player7_combobox, ui->player8_combobox,
 | 
			
		||||
    player_controllers = {
 | 
			
		||||
        new ConfigureInputPlayer(this, 0, ui->consoleInputSettings),
 | 
			
		||||
        new ConfigureInputPlayer(this, 1, ui->consoleInputSettings),
 | 
			
		||||
        new ConfigureInputPlayer(this, 2, ui->consoleInputSettings),
 | 
			
		||||
        new ConfigureInputPlayer(this, 3, ui->consoleInputSettings),
 | 
			
		||||
        new ConfigureInputPlayer(this, 4, ui->consoleInputSettings),
 | 
			
		||||
        new ConfigureInputPlayer(this, 5, ui->consoleInputSettings),
 | 
			
		||||
        new ConfigureInputPlayer(this, 6, ui->consoleInputSettings),
 | 
			
		||||
        new ConfigureInputPlayer(this, 7, ui->consoleInputSettings),
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    players_configure = {
 | 
			
		||||
        ui->player1_configure, ui->player2_configure, ui->player3_configure, ui->player4_configure,
 | 
			
		||||
        ui->player5_configure, ui->player6_configure, ui->player7_configure, ui->player8_configure,
 | 
			
		||||
    player_tabs = {
 | 
			
		||||
        ui->tabPlayer1, ui->tabPlayer2, ui->tabPlayer3, ui->tabPlayer4,
 | 
			
		||||
        ui->tabPlayer5, ui->tabPlayer6, ui->tabPlayer7, ui->tabPlayer8,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    player_connected = {
 | 
			
		||||
        ui->checkboxPlayer1Connected, ui->checkboxPlayer2Connected, ui->checkboxPlayer3Connected,
 | 
			
		||||
        ui->checkboxPlayer4Connected, ui->checkboxPlayer5Connected, ui->checkboxPlayer6Connected,
 | 
			
		||||
        ui->checkboxPlayer7Connected, ui->checkboxPlayer8Connected,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    for (std::size_t i = 0; i < player_tabs.size(); ++i) {
 | 
			
		||||
        player_tabs[i]->setLayout(new QHBoxLayout(player_tabs[i]));
 | 
			
		||||
        player_tabs[i]->layout()->addWidget(player_controllers[i]);
 | 
			
		||||
        connect(player_controllers[i], &ConfigureInputPlayer::Connected, [&, i](bool is_connected) {
 | 
			
		||||
            if (is_connected) {
 | 
			
		||||
                for (std::size_t index = 0; index <= i; ++index) {
 | 
			
		||||
                    player_connected[index]->setChecked(is_connected);
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                for (std::size_t index = i; index < player_tabs.size(); ++index) {
 | 
			
		||||
                    player_connected[index]->setChecked(is_connected);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
        connect(player_controllers[i], &ConfigureInputPlayer::RefreshInputDevices,
 | 
			
		||||
                [this] { UpdateAllInputDevices(); });
 | 
			
		||||
        connect(player_connected[i], &QCheckBox::stateChanged, [this, i](int state) {
 | 
			
		||||
            player_controllers[i]->ConnectPlayer(state == Qt::Checked);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    // Only the first player can choose handheld mode so connect the signal just to player 1
 | 
			
		||||
    connect(player_controllers[0], &ConfigureInputPlayer::HandheldStateChanged,
 | 
			
		||||
            [this](bool is_handheld) { UpdateDockedState(is_handheld); });
 | 
			
		||||
 | 
			
		||||
    advanced = new ConfigureInputAdvanced(this);
 | 
			
		||||
    ui->tabAdvanced->setLayout(new QHBoxLayout(ui->tabAdvanced));
 | 
			
		||||
    ui->tabAdvanced->layout()->addWidget(advanced);
 | 
			
		||||
    connect(advanced, &ConfigureInputAdvanced::CallDebugControllerDialog,
 | 
			
		||||
            [this] { CallConfigureDialog<ConfigureDebugController>(*this); });
 | 
			
		||||
    connect(advanced, &ConfigureInputAdvanced::CallMouseConfigDialog,
 | 
			
		||||
            [this] { CallConfigureDialog<ConfigureMouseAdvanced>(*this); });
 | 
			
		||||
    connect(advanced, &ConfigureInputAdvanced::CallTouchscreenConfigDialog,
 | 
			
		||||
            [this] { CallConfigureDialog<ConfigureTouchscreenAdvanced>(*this); });
 | 
			
		||||
 | 
			
		||||
    connect(ui->buttonClearAll, &QPushButton::clicked, [this] { ClearAll(); });
 | 
			
		||||
    connect(ui->buttonRestoreDefaults, &QPushButton::clicked, [this] { RestoreDefaults(); });
 | 
			
		||||
 | 
			
		||||
    RetranslateUI();
 | 
			
		||||
    LoadConfiguration();
 | 
			
		||||
    UpdateUIEnabled();
 | 
			
		||||
 | 
			
		||||
    connect(ui->restore_defaults_button, &QPushButton::clicked, this,
 | 
			
		||||
            &ConfigureInput::RestoreDefaults);
 | 
			
		||||
 | 
			
		||||
    for (auto* enabled : players_controller) {
 | 
			
		||||
        connect(enabled, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
 | 
			
		||||
                &ConfigureInput::UpdateUIEnabled);
 | 
			
		||||
    }
 | 
			
		||||
    connect(ui->use_docked_mode, &QCheckBox::stateChanged, this, &ConfigureInput::UpdateUIEnabled);
 | 
			
		||||
    connect(ui->handheld_connected, &QCheckBox::stateChanged, this,
 | 
			
		||||
            &ConfigureInput::UpdateUIEnabled);
 | 
			
		||||
    connect(ui->mouse_enabled, &QCheckBox::stateChanged, this, &ConfigureInput::UpdateUIEnabled);
 | 
			
		||||
    connect(ui->keyboard_enabled, &QCheckBox::stateChanged, this, &ConfigureInput::UpdateUIEnabled);
 | 
			
		||||
    connect(ui->debug_enabled, &QCheckBox::stateChanged, this, &ConfigureInput::UpdateUIEnabled);
 | 
			
		||||
    connect(ui->touchscreen_enabled, &QCheckBox::stateChanged, this,
 | 
			
		||||
            &ConfigureInput::UpdateUIEnabled);
 | 
			
		||||
 | 
			
		||||
    for (std::size_t i = 0; i < players_configure.size(); ++i) {
 | 
			
		||||
        connect(players_configure[i], &QPushButton::clicked, this,
 | 
			
		||||
                [this, i] { CallConfigureDialog<ConfigureInputPlayer>(*this, i, false); });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    connect(ui->handheld_configure, &QPushButton::clicked, this,
 | 
			
		||||
            [this] { CallConfigureDialog<ConfigureInputPlayer>(*this, 8, false); });
 | 
			
		||||
 | 
			
		||||
    connect(ui->debug_configure, &QPushButton::clicked, this,
 | 
			
		||||
            [this] { CallConfigureDialog<ConfigureInputPlayer>(*this, 9, true); });
 | 
			
		||||
 | 
			
		||||
    connect(ui->mouse_advanced, &QPushButton::clicked, this,
 | 
			
		||||
            [this] { CallConfigureDialog<ConfigureMouseAdvanced>(*this); });
 | 
			
		||||
 | 
			
		||||
    connect(ui->touchscreen_advanced, &QPushButton::clicked, this,
 | 
			
		||||
            [this] { CallConfigureDialog<ConfigureTouchscreenAdvanced>(*this); });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ConfigureInput::~ConfigureInput() = default;
 | 
			
		||||
 | 
			
		||||
QList<QWidget*> ConfigureInput::GetSubTabs() const {
 | 
			
		||||
    return {
 | 
			
		||||
        ui->tabPlayer1, ui->tabPlayer2, ui->tabPlayer3, ui->tabPlayer4,  ui->tabPlayer5,
 | 
			
		||||
        ui->tabPlayer6, ui->tabPlayer7, ui->tabPlayer8, ui->tabAdvanced,
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ConfigureInput::ApplyConfiguration() {
 | 
			
		||||
    for (std::size_t i = 0; i < players_controller.size(); ++i) {
 | 
			
		||||
        const auto controller_type_index = players_controller[i]->currentIndex();
 | 
			
		||||
 | 
			
		||||
        Settings::values.players[i].connected = controller_type_index != 0;
 | 
			
		||||
 | 
			
		||||
        if (controller_type_index > 0) {
 | 
			
		||||
            Settings::values.players[i].type =
 | 
			
		||||
                static_cast<Settings::ControllerType>(controller_type_index - 1);
 | 
			
		||||
        } else {
 | 
			
		||||
            Settings::values.players[i].type = Settings::ControllerType::DualJoycon;
 | 
			
		||||
        }
 | 
			
		||||
    for (auto controller : player_controllers) {
 | 
			
		||||
        controller->ApplyConfiguration();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    advanced->ApplyConfiguration();
 | 
			
		||||
 | 
			
		||||
    const bool pre_docked_mode = Settings::values.use_docked_mode;
 | 
			
		||||
    Settings::values.use_docked_mode = ui->use_docked_mode->isChecked();
 | 
			
		||||
    Settings::values.use_docked_mode = ui->radioDocked->isChecked();
 | 
			
		||||
    OnDockedModeChanged(pre_docked_mode, Settings::values.use_docked_mode);
 | 
			
		||||
    Settings::values
 | 
			
		||||
        .players[Service::HID::Controller_NPad::NPadIdToIndex(Service::HID::NPAD_HANDHELD)]
 | 
			
		||||
        .connected = ui->handheld_connected->isChecked();
 | 
			
		||||
    Settings::values.debug_pad_enabled = ui->debug_enabled->isChecked();
 | 
			
		||||
    Settings::values.mouse_enabled = ui->mouse_enabled->isChecked();
 | 
			
		||||
    Settings::values.keyboard_enabled = ui->keyboard_enabled->isChecked();
 | 
			
		||||
    Settings::values.touchscreen.enabled = ui->touchscreen_enabled->isChecked();
 | 
			
		||||
 | 
			
		||||
    Settings::values.vibration_enabled = ui->vibrationGroup->isChecked();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ConfigureInput::changeEvent(QEvent* event) {
 | 
			
		||||
@ -146,94 +157,63 @@ void ConfigureInput::changeEvent(QEvent* event) {
 | 
			
		||||
        RetranslateUI();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    QDialog::changeEvent(event);
 | 
			
		||||
    QWidget::changeEvent(event);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ConfigureInput::RetranslateUI() {
 | 
			
		||||
    ui->retranslateUi(this);
 | 
			
		||||
    RetranslateControllerComboBoxes();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ConfigureInput::RetranslateControllerComboBoxes() {
 | 
			
		||||
    for (auto* controller_box : players_controller) {
 | 
			
		||||
        [[maybe_unused]] const QSignalBlocker blocker(controller_box);
 | 
			
		||||
 | 
			
		||||
        controller_box->clear();
 | 
			
		||||
        controller_box->addItems({tr("None"), tr("Pro Controller"), tr("Dual Joycons"),
 | 
			
		||||
                                  tr("Single Right Joycon"), tr("Single Left Joycon")});
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    LoadPlayerControllerIndices();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ConfigureInput::UpdateUIEnabled() {
 | 
			
		||||
    bool hit_disabled = false;
 | 
			
		||||
    for (auto* player : players_controller) {
 | 
			
		||||
        player->setDisabled(hit_disabled);
 | 
			
		||||
        if (hit_disabled) {
 | 
			
		||||
            player->setCurrentIndex(0);
 | 
			
		||||
        }
 | 
			
		||||
        if (!hit_disabled && player->currentIndex() == 0) {
 | 
			
		||||
            hit_disabled = true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (std::size_t i = 0; i < players_controller.size(); ++i) {
 | 
			
		||||
        players_configure[i]->setEnabled(players_controller[i]->currentIndex() != 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ui->handheld_connected->setChecked(ui->handheld_connected->isChecked() &&
 | 
			
		||||
                                       !ui->use_docked_mode->isChecked());
 | 
			
		||||
    ui->handheld_connected->setEnabled(!ui->use_docked_mode->isChecked());
 | 
			
		||||
    ui->handheld_configure->setEnabled(ui->handheld_connected->isChecked() &&
 | 
			
		||||
                                       !ui->use_docked_mode->isChecked());
 | 
			
		||||
    ui->mouse_advanced->setEnabled(ui->mouse_enabled->isChecked());
 | 
			
		||||
    ui->debug_configure->setEnabled(ui->debug_enabled->isChecked());
 | 
			
		||||
    ui->touchscreen_advanced->setEnabled(ui->touchscreen_enabled->isChecked());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ConfigureInput::LoadConfiguration() {
 | 
			
		||||
    std::stable_partition(
 | 
			
		||||
        Settings::values.players.begin(),
 | 
			
		||||
        Settings::values.players.begin() +
 | 
			
		||||
            Service::HID::Controller_NPad::NPadIdToIndex(Service::HID::NPAD_HANDHELD),
 | 
			
		||||
        [](const auto& player) { return player.connected; });
 | 
			
		||||
 | 
			
		||||
    LoadPlayerControllerIndices();
 | 
			
		||||
    UpdateDockedState(Settings::values.players[0].controller_type ==
 | 
			
		||||
                      Settings::ControllerType::Handheld);
 | 
			
		||||
 | 
			
		||||
    ui->use_docked_mode->setChecked(Settings::values.use_docked_mode);
 | 
			
		||||
    ui->handheld_connected->setChecked(
 | 
			
		||||
        Settings::values
 | 
			
		||||
            .players[Service::HID::Controller_NPad::NPadIdToIndex(Service::HID::NPAD_HANDHELD)]
 | 
			
		||||
            .connected);
 | 
			
		||||
    ui->debug_enabled->setChecked(Settings::values.debug_pad_enabled);
 | 
			
		||||
    ui->mouse_enabled->setChecked(Settings::values.mouse_enabled);
 | 
			
		||||
    ui->keyboard_enabled->setChecked(Settings::values.keyboard_enabled);
 | 
			
		||||
    ui->touchscreen_enabled->setChecked(Settings::values.touchscreen.enabled);
 | 
			
		||||
 | 
			
		||||
    UpdateUIEnabled();
 | 
			
		||||
    ui->vibrationGroup->setChecked(Settings::values.vibration_enabled);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ConfigureInput::LoadPlayerControllerIndices() {
 | 
			
		||||
    for (std::size_t i = 0; i < players_controller.size(); ++i) {
 | 
			
		||||
        const auto connected = Settings::values.players[i].connected;
 | 
			
		||||
        players_controller[i]->setCurrentIndex(
 | 
			
		||||
            connected ? static_cast<u8>(Settings::values.players[i].type) + 1 : 0);
 | 
			
		||||
    for (std::size_t i = 0; i < player_connected.size(); ++i) {
 | 
			
		||||
        const auto connected = Settings::values.players[i].connected ||
 | 
			
		||||
                               (i == 0 && Settings::values.players[8].connected);
 | 
			
		||||
        player_connected[i]->setChecked(connected);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ConfigureInput::ClearAll() {
 | 
			
		||||
    // We don't have a good way to know what tab is active, but we can find out by getting the
 | 
			
		||||
    // parent of the consoleInputSettings
 | 
			
		||||
    auto* player_tab = static_cast<ConfigureInputPlayer*>(ui->consoleInputSettings->parent());
 | 
			
		||||
    player_tab->ClearAll();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ConfigureInput::RestoreDefaults() {
 | 
			
		||||
    players_controller[0]->setCurrentIndex(2);
 | 
			
		||||
    // We don't have a good way to know what tab is active, but we can find out by getting the
 | 
			
		||||
    // parent of the consoleInputSettings
 | 
			
		||||
    auto* player_tab = static_cast<ConfigureInputPlayer*>(ui->consoleInputSettings->parent());
 | 
			
		||||
    player_tab->RestoreDefaults();
 | 
			
		||||
 | 
			
		||||
    for (std::size_t i = 1; i < players_controller.size(); ++i) {
 | 
			
		||||
        players_controller[i]->setCurrentIndex(0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ui->use_docked_mode->setCheckState(Qt::Unchecked);
 | 
			
		||||
    ui->handheld_connected->setCheckState(Qt::Unchecked);
 | 
			
		||||
    ui->mouse_enabled->setCheckState(Qt::Unchecked);
 | 
			
		||||
    ui->keyboard_enabled->setCheckState(Qt::Unchecked);
 | 
			
		||||
    ui->debug_enabled->setCheckState(Qt::Unchecked);
 | 
			
		||||
    ui->touchscreen_enabled->setCheckState(Qt::Checked);
 | 
			
		||||
    UpdateUIEnabled();
 | 
			
		||||
    ui->radioDocked->setChecked(true);
 | 
			
		||||
    ui->radioUndocked->setChecked(false);
 | 
			
		||||
    ui->vibrationGroup->setChecked(true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ConfigureInput::UpdateDockedState(bool is_handheld) {
 | 
			
		||||
    // If the controller type is handheld only, disallow changing docked mode
 | 
			
		||||
    ui->radioDocked->setEnabled(!is_handheld);
 | 
			
		||||
    ui->radioUndocked->setEnabled(!is_handheld);
 | 
			
		||||
 | 
			
		||||
    ui->radioDocked->setChecked(Settings::values.use_docked_mode);
 | 
			
		||||
    ui->radioUndocked->setChecked(!Settings::values.use_docked_mode);
 | 
			
		||||
 | 
			
		||||
    // If its handheld only, force docked mode off (since you can't play handheld in a dock)
 | 
			
		||||
    if (is_handheld) {
 | 
			
		||||
        ui->radioUndocked->setChecked(true);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ConfigureInput::UpdateAllInputDevices() {
 | 
			
		||||
    for (const auto& player : player_controllers) {
 | 
			
		||||
        player->UpdateInputDevices();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -10,9 +10,12 @@
 | 
			
		||||
#include <QDialog>
 | 
			
		||||
#include <QKeyEvent>
 | 
			
		||||
 | 
			
		||||
#include "yuzu/configuration/configure_input_advanced.h"
 | 
			
		||||
#include "yuzu/configuration/configure_input_player.h"
 | 
			
		||||
 | 
			
		||||
#include "ui_configure_input.h"
 | 
			
		||||
 | 
			
		||||
class QPushButton;
 | 
			
		||||
class QCheckBox;
 | 
			
		||||
class QString;
 | 
			
		||||
class QTimer;
 | 
			
		||||
 | 
			
		||||
@ -22,22 +25,25 @@ class ConfigureInput;
 | 
			
		||||
 | 
			
		||||
void OnDockedModeChanged(bool last_state, bool new_state);
 | 
			
		||||
 | 
			
		||||
class ConfigureInput : public QDialog {
 | 
			
		||||
class ConfigureInput : public QWidget {
 | 
			
		||||
    Q_OBJECT
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    explicit ConfigureInput(QWidget* parent = nullptr);
 | 
			
		||||
    ~ConfigureInput() override;
 | 
			
		||||
 | 
			
		||||
    /// Save all button configurations to settings file
 | 
			
		||||
    /// Save all button configurations to settings file.
 | 
			
		||||
    void ApplyConfiguration();
 | 
			
		||||
 | 
			
		||||
    QList<QWidget*> GetSubTabs() const;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void changeEvent(QEvent* event) override;
 | 
			
		||||
    void RetranslateUI();
 | 
			
		||||
    void RetranslateControllerComboBoxes();
 | 
			
		||||
    void ClearAll();
 | 
			
		||||
 | 
			
		||||
    void UpdateUIEnabled();
 | 
			
		||||
    void UpdateDockedState(bool is_handheld);
 | 
			
		||||
    void UpdateAllInputDevices();
 | 
			
		||||
 | 
			
		||||
    /// Load configuration settings.
 | 
			
		||||
    void LoadConfiguration();
 | 
			
		||||
@ -48,6 +54,8 @@ private:
 | 
			
		||||
 | 
			
		||||
    std::unique_ptr<Ui::ConfigureInput> ui;
 | 
			
		||||
 | 
			
		||||
    std::array<QComboBox*, 8> players_controller;
 | 
			
		||||
    std::array<QPushButton*, 8> players_configure;
 | 
			
		||||
    std::array<ConfigureInputPlayer*, 8> player_controllers;
 | 
			
		||||
    std::array<QWidget*, 8> player_tabs;
 | 
			
		||||
    std::array<QCheckBox*, 8> player_connected;
 | 
			
		||||
    ConfigureInputAdvanced* advanced;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										169
									
								
								src/yuzu/configuration/configure_input_advanced.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,169 @@
 | 
			
		||||
// Copyright 2020 yuzu Emulator Project
 | 
			
		||||
// Licensed under GPLv2 or any later version
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#include <QColorDialog>
 | 
			
		||||
#include "core/core.h"
 | 
			
		||||
#include "core/settings.h"
 | 
			
		||||
#include "ui_configure_input_advanced.h"
 | 
			
		||||
#include "yuzu/configuration/configure_input_advanced.h"
 | 
			
		||||
 | 
			
		||||
ConfigureInputAdvanced::ConfigureInputAdvanced(QWidget* parent)
 | 
			
		||||
    : QWidget(parent), ui(std::make_unique<Ui::ConfigureInputAdvanced>()) {
 | 
			
		||||
    ui->setupUi(this);
 | 
			
		||||
 | 
			
		||||
    controllers_color_buttons = {{
 | 
			
		||||
        {
 | 
			
		||||
            ui->player1_left_body_button,
 | 
			
		||||
            ui->player1_left_buttons_button,
 | 
			
		||||
            ui->player1_right_body_button,
 | 
			
		||||
            ui->player1_right_buttons_button,
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            ui->player2_left_body_button,
 | 
			
		||||
            ui->player2_left_buttons_button,
 | 
			
		||||
            ui->player2_right_body_button,
 | 
			
		||||
            ui->player2_right_buttons_button,
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            ui->player3_left_body_button,
 | 
			
		||||
            ui->player3_left_buttons_button,
 | 
			
		||||
            ui->player3_right_body_button,
 | 
			
		||||
            ui->player3_right_buttons_button,
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            ui->player4_left_body_button,
 | 
			
		||||
            ui->player4_left_buttons_button,
 | 
			
		||||
            ui->player4_right_body_button,
 | 
			
		||||
            ui->player4_right_buttons_button,
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            ui->player5_left_body_button,
 | 
			
		||||
            ui->player5_left_buttons_button,
 | 
			
		||||
            ui->player5_right_body_button,
 | 
			
		||||
            ui->player5_right_buttons_button,
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            ui->player6_left_body_button,
 | 
			
		||||
            ui->player6_left_buttons_button,
 | 
			
		||||
            ui->player6_right_body_button,
 | 
			
		||||
            ui->player6_right_buttons_button,
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            ui->player7_left_body_button,
 | 
			
		||||
            ui->player7_left_buttons_button,
 | 
			
		||||
            ui->player7_right_body_button,
 | 
			
		||||
            ui->player7_right_buttons_button,
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            ui->player8_left_body_button,
 | 
			
		||||
            ui->player8_left_buttons_button,
 | 
			
		||||
            ui->player8_right_body_button,
 | 
			
		||||
            ui->player8_right_buttons_button,
 | 
			
		||||
        },
 | 
			
		||||
    }};
 | 
			
		||||
 | 
			
		||||
    for (std::size_t player_idx = 0; player_idx < controllers_color_buttons.size(); ++player_idx) {
 | 
			
		||||
        auto& color_buttons = controllers_color_buttons[player_idx];
 | 
			
		||||
        for (std::size_t button_idx = 0; button_idx < color_buttons.size(); ++button_idx) {
 | 
			
		||||
            connect(color_buttons[button_idx], &QPushButton::clicked, this,
 | 
			
		||||
                    [this, player_idx, button_idx] {
 | 
			
		||||
                        OnControllerButtonClick(static_cast<int>(player_idx),
 | 
			
		||||
                                                static_cast<int>(button_idx));
 | 
			
		||||
                    });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    connect(ui->mouse_enabled, &QCheckBox::stateChanged, this,
 | 
			
		||||
            &ConfigureInputAdvanced::UpdateUIEnabled);
 | 
			
		||||
    connect(ui->debug_enabled, &QCheckBox::stateChanged, this,
 | 
			
		||||
            &ConfigureInputAdvanced::UpdateUIEnabled);
 | 
			
		||||
    connect(ui->touchscreen_enabled, &QCheckBox::stateChanged, this,
 | 
			
		||||
            &ConfigureInputAdvanced::UpdateUIEnabled);
 | 
			
		||||
 | 
			
		||||
    connect(ui->debug_configure, &QPushButton::clicked, this,
 | 
			
		||||
            [this] { CallDebugControllerDialog(); });
 | 
			
		||||
    connect(ui->mouse_advanced, &QPushButton::clicked, this, [this] { CallMouseConfigDialog(); });
 | 
			
		||||
    connect(ui->touchscreen_advanced, &QPushButton::clicked, this,
 | 
			
		||||
            [this] { CallTouchscreenConfigDialog(); });
 | 
			
		||||
 | 
			
		||||
    LoadConfiguration();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ConfigureInputAdvanced::~ConfigureInputAdvanced() = default;
 | 
			
		||||
 | 
			
		||||
void ConfigureInputAdvanced::OnControllerButtonClick(int player_idx, int button_idx) {
 | 
			
		||||
    const QColor new_bg_color = QColorDialog::getColor(controllers_colors[player_idx][button_idx]);
 | 
			
		||||
    if (!new_bg_color.isValid()) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    controllers_colors[player_idx][button_idx] = new_bg_color;
 | 
			
		||||
    controllers_color_buttons[player_idx][button_idx]->setStyleSheet(
 | 
			
		||||
        QStringLiteral("background-color: %1; min-width: 55px;")
 | 
			
		||||
            .arg(controllers_colors[player_idx][button_idx].name()));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ConfigureInputAdvanced::ApplyConfiguration() {
 | 
			
		||||
    for (std::size_t player_idx = 0; player_idx < controllers_color_buttons.size(); ++player_idx) {
 | 
			
		||||
        auto& player = Settings::values.players[player_idx];
 | 
			
		||||
        std::array<u32, 4> colors{};
 | 
			
		||||
        std::transform(controllers_colors[player_idx].begin(), controllers_colors[player_idx].end(),
 | 
			
		||||
                       colors.begin(), [](QColor color) { return color.rgb(); });
 | 
			
		||||
 | 
			
		||||
        player.body_color_left = colors[0];
 | 
			
		||||
        player.button_color_left = colors[1];
 | 
			
		||||
        player.body_color_right = colors[2];
 | 
			
		||||
        player.button_color_right = colors[3];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Settings::values.debug_pad_enabled = ui->debug_enabled->isChecked();
 | 
			
		||||
    Settings::values.mouse_enabled = ui->mouse_enabled->isChecked();
 | 
			
		||||
    Settings::values.keyboard_enabled = ui->keyboard_enabled->isChecked();
 | 
			
		||||
    Settings::values.touchscreen.enabled = ui->touchscreen_enabled->isChecked();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ConfigureInputAdvanced::LoadConfiguration() {
 | 
			
		||||
    for (std::size_t player_idx = 0; player_idx < controllers_color_buttons.size(); ++player_idx) {
 | 
			
		||||
        auto& player = Settings::values.players[player_idx];
 | 
			
		||||
        std::array<u32, 4> colors = {
 | 
			
		||||
            player.body_color_left,
 | 
			
		||||
            player.button_color_left,
 | 
			
		||||
            player.body_color_right,
 | 
			
		||||
            player.button_color_right,
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        std::transform(colors.begin(), colors.end(), controllers_colors[player_idx].begin(),
 | 
			
		||||
                       [](u32 rgb) { return QColor::fromRgb(rgb); });
 | 
			
		||||
 | 
			
		||||
        for (std::size_t button_idx = 0; button_idx < colors.size(); ++button_idx) {
 | 
			
		||||
            controllers_color_buttons[player_idx][button_idx]->setStyleSheet(
 | 
			
		||||
                QStringLiteral("background-color: %1; min-width: 55px;")
 | 
			
		||||
                    .arg(controllers_colors[player_idx][button_idx].name()));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ui->debug_enabled->setChecked(Settings::values.debug_pad_enabled);
 | 
			
		||||
    ui->mouse_enabled->setChecked(Settings::values.mouse_enabled);
 | 
			
		||||
    ui->keyboard_enabled->setChecked(Settings::values.keyboard_enabled);
 | 
			
		||||
    ui->touchscreen_enabled->setChecked(Settings::values.touchscreen.enabled);
 | 
			
		||||
 | 
			
		||||
    UpdateUIEnabled();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ConfigureInputAdvanced::changeEvent(QEvent* event) {
 | 
			
		||||
    if (event->type() == QEvent::LanguageChange) {
 | 
			
		||||
        RetranslateUI();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    QWidget::changeEvent(event);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ConfigureInputAdvanced::RetranslateUI() {
 | 
			
		||||
    ui->retranslateUi(this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ConfigureInputAdvanced::UpdateUIEnabled() {
 | 
			
		||||
    ui->mouse_advanced->setEnabled(ui->mouse_enabled->isChecked());
 | 
			
		||||
    ui->debug_configure->setEnabled(ui->debug_enabled->isChecked());
 | 
			
		||||
    ui->touchscreen_advanced->setEnabled(ui->touchscreen_enabled->isChecked());
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										45
									
								
								src/yuzu/configuration/configure_input_advanced.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,45 @@
 | 
			
		||||
// Copyright 2020 yuzu Emulator Project
 | 
			
		||||
// Licensed under GPLv2 or any later version
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <QWidget>
 | 
			
		||||
 | 
			
		||||
class QColor;
 | 
			
		||||
class QPushButton;
 | 
			
		||||
 | 
			
		||||
namespace Ui {
 | 
			
		||||
class ConfigureInputAdvanced;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class ConfigureInputAdvanced : public QWidget {
 | 
			
		||||
    Q_OBJECT
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    explicit ConfigureInputAdvanced(QWidget* parent = nullptr);
 | 
			
		||||
    ~ConfigureInputAdvanced() override;
 | 
			
		||||
 | 
			
		||||
    void ApplyConfiguration();
 | 
			
		||||
 | 
			
		||||
signals:
 | 
			
		||||
    void CallDebugControllerDialog();
 | 
			
		||||
    void CallMouseConfigDialog();
 | 
			
		||||
    void CallTouchscreenConfigDialog();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void changeEvent(QEvent* event) override;
 | 
			
		||||
    void RetranslateUI();
 | 
			
		||||
    void UpdateUIEnabled();
 | 
			
		||||
 | 
			
		||||
    void OnControllerButtonClick(int player_idx, int button_idx);
 | 
			
		||||
 | 
			
		||||
    void LoadConfiguration();
 | 
			
		||||
 | 
			
		||||
    std::unique_ptr<Ui::ConfigureInputAdvanced> ui;
 | 
			
		||||
 | 
			
		||||
    std::array<std::array<QColor, 4>, 8> controllers_colors;
 | 
			
		||||
    std::array<std::array<QPushButton*, 4>, 8> controllers_color_buttons;
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										2688
									
								
								src/yuzu/configuration/configure_input_advanced.ui
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -15,11 +15,17 @@
 | 
			
		||||
#include "common/param_package.h"
 | 
			
		||||
#include "core/settings.h"
 | 
			
		||||
#include "ui_configure_input.h"
 | 
			
		||||
#include "yuzu/uisettings.h"
 | 
			
		||||
 | 
			
		||||
class QCheckBox;
 | 
			
		||||
class QKeyEvent;
 | 
			
		||||
class QLabel;
 | 
			
		||||
class QPushButton;
 | 
			
		||||
class QSlider;
 | 
			
		||||
class QSpinBox;
 | 
			
		||||
class QString;
 | 
			
		||||
class QTimer;
 | 
			
		||||
class QWidget;
 | 
			
		||||
 | 
			
		||||
namespace InputCommon::Polling {
 | 
			
		||||
class DevicePoller;
 | 
			
		||||
@ -30,43 +36,76 @@ namespace Ui {
 | 
			
		||||
class ConfigureInputPlayer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class ConfigureInputPlayer : public QDialog {
 | 
			
		||||
class ConfigureInputPlayer : public QWidget {
 | 
			
		||||
    Q_OBJECT
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    explicit ConfigureInputPlayer(QWidget* parent, std::size_t player_index, bool debug = false);
 | 
			
		||||
    explicit ConfigureInputPlayer(QWidget* parent, std::size_t player_index, QWidget* bottom_row,
 | 
			
		||||
                                  bool debug = false);
 | 
			
		||||
    ~ConfigureInputPlayer() override;
 | 
			
		||||
 | 
			
		||||
    /// Save all button configurations to settings file
 | 
			
		||||
    /// Save all button configurations to settings file.
 | 
			
		||||
    void ApplyConfiguration();
 | 
			
		||||
 | 
			
		||||
    /// Update the input devices combobox.
 | 
			
		||||
    void UpdateInputDevices();
 | 
			
		||||
 | 
			
		||||
    /// Restore all buttons to their default values.
 | 
			
		||||
    void RestoreDefaults();
 | 
			
		||||
 | 
			
		||||
    /// Clear all input configuration.
 | 
			
		||||
    void ClearAll();
 | 
			
		||||
 | 
			
		||||
    /// Set the connection state checkbox (used to sync state).
 | 
			
		||||
    void ConnectPlayer(bool connected);
 | 
			
		||||
 | 
			
		||||
signals:
 | 
			
		||||
    /// Emitted when this controller is connected by the user.
 | 
			
		||||
    void Connected(bool connected);
 | 
			
		||||
    /// Emitted when the Handheld mode is selected (undocked with dual joycons attached).
 | 
			
		||||
    void HandheldStateChanged(bool is_handheld);
 | 
			
		||||
    /// Emitted when the input devices combobox is being refreshed.
 | 
			
		||||
    void RefreshInputDevices();
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    void showEvent(QShowEvent* event) override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void changeEvent(QEvent* event) override;
 | 
			
		||||
    void RetranslateUI();
 | 
			
		||||
 | 
			
		||||
    void OnControllerButtonClick(int i);
 | 
			
		||||
 | 
			
		||||
    /// Load configuration settings.
 | 
			
		||||
    void LoadConfiguration();
 | 
			
		||||
    /// Restore all buttons to their default values.
 | 
			
		||||
    void RestoreDefaults();
 | 
			
		||||
    /// Clear all input configuration
 | 
			
		||||
    void ClearAll();
 | 
			
		||||
 | 
			
		||||
    /// Update UI to reflect current configuration.
 | 
			
		||||
    void UpdateButtonLabels();
 | 
			
		||||
 | 
			
		||||
    /// Called when the button was pressed.
 | 
			
		||||
    void HandleClick(QPushButton* button,
 | 
			
		||||
                     std::function<void(const Common::ParamPackage&)> new_input_setter,
 | 
			
		||||
                     InputCommon::Polling::DeviceType type);
 | 
			
		||||
 | 
			
		||||
    /// Finish polling and configure input using the input_setter
 | 
			
		||||
    /// Finish polling and configure input using the input_setter.
 | 
			
		||||
    void SetPollingResult(const Common::ParamPackage& params, bool abort);
 | 
			
		||||
 | 
			
		||||
    /// Handle mouse button press events.
 | 
			
		||||
    void mousePressEvent(QMouseEvent* event) override;
 | 
			
		||||
 | 
			
		||||
    /// Handle key press events.
 | 
			
		||||
    void keyPressEvent(QKeyEvent* event) override;
 | 
			
		||||
 | 
			
		||||
    /// Update UI to reflect current configuration.
 | 
			
		||||
    void UpdateUI();
 | 
			
		||||
 | 
			
		||||
    /// Update the controller selection combobox
 | 
			
		||||
    void UpdateControllerCombobox();
 | 
			
		||||
 | 
			
		||||
    /// Update the current controller icon.
 | 
			
		||||
    void UpdateControllerIcon();
 | 
			
		||||
 | 
			
		||||
    /// Hides and disables controller settings based on the current controller type.
 | 
			
		||||
    void UpdateControllerAvailableButtons();
 | 
			
		||||
 | 
			
		||||
    /// Gets the default controller mapping for this device and auto configures the input to match.
 | 
			
		||||
    void UpdateMappingWithDefaults();
 | 
			
		||||
 | 
			
		||||
    std::unique_ptr<Ui::ConfigureInputPlayer> ui;
 | 
			
		||||
 | 
			
		||||
    std::size_t player_index;
 | 
			
		||||
@ -75,32 +114,35 @@ private:
 | 
			
		||||
    std::unique_ptr<QTimer> timeout_timer;
 | 
			
		||||
    std::unique_ptr<QTimer> poll_timer;
 | 
			
		||||
 | 
			
		||||
    static constexpr int PLAYER_COUNT = 8;
 | 
			
		||||
    std::array<QCheckBox*, PLAYER_COUNT> player_connected_checkbox;
 | 
			
		||||
 | 
			
		||||
    /// This will be the the setting function when an input is awaiting configuration.
 | 
			
		||||
    std::optional<std::function<void(const Common::ParamPackage&)>> input_setter;
 | 
			
		||||
 | 
			
		||||
    std::array<Common::ParamPackage, Settings::NativeButton::NumButtons> buttons_param;
 | 
			
		||||
    std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs> analogs_param;
 | 
			
		||||
 | 
			
		||||
    static constexpr int ANALOG_SUB_BUTTONS_NUM = 5;
 | 
			
		||||
    static constexpr int ANALOG_SUB_BUTTONS_NUM = 4;
 | 
			
		||||
 | 
			
		||||
    /// Each button input is represented by a QPushButton.
 | 
			
		||||
    std::array<QPushButton*, Settings::NativeButton::NumButtons> button_map;
 | 
			
		||||
    /// Extra buttons for the modifiers.
 | 
			
		||||
    Common::ParamPackage lstick_mod;
 | 
			
		||||
    Common::ParamPackage rstick_mod;
 | 
			
		||||
 | 
			
		||||
    std::vector<QWidget*> debug_hidden;
 | 
			
		||||
    std::vector<QWidget*> layout_hidden;
 | 
			
		||||
 | 
			
		||||
    /// A group of five QPushButtons represent one analog input. The buttons each represent up,
 | 
			
		||||
    /// down, left, right, and modifier, respectively.
 | 
			
		||||
    /// A group of four QPushButtons represent one analog input. The buttons each represent up,
 | 
			
		||||
    /// down, left, right, respectively.
 | 
			
		||||
    std::array<std::array<QPushButton*, ANALOG_SUB_BUTTONS_NUM>, Settings::NativeAnalog::NumAnalogs>
 | 
			
		||||
        analog_map_buttons;
 | 
			
		||||
 | 
			
		||||
    /// Analog inputs are also represented each with a single button, used to configure with an
 | 
			
		||||
    /// actual analog stick
 | 
			
		||||
    std::array<QPushButton*, Settings::NativeAnalog::NumAnalogs> analog_map_stick;
 | 
			
		||||
    std::array<QSlider*, Settings::NativeAnalog::NumAnalogs>
 | 
			
		||||
        analog_map_deadzone_and_modifier_slider;
 | 
			
		||||
    std::array<QLabel*, Settings::NativeAnalog::NumAnalogs>
 | 
			
		||||
        analog_map_deadzone_and_modifier_slider_label;
 | 
			
		||||
    std::array<QLabel*, Settings::NativeAnalog::NumAnalogs> analog_map_deadzone_label;
 | 
			
		||||
    std::array<QSlider*, Settings::NativeAnalog::NumAnalogs> analog_map_deadzone_slider;
 | 
			
		||||
    std::array<QGroupBox*, Settings::NativeAnalog::NumAnalogs> analog_map_modifier_groupbox;
 | 
			
		||||
    std::array<QLabel*, Settings::NativeAnalog::NumAnalogs> analog_map_modifier_label;
 | 
			
		||||
    std::array<QSlider*, Settings::NativeAnalog::NumAnalogs> analog_map_modifier_slider;
 | 
			
		||||
    std::array<QGroupBox*, Settings::NativeAnalog::NumAnalogs> analog_map_range_groupbox;
 | 
			
		||||
    std::array<QSpinBox*, Settings::NativeAnalog::NumAnalogs> analog_map_range_spinbox;
 | 
			
		||||
 | 
			
		||||
    static const std::array<std::string, ANALOG_SUB_BUTTONS_NUM> analog_sub_buttons;
 | 
			
		||||
 | 
			
		||||
@ -108,8 +150,14 @@ private:
 | 
			
		||||
 | 
			
		||||
    /// A flag to indicate if keyboard keys are okay when configuring an input. If this is false,
 | 
			
		||||
    /// keyboard events are ignored.
 | 
			
		||||
    bool want_keyboard_keys = false;
 | 
			
		||||
    bool want_keyboard_mouse = false;
 | 
			
		||||
 | 
			
		||||
    std::array<QPushButton*, 4> controller_color_buttons;
 | 
			
		||||
    std::array<QColor, 4> controller_colors;
 | 
			
		||||
    /// List of physical devices users can map with. If a SDL backed device is selected, then you
 | 
			
		||||
    /// can usue this device to get a default mapping.
 | 
			
		||||
    std::vector<Common::ParamPackage> input_devices;
 | 
			
		||||
 | 
			
		||||
    /// Bottom row is where console wide settings are held, and its "owned" by the parent
 | 
			
		||||
    /// ConfigureInput widget. On show, add this widget to the main layout. This will change the
 | 
			
		||||
    /// parent of the widget to this widget (but thats fine).
 | 
			
		||||
    QWidget* bottom_row;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -1,152 +0,0 @@
 | 
			
		||||
// Copyright 2016 Citra Emulator Project
 | 
			
		||||
// Licensed under GPLv2 or any later version
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <tuple>
 | 
			
		||||
 | 
			
		||||
#include "ui_configure_input_simple.h"
 | 
			
		||||
#include "yuzu/configuration/configure_input.h"
 | 
			
		||||
#include "yuzu/configuration/configure_input_player.h"
 | 
			
		||||
#include "yuzu/configuration/configure_input_simple.h"
 | 
			
		||||
#include "yuzu/uisettings.h"
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
template <typename Dialog, typename... Args>
 | 
			
		||||
void CallConfigureDialog(ConfigureInputSimple* caller, Args&&... args) {
 | 
			
		||||
    caller->ApplyConfiguration();
 | 
			
		||||
    Dialog dialog(caller, std::forward<Args>(args)...);
 | 
			
		||||
 | 
			
		||||
    const auto res = dialog.exec();
 | 
			
		||||
    if (res == QDialog::Accepted) {
 | 
			
		||||
        dialog.ApplyConfiguration();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// OnProfileSelect functions should (when applicable):
 | 
			
		||||
// - Set controller types
 | 
			
		||||
// - Set controller enabled
 | 
			
		||||
// - Set docked mode
 | 
			
		||||
// - Set advanced controller config/enabled (i.e. debug, kbd, mouse, touch)
 | 
			
		||||
//
 | 
			
		||||
// OnProfileSelect function should NOT however:
 | 
			
		||||
// - Reset any button mappings
 | 
			
		||||
// - Open any dialogs
 | 
			
		||||
// - Block in any way
 | 
			
		||||
 | 
			
		||||
constexpr std::size_t PLAYER_0_INDEX = 0;
 | 
			
		||||
constexpr std::size_t HANDHELD_INDEX = 8;
 | 
			
		||||
 | 
			
		||||
void HandheldOnProfileSelect() {
 | 
			
		||||
    Settings::values.players[HANDHELD_INDEX].connected = true;
 | 
			
		||||
    Settings::values.players[HANDHELD_INDEX].type = Settings::ControllerType::DualJoycon;
 | 
			
		||||
 | 
			
		||||
    for (std::size_t player = 0; player < HANDHELD_INDEX; ++player) {
 | 
			
		||||
        Settings::values.players[player].connected = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Settings::values.use_docked_mode = false;
 | 
			
		||||
    Settings::values.keyboard_enabled = false;
 | 
			
		||||
    Settings::values.mouse_enabled = false;
 | 
			
		||||
    Settings::values.debug_pad_enabled = false;
 | 
			
		||||
    Settings::values.touchscreen.enabled = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DualJoyconsDockedOnProfileSelect() {
 | 
			
		||||
    Settings::values.players[PLAYER_0_INDEX].connected = true;
 | 
			
		||||
    Settings::values.players[PLAYER_0_INDEX].type = Settings::ControllerType::DualJoycon;
 | 
			
		||||
 | 
			
		||||
    for (std::size_t player = 1; player <= HANDHELD_INDEX; ++player) {
 | 
			
		||||
        Settings::values.players[player].connected = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Settings::values.use_docked_mode = true;
 | 
			
		||||
    Settings::values.keyboard_enabled = false;
 | 
			
		||||
    Settings::values.mouse_enabled = false;
 | 
			
		||||
    Settings::values.debug_pad_enabled = false;
 | 
			
		||||
    Settings::values.touchscreen.enabled = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Name, OnProfileSelect (called when selected in drop down), OnConfigure (called when configure
 | 
			
		||||
// is clicked)
 | 
			
		||||
using InputProfile = std::tuple<const char*, void (*)(), void (*)(ConfigureInputSimple*)>;
 | 
			
		||||
 | 
			
		||||
constexpr std::array<InputProfile, 3> INPUT_PROFILES{{
 | 
			
		||||
    {QT_TR_NOOP("Single Player - Handheld - Undocked"), HandheldOnProfileSelect,
 | 
			
		||||
     [](ConfigureInputSimple* caller) {
 | 
			
		||||
         CallConfigureDialog<ConfigureInputPlayer>(caller, HANDHELD_INDEX, false);
 | 
			
		||||
     }},
 | 
			
		||||
    {QT_TR_NOOP("Single Player - Dual Joycons - Docked"), DualJoyconsDockedOnProfileSelect,
 | 
			
		||||
     [](ConfigureInputSimple* caller) {
 | 
			
		||||
         CallConfigureDialog<ConfigureInputPlayer>(caller, PLAYER_0_INDEX, false);
 | 
			
		||||
     }},
 | 
			
		||||
    {QT_TR_NOOP("Custom"), [] {}, CallConfigureDialog<ConfigureInput>},
 | 
			
		||||
}};
 | 
			
		||||
 | 
			
		||||
} // namespace
 | 
			
		||||
 | 
			
		||||
void ApplyInputProfileConfiguration(int profile_index) {
 | 
			
		||||
    std::get<1>(
 | 
			
		||||
        INPUT_PROFILES.at(std::min(profile_index, static_cast<int>(INPUT_PROFILES.size() - 1))))();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ConfigureInputSimple::ConfigureInputSimple(QWidget* parent)
 | 
			
		||||
    : QWidget(parent), ui(std::make_unique<Ui::ConfigureInputSimple>()) {
 | 
			
		||||
    ui->setupUi(this);
 | 
			
		||||
 | 
			
		||||
    for (const auto& profile : INPUT_PROFILES) {
 | 
			
		||||
        const QString label = tr(std::get<0>(profile));
 | 
			
		||||
        ui->profile_combobox->addItem(label, label);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    connect(ui->profile_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
 | 
			
		||||
            &ConfigureInputSimple::OnSelectProfile);
 | 
			
		||||
    connect(ui->profile_configure, &QPushButton::clicked, this, &ConfigureInputSimple::OnConfigure);
 | 
			
		||||
 | 
			
		||||
    LoadConfiguration();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ConfigureInputSimple::~ConfigureInputSimple() = default;
 | 
			
		||||
 | 
			
		||||
void ConfigureInputSimple::ApplyConfiguration() {
 | 
			
		||||
    auto index = ui->profile_combobox->currentIndex();
 | 
			
		||||
    // Make the stored index for "Custom" very large so that if new profiles are added it
 | 
			
		||||
    // doesn't change.
 | 
			
		||||
    if (index >= static_cast<int>(INPUT_PROFILES.size() - 1)) {
 | 
			
		||||
        index = std::numeric_limits<int>::max();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    UISettings::values.profile_index = index;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ConfigureInputSimple::changeEvent(QEvent* event) {
 | 
			
		||||
    if (event->type() == QEvent::LanguageChange) {
 | 
			
		||||
        RetranslateUI();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    QWidget::changeEvent(event);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ConfigureInputSimple::RetranslateUI() {
 | 
			
		||||
    ui->retranslateUi(this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ConfigureInputSimple::LoadConfiguration() {
 | 
			
		||||
    const auto index = UISettings::values.profile_index;
 | 
			
		||||
    if (index >= static_cast<int>(INPUT_PROFILES.size()) || index < 0) {
 | 
			
		||||
        ui->profile_combobox->setCurrentIndex(static_cast<int>(INPUT_PROFILES.size() - 1));
 | 
			
		||||
    } else {
 | 
			
		||||
        ui->profile_combobox->setCurrentIndex(index);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ConfigureInputSimple::OnSelectProfile(int index) {
 | 
			
		||||
    const auto old_docked = Settings::values.use_docked_mode;
 | 
			
		||||
    ApplyInputProfileConfiguration(index);
 | 
			
		||||
    OnDockedModeChanged(old_docked, Settings::values.use_docked_mode);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ConfigureInputSimple::OnConfigure() {
 | 
			
		||||
    std::get<2>(INPUT_PROFILES.at(ui->profile_combobox->currentIndex()))(this);
 | 
			
		||||
}
 | 
			
		||||
@ -1,43 +0,0 @@
 | 
			
		||||
// Copyright 2016 Citra Emulator Project
 | 
			
		||||
// Licensed under GPLv2 or any later version
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <memory>
 | 
			
		||||
 | 
			
		||||
#include <QWidget>
 | 
			
		||||
 | 
			
		||||
class QPushButton;
 | 
			
		||||
class QString;
 | 
			
		||||
class QTimer;
 | 
			
		||||
 | 
			
		||||
namespace Ui {
 | 
			
		||||
class ConfigureInputSimple;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Used by configuration loader to apply a profile if the input is invalid.
 | 
			
		||||
void ApplyInputProfileConfiguration(int profile_index);
 | 
			
		||||
 | 
			
		||||
class ConfigureInputSimple : public QWidget {
 | 
			
		||||
    Q_OBJECT
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    explicit ConfigureInputSimple(QWidget* parent = nullptr);
 | 
			
		||||
    ~ConfigureInputSimple() override;
 | 
			
		||||
 | 
			
		||||
    /// Save all button configurations to settings file
 | 
			
		||||
    void ApplyConfiguration();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void changeEvent(QEvent* event) override;
 | 
			
		||||
    void RetranslateUI();
 | 
			
		||||
 | 
			
		||||
    /// Load configuration settings.
 | 
			
		||||
    void LoadConfiguration();
 | 
			
		||||
 | 
			
		||||
    void OnSelectProfile(int index);
 | 
			
		||||
    void OnConfigure();
 | 
			
		||||
 | 
			
		||||
    std::unique_ptr<Ui::ConfigureInputSimple> ui;
 | 
			
		||||
};
 | 
			
		||||
@ -1,97 +0,0 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<ui version="4.0">
 | 
			
		||||
 <class>ConfigureInputSimple</class>
 | 
			
		||||
 <widget class="QWidget" name="ConfigureInputSimple">
 | 
			
		||||
  <property name="geometry">
 | 
			
		||||
   <rect>
 | 
			
		||||
    <x>0</x>
 | 
			
		||||
    <y>0</y>
 | 
			
		||||
    <width>473</width>
 | 
			
		||||
    <height>685</height>
 | 
			
		||||
   </rect>
 | 
			
		||||
  </property>
 | 
			
		||||
  <property name="windowTitle">
 | 
			
		||||
   <string>ConfigureInputSimple</string>
 | 
			
		||||
  </property>
 | 
			
		||||
  <layout class="QVBoxLayout" name="verticalLayout_5">
 | 
			
		||||
   <item>
 | 
			
		||||
    <layout class="QVBoxLayout" name="verticalLayout">
 | 
			
		||||
     <item>
 | 
			
		||||
      <widget class="QGroupBox" name="gridGroupBox">
 | 
			
		||||
       <property name="title">
 | 
			
		||||
        <string>Profile</string>
 | 
			
		||||
       </property>
 | 
			
		||||
       <layout class="QGridLayout" name="gridLayout">
 | 
			
		||||
        <item row="1" column="2">
 | 
			
		||||
         <widget class="QPushButton" name="profile_configure">
 | 
			
		||||
          <property name="text">
 | 
			
		||||
           <string>Configure</string>
 | 
			
		||||
          </property>
 | 
			
		||||
         </widget>
 | 
			
		||||
        </item>
 | 
			
		||||
        <item row="1" column="0">
 | 
			
		||||
         <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 row="1" column="3">
 | 
			
		||||
         <spacer name="horizontalSpacer_2">
 | 
			
		||||
          <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 row="1" column="1">
 | 
			
		||||
         <widget class="QComboBox" name="profile_combobox">
 | 
			
		||||
          <property name="minimumSize">
 | 
			
		||||
           <size>
 | 
			
		||||
            <width>250</width>
 | 
			
		||||
            <height>0</height>
 | 
			
		||||
           </size>
 | 
			
		||||
          </property>
 | 
			
		||||
         </widget>
 | 
			
		||||
        </item>
 | 
			
		||||
        <item row="0" column="1" colspan="2">
 | 
			
		||||
         <widget class="QLabel" name="label">
 | 
			
		||||
          <property name="text">
 | 
			
		||||
           <string>Choose a controller configuration:</string>
 | 
			
		||||
          </property>
 | 
			
		||||
         </widget>
 | 
			
		||||
        </item>
 | 
			
		||||
       </layout>
 | 
			
		||||
      </widget>
 | 
			
		||||
     </item>
 | 
			
		||||
    </layout>
 | 
			
		||||
   </item>
 | 
			
		||||
   <item>
 | 
			
		||||
    <spacer name="verticalSpacer">
 | 
			
		||||
     <property name="orientation">
 | 
			
		||||
      <enum>Qt::Vertical</enum>
 | 
			
		||||
     </property>
 | 
			
		||||
     <property name="sizeHint" stdset="0">
 | 
			
		||||
      <size>
 | 
			
		||||
       <width>20</width>
 | 
			
		||||
       <height>40</height>
 | 
			
		||||
      </size>
 | 
			
		||||
     </property>
 | 
			
		||||
    </spacer>
 | 
			
		||||
   </item>
 | 
			
		||||
  </layout>
 | 
			
		||||
 </widget>
 | 
			
		||||
 <resources/>
 | 
			
		||||
 <connections/>
 | 
			
		||||
</ui>
 | 
			
		||||
@ -18,6 +18,16 @@
 | 
			
		||||
 | 
			
		||||
static QString GetKeyName(int key_code) {
 | 
			
		||||
    switch (key_code) {
 | 
			
		||||
    case Qt::LeftButton:
 | 
			
		||||
        return QObject::tr("Click 0");
 | 
			
		||||
    case Qt::RightButton:
 | 
			
		||||
        return QObject::tr("Click 1");
 | 
			
		||||
    case Qt::MiddleButton:
 | 
			
		||||
        return QObject::tr("Click 2");
 | 
			
		||||
    case Qt::BackButton:
 | 
			
		||||
        return QObject::tr("Click 3");
 | 
			
		||||
    case Qt::ForwardButton:
 | 
			
		||||
        return QObject::tr("Click 4");
 | 
			
		||||
    case Qt::Key_Shift:
 | 
			
		||||
        return QObject::tr("Shift");
 | 
			
		||||
    case Qt::Key_Control:
 | 
			
		||||
@ -188,9 +198,9 @@ void ConfigureMouseAdvanced::HandleClick(
 | 
			
		||||
    button->setText(tr("[press key]"));
 | 
			
		||||
    button->setFocus();
 | 
			
		||||
 | 
			
		||||
    // Keyboard keys can only be used as button devices
 | 
			
		||||
    want_keyboard_keys = type == InputCommon::Polling::DeviceType::Button;
 | 
			
		||||
    if (want_keyboard_keys) {
 | 
			
		||||
    // Keyboard keys or mouse buttons can only be used as button devices
 | 
			
		||||
    want_keyboard_mouse = type == InputCommon::Polling::DeviceType::Button;
 | 
			
		||||
    if (want_keyboard_mouse) {
 | 
			
		||||
        const auto iter = std::find(button_map.begin(), button_map.end(), button);
 | 
			
		||||
        ASSERT(iter != button_map.end());
 | 
			
		||||
        const auto index = std::distance(button_map.begin(), iter);
 | 
			
		||||
@ -205,21 +215,23 @@ void ConfigureMouseAdvanced::HandleClick(
 | 
			
		||||
        poller->Start();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    grabKeyboard();
 | 
			
		||||
    grabMouse();
 | 
			
		||||
    timeout_timer->start(5000); // Cancel after 5 seconds
 | 
			
		||||
    poll_timer->start(200);     // Check for new inputs every 200ms
 | 
			
		||||
    QWidget::grabMouse();
 | 
			
		||||
    QWidget::grabKeyboard();
 | 
			
		||||
 | 
			
		||||
    timeout_timer->start(2500); // Cancel after 2.5 seconds
 | 
			
		||||
    poll_timer->start(50);      // Check for new inputs every 50ms
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ConfigureMouseAdvanced::SetPollingResult(const Common::ParamPackage& params, bool abort) {
 | 
			
		||||
    releaseKeyboard();
 | 
			
		||||
    releaseMouse();
 | 
			
		||||
    timeout_timer->stop();
 | 
			
		||||
    poll_timer->stop();
 | 
			
		||||
    for (auto& poller : device_pollers) {
 | 
			
		||||
        poller->Stop();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    QWidget::releaseMouse();
 | 
			
		||||
    QWidget::releaseKeyboard();
 | 
			
		||||
 | 
			
		||||
    if (!abort) {
 | 
			
		||||
        (*input_setter)(params);
 | 
			
		||||
    }
 | 
			
		||||
@ -228,13 +240,29 @@ void ConfigureMouseAdvanced::SetPollingResult(const Common::ParamPackage& params
 | 
			
		||||
    input_setter = std::nullopt;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ConfigureMouseAdvanced::mousePressEvent(QMouseEvent* event) {
 | 
			
		||||
    if (!input_setter || !event) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (want_keyboard_mouse) {
 | 
			
		||||
        SetPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->button())},
 | 
			
		||||
                         false);
 | 
			
		||||
    } else {
 | 
			
		||||
        // We don't want any mouse buttons, so don't stop polling
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    SetPollingResult({}, true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ConfigureMouseAdvanced::keyPressEvent(QKeyEvent* event) {
 | 
			
		||||
    if (!input_setter || !event) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (event->key() != Qt::Key_Escape) {
 | 
			
		||||
        if (want_keyboard_keys) {
 | 
			
		||||
        if (want_keyboard_mouse) {
 | 
			
		||||
            SetPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->key())},
 | 
			
		||||
                             false);
 | 
			
		||||
        } else {
 | 
			
		||||
 | 
			
		||||
@ -49,6 +49,9 @@ private:
 | 
			
		||||
    /// Finish polling and configure input using the input_setter
 | 
			
		||||
    void SetPollingResult(const Common::ParamPackage& params, bool abort);
 | 
			
		||||
 | 
			
		||||
    /// Handle mouse button press events.
 | 
			
		||||
    void mousePressEvent(QMouseEvent* event) override;
 | 
			
		||||
 | 
			
		||||
    /// Handle key press events.
 | 
			
		||||
    void keyPressEvent(QKeyEvent* event) override;
 | 
			
		||||
 | 
			
		||||
@ -67,5 +70,5 @@ private:
 | 
			
		||||
 | 
			
		||||
    /// A flag to indicate if keyboard keys are okay when configuring an input. If this is false,
 | 
			
		||||
    /// keyboard events are ignored.
 | 
			
		||||
    bool want_keyboard_keys = false;
 | 
			
		||||
    bool want_keyboard_mouse = false;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -6,13 +6,18 @@
 | 
			
		||||
   <rect>
 | 
			
		||||
    <x>0</x>
 | 
			
		||||
    <y>0</y>
 | 
			
		||||
    <width>250</width>
 | 
			
		||||
    <height>261</height>
 | 
			
		||||
    <width>310</width>
 | 
			
		||||
    <height>193</height>
 | 
			
		||||
   </rect>
 | 
			
		||||
  </property>
 | 
			
		||||
  <property name="windowTitle">
 | 
			
		||||
   <string>Configure Mouse</string>
 | 
			
		||||
  </property>
 | 
			
		||||
  <property name="styleSheet">
 | 
			
		||||
   <string notr="true">QPushButton {
 | 
			
		||||
  min-width: 55px;
 | 
			
		||||
}</string>
 | 
			
		||||
  </property>
 | 
			
		||||
  <layout class="QVBoxLayout" name="verticalLayout">
 | 
			
		||||
   <item>
 | 
			
		||||
    <widget class="QGroupBox" name="gridGroupBox">
 | 
			
		||||
@ -20,81 +25,33 @@
 | 
			
		||||
      <string>Mouse Buttons</string>
 | 
			
		||||
     </property>
 | 
			
		||||
     <layout class="QGridLayout" name="gridLayout">
 | 
			
		||||
      <item row="0" column="4">
 | 
			
		||||
       <spacer name="horizontalSpacer_2">
 | 
			
		||||
        <property name="orientation">
 | 
			
		||||
         <enum>Qt::Horizontal</enum>
 | 
			
		||||
        </property>
 | 
			
		||||
        <property name="sizeType">
 | 
			
		||||
         <enum>QSizePolicy::Fixed</enum>
 | 
			
		||||
        </property>
 | 
			
		||||
        <property name="sizeHint" stdset="0">
 | 
			
		||||
         <size>
 | 
			
		||||
          <width>20</width>
 | 
			
		||||
          <height>20</height>
 | 
			
		||||
         </size>
 | 
			
		||||
        </property>
 | 
			
		||||
       </spacer>
 | 
			
		||||
      </item>
 | 
			
		||||
      <item row="0" column="3">
 | 
			
		||||
       <layout class="QVBoxLayout" name="verticalLayout_4">
 | 
			
		||||
      <item row="3" column="5">
 | 
			
		||||
       <layout class="QVBoxLayout" name="verticalLayout_6">
 | 
			
		||||
        <item>
 | 
			
		||||
         <layout class="QHBoxLayout" name="horizontalLayout_3">
 | 
			
		||||
         <layout class="QHBoxLayout" name="horizontalLayout_5">
 | 
			
		||||
          <item>
 | 
			
		||||
           <widget class="QLabel" name="label_3">
 | 
			
		||||
           <widget class="QLabel" name="label_5">
 | 
			
		||||
            <property name="text">
 | 
			
		||||
             <string>Right:</string>
 | 
			
		||||
             <string>Forward:</string>
 | 
			
		||||
            </property>
 | 
			
		||||
           </widget>
 | 
			
		||||
          </item>
 | 
			
		||||
         </layout>
 | 
			
		||||
        </item>
 | 
			
		||||
        <item>
 | 
			
		||||
         <widget class="QPushButton" name="right_button">
 | 
			
		||||
         <widget class="QPushButton" name="forward_button">
 | 
			
		||||
          <property name="minimumSize">
 | 
			
		||||
           <size>
 | 
			
		||||
            <width>75</width>
 | 
			
		||||
            <width>57</width>
 | 
			
		||||
            <height>0</height>
 | 
			
		||||
           </size>
 | 
			
		||||
          </property>
 | 
			
		||||
          <property name="text">
 | 
			
		||||
           <string/>
 | 
			
		||||
          <property name="maximumSize">
 | 
			
		||||
           <size>
 | 
			
		||||
            <width>16777215</width>
 | 
			
		||||
            <height>16777215</height>
 | 
			
		||||
           </size>
 | 
			
		||||
          </property>
 | 
			
		||||
         </widget>
 | 
			
		||||
        </item>
 | 
			
		||||
       </layout>
 | 
			
		||||
      </item>
 | 
			
		||||
      <item row="0" column="0">
 | 
			
		||||
       <spacer name="horizontalSpacer">
 | 
			
		||||
        <property name="orientation">
 | 
			
		||||
         <enum>Qt::Horizontal</enum>
 | 
			
		||||
        </property>
 | 
			
		||||
        <property name="sizeType">
 | 
			
		||||
         <enum>QSizePolicy::Fixed</enum>
 | 
			
		||||
        </property>
 | 
			
		||||
        <property name="sizeHint" stdset="0">
 | 
			
		||||
         <size>
 | 
			
		||||
          <width>20</width>
 | 
			
		||||
          <height>20</height>
 | 
			
		||||
         </size>
 | 
			
		||||
        </property>
 | 
			
		||||
       </spacer>
 | 
			
		||||
      </item>
 | 
			
		||||
      <item row="2" column="1">
 | 
			
		||||
       <layout class="QVBoxLayout" name="verticalLayout_3">
 | 
			
		||||
        <item>
 | 
			
		||||
         <layout class="QHBoxLayout" name="horizontalLayout_2">
 | 
			
		||||
          <item>
 | 
			
		||||
           <widget class="QLabel" name="label_2">
 | 
			
		||||
            <property name="text">
 | 
			
		||||
             <string>Middle:</string>
 | 
			
		||||
            </property>
 | 
			
		||||
           </widget>
 | 
			
		||||
          </item>
 | 
			
		||||
         </layout>
 | 
			
		||||
        </item>
 | 
			
		||||
        <item>
 | 
			
		||||
         <widget class="QPushButton" name="middle_button">
 | 
			
		||||
          <property name="text">
 | 
			
		||||
           <string/>
 | 
			
		||||
          </property>
 | 
			
		||||
@ -123,6 +80,12 @@
 | 
			
		||||
        </item>
 | 
			
		||||
        <item>
 | 
			
		||||
         <widget class="QPushButton" name="back_button">
 | 
			
		||||
          <property name="minimumSize">
 | 
			
		||||
           <size>
 | 
			
		||||
            <width>57</width>
 | 
			
		||||
            <height>0</height>
 | 
			
		||||
           </size>
 | 
			
		||||
          </property>
 | 
			
		||||
          <property name="text">
 | 
			
		||||
           <string/>
 | 
			
		||||
          </property>
 | 
			
		||||
@ -147,7 +110,7 @@
 | 
			
		||||
         <widget class="QPushButton" name="left_button">
 | 
			
		||||
          <property name="minimumSize">
 | 
			
		||||
           <size>
 | 
			
		||||
            <width>75</width>
 | 
			
		||||
            <width>57</width>
 | 
			
		||||
            <height>0</height>
 | 
			
		||||
           </size>
 | 
			
		||||
          </property>
 | 
			
		||||
@ -158,21 +121,33 @@
 | 
			
		||||
        </item>
 | 
			
		||||
       </layout>
 | 
			
		||||
      </item>
 | 
			
		||||
      <item row="3" column="3">
 | 
			
		||||
       <layout class="QVBoxLayout" name="verticalLayout_6">
 | 
			
		||||
      <item row="0" column="3">
 | 
			
		||||
       <layout class="QVBoxLayout" name="verticalLayout_3">
 | 
			
		||||
        <item>
 | 
			
		||||
         <layout class="QHBoxLayout" name="horizontalLayout_5">
 | 
			
		||||
         <layout class="QHBoxLayout" name="horizontalLayout_2">
 | 
			
		||||
          <item>
 | 
			
		||||
           <widget class="QLabel" name="label_5">
 | 
			
		||||
           <widget class="QLabel" name="label_2">
 | 
			
		||||
            <property name="text">
 | 
			
		||||
             <string>Forward:</string>
 | 
			
		||||
             <string>Middle:</string>
 | 
			
		||||
            </property>
 | 
			
		||||
           </widget>
 | 
			
		||||
          </item>
 | 
			
		||||
         </layout>
 | 
			
		||||
        </item>
 | 
			
		||||
        <item>
 | 
			
		||||
         <widget class="QPushButton" name="forward_button">
 | 
			
		||||
         <widget class="QPushButton" name="middle_button">
 | 
			
		||||
          <property name="minimumSize">
 | 
			
		||||
           <size>
 | 
			
		||||
            <width>57</width>
 | 
			
		||||
            <height>0</height>
 | 
			
		||||
           </size>
 | 
			
		||||
          </property>
 | 
			
		||||
          <property name="maximumSize">
 | 
			
		||||
           <size>
 | 
			
		||||
            <width>16777215</width>
 | 
			
		||||
            <height>16777215</height>
 | 
			
		||||
           </size>
 | 
			
		||||
          </property>
 | 
			
		||||
          <property name="text">
 | 
			
		||||
           <string/>
 | 
			
		||||
          </property>
 | 
			
		||||
@ -180,6 +155,98 @@
 | 
			
		||||
        </item>
 | 
			
		||||
       </layout>
 | 
			
		||||
      </item>
 | 
			
		||||
      <item row="0" column="6">
 | 
			
		||||
       <spacer name="horizontalSpacer_2">
 | 
			
		||||
        <property name="orientation">
 | 
			
		||||
         <enum>Qt::Horizontal</enum>
 | 
			
		||||
        </property>
 | 
			
		||||
        <property name="sizeType">
 | 
			
		||||
         <enum>QSizePolicy::Fixed</enum>
 | 
			
		||||
        </property>
 | 
			
		||||
        <property name="sizeHint" stdset="0">
 | 
			
		||||
         <size>
 | 
			
		||||
          <width>0</width>
 | 
			
		||||
          <height>20</height>
 | 
			
		||||
         </size>
 | 
			
		||||
        </property>
 | 
			
		||||
       </spacer>
 | 
			
		||||
      </item>
 | 
			
		||||
      <item row="0" column="0">
 | 
			
		||||
       <spacer name="horizontalSpacer">
 | 
			
		||||
        <property name="orientation">
 | 
			
		||||
         <enum>Qt::Horizontal</enum>
 | 
			
		||||
        </property>
 | 
			
		||||
        <property name="sizeType">
 | 
			
		||||
         <enum>QSizePolicy::Fixed</enum>
 | 
			
		||||
        </property>
 | 
			
		||||
        <property name="sizeHint" stdset="0">
 | 
			
		||||
         <size>
 | 
			
		||||
          <width>0</width>
 | 
			
		||||
          <height>20</height>
 | 
			
		||||
         </size>
 | 
			
		||||
        </property>
 | 
			
		||||
       </spacer>
 | 
			
		||||
      </item>
 | 
			
		||||
      <item row="0" column="5">
 | 
			
		||||
       <layout class="QVBoxLayout" name="verticalLayout_4">
 | 
			
		||||
        <item>
 | 
			
		||||
         <layout class="QHBoxLayout" name="horizontalLayout_3">
 | 
			
		||||
          <item>
 | 
			
		||||
           <widget class="QLabel" name="label_3">
 | 
			
		||||
            <property name="text">
 | 
			
		||||
             <string>Right:</string>
 | 
			
		||||
            </property>
 | 
			
		||||
           </widget>
 | 
			
		||||
          </item>
 | 
			
		||||
         </layout>
 | 
			
		||||
        </item>
 | 
			
		||||
        <item>
 | 
			
		||||
         <widget class="QPushButton" name="right_button">
 | 
			
		||||
          <property name="minimumSize">
 | 
			
		||||
           <size>
 | 
			
		||||
            <width>57</width>
 | 
			
		||||
            <height>0</height>
 | 
			
		||||
           </size>
 | 
			
		||||
          </property>
 | 
			
		||||
          <property name="maximumSize">
 | 
			
		||||
           <size>
 | 
			
		||||
            <width>16777215</width>
 | 
			
		||||
            <height>16777215</height>
 | 
			
		||||
           </size>
 | 
			
		||||
          </property>
 | 
			
		||||
          <property name="text">
 | 
			
		||||
           <string/>
 | 
			
		||||
          </property>
 | 
			
		||||
         </widget>
 | 
			
		||||
        </item>
 | 
			
		||||
       </layout>
 | 
			
		||||
      </item>
 | 
			
		||||
      <item row="0" column="2">
 | 
			
		||||
       <spacer name="horizontalSpacer_4">
 | 
			
		||||
        <property name="orientation">
 | 
			
		||||
         <enum>Qt::Horizontal</enum>
 | 
			
		||||
        </property>
 | 
			
		||||
        <property name="sizeHint" stdset="0">
 | 
			
		||||
         <size>
 | 
			
		||||
          <width>0</width>
 | 
			
		||||
          <height>20</height>
 | 
			
		||||
         </size>
 | 
			
		||||
        </property>
 | 
			
		||||
       </spacer>
 | 
			
		||||
      </item>
 | 
			
		||||
      <item row="0" column="4">
 | 
			
		||||
       <spacer name="horizontalSpacer_5">
 | 
			
		||||
        <property name="orientation">
 | 
			
		||||
         <enum>Qt::Horizontal</enum>
 | 
			
		||||
        </property>
 | 
			
		||||
        <property name="sizeHint" stdset="0">
 | 
			
		||||
         <size>
 | 
			
		||||
          <width>0</width>
 | 
			
		||||
          <height>20</height>
 | 
			
		||||
         </size>
 | 
			
		||||
        </property>
 | 
			
		||||
       </spacer>
 | 
			
		||||
      </item>
 | 
			
		||||
     </layout>
 | 
			
		||||
    </widget>
 | 
			
		||||
   </item>
 | 
			
		||||
@ -187,15 +254,39 @@
 | 
			
		||||
    <layout class="QHBoxLayout" name="horizontalLayout_6">
 | 
			
		||||
     <item>
 | 
			
		||||
      <widget class="QPushButton" name="buttonClearAll">
 | 
			
		||||
       <property name="minimumSize">
 | 
			
		||||
        <size>
 | 
			
		||||
         <width>57</width>
 | 
			
		||||
         <height>0</height>
 | 
			
		||||
        </size>
 | 
			
		||||
       </property>
 | 
			
		||||
       <property name="maximumSize">
 | 
			
		||||
        <size>
 | 
			
		||||
         <width>16777215</width>
 | 
			
		||||
         <height>16777215</height>
 | 
			
		||||
        </size>
 | 
			
		||||
       </property>
 | 
			
		||||
       <property name="text">
 | 
			
		||||
        <string>Clear All</string>
 | 
			
		||||
        <string>Clear</string>
 | 
			
		||||
       </property>
 | 
			
		||||
      </widget>
 | 
			
		||||
     </item>
 | 
			
		||||
     <item>
 | 
			
		||||
      <widget class="QPushButton" name="buttonRestoreDefaults">
 | 
			
		||||
       <property name="minimumSize">
 | 
			
		||||
        <size>
 | 
			
		||||
         <width>57</width>
 | 
			
		||||
         <height>0</height>
 | 
			
		||||
        </size>
 | 
			
		||||
       </property>
 | 
			
		||||
       <property name="maximumSize">
 | 
			
		||||
        <size>
 | 
			
		||||
         <width>16777215</width>
 | 
			
		||||
         <height>16777215</height>
 | 
			
		||||
        </size>
 | 
			
		||||
       </property>
 | 
			
		||||
       <property name="text">
 | 
			
		||||
        <string>Restore Defaults</string>
 | 
			
		||||
        <string>Defaults</string>
 | 
			
		||||
       </property>
 | 
			
		||||
      </widget>
 | 
			
		||||
     </item>
 | 
			
		||||
@ -206,21 +297,24 @@
 | 
			
		||||
       </property>
 | 
			
		||||
       <property name="sizeHint" stdset="0">
 | 
			
		||||
        <size>
 | 
			
		||||
         <width>40</width>
 | 
			
		||||
         <width>0</width>
 | 
			
		||||
         <height>20</height>
 | 
			
		||||
        </size>
 | 
			
		||||
       </property>
 | 
			
		||||
      </spacer>
 | 
			
		||||
     </item>
 | 
			
		||||
     <item>
 | 
			
		||||
      <widget class="QDialogButtonBox" name="buttonBox">
 | 
			
		||||
       <property name="styleSheet">
 | 
			
		||||
        <string notr="true"/>
 | 
			
		||||
       </property>
 | 
			
		||||
       <property name="standardButtons">
 | 
			
		||||
        <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
 | 
			
		||||
       </property>
 | 
			
		||||
      </widget>
 | 
			
		||||
     </item>
 | 
			
		||||
    </layout>
 | 
			
		||||
   </item>
 | 
			
		||||
   <item>
 | 
			
		||||
    <widget class="QDialogButtonBox" name="buttonBox">
 | 
			
		||||
     <property name="standardButtons">
 | 
			
		||||
      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
 | 
			
		||||
     </property>
 | 
			
		||||
    </widget>
 | 
			
		||||
   </item>
 | 
			
		||||
  </layout>
 | 
			
		||||
 </widget>
 | 
			
		||||
 <resources/>
 | 
			
		||||
 | 
			
		||||
@ -16,4 +16,5 @@ const Themes themes{{
 | 
			
		||||
}};
 | 
			
		||||
 | 
			
		||||
Values values = {};
 | 
			
		||||
 | 
			
		||||
} // namespace UISettings
 | 
			
		||||
 | 
			
		||||
@ -87,9 +87,6 @@ struct Values {
 | 
			
		||||
    // logging
 | 
			
		||||
    bool show_console;
 | 
			
		||||
 | 
			
		||||
    // Controllers
 | 
			
		||||
    int profile_index;
 | 
			
		||||
 | 
			
		||||
    // Game List
 | 
			
		||||
    bool show_add_ons;
 | 
			
		||||
    uint32_t icon_size;
 | 
			
		||||
@ -100,6 +97,7 @@ struct Values {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
extern Values values;
 | 
			
		||||
 | 
			
		||||
} // namespace UISettings
 | 
			
		||||
 | 
			
		||||
Q_DECLARE_METATYPE(UISettings::GameDir*);
 | 
			
		||||
 | 
			
		||||
@ -288,6 +288,8 @@ void Config::ReadValues() {
 | 
			
		||||
            Settings::values.debug_pad_analogs[i] = default_param;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Settings::values.vibration_enabled =
 | 
			
		||||
        sdl2_config->GetBoolean("ControlsGeneral", "vibration_enabled", true);
 | 
			
		||||
    Settings::values.touchscreen.enabled =
 | 
			
		||||
        sdl2_config->GetBoolean("ControlsGeneral", "touch_enabled", true);
 | 
			
		||||
    Settings::values.touchscreen.device =
 | 
			
		||||
 | 
			
		||||
@ -75,6 +75,7 @@ void Config::ReadValues() {
 | 
			
		||||
        Settings::values.debug_pad_analogs[i] = "";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Settings::values.vibration_enabled = true;
 | 
			
		||||
    Settings::values.touchscreen.enabled = "";
 | 
			
		||||
    Settings::values.touchscreen.device = "";
 | 
			
		||||
    Settings::values.touchscreen.finger = 0;
 | 
			
		||||
 | 
			
		||||