Merge pull request #4597 from Morph1984/mjolnir-p2
Project Mjölnir: Part 2 - Controller Applet
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/applet_dual_joycon.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 3.5 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/applet_dual_joycon_dark.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 3.5 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/applet_dual_joycon_dark_disabled.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 3.4 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/applet_dual_joycon_disabled.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 3.2 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/applet_dual_joycon_midnight.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 3.5 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/applet_dual_joycon_midnight_disabled.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 3.5 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/applet_handheld.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 1.6 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/applet_handheld_dark.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 1.6 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/applet_handheld_dark_disabled.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 2.6 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/applet_handheld_disabled.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 2.2 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/applet_handheld_midnight.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 1.6 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/applet_handheld_midnight_disabled.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 2.6 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/applet_pro_controller.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 4.3 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/applet_pro_controller_dark.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 4.1 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/applet_pro_controller_dark_disabled.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 4.4 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/applet_pro_controller_disabled.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 4.1 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/applet_pro_controller_midnight.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 4.3 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/applet_pro_controller_midnight_disabled.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 4.4 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/applet_single_joycon_left.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 2.0 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/applet_single_joycon_left_dark.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 2.0 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/applet_single_joycon_left_dark_disabled.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 2.5 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/applet_single_joycon_left_disabled.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 2.1 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/applet_single_joycon_left_midnight.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 2.0 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/applet_single_joycon_left_midnight_disabled.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 2.5 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/applet_single_joycon_right.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 2.1 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/applet_single_joycon_right_dark.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 2.1 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/applet_single_joycon_right_dark_disabled.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 2.5 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/applet_single_joycon_right_disabled.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 2.2 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/applet_single_joycon_right_midnight.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 2.1 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dist/icons/controller/applet_single_joycon_right_midnight_disabled.png
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 2.5 KiB  | 
							
								
								
									
										30
									
								
								dist/icons/controller/controller.qrc
									
									
									
									
										vendored
									
									
								
							
							
						
						@ -21,5 +21,35 @@
 | 
			
		||||
    <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>
 | 
			
		||||
    <file alias="applet_dual_joycon">applet_dual_joycon.png</file>
 | 
			
		||||
    <file alias="applet_dual_joycon_dark">applet_dual_joycon_dark.png</file>	
 | 
			
		||||
    <file alias="applet_dual_joycon_midnight">applet_dual_joycon_midnight.png</file>	
 | 
			
		||||
    <file alias="applet_handheld">applet_handheld.png</file>
 | 
			
		||||
    <file alias="applet_handheld_dark">applet_handheld_dark.png</file>	
 | 
			
		||||
    <file alias="applet_handheld_midnight">applet_handheld_midnight.png</file>
 | 
			
		||||
    <file alias="applet_pro_controller">applet_pro_controller.png</file>
 | 
			
		||||
    <file alias="applet_pro_controller_dark">applet_pro_controller_dark.png</file>
 | 
			
		||||
    <file alias="applet_pro_controller_midnight">applet_pro_controller_midnight.png</file>
 | 
			
		||||
    <file alias="applet_joycon_left">applet_single_joycon_left.png</file>
 | 
			
		||||
    <file alias="applet_joycon_left_dark">applet_single_joycon_left_dark.png</file>
 | 
			
		||||
    <file alias="applet_joycon_left_midnight">applet_single_joycon_left_midnight.png</file>
 | 
			
		||||
    <file alias="applet_joycon_right">applet_single_joycon_right.png</file>
 | 
			
		||||
    <file alias="applet_joycon_right_dark">applet_single_joycon_right_dark.png</file>
 | 
			
		||||
    <file alias="applet_joycon_right_midnight">applet_single_joycon_right_midnight.png</file>
 | 
			
		||||
    <file alias="applet_dual_joycon_disabled">applet_dual_joycon_disabled.png</file>
 | 
			
		||||
    <file alias="applet_dual_joycon_dark_disabled">applet_dual_joycon_dark_disabled.png</file>
 | 
			
		||||
    <file alias="applet_dual_joycon_midnight_disabled">applet_dual_joycon_midnight_disabled.png</file>
 | 
			
		||||
    <file alias="applet_handheld_disabled">applet_handheld_disabled.png</file>
 | 
			
		||||
    <file alias="applet_handheld_dark_disabled">applet_handheld_dark_disabled.png</file>
 | 
			
		||||
    <file alias="applet_handheld_midnight_disabled">applet_handheld_midnight_disabled.png</file>
 | 
			
		||||
    <file alias="applet_pro_controller_disabled">applet_pro_controller_disabled.png</file>
 | 
			
		||||
    <file alias="applet_pro_controller_dark_disabled">applet_pro_controller_dark_disabled.png</file>
 | 
			
		||||
    <file alias="applet_pro_controller_midnight_disabled">applet_pro_controller_midnight_disabled.png</file>
 | 
			
		||||
    <file alias="applet_joycon_left_disabled">applet_single_joycon_left_disabled.png</file>
 | 
			
		||||
    <file alias="applet_joycon_left_dark_disabled">applet_single_joycon_left_dark_disabled.png</file>
 | 
			
		||||
    <file alias="applet_joycon_left_midnight_disabled">applet_single_joycon_left_midnight_disabled.png</file>
 | 
			
		||||
    <file alias="applet_joycon_right_disabled">applet_single_joycon_right_disabled.png</file>
 | 
			
		||||
    <file alias="applet_joycon_right_dark_disabled">applet_single_joycon_right_dark_disabled.png</file>
 | 
			
		||||
    <file alias="applet_joycon_right_midnight_disabled">applet_single_joycon_right_midnight_disabled.png</file>
 | 
			
		||||
  </qresource>
 | 
			
		||||
</RCC>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										188
									
								
								dist/qt_themes/default/style.qss
									
									
									
									
										vendored
									
									
								
							
							
						
						@ -41,6 +41,99 @@ QPushButton#buttonRefreshDevices {
 | 
			
		||||
    max-height: 20px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QWidget#bottomPerGameInput,
 | 
			
		||||
QWidget#topControllerApplet,
 | 
			
		||||
QWidget#bottomControllerApplet,
 | 
			
		||||
QGroupBox#groupPlayer1Connected:checked,
 | 
			
		||||
QGroupBox#groupPlayer2Connected:checked,
 | 
			
		||||
QGroupBox#groupPlayer3Connected:checked,
 | 
			
		||||
QGroupBox#groupPlayer4Connected:checked,
 | 
			
		||||
QGroupBox#groupPlayer5Connected:checked,
 | 
			
		||||
QGroupBox#groupPlayer6Connected:checked,
 | 
			
		||||
QGroupBox#groupPlayer7Connected:checked,
 | 
			
		||||
QGroupBox#groupPlayer8Connected:checked {
 | 
			
		||||
    background-color: #f5f5f5;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QWidget#topControllerApplet {
 | 
			
		||||
    border-bottom: 1px solid #828790
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QWidget#bottomPerGameInput,
 | 
			
		||||
QWidget#bottomControllerApplet {
 | 
			
		||||
    border-top: 1px solid #828790
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QWidget#topPerGameInput,
 | 
			
		||||
QWidget#middleControllerApplet {
 | 
			
		||||
    background-color: #fff;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QWidget#topPerGameInput QComboBox,
 | 
			
		||||
QWidget#middleControllerApplet QComboBox {
 | 
			
		||||
    width: 123px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QWidget#connectedControllers {
 | 
			
		||||
    background: transparent;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QWidget#playersSupported,
 | 
			
		||||
QWidget#controllersSupported,
 | 
			
		||||
QWidget#controllerSupported1,
 | 
			
		||||
QWidget#controllerSupported2,
 | 
			
		||||
QWidget#controllerSupported3,
 | 
			
		||||
QWidget#controllerSupported4,
 | 
			
		||||
QWidget#controllerSupported5,
 | 
			
		||||
QWidget#controllerSupported6 {
 | 
			
		||||
    border: none;
 | 
			
		||||
    background: transparent;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QGroupBox#groupPlayer1Connected,
 | 
			
		||||
QGroupBox#groupPlayer2Connected,
 | 
			
		||||
QGroupBox#groupPlayer3Connected,
 | 
			
		||||
QGroupBox#groupPlayer4Connected,
 | 
			
		||||
QGroupBox#groupPlayer5Connected,
 | 
			
		||||
QGroupBox#groupPlayer6Connected,
 | 
			
		||||
QGroupBox#groupPlayer7Connected,
 | 
			
		||||
QGroupBox#groupPlayer8Connected {
 | 
			
		||||
    border: 1px solid #828790;
 | 
			
		||||
    border-radius: 3px;
 | 
			
		||||
    padding: 0px;
 | 
			
		||||
    min-height: 98px;
 | 
			
		||||
    max-height: 98px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QGroupBox#groupPlayer1Connected:unchecked,
 | 
			
		||||
QGroupBox#groupPlayer2Connected:unchecked,
 | 
			
		||||
QGroupBox#groupPlayer3Connected:unchecked,
 | 
			
		||||
QGroupBox#groupPlayer4Connected:unchecked,
 | 
			
		||||
QGroupBox#groupPlayer5Connected:unchecked,
 | 
			
		||||
QGroupBox#groupPlayer6Connected:unchecked,
 | 
			
		||||
QGroupBox#groupPlayer7Connected:unchecked,
 | 
			
		||||
QGroupBox#groupPlayer8Connected:unchecked {
 | 
			
		||||
    border: 1px solid #d9d9d9;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QGroupBox#groupPlayer1Connected::title,
 | 
			
		||||
QGroupBox#groupPlayer2Connected::title,
 | 
			
		||||
QGroupBox#groupPlayer3Connected::title,
 | 
			
		||||
QGroupBox#groupPlayer4Connected::title,
 | 
			
		||||
QGroupBox#groupPlayer5Connected::title,
 | 
			
		||||
QGroupBox#groupPlayer6Connected::title,
 | 
			
		||||
QGroupBox#groupPlayer7Connected::title,
 | 
			
		||||
QGroupBox#groupPlayer8Connected::title {
 | 
			
		||||
    subcontrol-origin: margin;
 | 
			
		||||
    subcontrol-position: top left;
 | 
			
		||||
    padding-left: 0px;
 | 
			
		||||
    padding-right: 0px;
 | 
			
		||||
    padding-top: 1px;
 | 
			
		||||
    margin-left: 0px;
 | 
			
		||||
    margin-right: -4px;
 | 
			
		||||
    margin-bottom: 4px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QCheckBox#checkboxPlayer1Connected,
 | 
			
		||||
QCheckBox#checkboxPlayer2Connected,
 | 
			
		||||
QCheckBox#checkboxPlayer3Connected,
 | 
			
		||||
@ -52,6 +145,42 @@ QCheckBox#checkboxPlayer8Connected {
 | 
			
		||||
    spacing: 0px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QWidget#Player1LEDs QCheckBox,
 | 
			
		||||
QWidget#Player2LEDs QCheckBox,
 | 
			
		||||
QWidget#Player3LEDs QCheckBox,
 | 
			
		||||
QWidget#Player4LEDs QCheckBox,
 | 
			
		||||
QWidget#Player5LEDs QCheckBox,
 | 
			
		||||
QWidget#Player6LEDs QCheckBox,
 | 
			
		||||
QWidget#Player7LEDs QCheckBox,
 | 
			
		||||
QWidget#Player8LEDs QCheckBox {
 | 
			
		||||
    spacing: 0px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QWidget#Player1LEDs QCheckBox::indicator,
 | 
			
		||||
QWidget#Player2LEDs QCheckBox::indicator,
 | 
			
		||||
QWidget#Player3LEDs QCheckBox::indicator,
 | 
			
		||||
QWidget#Player4LEDs QCheckBox::indicator,
 | 
			
		||||
QWidget#Player5LEDs QCheckBox::indicator,
 | 
			
		||||
QWidget#Player6LEDs QCheckBox::indicator,
 | 
			
		||||
QWidget#Player7LEDs QCheckBox::indicator,
 | 
			
		||||
QWidget#Player8LEDs QCheckBox::indicator {
 | 
			
		||||
    width: 6px;
 | 
			
		||||
    height: 6px;
 | 
			
		||||
    margin-left: 0px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer1Connected::indicator,
 | 
			
		||||
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer2Connected::indicator,
 | 
			
		||||
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer3Connected::indicator,
 | 
			
		||||
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer4Connected::indicator,
 | 
			
		||||
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer5Connected::indicator,
 | 
			
		||||
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer6Connected::indicator,
 | 
			
		||||
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer7Connected::indicator,
 | 
			
		||||
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer8Connected::indicator {
 | 
			
		||||
    width: 12px;
 | 
			
		||||
    height: 12px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QCheckBox#checkboxPlayer1Connected::indicator,
 | 
			
		||||
QCheckBox#checkboxPlayer2Connected::indicator,
 | 
			
		||||
QCheckBox#checkboxPlayer3Connected::indicator,
 | 
			
		||||
@ -64,6 +193,34 @@ QCheckBox#checkboxPlayer8Connected::indicator {
 | 
			
		||||
    height: 14px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QGroupBox#groupPlayer1Connected::indicator,
 | 
			
		||||
QGroupBox#groupPlayer2Connected::indicator,
 | 
			
		||||
QGroupBox#groupPlayer3Connected::indicator,
 | 
			
		||||
QGroupBox#groupPlayer4Connected::indicator,
 | 
			
		||||
QGroupBox#groupPlayer5Connected::indicator,
 | 
			
		||||
QGroupBox#groupPlayer6Connected::indicator,
 | 
			
		||||
QGroupBox#groupPlayer7Connected::indicator,
 | 
			
		||||
QGroupBox#groupPlayer8Connected::indicator {
 | 
			
		||||
    width: 16px;
 | 
			
		||||
    height: 16px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QWidget#Player1LEDs QCheckBox::indicator:checked,
 | 
			
		||||
QWidget#Player2LEDs QCheckBox::indicator:checked,
 | 
			
		||||
QWidget#Player3LEDs QCheckBox::indicator:checked,
 | 
			
		||||
QWidget#Player4LEDs QCheckBox::indicator:checked,
 | 
			
		||||
QWidget#Player5LEDs QCheckBox::indicator:checked,
 | 
			
		||||
QWidget#Player6LEDs QCheckBox::indicator:checked,
 | 
			
		||||
QWidget#Player7LEDs QCheckBox::indicator:checked,
 | 
			
		||||
QWidget#Player8LEDs QCheckBox::indicator:checked,
 | 
			
		||||
QGroupBox#groupPlayer1Connected::indicator:checked,
 | 
			
		||||
QGroupBox#groupPlayer2Connected::indicator:checked,
 | 
			
		||||
QGroupBox#groupPlayer3Connected::indicator:checked,
 | 
			
		||||
QGroupBox#groupPlayer4Connected::indicator:checked,
 | 
			
		||||
QGroupBox#groupPlayer5Connected::indicator:checked,
 | 
			
		||||
QGroupBox#groupPlayer6Connected::indicator:checked,
 | 
			
		||||
QGroupBox#groupPlayer7Connected::indicator:checked,
 | 
			
		||||
QGroupBox#groupPlayer8Connected::indicator:checked,
 | 
			
		||||
QCheckBox#checkboxPlayer1Connected::indicator:checked,
 | 
			
		||||
QCheckBox#checkboxPlayer2Connected::indicator:checked,
 | 
			
		||||
QCheckBox#checkboxPlayer3Connected::indicator:checked,
 | 
			
		||||
@ -74,11 +231,27 @@ QCheckBox#checkboxPlayer7Connected::indicator:checked,
 | 
			
		||||
QCheckBox#checkboxPlayer8Connected::indicator:checked,
 | 
			
		||||
QGroupBox#groupConnectedController::indicator:checked {
 | 
			
		||||
    border-radius: 2px;
 | 
			
		||||
    border: 1px solid black;
 | 
			
		||||
    border: 1px solid #929192;
 | 
			
		||||
    background: #39ff14;
 | 
			
		||||
    image: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QWidget#Player1LEDs QCheckBox::indicator:unchecked,
 | 
			
		||||
QWidget#Player2LEDs QCheckBox::indicator:unchecked,
 | 
			
		||||
QWidget#Player3LEDs QCheckBox::indicator:unchecked,
 | 
			
		||||
QWidget#Player4LEDs QCheckBox::indicator:unchecked,
 | 
			
		||||
QWidget#Player5LEDs QCheckBox::indicator:unchecked,
 | 
			
		||||
QWidget#Player6LEDs QCheckBox::indicator:unchecked,
 | 
			
		||||
QWidget#Player7LEDs QCheckBox::indicator:unchecked,
 | 
			
		||||
QWidget#Player8LEDs QCheckBox::indicator:unchecked,
 | 
			
		||||
QGroupBox#groupPlayer1Connected::indicator:unchecked,
 | 
			
		||||
QGroupBox#groupPlayer2Connected::indicator:unchecked,
 | 
			
		||||
QGroupBox#groupPlayer3Connected::indicator:unchecked,
 | 
			
		||||
QGroupBox#groupPlayer4Connected::indicator:unchecked,
 | 
			
		||||
QGroupBox#groupPlayer5Connected::indicator:unchecked,
 | 
			
		||||
QGroupBox#groupPlayer6Connected::indicator:unchecked,
 | 
			
		||||
QGroupBox#groupPlayer7Connected::indicator:unchecked,
 | 
			
		||||
QGroupBox#groupPlayer8Connected::indicator:unchecked,
 | 
			
		||||
QCheckBox#checkboxPlayer1Connected::indicator:unchecked,
 | 
			
		||||
QCheckBox#checkboxPlayer2Connected::indicator:unchecked,
 | 
			
		||||
QCheckBox#checkboxPlayer3Connected::indicator:unchecked,
 | 
			
		||||
@ -89,7 +262,18 @@ QCheckBox#checkboxPlayer7Connected::indicator:unchecked,
 | 
			
		||||
QCheckBox#checkboxPlayer8Connected::indicator:unchecked,
 | 
			
		||||
QGroupBox#groupConnectedController::indicator:unchecked {
 | 
			
		||||
    border-radius: 2px;
 | 
			
		||||
    border: 1px solid black;
 | 
			
		||||
    border: 1px solid #929192;
 | 
			
		||||
    background: transparent;
 | 
			
		||||
    image: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QWidget#controllerPlayer1,
 | 
			
		||||
QWidget#controllerPlayer2,
 | 
			
		||||
QWidget#controllerPlayer3,
 | 
			
		||||
QWidget#controllerPlayer4,
 | 
			
		||||
QWidget#controllerPlayer5,
 | 
			
		||||
QWidget#controllerPlayer6,
 | 
			
		||||
QWidget#controllerPlayer7,
 | 
			
		||||
QWidget#controllerPlayer8 {
 | 
			
		||||
    background: transparent;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2
									
								
								dist/qt_themes/qdarkstyle/style.qrc
									
									
									
									
										vendored
									
									
								
							
							
						
						@ -52,6 +52,6 @@
 | 
			
		||||
    <file>rc/radio_unchecked.png</file>
 | 
			
		||||
  </qresource>
 | 
			
		||||
  <qresource prefix="qdarkstyle">
 | 
			
		||||
      <file>style.qss</file>
 | 
			
		||||
    <file>style.qss</file>
 | 
			
		||||
  </qresource>
 | 
			
		||||
</RCC>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										310
									
								
								dist/qt_themes/qdarkstyle/style.qss
									
									
									
									
										vendored
									
									
								
							
							
						
						@ -1284,59 +1284,6 @@ QPushButton#buttonRefreshDevices {
 | 
			
		||||
    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;
 | 
			
		||||
@ -1367,9 +1314,260 @@ QGroupBox#vibrationGroup::indicator {
 | 
			
		||||
 | 
			
		||||
QGroupBox#motionGroup::title,
 | 
			
		||||
QGroupBox#vibrationGroup::title {
 | 
			
		||||
	spacing: 2px;
 | 
			
		||||
	padding-left: 1px;
 | 
			
		||||
	padding-right: 1px;
 | 
			
		||||
    spacing: 2px;
 | 
			
		||||
    padding-left: 1px;
 | 
			
		||||
    padding-right: 1px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QWidget#bottomPerGameInput,
 | 
			
		||||
QWidget#topControllerApplet,
 | 
			
		||||
QWidget#bottomControllerApplet,
 | 
			
		||||
QGroupBox#groupPlayer1Connected:checked,
 | 
			
		||||
QGroupBox#groupPlayer2Connected:checked,
 | 
			
		||||
QGroupBox#groupPlayer3Connected:checked,
 | 
			
		||||
QGroupBox#groupPlayer4Connected:checked,
 | 
			
		||||
QGroupBox#groupPlayer5Connected:checked,
 | 
			
		||||
QGroupBox#groupPlayer6Connected:checked,
 | 
			
		||||
QGroupBox#groupPlayer7Connected:checked,
 | 
			
		||||
QGroupBox#groupPlayer8Connected:checked {
 | 
			
		||||
    background-color: #232629;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QWidget#topPerGameInput,
 | 
			
		||||
QWidget#middleControllerApplet {
 | 
			
		||||
    background-color: #31363b;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QWidget#topPerGameInput QComboBox,
 | 
			
		||||
QWidget#middleControllerApplet QComboBox {
 | 
			
		||||
    width: 119px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QRadioButton#radioDocked {
 | 
			
		||||
    margin-left: -3px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
QRadioButton#radioUndocked {
 | 
			
		||||
    margin-right: 5px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QWidget#connectedControllers {
 | 
			
		||||
    background: transparent;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QWidget#playersSupported,
 | 
			
		||||
QWidget#controllersSupported,
 | 
			
		||||
QWidget#controllerSupported1,
 | 
			
		||||
QWidget#controllerSupported2,
 | 
			
		||||
QWidget#controllerSupported3,
 | 
			
		||||
QWidget#controllerSupported4,
 | 
			
		||||
QWidget#controllerSupported5,
 | 
			
		||||
QWidget#controllerSupported6 {
 | 
			
		||||
    border: none;
 | 
			
		||||
    background: transparent;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QGroupBox#groupPlayer1Connected,
 | 
			
		||||
QGroupBox#groupPlayer2Connected,
 | 
			
		||||
QGroupBox#groupPlayer3Connected,
 | 
			
		||||
QGroupBox#groupPlayer4Connected,
 | 
			
		||||
QGroupBox#groupPlayer5Connected,
 | 
			
		||||
QGroupBox#groupPlayer6Connected,
 | 
			
		||||
QGroupBox#groupPlayer7Connected,
 | 
			
		||||
QGroupBox#groupPlayer8Connected {
 | 
			
		||||
    border: 1px solid #76797c;
 | 
			
		||||
    border-radius: 3px;
 | 
			
		||||
    padding: 0px;
 | 
			
		||||
    min-height: 98px;
 | 
			
		||||
    max-height: 98px;
 | 
			
		||||
    margin-top: 0px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QGroupBox#groupPlayer1Connected:unchecked,
 | 
			
		||||
QGroupBox#groupPlayer2Connected:unchecked,
 | 
			
		||||
QGroupBox#groupPlayer3Connected:unchecked,
 | 
			
		||||
QGroupBox#groupPlayer4Connected:unchecked,
 | 
			
		||||
QGroupBox#groupPlayer5Connected:unchecked,
 | 
			
		||||
QGroupBox#groupPlayer6Connected:unchecked,
 | 
			
		||||
QGroupBox#groupPlayer7Connected:unchecked,
 | 
			
		||||
QGroupBox#groupPlayer8Connected:unchecked {
 | 
			
		||||
    border: 1px solid #54575b;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QGroupBox#groupPlayer1Connected::title,
 | 
			
		||||
QGroupBox#groupPlayer2Connected::title,
 | 
			
		||||
QGroupBox#groupPlayer3Connected::title,
 | 
			
		||||
QGroupBox#groupPlayer4Connected::title,
 | 
			
		||||
QGroupBox#groupPlayer5Connected::title,
 | 
			
		||||
QGroupBox#groupPlayer6Connected::title,
 | 
			
		||||
QGroupBox#groupPlayer7Connected::title,
 | 
			
		||||
QGroupBox#groupPlayer8Connected::title {
 | 
			
		||||
    subcontrol-origin: margin;
 | 
			
		||||
    subcontrol-position: top left;
 | 
			
		||||
    padding-left: 0px;
 | 
			
		||||
    padding-right: 0px;
 | 
			
		||||
    padding-top: 1px;
 | 
			
		||||
    margin-left: -2px;
 | 
			
		||||
    margin-right: -4px;
 | 
			
		||||
    margin-bottom: 6px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QCheckBox#checkboxPlayer1Connected,
 | 
			
		||||
QCheckBox#checkboxPlayer2Connected,
 | 
			
		||||
QCheckBox#checkboxPlayer3Connected,
 | 
			
		||||
QCheckBox#checkboxPlayer4Connected,
 | 
			
		||||
QCheckBox#checkboxPlayer5Connected,
 | 
			
		||||
QCheckBox#checkboxPlayer6Connected,
 | 
			
		||||
QCheckBox#checkboxPlayer7Connected,
 | 
			
		||||
QCheckBox#checkboxPlayer8Connected {
 | 
			
		||||
    spacing: 0px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QWidget#Player1LEDs,
 | 
			
		||||
QWidget#Player2LEDs,
 | 
			
		||||
QWidget#Player3LEDs,
 | 
			
		||||
QWidget#Player4LEDs,
 | 
			
		||||
QWidget#Player5LEDs,
 | 
			
		||||
QWidget#Player6LEDs,
 | 
			
		||||
QWidget#Player7LEDs,
 | 
			
		||||
QWidget#Player8LEDs {
 | 
			
		||||
    background: transparent;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QWidget#Player1LEDs QCheckBox,
 | 
			
		||||
QWidget#Player2LEDs QCheckBox,
 | 
			
		||||
QWidget#Player3LEDs QCheckBox,
 | 
			
		||||
QWidget#Player4LEDs QCheckBox,
 | 
			
		||||
QWidget#Player5LEDs QCheckBox,
 | 
			
		||||
QWidget#Player6LEDs QCheckBox,
 | 
			
		||||
QWidget#Player7LEDs QCheckBox,
 | 
			
		||||
QWidget#Player8LEDs QCheckBox {
 | 
			
		||||
    spacing: 0px;
 | 
			
		||||
    margin-bottom: 0px;
 | 
			
		||||
    margin-right: 0px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QWidget#Player1LEDs QCheckBox::indicator,
 | 
			
		||||
QWidget#Player2LEDs QCheckBox::indicator,
 | 
			
		||||
QWidget#Player3LEDs QCheckBox::indicator,
 | 
			
		||||
QWidget#Player4LEDs QCheckBox::indicator,
 | 
			
		||||
QWidget#Player5LEDs QCheckBox::indicator,
 | 
			
		||||
QWidget#Player6LEDs QCheckBox::indicator,
 | 
			
		||||
QWidget#Player7LEDs QCheckBox::indicator,
 | 
			
		||||
QWidget#Player8LEDs QCheckBox::indicator {
 | 
			
		||||
    width: 6px;
 | 
			
		||||
    height: 6px;
 | 
			
		||||
    margin-left: 0px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer1Connected::indicator,
 | 
			
		||||
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer2Connected::indicator,
 | 
			
		||||
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer3Connected::indicator,
 | 
			
		||||
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer4Connected::indicator,
 | 
			
		||||
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer5Connected::indicator,
 | 
			
		||||
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer6Connected::indicator,
 | 
			
		||||
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer7Connected::indicator,
 | 
			
		||||
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer8Connected::indicator {
 | 
			
		||||
    width: 12px;
 | 
			
		||||
    height: 12px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QGroupBox#groupPlayer1Connected::indicator,
 | 
			
		||||
QGroupBox#groupPlayer2Connected::indicator,
 | 
			
		||||
QGroupBox#groupPlayer3Connected::indicator,
 | 
			
		||||
QGroupBox#groupPlayer4Connected::indicator,
 | 
			
		||||
QGroupBox#groupPlayer5Connected::indicator,
 | 
			
		||||
QGroupBox#groupPlayer6Connected::indicator,
 | 
			
		||||
QGroupBox#groupPlayer7Connected::indicator,
 | 
			
		||||
QGroupBox#groupPlayer8Connected::indicator {
 | 
			
		||||
    width: 16px;
 | 
			
		||||
    height: 16px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QWidget#Player1LEDs QCheckBox::indicator:checked,
 | 
			
		||||
QWidget#Player2LEDs QCheckBox::indicator:checked,
 | 
			
		||||
QWidget#Player3LEDs QCheckBox::indicator:checked,
 | 
			
		||||
QWidget#Player4LEDs QCheckBox::indicator:checked,
 | 
			
		||||
QWidget#Player5LEDs QCheckBox::indicator:checked,
 | 
			
		||||
QWidget#Player6LEDs QCheckBox::indicator:checked,
 | 
			
		||||
QWidget#Player7LEDs QCheckBox::indicator:checked,
 | 
			
		||||
QWidget#Player8LEDs QCheckBox::indicator:checked,
 | 
			
		||||
QGroupBox#groupPlayer1Connected::indicator:checked,
 | 
			
		||||
QGroupBox#groupPlayer2Connected::indicator:checked,
 | 
			
		||||
QGroupBox#groupPlayer3Connected::indicator:checked,
 | 
			
		||||
QGroupBox#groupPlayer4Connected::indicator:checked,
 | 
			
		||||
QGroupBox#groupPlayer5Connected::indicator:checked,
 | 
			
		||||
QGroupBox#groupPlayer6Connected::indicator:checked,
 | 
			
		||||
QGroupBox#groupPlayer7Connected::indicator:checked,
 | 
			
		||||
QGroupBox#groupPlayer8Connected::indicator:checked,
 | 
			
		||||
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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QWidget#Player1LEDs QCheckBox::indicator:unchecked,
 | 
			
		||||
QWidget#Player2LEDs QCheckBox::indicator:unchecked,
 | 
			
		||||
QWidget#Player3LEDs QCheckBox::indicator:unchecked,
 | 
			
		||||
QWidget#Player4LEDs QCheckBox::indicator:unchecked,
 | 
			
		||||
QWidget#Player5LEDs QCheckBox::indicator:unchecked,
 | 
			
		||||
QWidget#Player6LEDs QCheckBox::indicator:unchecked,
 | 
			
		||||
QWidget#Player7LEDs QCheckBox::indicator:unchecked,
 | 
			
		||||
QWidget#Player8LEDs QCheckBox::indicator:unchecked,
 | 
			
		||||
QGroupBox#groupPlayer1Connected::indicator:unchecked,
 | 
			
		||||
QGroupBox#groupPlayer2Connected::indicator:unchecked,
 | 
			
		||||
QGroupBox#groupPlayer3Connected::indicator:unchecked,
 | 
			
		||||
QGroupBox#groupPlayer4Connected::indicator:unchecked,
 | 
			
		||||
QGroupBox#groupPlayer5Connected::indicator:unchecked,
 | 
			
		||||
QGroupBox#groupPlayer6Connected::indicator:unchecked,
 | 
			
		||||
QGroupBox#groupPlayer7Connected::indicator:unchecked,
 | 
			
		||||
QGroupBox#groupPlayer8Connected::indicator:unchecked,
 | 
			
		||||
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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QWidget#controllerPlayer1,
 | 
			
		||||
QWidget#controllerPlayer2,
 | 
			
		||||
QWidget#controllerPlayer3,
 | 
			
		||||
QWidget#controllerPlayer4,
 | 
			
		||||
QWidget#controllerPlayer5,
 | 
			
		||||
QWidget#controllerPlayer6,
 | 
			
		||||
QWidget#controllerPlayer7,
 | 
			
		||||
QWidget#controllerPlayer8 {
 | 
			
		||||
    background: transparent;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* touchscreen mapping widget */
 | 
			
		||||
 | 
			
		||||
@ -221,6 +221,6 @@
 | 
			
		||||
    <file>rc/window_undock_pressed@2x.png</file>
 | 
			
		||||
  </qresource>
 | 
			
		||||
  <qresource prefix="qdarkstyle_midnight_blue">
 | 
			
		||||
      <file>style.qss</file>
 | 
			
		||||
    <file>style.qss</file>
 | 
			
		||||
  </qresource>
 | 
			
		||||
</RCC>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										290
									
								
								dist/qt_themes/qdarkstyle_midnight_blue/style.qss
									
									
									
									
										vendored
									
									
								
							
							
						
						@ -235,19 +235,19 @@ https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qgroupbox
 | 
			
		||||
 | 
			
		||||
--------------------------------------------------------------------------- */
 | 
			
		||||
QGroupBox {
 | 
			
		||||
    font-weight: bold;
 | 
			
		||||
    border: 1px solid #32414B;
 | 
			
		||||
    border-radius: 4px;
 | 
			
		||||
    margin-top: 12px;
 | 
			
		||||
    padding: 4px;
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
  border: 1px solid #32414B;
 | 
			
		||||
  border-radius: 4px;
 | 
			
		||||
  margin-top: 12px;
 | 
			
		||||
  padding: 4px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QGroupBox::title {
 | 
			
		||||
    subcontrol-origin: margin;
 | 
			
		||||
    subcontrol-position: top left;
 | 
			
		||||
    padding-left: 3px;
 | 
			
		||||
    padding-right: 5px;
 | 
			
		||||
    padding-top: 4px;
 | 
			
		||||
  subcontrol-origin: margin;
 | 
			
		||||
  subcontrol-position: top left;
 | 
			
		||||
  padding-left: 3px;
 | 
			
		||||
  padding-right: 5px;
 | 
			
		||||
  padding-top: 4px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QGroupBox::indicator {
 | 
			
		||||
@ -2205,7 +2205,179 @@ QPushButton#buttonRefreshDevices {
 | 
			
		||||
  padding: 0px 0px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QSpinBox#spinboxLStickRange,
 | 
			
		||||
QSpinBox#spinboxRStickRange {
 | 
			
		||||
  min-width: 38px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QGroupBox#motionGroup::indicator,
 | 
			
		||||
QGroupBox#vibrationGroup::indicator {
 | 
			
		||||
  margin-left: 0px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QWidget#bottomPerGameInput QGroupBox#motionGroup,
 | 
			
		||||
QWidget#bottomPerGameInput QGroupBox#vibrationGroup,
 | 
			
		||||
QWidget#bottomPerGameInput QGroupBox#inputConfigGroup {
 | 
			
		||||
  padding: 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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QWidget#bottomPerGameInput,
 | 
			
		||||
QWidget#topControllerApplet,
 | 
			
		||||
QWidget#bottomControllerApplet,
 | 
			
		||||
QGroupBox#groupPlayer1Connected:checked,
 | 
			
		||||
QGroupBox#groupPlayer2Connected:checked,
 | 
			
		||||
QGroupBox#groupPlayer3Connected:checked,
 | 
			
		||||
QGroupBox#groupPlayer4Connected:checked,
 | 
			
		||||
QGroupBox#groupPlayer5Connected:checked,
 | 
			
		||||
QGroupBox#groupPlayer6Connected:checked,
 | 
			
		||||
QGroupBox#groupPlayer7Connected:checked,
 | 
			
		||||
QGroupBox#groupPlayer8Connected:checked {
 | 
			
		||||
  background-color: #0f1922;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QWidget#topPerGameInput,
 | 
			
		||||
QWidget#middleControllerApplet {
 | 
			
		||||
  background-color: #19232d;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QWidget#topPerGameInput QComboBox,
 | 
			
		||||
QWidget#middleControllerApplet QComboBox {
 | 
			
		||||
  padding-right: 2px;
 | 
			
		||||
  width: 127px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QGroupBox#handheldGroup {
 | 
			
		||||
  padding-left: 0px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QRadioButton#radioDocked {
 | 
			
		||||
  margin-left: -1px;
 | 
			
		||||
  padding-left: 0px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QRadioButton#radioDocked::indicator {
 | 
			
		||||
  margin-left: 0px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
QRadioButton#radioUndocked {
 | 
			
		||||
  margin-right: 2px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QWidget#connectedControllers {
 | 
			
		||||
  background: transparent;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QWidget#playersSupported,
 | 
			
		||||
QWidget#controllersSupported,
 | 
			
		||||
QWidget#controllerSupported1,
 | 
			
		||||
QWidget#controllerSupported2,
 | 
			
		||||
QWidget#controllerSupported3,
 | 
			
		||||
QWidget#controllerSupported4,
 | 
			
		||||
QWidget#controllerSupported5,
 | 
			
		||||
QWidget#controllerSupported6 {
 | 
			
		||||
  border: none;
 | 
			
		||||
  background: transparent;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QGroupBox#groupPlayer1Connected,
 | 
			
		||||
QGroupBox#groupPlayer2Connected,
 | 
			
		||||
QGroupBox#groupPlayer3Connected,
 | 
			
		||||
QGroupBox#groupPlayer4Connected,
 | 
			
		||||
QGroupBox#groupPlayer5Connected,
 | 
			
		||||
QGroupBox#groupPlayer6Connected,
 | 
			
		||||
QGroupBox#groupPlayer7Connected,
 | 
			
		||||
QGroupBox#groupPlayer8Connected {
 | 
			
		||||
  border: 1px solid #76797c;
 | 
			
		||||
  border-radius: 3px;
 | 
			
		||||
  padding: 0px;
 | 
			
		||||
  min-height: 98px;
 | 
			
		||||
  max-height: 98px;
 | 
			
		||||
  margin-top: 0px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
QGroupBox#groupPlayer1Connected:unchecked,
 | 
			
		||||
QGroupBox#groupPlayer2Connected:unchecked,
 | 
			
		||||
QGroupBox#groupPlayer3Connected:unchecked,
 | 
			
		||||
QGroupBox#groupPlayer4Connected:unchecked,
 | 
			
		||||
QGroupBox#groupPlayer5Connected:unchecked,
 | 
			
		||||
QGroupBox#groupPlayer6Connected:unchecked,
 | 
			
		||||
QGroupBox#groupPlayer7Connected:unchecked,
 | 
			
		||||
QGroupBox#groupPlayer8Connected:unchecked {
 | 
			
		||||
  border: 1px solid #32414b;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QGroupBox#groupPlayer1Connected::title,
 | 
			
		||||
QGroupBox#groupPlayer2Connected::title,
 | 
			
		||||
QGroupBox#groupPlayer3Connected::title,
 | 
			
		||||
QGroupBox#groupPlayer4Connected::title,
 | 
			
		||||
QGroupBox#groupPlayer5Connected::title,
 | 
			
		||||
QGroupBox#groupPlayer6Connected::title,
 | 
			
		||||
QGroupBox#groupPlayer7Connected::title,
 | 
			
		||||
QGroupBox#groupPlayer8Connected::title {
 | 
			
		||||
  subcontrol-origin: margin;
 | 
			
		||||
  subcontrol-position: top left;
 | 
			
		||||
  padding-left: 0px;
 | 
			
		||||
  padding-right: 0px;
 | 
			
		||||
  padding-top: 1px;
 | 
			
		||||
  margin-left: -2px;
 | 
			
		||||
  margin-right: -4px;
 | 
			
		||||
  margin-bottom: 6px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QCheckBox#checkboxPlayer1Connected,
 | 
			
		||||
QCheckBox#checkboxPlayer2Connected,
 | 
			
		||||
QCheckBox#checkboxPlayer3Connected,
 | 
			
		||||
QCheckBox#checkboxPlayer4Connected,
 | 
			
		||||
QCheckBox#checkboxPlayer5Connected,
 | 
			
		||||
QCheckBox#checkboxPlayer6Connected,
 | 
			
		||||
QCheckBox#checkboxPlayer7Connected,
 | 
			
		||||
QCheckBox#checkboxPlayer8Connected {
 | 
			
		||||
    spacing: 0px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QWidget#connectedControllers QLabel {
 | 
			
		||||
  padding: 0px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QWidget#Player1LEDs,
 | 
			
		||||
QWidget#Player2LEDs,
 | 
			
		||||
QWidget#Player3LEDs,
 | 
			
		||||
QWidget#Player4LEDs,
 | 
			
		||||
QWidget#Player5LEDs,
 | 
			
		||||
QWidget#Player6LEDs,
 | 
			
		||||
QWidget#Player7LEDs,
 | 
			
		||||
QWidget#Player8LEDs {
 | 
			
		||||
  background: transparent;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QWidget#Player1LEDs QCheckBox,
 | 
			
		||||
QWidget#Player2LEDs QCheckBox,
 | 
			
		||||
QWidget#Player3LEDs QCheckBox,
 | 
			
		||||
QWidget#Player4LEDs QCheckBox,
 | 
			
		||||
QWidget#Player5LEDs QCheckBox,
 | 
			
		||||
QWidget#Player6LEDs QCheckBox,
 | 
			
		||||
QWidget#Player7LEDs QCheckBox,
 | 
			
		||||
QWidget#Player8LEDs QCheckBox,
 | 
			
		||||
QCheckBox#checkboxPlayer1Connected,
 | 
			
		||||
QCheckBox#checkboxPlayer2Connected,
 | 
			
		||||
QCheckBox#checkboxPlayer3Connected,
 | 
			
		||||
@ -2215,6 +2387,34 @@ QCheckBox#checkboxPlayer6Connected,
 | 
			
		||||
QCheckBox#checkboxPlayer7Connected,
 | 
			
		||||
QCheckBox#checkboxPlayer8Connected {
 | 
			
		||||
  spacing: 0px;
 | 
			
		||||
  padding-top: 0px;
 | 
			
		||||
  padding-bottom: 0px;
 | 
			
		||||
  background: transparent;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QWidget#Player1LEDs QCheckBox::indicator,
 | 
			
		||||
QWidget#Player2LEDs QCheckBox::indicator,
 | 
			
		||||
QWidget#Player3LEDs QCheckBox::indicator,
 | 
			
		||||
QWidget#Player4LEDs QCheckBox::indicator,
 | 
			
		||||
QWidget#Player5LEDs QCheckBox::indicator,
 | 
			
		||||
QWidget#Player6LEDs QCheckBox::indicator,
 | 
			
		||||
QWidget#Player7LEDs QCheckBox::indicator,
 | 
			
		||||
QWidget#Player8LEDs QCheckBox::indicator {
 | 
			
		||||
  width: 6px;
 | 
			
		||||
  height: 6px;
 | 
			
		||||
  margin-left: 0px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer1Connected::indicator,
 | 
			
		||||
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer2Connected::indicator,
 | 
			
		||||
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer3Connected::indicator,
 | 
			
		||||
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer4Connected::indicator,
 | 
			
		||||
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer5Connected::indicator,
 | 
			
		||||
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer6Connected::indicator,
 | 
			
		||||
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer7Connected::indicator,
 | 
			
		||||
QWidget#bottomPerGameInput QCheckBox#checkboxPlayer8Connected::indicator {
 | 
			
		||||
  width: 12px;
 | 
			
		||||
  height: 12px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QCheckBox#checkboxPlayer1Connected::indicator,
 | 
			
		||||
@ -2227,8 +2427,25 @@ QCheckBox#checkboxPlayer7Connected::indicator,
 | 
			
		||||
QCheckBox#checkboxPlayer8Connected::indicator {
 | 
			
		||||
  width: 14px;
 | 
			
		||||
  height: 14px;
 | 
			
		||||
  margin-left: 2px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QWidget#Player1LEDs QCheckBox::indicator:checked,
 | 
			
		||||
QWidget#Player2LEDs QCheckBox::indicator:checked,
 | 
			
		||||
QWidget#Player3LEDs QCheckBox::indicator:checked,
 | 
			
		||||
QWidget#Player4LEDs QCheckBox::indicator:checked,
 | 
			
		||||
QWidget#Player5LEDs QCheckBox::indicator:checked,
 | 
			
		||||
QWidget#Player6LEDs QCheckBox::indicator:checked,
 | 
			
		||||
QWidget#Player7LEDs QCheckBox::indicator:checked,
 | 
			
		||||
QWidget#Player8LEDs QCheckBox::indicator:checked,
 | 
			
		||||
QGroupBox#groupPlayer1Connected::indicator:checked,
 | 
			
		||||
QGroupBox#groupPlayer2Connected::indicator:checked,
 | 
			
		||||
QGroupBox#groupPlayer3Connected::indicator:checked,
 | 
			
		||||
QGroupBox#groupPlayer4Connected::indicator:checked,
 | 
			
		||||
QGroupBox#groupPlayer5Connected::indicator:checked,
 | 
			
		||||
QGroupBox#groupPlayer6Connected::indicator:checked,
 | 
			
		||||
QGroupBox#groupPlayer7Connected::indicator:checked,
 | 
			
		||||
QGroupBox#groupPlayer8Connected::indicator:checked,
 | 
			
		||||
QCheckBox#checkboxPlayer1Connected::indicator:checked,
 | 
			
		||||
QCheckBox#checkboxPlayer2Connected::indicator:checked,
 | 
			
		||||
QCheckBox#checkboxPlayer3Connected::indicator:checked,
 | 
			
		||||
@ -2244,6 +2461,22 @@ QGroupBox#groupConnectedController::indicator:checked {
 | 
			
		||||
  image: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QWidget#Player1LEDs QCheckBox::indicator:unchecked,
 | 
			
		||||
QWidget#Player2LEDs QCheckBox::indicator:unchecked,
 | 
			
		||||
QWidget#Player3LEDs QCheckBox::indicator:unchecked,
 | 
			
		||||
QWidget#Player4LEDs QCheckBox::indicator:unchecked,
 | 
			
		||||
QWidget#Player5LEDs QCheckBox::indicator:unchecked,
 | 
			
		||||
QWidget#Player6LEDs QCheckBox::indicator:unchecked,
 | 
			
		||||
QWidget#Player7LEDs QCheckBox::indicator:unchecked,
 | 
			
		||||
QWidget#Player8LEDs QCheckBox::indicator:unchecked,
 | 
			
		||||
QGroupBox#groupPlayer1Connected::indicator:unchecked,
 | 
			
		||||
QGroupBox#groupPlayer2Connected::indicator:unchecked,
 | 
			
		||||
QGroupBox#groupPlayer3Connected::indicator:unchecked,
 | 
			
		||||
QGroupBox#groupPlayer4Connected::indicator:unchecked,
 | 
			
		||||
QGroupBox#groupPlayer5Connected::indicator:unchecked,
 | 
			
		||||
QGroupBox#groupPlayer6Connected::indicator:unchecked,
 | 
			
		||||
QGroupBox#groupPlayer7Connected::indicator:unchecked,
 | 
			
		||||
QGroupBox#groupPlayer8Connected::indicator:unchecked,
 | 
			
		||||
QCheckBox#checkboxPlayer1Connected::indicator:unchecked,
 | 
			
		||||
QCheckBox#checkboxPlayer2Connected::indicator:unchecked,
 | 
			
		||||
QCheckBox#checkboxPlayer3Connected::indicator:unchecked,
 | 
			
		||||
@ -2255,34 +2488,17 @@ QCheckBox#checkboxPlayer8Connected::indicator:unchecked,
 | 
			
		||||
QGroupBox#groupConnectedController::indicator:unchecked {
 | 
			
		||||
  border-radius: 2px;
 | 
			
		||||
  border: 1px solid #929192;
 | 
			
		||||
  background: transparent;
 | 
			
		||||
  background: #19232d;
 | 
			
		||||
  image: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QSpinBox#spinboxLStickRange,
 | 
			
		||||
QSpinBox#spinboxRStickRange {
 | 
			
		||||
  min-width: 38px;
 | 
			
		||||
QWidget#controllerPlayer1,
 | 
			
		||||
QWidget#controllerPlayer2,
 | 
			
		||||
QWidget#controllerPlayer3,
 | 
			
		||||
QWidget#controllerPlayer4,
 | 
			
		||||
QWidget#controllerPlayer5,
 | 
			
		||||
QWidget#controllerPlayer6,
 | 
			
		||||
QWidget#controllerPlayer7,
 | 
			
		||||
QWidget#controllerPlayer8 {
 | 
			
		||||
  background: transparent;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
}
 | 
			
		||||
@ -126,6 +126,8 @@ add_library(core STATIC
 | 
			
		||||
    file_sys/vfs_vector.h
 | 
			
		||||
    file_sys/xts_archive.cpp
 | 
			
		||||
    file_sys/xts_archive.h
 | 
			
		||||
    frontend/applets/controller.cpp
 | 
			
		||||
    frontend/applets/controller.h
 | 
			
		||||
    frontend/applets/error.cpp
 | 
			
		||||
    frontend/applets/error.h
 | 
			
		||||
    frontend/applets/general_frontend.cpp
 | 
			
		||||
@ -244,6 +246,8 @@ add_library(core STATIC
 | 
			
		||||
    hle/service/am/applet_oe.h
 | 
			
		||||
    hle/service/am/applets/applets.cpp
 | 
			
		||||
    hle/service/am/applets/applets.h
 | 
			
		||||
    hle/service/am/applets/controller.cpp
 | 
			
		||||
    hle/service/am/applets/controller.h
 | 
			
		||||
    hle/service/am/applets/error.cpp
 | 
			
		||||
    hle/service/am/applets/error.h
 | 
			
		||||
    hle/service/am/applets/general_backend.cpp
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										81
									
								
								src/core/frontend/applets/controller.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,81 @@
 | 
			
		||||
// Copyright 2020 yuzu Emulator Project
 | 
			
		||||
// Licensed under GPLv2 or any later version
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#include "common/assert.h"
 | 
			
		||||
#include "common/logging/log.h"
 | 
			
		||||
#include "core/core.h"
 | 
			
		||||
#include "core/frontend/applets/controller.h"
 | 
			
		||||
#include "core/hle/service/hid/controllers/npad.h"
 | 
			
		||||
#include "core/hle/service/hid/hid.h"
 | 
			
		||||
#include "core/hle/service/sm/sm.h"
 | 
			
		||||
 | 
			
		||||
namespace Core::Frontend {
 | 
			
		||||
 | 
			
		||||
ControllerApplet::~ControllerApplet() = default;
 | 
			
		||||
 | 
			
		||||
DefaultControllerApplet::~DefaultControllerApplet() = default;
 | 
			
		||||
 | 
			
		||||
void DefaultControllerApplet::ReconfigureControllers(std::function<void()> callback,
 | 
			
		||||
                                                     ControllerParameters parameters) const {
 | 
			
		||||
    LOG_INFO(Service_HID, "called, deducing the best configuration based on the given parameters!");
 | 
			
		||||
 | 
			
		||||
    auto& npad =
 | 
			
		||||
        Core::System::GetInstance()
 | 
			
		||||
            .ServiceManager()
 | 
			
		||||
            .GetService<Service::HID::Hid>("hid")
 | 
			
		||||
            ->GetAppletResource()
 | 
			
		||||
            ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad);
 | 
			
		||||
 | 
			
		||||
    auto& players = Settings::values.players;
 | 
			
		||||
 | 
			
		||||
    const std::size_t min_supported_players =
 | 
			
		||||
        parameters.enable_single_mode ? 1 : parameters.min_players;
 | 
			
		||||
 | 
			
		||||
    // Disconnect Handheld first.
 | 
			
		||||
    npad.DisconnectNPadAtIndex(8);
 | 
			
		||||
 | 
			
		||||
    // Deduce the best configuration based on the input parameters.
 | 
			
		||||
    for (std::size_t index = 0; index < players.size() - 2; ++index) {
 | 
			
		||||
        // First, disconnect all controllers regardless of the value of keep_controllers_connected.
 | 
			
		||||
        // This makes it easy to connect the desired controllers.
 | 
			
		||||
        npad.DisconnectNPadAtIndex(index);
 | 
			
		||||
 | 
			
		||||
        // Only connect the minimum number of required players.
 | 
			
		||||
        if (index >= min_supported_players) {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Connect controllers based on the following priority list from highest to lowest priority:
 | 
			
		||||
        // Pro Controller -> Dual Joycons -> Left Joycon/Right Joycon -> Handheld
 | 
			
		||||
        if (parameters.allow_pro_controller) {
 | 
			
		||||
            npad.AddNewControllerAt(
 | 
			
		||||
                npad.MapSettingsTypeToNPad(Settings::ControllerType::ProController), index);
 | 
			
		||||
        } else if (parameters.allow_dual_joycons) {
 | 
			
		||||
            npad.AddNewControllerAt(
 | 
			
		||||
                npad.MapSettingsTypeToNPad(Settings::ControllerType::DualJoyconDetached), index);
 | 
			
		||||
        } else if (parameters.allow_left_joycon && parameters.allow_right_joycon) {
 | 
			
		||||
            // Assign left joycons to even player indices and right joycons to odd player indices.
 | 
			
		||||
            // We do this since Captain Toad Treasure Tracker expects a left joycon for Player 1 and
 | 
			
		||||
            // a right Joycon for Player 2 in 2 Player Assist mode.
 | 
			
		||||
            if (index % 2 == 0) {
 | 
			
		||||
                npad.AddNewControllerAt(
 | 
			
		||||
                    npad.MapSettingsTypeToNPad(Settings::ControllerType::LeftJoycon), index);
 | 
			
		||||
            } else {
 | 
			
		||||
                npad.AddNewControllerAt(
 | 
			
		||||
                    npad.MapSettingsTypeToNPad(Settings::ControllerType::RightJoycon), index);
 | 
			
		||||
            }
 | 
			
		||||
        } else if (index == 0 && parameters.enable_single_mode && parameters.allow_handheld &&
 | 
			
		||||
                   !Settings::values.use_docked_mode) {
 | 
			
		||||
            // We should *never* reach here under any normal circumstances.
 | 
			
		||||
            npad.AddNewControllerAt(npad.MapSettingsTypeToNPad(Settings::ControllerType::Handheld),
 | 
			
		||||
                                    index);
 | 
			
		||||
        } else {
 | 
			
		||||
            UNREACHABLE_MSG("Unable to add a new controller based on the given parameters!");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    callback();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace Core::Frontend
 | 
			
		||||
							
								
								
									
										48
									
								
								src/core/frontend/applets/controller.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,48 @@
 | 
			
		||||
// Copyright 2020 yuzu Emulator Project
 | 
			
		||||
// Licensed under GPLv2 or any later version
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <functional>
 | 
			
		||||
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
 | 
			
		||||
namespace Core::Frontend {
 | 
			
		||||
 | 
			
		||||
using BorderColor = std::array<u8, 4>;
 | 
			
		||||
using ExplainText = std::array<char, 0x81>;
 | 
			
		||||
 | 
			
		||||
struct ControllerParameters {
 | 
			
		||||
    s8 min_players{};
 | 
			
		||||
    s8 max_players{};
 | 
			
		||||
    bool keep_controllers_connected{};
 | 
			
		||||
    bool enable_single_mode{};
 | 
			
		||||
    bool enable_border_color{};
 | 
			
		||||
    std::vector<BorderColor> border_colors{};
 | 
			
		||||
    bool enable_explain_text{};
 | 
			
		||||
    std::vector<ExplainText> explain_text{};
 | 
			
		||||
    bool allow_pro_controller{};
 | 
			
		||||
    bool allow_handheld{};
 | 
			
		||||
    bool allow_dual_joycons{};
 | 
			
		||||
    bool allow_left_joycon{};
 | 
			
		||||
    bool allow_right_joycon{};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class ControllerApplet {
 | 
			
		||||
public:
 | 
			
		||||
    virtual ~ControllerApplet();
 | 
			
		||||
 | 
			
		||||
    virtual void ReconfigureControllers(std::function<void()> callback,
 | 
			
		||||
                                        ControllerParameters parameters) const = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class DefaultControllerApplet final : public ControllerApplet {
 | 
			
		||||
public:
 | 
			
		||||
    ~DefaultControllerApplet() override;
 | 
			
		||||
 | 
			
		||||
    void ReconfigureControllers(std::function<void()> callback,
 | 
			
		||||
                                ControllerParameters parameters) const override;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace Core::Frontend
 | 
			
		||||
@ -5,6 +5,7 @@
 | 
			
		||||
#include <cstring>
 | 
			
		||||
#include "common/assert.h"
 | 
			
		||||
#include "core/core.h"
 | 
			
		||||
#include "core/frontend/applets/controller.h"
 | 
			
		||||
#include "core/frontend/applets/error.h"
 | 
			
		||||
#include "core/frontend/applets/general_frontend.h"
 | 
			
		||||
#include "core/frontend/applets/profile_select.h"
 | 
			
		||||
@ -15,6 +16,7 @@
 | 
			
		||||
#include "core/hle/kernel/writable_event.h"
 | 
			
		||||
#include "core/hle/service/am/am.h"
 | 
			
		||||
#include "core/hle/service/am/applets/applets.h"
 | 
			
		||||
#include "core/hle/service/am/applets/controller.h"
 | 
			
		||||
#include "core/hle/service/am/applets/error.h"
 | 
			
		||||
#include "core/hle/service/am/applets/general_backend.h"
 | 
			
		||||
#include "core/hle/service/am/applets/profile_select.h"
 | 
			
		||||
@ -140,14 +142,14 @@ void Applet::Initialize() {
 | 
			
		||||
 | 
			
		||||
AppletFrontendSet::AppletFrontendSet() = default;
 | 
			
		||||
 | 
			
		||||
AppletFrontendSet::AppletFrontendSet(ParentalControlsApplet parental_controls, ErrorApplet error,
 | 
			
		||||
AppletFrontendSet::AppletFrontendSet(ControllerApplet controller, ECommerceApplet e_commerce,
 | 
			
		||||
                                     ErrorApplet error, ParentalControlsApplet parental_controls,
 | 
			
		||||
                                     PhotoViewer photo_viewer, ProfileSelect profile_select,
 | 
			
		||||
                                     SoftwareKeyboard software_keyboard, WebBrowser web_browser,
 | 
			
		||||
                                     ECommerceApplet e_commerce)
 | 
			
		||||
    : parental_controls{std::move(parental_controls)}, error{std::move(error)},
 | 
			
		||||
      photo_viewer{std::move(photo_viewer)}, profile_select{std::move(profile_select)},
 | 
			
		||||
      software_keyboard{std::move(software_keyboard)}, web_browser{std::move(web_browser)},
 | 
			
		||||
      e_commerce{std::move(e_commerce)} {}
 | 
			
		||||
                                     SoftwareKeyboard software_keyboard, WebBrowser web_browser)
 | 
			
		||||
    : controller{std::move(controller)}, e_commerce{std::move(e_commerce)}, error{std::move(error)},
 | 
			
		||||
      parental_controls{std::move(parental_controls)}, photo_viewer{std::move(photo_viewer)},
 | 
			
		||||
      profile_select{std::move(profile_select)}, software_keyboard{std::move(software_keyboard)},
 | 
			
		||||
      web_browser{std::move(web_browser)} {}
 | 
			
		||||
 | 
			
		||||
AppletFrontendSet::~AppletFrontendSet() = default;
 | 
			
		||||
 | 
			
		||||
@ -164,20 +166,37 @@ const AppletFrontendSet& AppletManager::GetAppletFrontendSet() const {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) {
 | 
			
		||||
    if (set.parental_controls != nullptr)
 | 
			
		||||
        frontend.parental_controls = std::move(set.parental_controls);
 | 
			
		||||
    if (set.error != nullptr)
 | 
			
		||||
        frontend.error = std::move(set.error);
 | 
			
		||||
    if (set.photo_viewer != nullptr)
 | 
			
		||||
        frontend.photo_viewer = std::move(set.photo_viewer);
 | 
			
		||||
    if (set.profile_select != nullptr)
 | 
			
		||||
        frontend.profile_select = std::move(set.profile_select);
 | 
			
		||||
    if (set.software_keyboard != nullptr)
 | 
			
		||||
        frontend.software_keyboard = std::move(set.software_keyboard);
 | 
			
		||||
    if (set.web_browser != nullptr)
 | 
			
		||||
        frontend.web_browser = std::move(set.web_browser);
 | 
			
		||||
    if (set.e_commerce != nullptr)
 | 
			
		||||
    if (set.controller != nullptr) {
 | 
			
		||||
        frontend.controller = std::move(set.controller);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (set.e_commerce != nullptr) {
 | 
			
		||||
        frontend.e_commerce = std::move(set.e_commerce);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (set.error != nullptr) {
 | 
			
		||||
        frontend.error = std::move(set.error);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (set.parental_controls != nullptr) {
 | 
			
		||||
        frontend.parental_controls = std::move(set.parental_controls);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (set.photo_viewer != nullptr) {
 | 
			
		||||
        frontend.photo_viewer = std::move(set.photo_viewer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (set.profile_select != nullptr) {
 | 
			
		||||
        frontend.profile_select = std::move(set.profile_select);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (set.software_keyboard != nullptr) {
 | 
			
		||||
        frontend.software_keyboard = std::move(set.software_keyboard);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (set.web_browser != nullptr) {
 | 
			
		||||
        frontend.web_browser = std::move(set.web_browser);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AppletManager::SetDefaultAppletFrontendSet() {
 | 
			
		||||
@ -186,15 +205,23 @@ void AppletManager::SetDefaultAppletFrontendSet() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AppletManager::SetDefaultAppletsIfMissing() {
 | 
			
		||||
    if (frontend.parental_controls == nullptr) {
 | 
			
		||||
        frontend.parental_controls =
 | 
			
		||||
            std::make_unique<Core::Frontend::DefaultParentalControlsApplet>();
 | 
			
		||||
    if (frontend.controller == nullptr) {
 | 
			
		||||
        frontend.controller = std::make_unique<Core::Frontend::DefaultControllerApplet>();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (frontend.e_commerce == nullptr) {
 | 
			
		||||
        frontend.e_commerce = std::make_unique<Core::Frontend::DefaultECommerceApplet>();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (frontend.error == nullptr) {
 | 
			
		||||
        frontend.error = std::make_unique<Core::Frontend::DefaultErrorApplet>();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (frontend.parental_controls == nullptr) {
 | 
			
		||||
        frontend.parental_controls =
 | 
			
		||||
            std::make_unique<Core::Frontend::DefaultParentalControlsApplet>();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (frontend.photo_viewer == nullptr) {
 | 
			
		||||
        frontend.photo_viewer = std::make_unique<Core::Frontend::DefaultPhotoViewerApplet>();
 | 
			
		||||
    }
 | 
			
		||||
@ -211,10 +238,6 @@ void AppletManager::SetDefaultAppletsIfMissing() {
 | 
			
		||||
    if (frontend.web_browser == nullptr) {
 | 
			
		||||
        frontend.web_browser = std::make_unique<Core::Frontend::DefaultWebBrowserApplet>();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (frontend.e_commerce == nullptr) {
 | 
			
		||||
        frontend.e_commerce = std::make_unique<Core::Frontend::DefaultECommerceApplet>();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AppletManager::ClearAll() {
 | 
			
		||||
@ -225,6 +248,8 @@ std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id) const {
 | 
			
		||||
    switch (id) {
 | 
			
		||||
    case AppletId::Auth:
 | 
			
		||||
        return std::make_shared<Auth>(system, *frontend.parental_controls);
 | 
			
		||||
    case AppletId::Controller:
 | 
			
		||||
        return std::make_shared<Controller>(system, *frontend.controller);
 | 
			
		||||
    case AppletId::Error:
 | 
			
		||||
        return std::make_shared<Error>(system, *frontend.error);
 | 
			
		||||
    case AppletId::ProfileSelect:
 | 
			
		||||
 | 
			
		||||
@ -17,6 +17,7 @@ class System;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace Core::Frontend {
 | 
			
		||||
class ControllerApplet;
 | 
			
		||||
class ECommerceApplet;
 | 
			
		||||
class ErrorApplet;
 | 
			
		||||
class ParentalControlsApplet;
 | 
			
		||||
@ -155,19 +156,20 @@ protected:
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct AppletFrontendSet {
 | 
			
		||||
    using ParentalControlsApplet = std::unique_ptr<Core::Frontend::ParentalControlsApplet>;
 | 
			
		||||
    using ControllerApplet = std::unique_ptr<Core::Frontend::ControllerApplet>;
 | 
			
		||||
    using ECommerceApplet = std::unique_ptr<Core::Frontend::ECommerceApplet>;
 | 
			
		||||
    using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>;
 | 
			
		||||
    using ParentalControlsApplet = std::unique_ptr<Core::Frontend::ParentalControlsApplet>;
 | 
			
		||||
    using PhotoViewer = std::unique_ptr<Core::Frontend::PhotoViewerApplet>;
 | 
			
		||||
    using ProfileSelect = std::unique_ptr<Core::Frontend::ProfileSelectApplet>;
 | 
			
		||||
    using SoftwareKeyboard = std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet>;
 | 
			
		||||
    using WebBrowser = std::unique_ptr<Core::Frontend::WebBrowserApplet>;
 | 
			
		||||
    using ECommerceApplet = std::unique_ptr<Core::Frontend::ECommerceApplet>;
 | 
			
		||||
 | 
			
		||||
    AppletFrontendSet();
 | 
			
		||||
    AppletFrontendSet(ParentalControlsApplet parental_controls, ErrorApplet error,
 | 
			
		||||
                      PhotoViewer photo_viewer, ProfileSelect profile_select,
 | 
			
		||||
                      SoftwareKeyboard software_keyboard, WebBrowser web_browser,
 | 
			
		||||
                      ECommerceApplet e_commerce);
 | 
			
		||||
    AppletFrontendSet(ControllerApplet controller, ECommerceApplet e_commerce, ErrorApplet error,
 | 
			
		||||
                      ParentalControlsApplet parental_controls, PhotoViewer photo_viewer,
 | 
			
		||||
                      ProfileSelect profile_select, SoftwareKeyboard software_keyboard,
 | 
			
		||||
                      WebBrowser web_browser);
 | 
			
		||||
    ~AppletFrontendSet();
 | 
			
		||||
 | 
			
		||||
    AppletFrontendSet(const AppletFrontendSet&) = delete;
 | 
			
		||||
@ -176,13 +178,14 @@ struct AppletFrontendSet {
 | 
			
		||||
    AppletFrontendSet(AppletFrontendSet&&) noexcept;
 | 
			
		||||
    AppletFrontendSet& operator=(AppletFrontendSet&&) noexcept;
 | 
			
		||||
 | 
			
		||||
    ParentalControlsApplet parental_controls;
 | 
			
		||||
    ControllerApplet controller;
 | 
			
		||||
    ECommerceApplet e_commerce;
 | 
			
		||||
    ErrorApplet error;
 | 
			
		||||
    ParentalControlsApplet parental_controls;
 | 
			
		||||
    PhotoViewer photo_viewer;
 | 
			
		||||
    ProfileSelect profile_select;
 | 
			
		||||
    SoftwareKeyboard software_keyboard;
 | 
			
		||||
    WebBrowser web_browser;
 | 
			
		||||
    ECommerceApplet e_commerce;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class AppletManager {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										210
									
								
								src/core/hle/service/am/applets/controller.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,210 @@
 | 
			
		||||
// Copyright 2020 yuzu Emulator Project
 | 
			
		||||
// Licensed under GPLv2 or any later version
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <cstring>
 | 
			
		||||
 | 
			
		||||
#include "common/assert.h"
 | 
			
		||||
#include "common/logging/log.h"
 | 
			
		||||
#include "common/string_util.h"
 | 
			
		||||
#include "core/core.h"
 | 
			
		||||
#include "core/frontend/applets/controller.h"
 | 
			
		||||
#include "core/hle/result.h"
 | 
			
		||||
#include "core/hle/service/am/am.h"
 | 
			
		||||
#include "core/hle/service/am/applets/controller.h"
 | 
			
		||||
#include "core/hle/service/hid/controllers/npad.h"
 | 
			
		||||
 | 
			
		||||
namespace Service::AM::Applets {
 | 
			
		||||
 | 
			
		||||
// This error code (0x183ACA) is thrown when the applet fails to initialize.
 | 
			
		||||
[[maybe_unused]] constexpr ResultCode ERR_CONTROLLER_APPLET_3101{ErrorModule::HID, 3101};
 | 
			
		||||
// This error code (0x183CCA) is thrown when the u32 result in ControllerSupportResultInfo is 2.
 | 
			
		||||
[[maybe_unused]] constexpr ResultCode ERR_CONTROLLER_APPLET_3102{ErrorModule::HID, 3102};
 | 
			
		||||
 | 
			
		||||
static Core::Frontend::ControllerParameters ConvertToFrontendParameters(
 | 
			
		||||
    ControllerSupportArgPrivate private_arg, ControllerSupportArgHeader header, bool enable_text,
 | 
			
		||||
    std::vector<IdentificationColor> identification_colors, std::vector<ExplainText> text) {
 | 
			
		||||
    HID::Controller_NPad::NPadType npad_style_set;
 | 
			
		||||
    npad_style_set.raw = private_arg.style_set;
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
        .min_players = std::max(s8(1), header.player_count_min),
 | 
			
		||||
        .max_players = header.player_count_max,
 | 
			
		||||
        .keep_controllers_connected = header.enable_take_over_connection,
 | 
			
		||||
        .enable_single_mode = header.enable_single_mode,
 | 
			
		||||
        .enable_border_color = header.enable_identification_color,
 | 
			
		||||
        .border_colors = identification_colors,
 | 
			
		||||
        .enable_explain_text = enable_text,
 | 
			
		||||
        .explain_text = text,
 | 
			
		||||
        .allow_pro_controller = npad_style_set.pro_controller == 1,
 | 
			
		||||
        .allow_handheld = npad_style_set.handheld == 1,
 | 
			
		||||
        .allow_dual_joycons = npad_style_set.joycon_dual == 1,
 | 
			
		||||
        .allow_left_joycon = npad_style_set.joycon_left == 1,
 | 
			
		||||
        .allow_right_joycon = npad_style_set.joycon_right == 1,
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Controller::Controller(Core::System& system_, const Core::Frontend::ControllerApplet& frontend_)
 | 
			
		||||
    : Applet{system_.Kernel()}, frontend(frontend_) {}
 | 
			
		||||
 | 
			
		||||
Controller::~Controller() = default;
 | 
			
		||||
 | 
			
		||||
void Controller::Initialize() {
 | 
			
		||||
    Applet::Initialize();
 | 
			
		||||
 | 
			
		||||
    LOG_INFO(Service_HID, "Initializing Controller Applet.");
 | 
			
		||||
 | 
			
		||||
    LOG_DEBUG(Service_HID,
 | 
			
		||||
              "Initializing Applet with common_args: arg_version={}, lib_version={}, "
 | 
			
		||||
              "play_startup_sound={}, size={}, system_tick={}, theme_color={}",
 | 
			
		||||
              common_args.arguments_version, common_args.library_version,
 | 
			
		||||
              common_args.play_startup_sound, common_args.size, common_args.system_tick,
 | 
			
		||||
              common_args.theme_color);
 | 
			
		||||
 | 
			
		||||
    library_applet_version = LibraryAppletVersion{common_args.library_version};
 | 
			
		||||
 | 
			
		||||
    const auto private_arg_storage = broker.PopNormalDataToApplet();
 | 
			
		||||
    ASSERT(private_arg_storage != nullptr);
 | 
			
		||||
 | 
			
		||||
    const auto& private_arg = private_arg_storage->GetData();
 | 
			
		||||
    ASSERT(private_arg.size() == sizeof(ControllerSupportArgPrivate));
 | 
			
		||||
 | 
			
		||||
    std::memcpy(&controller_private_arg, private_arg.data(), sizeof(ControllerSupportArgPrivate));
 | 
			
		||||
    ASSERT_MSG(controller_private_arg.arg_private_size == sizeof(ControllerSupportArgPrivate),
 | 
			
		||||
               "Unknown ControllerSupportArgPrivate revision={} with size={}",
 | 
			
		||||
               library_applet_version, controller_private_arg.arg_private_size);
 | 
			
		||||
 | 
			
		||||
    switch (controller_private_arg.mode) {
 | 
			
		||||
    case ControllerSupportMode::ShowControllerSupport: {
 | 
			
		||||
        const auto user_arg_storage = broker.PopNormalDataToApplet();
 | 
			
		||||
        ASSERT(user_arg_storage != nullptr);
 | 
			
		||||
 | 
			
		||||
        const auto& user_arg = user_arg_storage->GetData();
 | 
			
		||||
        switch (library_applet_version) {
 | 
			
		||||
        case LibraryAppletVersion::Version3:
 | 
			
		||||
        case LibraryAppletVersion::Version4:
 | 
			
		||||
        case LibraryAppletVersion::Version5:
 | 
			
		||||
            ASSERT(user_arg.size() == sizeof(ControllerSupportArgOld));
 | 
			
		||||
            std::memcpy(&controller_user_arg_old, user_arg.data(), sizeof(ControllerSupportArgOld));
 | 
			
		||||
            break;
 | 
			
		||||
        case LibraryAppletVersion::Version7:
 | 
			
		||||
            ASSERT(user_arg.size() == sizeof(ControllerSupportArgNew));
 | 
			
		||||
            std::memcpy(&controller_user_arg_new, user_arg.data(), sizeof(ControllerSupportArgNew));
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            UNIMPLEMENTED_MSG("Unknown ControllerSupportArg revision={} with size={}",
 | 
			
		||||
                              library_applet_version, controller_private_arg.arg_size);
 | 
			
		||||
            ASSERT(user_arg.size() >= sizeof(ControllerSupportArgNew));
 | 
			
		||||
            std::memcpy(&controller_user_arg_new, user_arg.data(), sizeof(ControllerSupportArgNew));
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    case ControllerSupportMode::ShowControllerStrapGuide:
 | 
			
		||||
    case ControllerSupportMode::ShowControllerFirmwareUpdate:
 | 
			
		||||
    default: {
 | 
			
		||||
        UNIMPLEMENTED_MSG("Unimplemented ControllerSupportMode={}", controller_private_arg.mode);
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool Controller::TransactionComplete() const {
 | 
			
		||||
    return complete;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ResultCode Controller::GetStatus() const {
 | 
			
		||||
    return status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Controller::ExecuteInteractive() {
 | 
			
		||||
    UNREACHABLE_MSG("Attempted to call interactive execution on non-interactive applet.");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Controller::Execute() {
 | 
			
		||||
    switch (controller_private_arg.mode) {
 | 
			
		||||
    case ControllerSupportMode::ShowControllerSupport: {
 | 
			
		||||
        const auto parameters = [this] {
 | 
			
		||||
            switch (library_applet_version) {
 | 
			
		||||
            case LibraryAppletVersion::Version3:
 | 
			
		||||
            case LibraryAppletVersion::Version4:
 | 
			
		||||
            case LibraryAppletVersion::Version5:
 | 
			
		||||
                return ConvertToFrontendParameters(
 | 
			
		||||
                    controller_private_arg, controller_user_arg_old.header,
 | 
			
		||||
                    controller_user_arg_old.enable_explain_text,
 | 
			
		||||
                    std::vector<IdentificationColor>(
 | 
			
		||||
                        controller_user_arg_old.identification_colors.begin(),
 | 
			
		||||
                        controller_user_arg_old.identification_colors.end()),
 | 
			
		||||
                    std::vector<ExplainText>(controller_user_arg_old.explain_text.begin(),
 | 
			
		||||
                                             controller_user_arg_old.explain_text.end()));
 | 
			
		||||
            case LibraryAppletVersion::Version7:
 | 
			
		||||
            default:
 | 
			
		||||
                return ConvertToFrontendParameters(
 | 
			
		||||
                    controller_private_arg, controller_user_arg_new.header,
 | 
			
		||||
                    controller_user_arg_new.enable_explain_text,
 | 
			
		||||
                    std::vector<IdentificationColor>(
 | 
			
		||||
                        controller_user_arg_new.identification_colors.begin(),
 | 
			
		||||
                        controller_user_arg_new.identification_colors.end()),
 | 
			
		||||
                    std::vector<ExplainText>(controller_user_arg_new.explain_text.begin(),
 | 
			
		||||
                                             controller_user_arg_new.explain_text.end()));
 | 
			
		||||
            }
 | 
			
		||||
        }();
 | 
			
		||||
 | 
			
		||||
        is_single_mode = parameters.enable_single_mode;
 | 
			
		||||
 | 
			
		||||
        LOG_DEBUG(Service_HID,
 | 
			
		||||
                  "Controller Parameters: min_players={}, max_players={}, "
 | 
			
		||||
                  "keep_controllers_connected={}, enable_single_mode={}, enable_border_color={}, "
 | 
			
		||||
                  "enable_explain_text={}, allow_pro_controller={}, allow_handheld={}, "
 | 
			
		||||
                  "allow_dual_joycons={}, allow_left_joycon={}, allow_right_joycon={}",
 | 
			
		||||
                  parameters.min_players, parameters.max_players,
 | 
			
		||||
                  parameters.keep_controllers_connected, parameters.enable_single_mode,
 | 
			
		||||
                  parameters.enable_border_color, parameters.enable_explain_text,
 | 
			
		||||
                  parameters.allow_pro_controller, parameters.allow_handheld,
 | 
			
		||||
                  parameters.allow_dual_joycons, parameters.allow_left_joycon,
 | 
			
		||||
                  parameters.allow_right_joycon);
 | 
			
		||||
 | 
			
		||||
        frontend.ReconfigureControllers([this] { ConfigurationComplete(); }, parameters);
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    case ControllerSupportMode::ShowControllerStrapGuide:
 | 
			
		||||
    case ControllerSupportMode::ShowControllerFirmwareUpdate:
 | 
			
		||||
    default: {
 | 
			
		||||
        ConfigurationComplete();
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Controller::ConfigurationComplete() {
 | 
			
		||||
    ControllerSupportResultInfo result_info{};
 | 
			
		||||
 | 
			
		||||
    const auto& players = Settings::values.players;
 | 
			
		||||
 | 
			
		||||
    // If enable_single_mode is enabled, player_count is 1 regardless of any other parameters.
 | 
			
		||||
    // Otherwise, only count connected players from P1-P8.
 | 
			
		||||
    result_info.player_count =
 | 
			
		||||
        is_single_mode ? 1
 | 
			
		||||
                       : static_cast<s8>(std::count_if(
 | 
			
		||||
                             players.begin(), players.end() - 2,
 | 
			
		||||
                             [](Settings::PlayerInput player) { return player.connected; }));
 | 
			
		||||
 | 
			
		||||
    result_info.selected_id = HID::Controller_NPad::IndexToNPad(
 | 
			
		||||
        std::distance(players.begin(),
 | 
			
		||||
                      std::find_if(players.begin(), players.end(),
 | 
			
		||||
                                   [](Settings::PlayerInput player) { return player.connected; })));
 | 
			
		||||
 | 
			
		||||
    result_info.result = 0;
 | 
			
		||||
 | 
			
		||||
    LOG_DEBUG(Service_HID, "Result Info: player_count={}, selected_id={}, result={}",
 | 
			
		||||
              result_info.player_count, result_info.selected_id, result_info.result);
 | 
			
		||||
 | 
			
		||||
    complete = true;
 | 
			
		||||
    out_data = std::vector<u8>(sizeof(ControllerSupportResultInfo));
 | 
			
		||||
    std::memcpy(out_data.data(), &result_info, out_data.size());
 | 
			
		||||
    broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(out_data)));
 | 
			
		||||
    broker.SignalStateChanged();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace Service::AM::Applets
 | 
			
		||||
							
								
								
									
										123
									
								
								src/core/hle/service/am/applets/controller.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,123 @@
 | 
			
		||||
// Copyright 2020 yuzu Emulator Project
 | 
			
		||||
// Licensed under GPLv2 or any later version
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include "common/common_funcs.h"
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "core/hle/result.h"
 | 
			
		||||
#include "core/hle/service/am/applets/applets.h"
 | 
			
		||||
 | 
			
		||||
namespace Core {
 | 
			
		||||
class System;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace Service::AM::Applets {
 | 
			
		||||
 | 
			
		||||
using IdentificationColor = std::array<u8, 4>;
 | 
			
		||||
using ExplainText = std::array<char, 0x81>;
 | 
			
		||||
 | 
			
		||||
enum class LibraryAppletVersion : u32_le {
 | 
			
		||||
    Version3 = 0x3, // 1.0.0 - 2.3.0
 | 
			
		||||
    Version4 = 0x4, // 3.0.0 - 5.1.0
 | 
			
		||||
    Version5 = 0x5, // 6.0.0 - 7.0.1
 | 
			
		||||
    Version7 = 0x7, // 8.0.0+
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class ControllerSupportMode : u8 {
 | 
			
		||||
    ShowControllerSupport = 0,
 | 
			
		||||
    ShowControllerStrapGuide = 1,
 | 
			
		||||
    ShowControllerFirmwareUpdate = 2,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class ControllerSupportCaller : u8 {
 | 
			
		||||
    Application = 0,
 | 
			
		||||
    System = 1,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ControllerSupportArgPrivate {
 | 
			
		||||
    u32 arg_private_size{};
 | 
			
		||||
    u32 arg_size{};
 | 
			
		||||
    bool flag_0{};
 | 
			
		||||
    bool flag_1{};
 | 
			
		||||
    ControllerSupportMode mode{};
 | 
			
		||||
    ControllerSupportCaller caller{};
 | 
			
		||||
    u32 style_set{};
 | 
			
		||||
    u32 joy_hold_type{};
 | 
			
		||||
};
 | 
			
		||||
static_assert(sizeof(ControllerSupportArgPrivate) == 0x14,
 | 
			
		||||
              "ControllerSupportArgPrivate has incorrect size.");
 | 
			
		||||
 | 
			
		||||
struct ControllerSupportArgHeader {
 | 
			
		||||
    s8 player_count_min{};
 | 
			
		||||
    s8 player_count_max{};
 | 
			
		||||
    bool enable_take_over_connection{};
 | 
			
		||||
    bool enable_left_justify{};
 | 
			
		||||
    bool enable_permit_joy_dual{};
 | 
			
		||||
    bool enable_single_mode{};
 | 
			
		||||
    bool enable_identification_color{};
 | 
			
		||||
};
 | 
			
		||||
static_assert(sizeof(ControllerSupportArgHeader) == 0x7,
 | 
			
		||||
              "ControllerSupportArgHeader has incorrect size.");
 | 
			
		||||
 | 
			
		||||
// LibraryAppletVersion 0x3, 0x4, 0x5
 | 
			
		||||
struct ControllerSupportArgOld {
 | 
			
		||||
    ControllerSupportArgHeader header{};
 | 
			
		||||
    std::array<IdentificationColor, 4> identification_colors{};
 | 
			
		||||
    bool enable_explain_text{};
 | 
			
		||||
    std::array<ExplainText, 4> explain_text{};
 | 
			
		||||
};
 | 
			
		||||
static_assert(sizeof(ControllerSupportArgOld) == 0x21C,
 | 
			
		||||
              "ControllerSupportArgOld has incorrect size.");
 | 
			
		||||
 | 
			
		||||
// LibraryAppletVersion 0x7
 | 
			
		||||
struct ControllerSupportArgNew {
 | 
			
		||||
    ControllerSupportArgHeader header{};
 | 
			
		||||
    std::array<IdentificationColor, 8> identification_colors{};
 | 
			
		||||
    bool enable_explain_text{};
 | 
			
		||||
    std::array<ExplainText, 8> explain_text{};
 | 
			
		||||
};
 | 
			
		||||
static_assert(sizeof(ControllerSupportArgNew) == 0x430,
 | 
			
		||||
              "ControllerSupportArgNew has incorrect size.");
 | 
			
		||||
 | 
			
		||||
struct ControllerSupportResultInfo {
 | 
			
		||||
    s8 player_count{};
 | 
			
		||||
    INSERT_PADDING_BYTES(3);
 | 
			
		||||
    u32 selected_id{};
 | 
			
		||||
    u32 result{};
 | 
			
		||||
};
 | 
			
		||||
static_assert(sizeof(ControllerSupportResultInfo) == 0xC,
 | 
			
		||||
              "ControllerSupportResultInfo has incorrect size.");
 | 
			
		||||
 | 
			
		||||
class Controller final : public Applet {
 | 
			
		||||
public:
 | 
			
		||||
    explicit Controller(Core::System& system_, const Core::Frontend::ControllerApplet& frontend_);
 | 
			
		||||
    ~Controller() override;
 | 
			
		||||
 | 
			
		||||
    void Initialize() override;
 | 
			
		||||
 | 
			
		||||
    bool TransactionComplete() const override;
 | 
			
		||||
    ResultCode GetStatus() const override;
 | 
			
		||||
    void ExecuteInteractive() override;
 | 
			
		||||
    void Execute() override;
 | 
			
		||||
 | 
			
		||||
    void ConfigurationComplete();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    const Core::Frontend::ControllerApplet& frontend;
 | 
			
		||||
 | 
			
		||||
    LibraryAppletVersion library_applet_version;
 | 
			
		||||
    ControllerSupportArgPrivate controller_private_arg;
 | 
			
		||||
    ControllerSupportArgOld controller_user_arg_old;
 | 
			
		||||
    ControllerSupportArgNew controller_user_arg_new;
 | 
			
		||||
    bool complete{false};
 | 
			
		||||
    ResultCode status{RESULT_SUCCESS};
 | 
			
		||||
    bool is_single_mode{false};
 | 
			
		||||
    std::vector<u8> out_data;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace Service::AM::Applets
 | 
			
		||||
@ -193,7 +193,8 @@ void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) {
 | 
			
		||||
    controller.battery_level[0] = BATTERY_FULL;
 | 
			
		||||
    controller.battery_level[1] = BATTERY_FULL;
 | 
			
		||||
    controller.battery_level[2] = BATTERY_FULL;
 | 
			
		||||
    styleset_changed_events[controller_idx].writable->Signal();
 | 
			
		||||
 | 
			
		||||
    SignalStyleSetChangedEvent(IndexToNPad(controller_idx));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Controller_NPad::OnInit() {
 | 
			
		||||
@ -518,13 +519,17 @@ void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids,
 | 
			
		||||
    last_processed_vibration = vibrations.back();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Controller_NPad::Vibration Controller_NPad::GetLastVibration() const {
 | 
			
		||||
    return last_processed_vibration;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::shared_ptr<Kernel::ReadableEvent> Controller_NPad::GetStyleSetChangedEvent(u32 npad_id) const {
 | 
			
		||||
    const auto& styleset_event = styleset_changed_events[NPadIdToIndex(npad_id)];
 | 
			
		||||
    return styleset_event.readable;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Controller_NPad::Vibration Controller_NPad::GetLastVibration() const {
 | 
			
		||||
    return last_processed_vibration;
 | 
			
		||||
void Controller_NPad::SignalStyleSetChangedEvent(u32 npad_id) const {
 | 
			
		||||
    styleset_changed_events[NPadIdToIndex(npad_id)].writable->Signal();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Controller_NPad::AddNewControllerAt(NPadControllerType controller, std::size_t npad_index) {
 | 
			
		||||
@ -534,7 +539,7 @@ void Controller_NPad::AddNewControllerAt(NPadControllerType controller, std::siz
 | 
			
		||||
void Controller_NPad::UpdateControllerAt(NPadControllerType controller, std::size_t npad_index,
 | 
			
		||||
                                         bool connected) {
 | 
			
		||||
    if (!connected) {
 | 
			
		||||
        DisconnectNPad(IndexToNPad(npad_index));
 | 
			
		||||
        DisconnectNPadAtIndex(npad_index);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -554,16 +559,19 @@ void Controller_NPad::UpdateControllerAt(NPadControllerType controller, std::siz
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Controller_NPad::DisconnectNPad(u32 npad_id) {
 | 
			
		||||
    const auto npad_index = NPadIdToIndex(npad_id);
 | 
			
		||||
    connected_controllers[npad_index].is_connected = false;
 | 
			
		||||
    DisconnectNPadAtIndex(NPadIdToIndex(npad_id));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Controller_NPad::DisconnectNPadAtIndex(std::size_t npad_index) {
 | 
			
		||||
    Settings::values.players[npad_index].connected = false;
 | 
			
		||||
    connected_controllers[npad_index].is_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();
 | 
			
		||||
    SignalStyleSetChangedEvent(IndexToNPad(npad_index));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Controller_NPad::SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode) {
 | 
			
		||||
@ -666,13 +674,13 @@ void Controller_NPad::ClearAllConnectedControllers() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Controller_NPad::DisconnectAllConnectedControllers() {
 | 
			
		||||
    for (ControllerHolder& controller : connected_controllers) {
 | 
			
		||||
    for (auto& controller : connected_controllers) {
 | 
			
		||||
        controller.is_connected = false;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Controller_NPad::ConnectAllDisconnectedControllers() {
 | 
			
		||||
    for (ControllerHolder& controller : connected_controllers) {
 | 
			
		||||
    for (auto& controller : connected_controllers) {
 | 
			
		||||
        if (controller.type != NPadControllerType::None && !controller.is_connected) {
 | 
			
		||||
            controller.is_connected = true;
 | 
			
		||||
        }
 | 
			
		||||
@ -680,7 +688,7 @@ void Controller_NPad::ConnectAllDisconnectedControllers() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void Controller_NPad::ClearAllControllers() {
 | 
			
		||||
    for (ControllerHolder& controller : connected_controllers) {
 | 
			
		||||
    for (auto& controller : connected_controllers) {
 | 
			
		||||
        controller.type = NPadControllerType::None;
 | 
			
		||||
        controller.is_connected = false;
 | 
			
		||||
    }
 | 
			
		||||
@ -728,92 +736,4 @@ bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Controller_NPad::NPadControllerType Controller_NPad::DecideBestController(
 | 
			
		||||
    NPadControllerType priority) const {
 | 
			
		||||
    if (IsControllerSupported(priority)) {
 | 
			
		||||
        return priority;
 | 
			
		||||
    }
 | 
			
		||||
    const auto is_docked = Settings::values.use_docked_mode;
 | 
			
		||||
    if (is_docked && priority == NPadControllerType::Handheld) {
 | 
			
		||||
        priority = NPadControllerType::JoyDual;
 | 
			
		||||
        if (IsControllerSupported(priority)) {
 | 
			
		||||
            return priority;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    std::vector<NPadControllerType> priority_list;
 | 
			
		||||
    switch (priority) {
 | 
			
		||||
    case NPadControllerType::ProController:
 | 
			
		||||
        priority_list.push_back(NPadControllerType::JoyDual);
 | 
			
		||||
        if (!is_docked) {
 | 
			
		||||
            priority_list.push_back(NPadControllerType::Handheld);
 | 
			
		||||
        }
 | 
			
		||||
        priority_list.push_back(NPadControllerType::JoyLeft);
 | 
			
		||||
        priority_list.push_back(NPadControllerType::JoyRight);
 | 
			
		||||
        priority_list.push_back(NPadControllerType::Pokeball);
 | 
			
		||||
        break;
 | 
			
		||||
    case NPadControllerType::Handheld:
 | 
			
		||||
        priority_list.push_back(NPadControllerType::JoyDual);
 | 
			
		||||
        priority_list.push_back(NPadControllerType::ProController);
 | 
			
		||||
        priority_list.push_back(NPadControllerType::JoyLeft);
 | 
			
		||||
        priority_list.push_back(NPadControllerType::JoyRight);
 | 
			
		||||
        priority_list.push_back(NPadControllerType::Pokeball);
 | 
			
		||||
        break;
 | 
			
		||||
    case NPadControllerType::JoyDual:
 | 
			
		||||
        if (!is_docked) {
 | 
			
		||||
            priority_list.push_back(NPadControllerType::Handheld);
 | 
			
		||||
        }
 | 
			
		||||
        priority_list.push_back(NPadControllerType::ProController);
 | 
			
		||||
        priority_list.push_back(NPadControllerType::JoyLeft);
 | 
			
		||||
        priority_list.push_back(NPadControllerType::JoyRight);
 | 
			
		||||
        priority_list.push_back(NPadControllerType::Pokeball);
 | 
			
		||||
        break;
 | 
			
		||||
    case NPadControllerType::JoyLeft:
 | 
			
		||||
        priority_list.push_back(NPadControllerType::JoyRight);
 | 
			
		||||
        priority_list.push_back(NPadControllerType::JoyDual);
 | 
			
		||||
        if (!is_docked) {
 | 
			
		||||
            priority_list.push_back(NPadControllerType::Handheld);
 | 
			
		||||
        }
 | 
			
		||||
        priority_list.push_back(NPadControllerType::ProController);
 | 
			
		||||
        priority_list.push_back(NPadControllerType::Pokeball);
 | 
			
		||||
        break;
 | 
			
		||||
    case NPadControllerType::JoyRight:
 | 
			
		||||
        priority_list.push_back(NPadControllerType::JoyLeft);
 | 
			
		||||
        priority_list.push_back(NPadControllerType::JoyDual);
 | 
			
		||||
        if (!is_docked) {
 | 
			
		||||
            priority_list.push_back(NPadControllerType::Handheld);
 | 
			
		||||
        }
 | 
			
		||||
        priority_list.push_back(NPadControllerType::ProController);
 | 
			
		||||
        priority_list.push_back(NPadControllerType::Pokeball);
 | 
			
		||||
        break;
 | 
			
		||||
    case NPadControllerType::Pokeball:
 | 
			
		||||
        priority_list.push_back(NPadControllerType::JoyLeft);
 | 
			
		||||
        priority_list.push_back(NPadControllerType::JoyRight);
 | 
			
		||||
        priority_list.push_back(NPadControllerType::JoyDual);
 | 
			
		||||
        if (!is_docked) {
 | 
			
		||||
            priority_list.push_back(NPadControllerType::Handheld);
 | 
			
		||||
        }
 | 
			
		||||
        priority_list.push_back(NPadControllerType::ProController);
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
        priority_list.push_back(NPadControllerType::JoyDual);
 | 
			
		||||
        if (!is_docked) {
 | 
			
		||||
            priority_list.push_back(NPadControllerType::Handheld);
 | 
			
		||||
        }
 | 
			
		||||
        priority_list.push_back(NPadControllerType::ProController);
 | 
			
		||||
        priority_list.push_back(NPadControllerType::JoyLeft);
 | 
			
		||||
        priority_list.push_back(NPadControllerType::JoyRight);
 | 
			
		||||
        priority_list.push_back(NPadControllerType::JoyDual);
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const auto iter = std::find_if(priority_list.begin(), priority_list.end(),
 | 
			
		||||
                                   [this](auto type) { return IsControllerSupported(type); });
 | 
			
		||||
    if (iter == priority_list.end()) {
 | 
			
		||||
        UNIMPLEMENTED_MSG("Could not find supported controller!");
 | 
			
		||||
        return priority;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return *iter;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace Service::HID
 | 
			
		||||
 | 
			
		||||
@ -115,15 +115,19 @@ public:
 | 
			
		||||
    void VibrateController(const std::vector<u32>& controller_ids,
 | 
			
		||||
                           const std::vector<Vibration>& vibrations);
 | 
			
		||||
 | 
			
		||||
    std::shared_ptr<Kernel::ReadableEvent> GetStyleSetChangedEvent(u32 npad_id) const;
 | 
			
		||||
    Vibration GetLastVibration() const;
 | 
			
		||||
 | 
			
		||||
    std::shared_ptr<Kernel::ReadableEvent> GetStyleSetChangedEvent(u32 npad_id) const;
 | 
			
		||||
    void SignalStyleSetChangedEvent(u32 npad_id) const;
 | 
			
		||||
 | 
			
		||||
    // 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 DisconnectNPad(u32 npad_id);
 | 
			
		||||
    void DisconnectNPadAtIndex(std::size_t index);
 | 
			
		||||
 | 
			
		||||
    void SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode);
 | 
			
		||||
    GyroscopeZeroDriftMode GetGyroscopeZeroDriftMode() const;
 | 
			
		||||
    LedPattern GetLedPattern(u32 npad_id);
 | 
			
		||||
@ -315,7 +319,6 @@ private:
 | 
			
		||||
 | 
			
		||||
    void InitNewlyAddedController(std::size_t controller_idx);
 | 
			
		||||
    bool IsControllerSupported(NPadControllerType controller) const;
 | 
			
		||||
    NPadControllerType DecideBestController(NPadControllerType priority) const;
 | 
			
		||||
    void RequestPadStateUpdate(u32 npad_id);
 | 
			
		||||
 | 
			
		||||
    u32 press_state{};
 | 
			
		||||
 | 
			
		||||
@ -9,6 +9,9 @@ add_executable(yuzu
 | 
			
		||||
    about_dialog.cpp
 | 
			
		||||
    about_dialog.h
 | 
			
		||||
    aboutdialog.ui
 | 
			
		||||
    applets/controller.cpp
 | 
			
		||||
    applets/controller.h
 | 
			
		||||
    applets/controller.ui
 | 
			
		||||
    applets/error.cpp
 | 
			
		||||
    applets/error.h
 | 
			
		||||
    applets/profile_select.cpp
 | 
			
		||||
@ -62,12 +65,15 @@ add_executable(yuzu
 | 
			
		||||
    configuration/configure_input.cpp
 | 
			
		||||
    configuration/configure_input.h
 | 
			
		||||
    configuration/configure_input.ui
 | 
			
		||||
    configuration/configure_input_player.cpp
 | 
			
		||||
    configuration/configure_input_player.h
 | 
			
		||||
    configuration/configure_input_player.ui
 | 
			
		||||
    configuration/configure_input_advanced.cpp
 | 
			
		||||
    configuration/configure_input_advanced.h
 | 
			
		||||
    configuration/configure_input_advanced.ui
 | 
			
		||||
    configuration/configure_input_dialog.cpp
 | 
			
		||||
    configuration/configure_input_dialog.h
 | 
			
		||||
    configuration/configure_input_dialog.ui
 | 
			
		||||
    configuration/configure_input_player.cpp
 | 
			
		||||
    configuration/configure_input_player.h
 | 
			
		||||
    configuration/configure_input_player.ui
 | 
			
		||||
    configuration/configure_motion_touch.cpp
 | 
			
		||||
    configuration/configure_motion_touch.h
 | 
			
		||||
    configuration/configure_motion_touch.ui
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										601
									
								
								src/yuzu/applets/controller.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,601 @@
 | 
			
		||||
// Copyright 2020 yuzu Emulator Project
 | 
			
		||||
// Licensed under GPLv2 or any later version
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
 | 
			
		||||
#include "common/assert.h"
 | 
			
		||||
#include "common/string_util.h"
 | 
			
		||||
#include "core/core.h"
 | 
			
		||||
#include "core/hle/lock.h"
 | 
			
		||||
#include "core/hle/service/hid/controllers/npad.h"
 | 
			
		||||
#include "core/hle/service/hid/hid.h"
 | 
			
		||||
#include "core/hle/service/sm/sm.h"
 | 
			
		||||
#include "ui_controller.h"
 | 
			
		||||
#include "yuzu/applets/controller.h"
 | 
			
		||||
#include "yuzu/configuration/configure_input_dialog.h"
 | 
			
		||||
#include "yuzu/main.h"
 | 
			
		||||
 | 
			
		||||
namespace {
 | 
			
		||||
 | 
			
		||||
constexpr std::array<std::array<bool, 4>, 8> led_patterns = {{
 | 
			
		||||
    {1, 0, 0, 0},
 | 
			
		||||
    {1, 1, 0, 0},
 | 
			
		||||
    {1, 1, 1, 0},
 | 
			
		||||
    {1, 1, 1, 1},
 | 
			
		||||
    {1, 0, 0, 1},
 | 
			
		||||
    {1, 0, 1, 0},
 | 
			
		||||
    {1, 0, 1, 1},
 | 
			
		||||
    {0, 1, 1, 0},
 | 
			
		||||
}};
 | 
			
		||||
 | 
			
		||||
void UpdateController(Settings::ControllerType controller_type, std::size_t npad_index,
 | 
			
		||||
                      bool connected) {
 | 
			
		||||
    Core::System& system{Core::System::GetInstance()};
 | 
			
		||||
 | 
			
		||||
    if (!system.IsPoweredOn()) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Service::SM::ServiceManager& sm = system.ServiceManager();
 | 
			
		||||
 | 
			
		||||
    auto& npad =
 | 
			
		||||
        sm.GetService<Service::HID::Hid>("hid")
 | 
			
		||||
            ->GetAppletResource()
 | 
			
		||||
            ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad);
 | 
			
		||||
 | 
			
		||||
    npad.UpdateControllerAt(npad.MapSettingsTypeToNPad(controller_type), npad_index, connected);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Returns true if the given controller type is compatible with the given parameters.
 | 
			
		||||
bool IsControllerCompatible(Settings::ControllerType controller_type,
 | 
			
		||||
                            Core::Frontend::ControllerParameters parameters) {
 | 
			
		||||
    switch (controller_type) {
 | 
			
		||||
    case Settings::ControllerType::ProController:
 | 
			
		||||
        return parameters.allow_pro_controller;
 | 
			
		||||
    case Settings::ControllerType::DualJoyconDetached:
 | 
			
		||||
        return parameters.allow_dual_joycons;
 | 
			
		||||
    case Settings::ControllerType::LeftJoycon:
 | 
			
		||||
        return parameters.allow_left_joycon;
 | 
			
		||||
    case Settings::ControllerType::RightJoycon:
 | 
			
		||||
        return parameters.allow_right_joycon;
 | 
			
		||||
    case Settings::ControllerType::Handheld:
 | 
			
		||||
        return parameters.enable_single_mode && parameters.allow_handheld;
 | 
			
		||||
    default:
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Maps the controller type combobox index to Controller Type enum
 | 
			
		||||
constexpr Settings::ControllerType GetControllerTypeFromIndex(int index) {
 | 
			
		||||
    switch (index) {
 | 
			
		||||
    case 0:
 | 
			
		||||
    default:
 | 
			
		||||
        return Settings::ControllerType::ProController;
 | 
			
		||||
    case 1:
 | 
			
		||||
        return Settings::ControllerType::DualJoyconDetached;
 | 
			
		||||
    case 2:
 | 
			
		||||
        return Settings::ControllerType::LeftJoycon;
 | 
			
		||||
    case 3:
 | 
			
		||||
        return Settings::ControllerType::RightJoycon;
 | 
			
		||||
    case 4:
 | 
			
		||||
        return Settings::ControllerType::Handheld;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Maps the Controller Type enum to controller type combobox index
 | 
			
		||||
constexpr int GetIndexFromControllerType(Settings::ControllerType type) {
 | 
			
		||||
    switch (type) {
 | 
			
		||||
    case Settings::ControllerType::ProController:
 | 
			
		||||
    default:
 | 
			
		||||
        return 0;
 | 
			
		||||
    case Settings::ControllerType::DualJoyconDetached:
 | 
			
		||||
        return 1;
 | 
			
		||||
    case Settings::ControllerType::LeftJoycon:
 | 
			
		||||
        return 2;
 | 
			
		||||
    case Settings::ControllerType::RightJoycon:
 | 
			
		||||
        return 3;
 | 
			
		||||
    case Settings::ControllerType::Handheld:
 | 
			
		||||
        return 4;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace
 | 
			
		||||
 | 
			
		||||
QtControllerSelectorDialog::QtControllerSelectorDialog(
 | 
			
		||||
    QWidget* parent, Core::Frontend::ControllerParameters parameters_,
 | 
			
		||||
    InputCommon::InputSubsystem* input_subsystem_)
 | 
			
		||||
    : QDialog(parent), ui(std::make_unique<Ui::QtControllerSelectorDialog>()),
 | 
			
		||||
      parameters(std::move(parameters_)), input_subsystem(input_subsystem_) {
 | 
			
		||||
    ui->setupUi(this);
 | 
			
		||||
 | 
			
		||||
    player_widgets = {
 | 
			
		||||
        ui->widgetPlayer1, ui->widgetPlayer2, ui->widgetPlayer3, ui->widgetPlayer4,
 | 
			
		||||
        ui->widgetPlayer5, ui->widgetPlayer6, ui->widgetPlayer7, ui->widgetPlayer8,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    player_groupboxes = {
 | 
			
		||||
        ui->groupPlayer1Connected, ui->groupPlayer2Connected, ui->groupPlayer3Connected,
 | 
			
		||||
        ui->groupPlayer4Connected, ui->groupPlayer5Connected, ui->groupPlayer6Connected,
 | 
			
		||||
        ui->groupPlayer7Connected, ui->groupPlayer8Connected,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    connected_controller_icons = {
 | 
			
		||||
        ui->controllerPlayer1, ui->controllerPlayer2, ui->controllerPlayer3, ui->controllerPlayer4,
 | 
			
		||||
        ui->controllerPlayer5, ui->controllerPlayer6, ui->controllerPlayer7, ui->controllerPlayer8,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    led_patterns_boxes = {{
 | 
			
		||||
        {ui->checkboxPlayer1LED1, ui->checkboxPlayer1LED2, ui->checkboxPlayer1LED3,
 | 
			
		||||
         ui->checkboxPlayer1LED4},
 | 
			
		||||
        {ui->checkboxPlayer2LED1, ui->checkboxPlayer2LED2, ui->checkboxPlayer2LED3,
 | 
			
		||||
         ui->checkboxPlayer2LED4},
 | 
			
		||||
        {ui->checkboxPlayer3LED1, ui->checkboxPlayer3LED2, ui->checkboxPlayer3LED3,
 | 
			
		||||
         ui->checkboxPlayer3LED4},
 | 
			
		||||
        {ui->checkboxPlayer4LED1, ui->checkboxPlayer4LED2, ui->checkboxPlayer4LED3,
 | 
			
		||||
         ui->checkboxPlayer4LED4},
 | 
			
		||||
        {ui->checkboxPlayer5LED1, ui->checkboxPlayer5LED2, ui->checkboxPlayer5LED3,
 | 
			
		||||
         ui->checkboxPlayer5LED4},
 | 
			
		||||
        {ui->checkboxPlayer6LED1, ui->checkboxPlayer6LED2, ui->checkboxPlayer6LED3,
 | 
			
		||||
         ui->checkboxPlayer6LED4},
 | 
			
		||||
        {ui->checkboxPlayer7LED1, ui->checkboxPlayer7LED2, ui->checkboxPlayer7LED3,
 | 
			
		||||
         ui->checkboxPlayer7LED4},
 | 
			
		||||
        {ui->checkboxPlayer8LED1, ui->checkboxPlayer8LED2, ui->checkboxPlayer8LED3,
 | 
			
		||||
         ui->checkboxPlayer8LED4},
 | 
			
		||||
    }};
 | 
			
		||||
 | 
			
		||||
    explain_text_labels = {
 | 
			
		||||
        ui->labelPlayer1Explain, ui->labelPlayer2Explain, ui->labelPlayer3Explain,
 | 
			
		||||
        ui->labelPlayer4Explain, ui->labelPlayer5Explain, ui->labelPlayer6Explain,
 | 
			
		||||
        ui->labelPlayer7Explain, ui->labelPlayer8Explain,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    emulated_controllers = {
 | 
			
		||||
        ui->comboPlayer1Emulated, ui->comboPlayer2Emulated, ui->comboPlayer3Emulated,
 | 
			
		||||
        ui->comboPlayer4Emulated, ui->comboPlayer5Emulated, ui->comboPlayer6Emulated,
 | 
			
		||||
        ui->comboPlayer7Emulated, ui->comboPlayer8Emulated,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    player_labels = {
 | 
			
		||||
        ui->labelPlayer1, ui->labelPlayer2, ui->labelPlayer3, ui->labelPlayer4,
 | 
			
		||||
        ui->labelPlayer5, ui->labelPlayer6, ui->labelPlayer7, ui->labelPlayer8,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    connected_controller_labels = {
 | 
			
		||||
        ui->labelConnectedPlayer1, ui->labelConnectedPlayer2, ui->labelConnectedPlayer3,
 | 
			
		||||
        ui->labelConnectedPlayer4, ui->labelConnectedPlayer5, ui->labelConnectedPlayer6,
 | 
			
		||||
        ui->labelConnectedPlayer7, ui->labelConnectedPlayer8,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    connected_controller_checkboxes = {
 | 
			
		||||
        ui->checkboxPlayer1Connected, ui->checkboxPlayer2Connected, ui->checkboxPlayer3Connected,
 | 
			
		||||
        ui->checkboxPlayer4Connected, ui->checkboxPlayer5Connected, ui->checkboxPlayer6Connected,
 | 
			
		||||
        ui->checkboxPlayer7Connected, ui->checkboxPlayer8Connected,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // Setup/load everything prior to setting up connections.
 | 
			
		||||
    // This avoids unintentionally changing the states of elements while loading them in.
 | 
			
		||||
    SetSupportedControllers();
 | 
			
		||||
    DisableUnsupportedPlayers();
 | 
			
		||||
    LoadConfiguration();
 | 
			
		||||
 | 
			
		||||
    for (std::size_t i = 0; i < NUM_PLAYERS; ++i) {
 | 
			
		||||
        SetExplainText(i);
 | 
			
		||||
        UpdateControllerIcon(i);
 | 
			
		||||
        UpdateLEDPattern(i);
 | 
			
		||||
        UpdateBorderColor(i);
 | 
			
		||||
 | 
			
		||||
        connect(player_groupboxes[i], &QGroupBox::toggled, [this, i](bool checked) {
 | 
			
		||||
            if (checked) {
 | 
			
		||||
                for (std::size_t index = 0; index <= i; ++index) {
 | 
			
		||||
                    connected_controller_checkboxes[index]->setChecked(checked);
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                for (std::size_t index = i; index < NUM_PLAYERS; ++index) {
 | 
			
		||||
                    connected_controller_checkboxes[index]->setChecked(checked);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        connect(emulated_controllers[i], qOverload<int>(&QComboBox::currentIndexChanged),
 | 
			
		||||
                [this, i](int) {
 | 
			
		||||
                    UpdateControllerIcon(i);
 | 
			
		||||
                    UpdateControllerState(i);
 | 
			
		||||
                    UpdateLEDPattern(i);
 | 
			
		||||
                    CheckIfParametersMet();
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
        connect(connected_controller_checkboxes[i], &QCheckBox::stateChanged, [this, i](int state) {
 | 
			
		||||
            player_groupboxes[i]->setChecked(state == Qt::Checked);
 | 
			
		||||
            UpdateControllerIcon(i);
 | 
			
		||||
            UpdateControllerState(i);
 | 
			
		||||
            UpdateLEDPattern(i);
 | 
			
		||||
            UpdateBorderColor(i);
 | 
			
		||||
            CheckIfParametersMet();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        if (i == 0) {
 | 
			
		||||
            connect(emulated_controllers[i], qOverload<int>(&QComboBox::currentIndexChanged),
 | 
			
		||||
                    [this](int index) {
 | 
			
		||||
                        UpdateDockedState(GetControllerTypeFromIndex(index) ==
 | 
			
		||||
                                          Settings::ControllerType::Handheld);
 | 
			
		||||
                    });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    connect(ui->inputConfigButton, &QPushButton::clicked, this,
 | 
			
		||||
            &QtControllerSelectorDialog::CallConfigureInputDialog);
 | 
			
		||||
 | 
			
		||||
    connect(ui->buttonBox, &QDialogButtonBox::accepted, this,
 | 
			
		||||
            &QtControllerSelectorDialog::ApplyConfiguration);
 | 
			
		||||
 | 
			
		||||
    // If keep_controllers_connected is false, forcefully disconnect all controllers
 | 
			
		||||
    if (!parameters.keep_controllers_connected) {
 | 
			
		||||
        for (auto player : player_groupboxes) {
 | 
			
		||||
            player->setChecked(false);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    CheckIfParametersMet();
 | 
			
		||||
 | 
			
		||||
    resize(0, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QtControllerSelectorDialog::~QtControllerSelectorDialog() = default;
 | 
			
		||||
 | 
			
		||||
void QtControllerSelectorDialog::ApplyConfiguration() {
 | 
			
		||||
    // Update the controller state once more, just to be sure they are properly applied.
 | 
			
		||||
    for (std::size_t index = 0; index < NUM_PLAYERS; ++index) {
 | 
			
		||||
        UpdateControllerState(index);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const bool pre_docked_mode = Settings::values.use_docked_mode;
 | 
			
		||||
    Settings::values.use_docked_mode = ui->radioDocked->isChecked();
 | 
			
		||||
    OnDockedModeChanged(pre_docked_mode, Settings::values.use_docked_mode);
 | 
			
		||||
 | 
			
		||||
    Settings::values.vibration_enabled = ui->vibrationGroup->isChecked();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void QtControllerSelectorDialog::LoadConfiguration() {
 | 
			
		||||
    for (std::size_t index = 0; index < NUM_PLAYERS; ++index) {
 | 
			
		||||
        const auto connected = Settings::values.players[index].connected ||
 | 
			
		||||
                               (index == 0 && Settings::values.players[8].connected);
 | 
			
		||||
        player_groupboxes[index]->setChecked(connected);
 | 
			
		||||
        connected_controller_checkboxes[index]->setChecked(connected);
 | 
			
		||||
        emulated_controllers[index]->setCurrentIndex(
 | 
			
		||||
            GetIndexFromControllerType(Settings::values.players[index].controller_type));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    UpdateDockedState(Settings::values.players[8].connected);
 | 
			
		||||
 | 
			
		||||
    ui->vibrationGroup->setChecked(Settings::values.vibration_enabled);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void QtControllerSelectorDialog::CallConfigureInputDialog() {
 | 
			
		||||
    const auto max_supported_players = parameters.enable_single_mode ? 1 : parameters.max_players;
 | 
			
		||||
 | 
			
		||||
    ConfigureInputDialog dialog(this, max_supported_players, input_subsystem);
 | 
			
		||||
 | 
			
		||||
    dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
 | 
			
		||||
                          Qt::WindowSystemMenuHint);
 | 
			
		||||
    dialog.setWindowModality(Qt::WindowModal);
 | 
			
		||||
    dialog.exec();
 | 
			
		||||
 | 
			
		||||
    dialog.ApplyConfiguration();
 | 
			
		||||
 | 
			
		||||
    LoadConfiguration();
 | 
			
		||||
    CheckIfParametersMet();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void QtControllerSelectorDialog::CheckIfParametersMet() {
 | 
			
		||||
    // Here, we check and validate the current configuration against all applicable parameters.
 | 
			
		||||
    const auto num_connected_players = static_cast<int>(
 | 
			
		||||
        std::count_if(player_groupboxes.begin(), player_groupboxes.end(),
 | 
			
		||||
                      [this](const QGroupBox* player) { return player->isChecked(); }));
 | 
			
		||||
 | 
			
		||||
    const auto min_supported_players = parameters.enable_single_mode ? 1 : parameters.min_players;
 | 
			
		||||
    const auto max_supported_players = parameters.enable_single_mode ? 1 : parameters.max_players;
 | 
			
		||||
 | 
			
		||||
    // First, check against the number of connected players.
 | 
			
		||||
    if (num_connected_players < min_supported_players ||
 | 
			
		||||
        num_connected_players > max_supported_players) {
 | 
			
		||||
        parameters_met = false;
 | 
			
		||||
        ui->buttonBox->setEnabled(parameters_met);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Next, check against all connected controllers.
 | 
			
		||||
    const auto all_controllers_compatible = [this] {
 | 
			
		||||
        for (std::size_t index = 0; index < NUM_PLAYERS; ++index) {
 | 
			
		||||
            // Skip controllers that are not used, we only care about the currently connected ones.
 | 
			
		||||
            if (!player_groupboxes[index]->isChecked() || !player_groupboxes[index]->isEnabled()) {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            const auto compatible = IsControllerCompatible(
 | 
			
		||||
                GetControllerTypeFromIndex(emulated_controllers[index]->currentIndex()),
 | 
			
		||||
                parameters);
 | 
			
		||||
 | 
			
		||||
            // If any controller is found to be incompatible, return false early.
 | 
			
		||||
            if (!compatible) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Reaching here means all currently connected controllers are compatible.
 | 
			
		||||
        return true;
 | 
			
		||||
    }();
 | 
			
		||||
 | 
			
		||||
    if (!all_controllers_compatible) {
 | 
			
		||||
        parameters_met = false;
 | 
			
		||||
        ui->buttonBox->setEnabled(parameters_met);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    parameters_met = true;
 | 
			
		||||
    ui->buttonBox->setEnabled(parameters_met);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void QtControllerSelectorDialog::SetSupportedControllers() {
 | 
			
		||||
    const QString theme = [this] {
 | 
			
		||||
        if (QIcon::themeName().contains(QStringLiteral("dark"))) {
 | 
			
		||||
            return QStringLiteral("_dark");
 | 
			
		||||
        } else if (QIcon::themeName().contains(QStringLiteral("midnight"))) {
 | 
			
		||||
            return QStringLiteral("_midnight");
 | 
			
		||||
        } else {
 | 
			
		||||
            return QString{};
 | 
			
		||||
        }
 | 
			
		||||
    }();
 | 
			
		||||
 | 
			
		||||
    if (parameters.enable_single_mode && parameters.allow_handheld) {
 | 
			
		||||
        ui->controllerSupported1->setStyleSheet(
 | 
			
		||||
            QStringLiteral("image: url(:/controller/applet_handheld%0); ").arg(theme));
 | 
			
		||||
    } else {
 | 
			
		||||
        ui->controllerSupported1->setStyleSheet(
 | 
			
		||||
            QStringLiteral("image: url(:/controller/applet_handheld%0_disabled); ").arg(theme));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (parameters.allow_dual_joycons) {
 | 
			
		||||
        ui->controllerSupported2->setStyleSheet(
 | 
			
		||||
            QStringLiteral("image: url(:/controller/applet_dual_joycon%0); ").arg(theme));
 | 
			
		||||
    } else {
 | 
			
		||||
        ui->controllerSupported2->setStyleSheet(
 | 
			
		||||
            QStringLiteral("image: url(:/controller/applet_dual_joycon%0_disabled); ").arg(theme));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (parameters.allow_left_joycon) {
 | 
			
		||||
        ui->controllerSupported3->setStyleSheet(
 | 
			
		||||
            QStringLiteral("image: url(:/controller/applet_joycon_left%0); ").arg(theme));
 | 
			
		||||
    } else {
 | 
			
		||||
        ui->controllerSupported3->setStyleSheet(
 | 
			
		||||
            QStringLiteral("image: url(:/controller/applet_joycon_left%0_disabled); ").arg(theme));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (parameters.allow_right_joycon) {
 | 
			
		||||
        ui->controllerSupported4->setStyleSheet(
 | 
			
		||||
            QStringLiteral("image: url(:/controller/applet_joycon_right%0); ").arg(theme));
 | 
			
		||||
    } else {
 | 
			
		||||
        ui->controllerSupported4->setStyleSheet(
 | 
			
		||||
            QStringLiteral("image: url(:/controller/applet_joycon_right%0_disabled); ").arg(theme));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (parameters.allow_pro_controller) {
 | 
			
		||||
        ui->controllerSupported5->setStyleSheet(
 | 
			
		||||
            QStringLiteral("image: url(:/controller/applet_pro_controller%0); ").arg(theme));
 | 
			
		||||
    } else {
 | 
			
		||||
        ui->controllerSupported5->setStyleSheet(
 | 
			
		||||
            QStringLiteral("image: url(:/controller/applet_pro_controller%0_disabled); ")
 | 
			
		||||
                .arg(theme));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // enable_single_mode overrides min_players and max_players.
 | 
			
		||||
    if (parameters.enable_single_mode) {
 | 
			
		||||
        ui->numberSupportedLabel->setText(QStringLiteral("1"));
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (parameters.min_players == parameters.max_players) {
 | 
			
		||||
        ui->numberSupportedLabel->setText(QStringLiteral("%1").arg(parameters.max_players));
 | 
			
		||||
    } else {
 | 
			
		||||
        ui->numberSupportedLabel->setText(
 | 
			
		||||
            QStringLiteral("%1 - %2").arg(parameters.min_players).arg(parameters.max_players));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void QtControllerSelectorDialog::UpdateControllerIcon(std::size_t player_index) {
 | 
			
		||||
    if (!player_groupboxes[player_index]->isChecked()) {
 | 
			
		||||
        connected_controller_icons[player_index]->setStyleSheet(QString{});
 | 
			
		||||
        player_labels[player_index]->show();
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const QString stylesheet = [this, player_index] {
 | 
			
		||||
        switch (GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex())) {
 | 
			
		||||
        case Settings::ControllerType::ProController:
 | 
			
		||||
            return QStringLiteral("image: url(:/controller/applet_pro_controller%0); ");
 | 
			
		||||
        case Settings::ControllerType::DualJoyconDetached:
 | 
			
		||||
            return QStringLiteral("image: url(:/controller/applet_dual_joycon%0); ");
 | 
			
		||||
        case Settings::ControllerType::LeftJoycon:
 | 
			
		||||
            return QStringLiteral("image: url(:/controller/applet_joycon_left%0); ");
 | 
			
		||||
        case Settings::ControllerType::RightJoycon:
 | 
			
		||||
            return QStringLiteral("image: url(:/controller/applet_joycon_right%0); ");
 | 
			
		||||
        case Settings::ControllerType::Handheld:
 | 
			
		||||
            return QStringLiteral("image: url(:/controller/applet_handheld%0); ");
 | 
			
		||||
        default:
 | 
			
		||||
            return QString{};
 | 
			
		||||
        }
 | 
			
		||||
    }();
 | 
			
		||||
 | 
			
		||||
    const QString theme = [this] {
 | 
			
		||||
        if (QIcon::themeName().contains(QStringLiteral("dark"))) {
 | 
			
		||||
            return QStringLiteral("_dark");
 | 
			
		||||
        } else if (QIcon::themeName().contains(QStringLiteral("midnight"))) {
 | 
			
		||||
            return QStringLiteral("_midnight");
 | 
			
		||||
        } else {
 | 
			
		||||
            return QString{};
 | 
			
		||||
        }
 | 
			
		||||
    }();
 | 
			
		||||
 | 
			
		||||
    connected_controller_icons[player_index]->setStyleSheet(stylesheet.arg(theme));
 | 
			
		||||
    player_labels[player_index]->hide();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void QtControllerSelectorDialog::UpdateControllerState(std::size_t player_index) {
 | 
			
		||||
    auto& player = Settings::values.players[player_index];
 | 
			
		||||
 | 
			
		||||
    player.controller_type =
 | 
			
		||||
        GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex());
 | 
			
		||||
    player.connected = player_groupboxes[player_index]->isChecked();
 | 
			
		||||
 | 
			
		||||
    // Player 2-8
 | 
			
		||||
    if (player_index != 0) {
 | 
			
		||||
        UpdateController(player.controller_type, player_index, player.connected);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Player 1 and Handheld
 | 
			
		||||
    auto& handheld = Settings::values.players[8];
 | 
			
		||||
    // If Handheld is selected, copy all the settings from Player 1 to Handheld.
 | 
			
		||||
    if (player.controller_type == Settings::ControllerType::Handheld) {
 | 
			
		||||
        handheld = player;
 | 
			
		||||
        handheld.connected = player_groupboxes[player_index]->isChecked();
 | 
			
		||||
        player.connected = false; // Disconnect Player 1
 | 
			
		||||
    } else {
 | 
			
		||||
        player.connected = player_groupboxes[player_index]->isChecked();
 | 
			
		||||
        handheld.connected = false; // Disconnect Handheld
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    UpdateController(player.controller_type, player_index, player.connected);
 | 
			
		||||
    UpdateController(Settings::ControllerType::Handheld, 8, handheld.connected);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void QtControllerSelectorDialog::UpdateLEDPattern(std::size_t player_index) {
 | 
			
		||||
    if (!player_groupboxes[player_index]->isChecked() ||
 | 
			
		||||
        GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex()) ==
 | 
			
		||||
            Settings::ControllerType::Handheld) {
 | 
			
		||||
        led_patterns_boxes[player_index][0]->setChecked(false);
 | 
			
		||||
        led_patterns_boxes[player_index][1]->setChecked(false);
 | 
			
		||||
        led_patterns_boxes[player_index][2]->setChecked(false);
 | 
			
		||||
        led_patterns_boxes[player_index][3]->setChecked(false);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    led_patterns_boxes[player_index][0]->setChecked(led_patterns[player_index][0]);
 | 
			
		||||
    led_patterns_boxes[player_index][1]->setChecked(led_patterns[player_index][1]);
 | 
			
		||||
    led_patterns_boxes[player_index][2]->setChecked(led_patterns[player_index][2]);
 | 
			
		||||
    led_patterns_boxes[player_index][3]->setChecked(led_patterns[player_index][3]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void QtControllerSelectorDialog::UpdateBorderColor(std::size_t player_index) {
 | 
			
		||||
    if (!parameters.enable_border_color ||
 | 
			
		||||
        player_index >= static_cast<std::size_t>(parameters.max_players) ||
 | 
			
		||||
        player_groupboxes[player_index]->styleSheet().contains(QStringLiteral("QGroupBox"))) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    player_groupboxes[player_index]->setStyleSheet(
 | 
			
		||||
        player_groupboxes[player_index]->styleSheet().append(
 | 
			
		||||
            QStringLiteral("QGroupBox#groupPlayer%1Connected:checked "
 | 
			
		||||
                           "{ border: 1px solid rgba(%2, %3, %4, %5); }")
 | 
			
		||||
                .arg(player_index + 1)
 | 
			
		||||
                .arg(parameters.border_colors[player_index][0])
 | 
			
		||||
                .arg(parameters.border_colors[player_index][1])
 | 
			
		||||
                .arg(parameters.border_colors[player_index][2])
 | 
			
		||||
                .arg(parameters.border_colors[player_index][3])));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void QtControllerSelectorDialog::SetExplainText(std::size_t player_index) {
 | 
			
		||||
    if (!parameters.enable_explain_text ||
 | 
			
		||||
        player_index >= static_cast<std::size_t>(parameters.max_players)) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    explain_text_labels[player_index]->setText(QString::fromStdString(
 | 
			
		||||
        Common::StringFromFixedZeroTerminatedBuffer(parameters.explain_text[player_index].data(),
 | 
			
		||||
                                                    parameters.explain_text[player_index].size())));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void QtControllerSelectorDialog::UpdateDockedState(bool is_handheld) {
 | 
			
		||||
    // Disallow changing the console mode if the controller type is handheld.
 | 
			
		||||
    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);
 | 
			
		||||
 | 
			
		||||
    // Also force into undocked mode if the controller type is handheld.
 | 
			
		||||
    if (is_handheld) {
 | 
			
		||||
        ui->radioUndocked->setChecked(true);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void QtControllerSelectorDialog::DisableUnsupportedPlayers() {
 | 
			
		||||
    const auto max_supported_players = parameters.enable_single_mode ? 1 : parameters.max_players;
 | 
			
		||||
 | 
			
		||||
    switch (max_supported_players) {
 | 
			
		||||
    case 0:
 | 
			
		||||
    default:
 | 
			
		||||
        UNREACHABLE();
 | 
			
		||||
        return;
 | 
			
		||||
    case 1:
 | 
			
		||||
        ui->widgetSpacer->hide();
 | 
			
		||||
        ui->widgetSpacer2->hide();
 | 
			
		||||
        ui->widgetSpacer3->hide();
 | 
			
		||||
        ui->widgetSpacer4->hide();
 | 
			
		||||
        break;
 | 
			
		||||
    case 2:
 | 
			
		||||
        ui->widgetSpacer->hide();
 | 
			
		||||
        ui->widgetSpacer2->hide();
 | 
			
		||||
        ui->widgetSpacer3->hide();
 | 
			
		||||
        break;
 | 
			
		||||
    case 3:
 | 
			
		||||
        ui->widgetSpacer->hide();
 | 
			
		||||
        ui->widgetSpacer2->hide();
 | 
			
		||||
        break;
 | 
			
		||||
    case 4:
 | 
			
		||||
        ui->widgetSpacer->hide();
 | 
			
		||||
        break;
 | 
			
		||||
    case 5:
 | 
			
		||||
    case 6:
 | 
			
		||||
    case 7:
 | 
			
		||||
    case 8:
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (std::size_t index = max_supported_players; index < NUM_PLAYERS; ++index) {
 | 
			
		||||
        // Disconnect any unsupported players here and disable or hide them if applicable.
 | 
			
		||||
        Settings::values.players[index].connected = false;
 | 
			
		||||
        UpdateController(Settings::values.players[index].controller_type, index, false);
 | 
			
		||||
        // Hide the player widgets when max_supported_controllers is less than or equal to 4.
 | 
			
		||||
        if (max_supported_players <= 4) {
 | 
			
		||||
            player_widgets[index]->hide();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Disable and hide the following to prevent these from interaction.
 | 
			
		||||
        player_widgets[index]->setDisabled(true);
 | 
			
		||||
        connected_controller_checkboxes[index]->setDisabled(true);
 | 
			
		||||
        connected_controller_labels[index]->hide();
 | 
			
		||||
        connected_controller_checkboxes[index]->hide();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QtControllerSelector::QtControllerSelector(GMainWindow& parent) {
 | 
			
		||||
    connect(this, &QtControllerSelector::MainWindowReconfigureControllers, &parent,
 | 
			
		||||
            &GMainWindow::ControllerSelectorReconfigureControllers, Qt::QueuedConnection);
 | 
			
		||||
    connect(&parent, &GMainWindow::ControllerSelectorReconfigureFinished, this,
 | 
			
		||||
            &QtControllerSelector::MainWindowReconfigureFinished, Qt::QueuedConnection);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
QtControllerSelector::~QtControllerSelector() = default;
 | 
			
		||||
 | 
			
		||||
void QtControllerSelector::ReconfigureControllers(
 | 
			
		||||
    std::function<void()> callback, Core::Frontend::ControllerParameters parameters) const {
 | 
			
		||||
    this->callback = std::move(callback);
 | 
			
		||||
    emit MainWindowReconfigureControllers(parameters);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void QtControllerSelector::MainWindowReconfigureFinished() {
 | 
			
		||||
    // Acquire the HLE mutex
 | 
			
		||||
    std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
 | 
			
		||||
    callback();
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										133
									
								
								src/yuzu/applets/controller.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,133 @@
 | 
			
		||||
// 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 <QDialog>
 | 
			
		||||
#include "core/frontend/applets/controller.h"
 | 
			
		||||
 | 
			
		||||
class GMainWindow;
 | 
			
		||||
class QCheckBox;
 | 
			
		||||
class QComboBox;
 | 
			
		||||
class QDialogButtonBox;
 | 
			
		||||
class QGroupBox;
 | 
			
		||||
class QLabel;
 | 
			
		||||
 | 
			
		||||
namespace InputCommon {
 | 
			
		||||
class InputSubsystem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace Ui {
 | 
			
		||||
class QtControllerSelectorDialog;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class QtControllerSelectorDialog final : public QDialog {
 | 
			
		||||
    Q_OBJECT
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    explicit QtControllerSelectorDialog(QWidget* parent,
 | 
			
		||||
                                        Core::Frontend::ControllerParameters parameters_,
 | 
			
		||||
                                        InputCommon::InputSubsystem* input_subsystem_);
 | 
			
		||||
    ~QtControllerSelectorDialog() override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    // Applies the current configuration.
 | 
			
		||||
    void ApplyConfiguration();
 | 
			
		||||
 | 
			
		||||
    // Loads the current input configuration into the frontend applet.
 | 
			
		||||
    void LoadConfiguration();
 | 
			
		||||
 | 
			
		||||
    // Initializes the "Configure Input" Dialog.
 | 
			
		||||
    void CallConfigureInputDialog();
 | 
			
		||||
 | 
			
		||||
    // Checks the current configuration against the given parameters and
 | 
			
		||||
    // sets the value of parameters_met.
 | 
			
		||||
    void CheckIfParametersMet();
 | 
			
		||||
 | 
			
		||||
    // Sets the controller icons for "Supported Controller Types".
 | 
			
		||||
    void SetSupportedControllers();
 | 
			
		||||
 | 
			
		||||
    // Updates the controller icons per player.
 | 
			
		||||
    void UpdateControllerIcon(std::size_t player_index);
 | 
			
		||||
 | 
			
		||||
    // Updates the controller state (type and connection status) per player.
 | 
			
		||||
    void UpdateControllerState(std::size_t player_index);
 | 
			
		||||
 | 
			
		||||
    // Updates the LED pattern per player.
 | 
			
		||||
    void UpdateLEDPattern(std::size_t player_index);
 | 
			
		||||
 | 
			
		||||
    // Updates the border color per player.
 | 
			
		||||
    void UpdateBorderColor(std::size_t player_index);
 | 
			
		||||
 | 
			
		||||
    // Sets the "Explain Text" per player.
 | 
			
		||||
    void SetExplainText(std::size_t player_index);
 | 
			
		||||
 | 
			
		||||
    // Updates the console mode.
 | 
			
		||||
    void UpdateDockedState(bool is_handheld);
 | 
			
		||||
 | 
			
		||||
    // Disables and disconnects unsupported players based on the given parameters.
 | 
			
		||||
    void DisableUnsupportedPlayers();
 | 
			
		||||
 | 
			
		||||
    std::unique_ptr<Ui::QtControllerSelectorDialog> ui;
 | 
			
		||||
 | 
			
		||||
    // Parameters sent in from the backend HLE applet.
 | 
			
		||||
    Core::Frontend::ControllerParameters parameters;
 | 
			
		||||
 | 
			
		||||
    InputCommon::InputSubsystem* input_subsystem;
 | 
			
		||||
 | 
			
		||||
    // This is true if and only if all parameters are met. Otherwise, this is false.
 | 
			
		||||
    // This determines whether the "OK" button can be clicked to exit the applet.
 | 
			
		||||
    bool parameters_met{false};
 | 
			
		||||
 | 
			
		||||
    static constexpr std::size_t NUM_PLAYERS = 8;
 | 
			
		||||
 | 
			
		||||
    // Widgets encapsulating the groupboxes and comboboxes per player.
 | 
			
		||||
    std::array<QWidget*, NUM_PLAYERS> player_widgets;
 | 
			
		||||
 | 
			
		||||
    // Groupboxes encapsulating the controller icons and LED patterns per player.
 | 
			
		||||
    std::array<QGroupBox*, NUM_PLAYERS> player_groupboxes;
 | 
			
		||||
 | 
			
		||||
    // Icons for currently connected controllers/players.
 | 
			
		||||
    std::array<QWidget*, NUM_PLAYERS> connected_controller_icons;
 | 
			
		||||
 | 
			
		||||
    // Labels that represent the player numbers in place of the controller icons.
 | 
			
		||||
    std::array<QLabel*, NUM_PLAYERS> player_labels;
 | 
			
		||||
 | 
			
		||||
    // LED patterns for currently connected controllers/players.
 | 
			
		||||
    std::array<std::array<QCheckBox*, 4>, NUM_PLAYERS> led_patterns_boxes;
 | 
			
		||||
 | 
			
		||||
    // Labels representing additional information known as "Explain Text" per player.
 | 
			
		||||
    std::array<QLabel*, NUM_PLAYERS> explain_text_labels;
 | 
			
		||||
 | 
			
		||||
    // Comboboxes with a list of emulated controllers per player.
 | 
			
		||||
    std::array<QComboBox*, NUM_PLAYERS> emulated_controllers;
 | 
			
		||||
 | 
			
		||||
    // Labels representing the number of connected controllers
 | 
			
		||||
    // above the "Connected Controllers" checkboxes.
 | 
			
		||||
    std::array<QLabel*, NUM_PLAYERS> connected_controller_labels;
 | 
			
		||||
 | 
			
		||||
    // Checkboxes representing the "Connected Controllers".
 | 
			
		||||
    std::array<QCheckBox*, NUM_PLAYERS> connected_controller_checkboxes;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class QtControllerSelector final : public QObject, public Core::Frontend::ControllerApplet {
 | 
			
		||||
    Q_OBJECT
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    explicit QtControllerSelector(GMainWindow& parent);
 | 
			
		||||
    ~QtControllerSelector() override;
 | 
			
		||||
 | 
			
		||||
    void ReconfigureControllers(std::function<void()> callback,
 | 
			
		||||
                                Core::Frontend::ControllerParameters parameters) const override;
 | 
			
		||||
 | 
			
		||||
signals:
 | 
			
		||||
    void MainWindowReconfigureControllers(Core::Frontend::ControllerParameters parameters) const;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void MainWindowReconfigureFinished();
 | 
			
		||||
 | 
			
		||||
    mutable std::function<void()> callback;
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										2672
									
								
								src/yuzu/applets/controller.ui
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -70,7 +70,8 @@ ConfigureInput::ConfigureInput(QWidget* parent)
 | 
			
		||||
 | 
			
		||||
ConfigureInput::~ConfigureInput() = default;
 | 
			
		||||
 | 
			
		||||
void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem) {
 | 
			
		||||
void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem,
 | 
			
		||||
                                std::size_t max_players) {
 | 
			
		||||
    player_controllers = {
 | 
			
		||||
        new ConfigureInputPlayer(this, 0, ui->consoleInputSettings, input_subsystem),
 | 
			
		||||
        new ConfigureInputPlayer(this, 1, ui->consoleInputSettings, input_subsystem),
 | 
			
		||||
@ -93,6 +94,11 @@ void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem) {
 | 
			
		||||
        ui->checkboxPlayer7Connected, ui->checkboxPlayer8Connected,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    std::array<QLabel*, 8> player_connected_labels = {
 | 
			
		||||
        ui->label,   ui->label_3, ui->label_4, ui->label_5,
 | 
			
		||||
        ui->label_6, ui->label_7, ui->label_8, ui->label_9,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    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]);
 | 
			
		||||
@ -112,6 +118,13 @@ void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem) {
 | 
			
		||||
        connect(player_connected[i], &QCheckBox::stateChanged, [this, i](int state) {
 | 
			
		||||
            player_controllers[i]->ConnectPlayer(state == Qt::Checked);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Remove/hide all the elements that exceed max_players, if applicable.
 | 
			
		||||
        if (i >= max_players) {
 | 
			
		||||
            ui->tabWidget->removeTab(static_cast<int>(max_players));
 | 
			
		||||
            player_connected[i]->hide();
 | 
			
		||||
            player_connected_labels[i]->hide();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    // Only the first player can choose handheld mode so connect the signal just to player 1
 | 
			
		||||
    connect(player_controllers[0], &ConfigureInputPlayer::HandheldStateChanged,
 | 
			
		||||
@ -175,8 +188,7 @@ void ConfigureInput::RetranslateUI() {
 | 
			
		||||
 | 
			
		||||
void ConfigureInput::LoadConfiguration() {
 | 
			
		||||
    LoadPlayerControllerIndices();
 | 
			
		||||
    UpdateDockedState(Settings::values.players[0].controller_type ==
 | 
			
		||||
                      Settings::ControllerType::Handheld);
 | 
			
		||||
    UpdateDockedState(Settings::values.players[8].connected);
 | 
			
		||||
 | 
			
		||||
    ui->vibrationGroup->setChecked(Settings::values.vibration_enabled);
 | 
			
		||||
}
 | 
			
		||||
@ -208,14 +220,14 @@ void ConfigureInput::RestoreDefaults() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ConfigureInput::UpdateDockedState(bool is_handheld) {
 | 
			
		||||
    // If the controller type is handheld only, disallow changing docked mode
 | 
			
		||||
    // Disallow changing the console mode if the controller type is handheld.
 | 
			
		||||
    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)
 | 
			
		||||
    // Also force into undocked mode if the controller type is handheld.
 | 
			
		||||
    if (is_handheld) {
 | 
			
		||||
        ui->radioUndocked->setChecked(true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -37,7 +37,7 @@ public:
 | 
			
		||||
    ~ConfigureInput() override;
 | 
			
		||||
 | 
			
		||||
    /// Initializes the input dialog with the given input subsystem.
 | 
			
		||||
    void Initialize(InputCommon::InputSubsystem* input_subsystem_);
 | 
			
		||||
    void Initialize(InputCommon::InputSubsystem* input_subsystem_, std::size_t max_players = 8);
 | 
			
		||||
 | 
			
		||||
    /// Save all button configurations to settings file.
 | 
			
		||||
    void ApplyConfiguration();
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										37
									
								
								src/yuzu/configuration/configure_input_dialog.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,37 @@
 | 
			
		||||
// Copyright 2020 yuzu Emulator Project
 | 
			
		||||
// Licensed under GPLv2 or any later version
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#include "ui_configure_input_dialog.h"
 | 
			
		||||
#include "yuzu/configuration/configure_input_dialog.h"
 | 
			
		||||
 | 
			
		||||
ConfigureInputDialog::ConfigureInputDialog(QWidget* parent, std::size_t max_players,
 | 
			
		||||
                                           InputCommon::InputSubsystem* input_subsystem)
 | 
			
		||||
    : QDialog(parent), ui(std::make_unique<Ui::ConfigureInputDialog>()),
 | 
			
		||||
      input_widget(new ConfigureInput(this)) {
 | 
			
		||||
    ui->setupUi(this);
 | 
			
		||||
 | 
			
		||||
    input_widget->Initialize(input_subsystem, max_players);
 | 
			
		||||
 | 
			
		||||
    ui->inputLayout->addWidget(input_widget);
 | 
			
		||||
 | 
			
		||||
    RetranslateUI();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ConfigureInputDialog::~ConfigureInputDialog() = default;
 | 
			
		||||
 | 
			
		||||
void ConfigureInputDialog::ApplyConfiguration() {
 | 
			
		||||
    input_widget->ApplyConfiguration();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ConfigureInputDialog::changeEvent(QEvent* event) {
 | 
			
		||||
    if (event->type() == QEvent::LanguageChange) {
 | 
			
		||||
        RetranslateUI();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    QDialog::changeEvent(event);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ConfigureInputDialog::RetranslateUI() {
 | 
			
		||||
    ui->retranslateUi(this);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										38
									
								
								src/yuzu/configuration/configure_input_dialog.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,38 @@
 | 
			
		||||
// 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.h"
 | 
			
		||||
 | 
			
		||||
class QPushButton;
 | 
			
		||||
 | 
			
		||||
namespace InputCommon {
 | 
			
		||||
class InputSubsystem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace Ui {
 | 
			
		||||
class ConfigureInputDialog;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class ConfigureInputDialog : public QDialog {
 | 
			
		||||
    Q_OBJECT
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    explicit ConfigureInputDialog(QWidget* parent, std::size_t max_players,
 | 
			
		||||
                                  InputCommon::InputSubsystem* input_subsystem);
 | 
			
		||||
    ~ConfigureInputDialog() override;
 | 
			
		||||
 | 
			
		||||
    void ApplyConfiguration();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void changeEvent(QEvent* event) override;
 | 
			
		||||
    void RetranslateUI();
 | 
			
		||||
 | 
			
		||||
    std::unique_ptr<Ui::ConfigureInputDialog> ui;
 | 
			
		||||
 | 
			
		||||
    ConfigureInput* input_widget;
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										57
									
								
								src/yuzu/configuration/configure_input_dialog.ui
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,57 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<ui version="4.0">
 | 
			
		||||
 <class>ConfigureInputDialog</class>
 | 
			
		||||
 <widget class="QDialog" name="ConfigureInputDialog">
 | 
			
		||||
  <property name="geometry">
 | 
			
		||||
   <rect>
 | 
			
		||||
    <x>0</x>
 | 
			
		||||
    <y>0</y>
 | 
			
		||||
    <width>70</width>
 | 
			
		||||
    <height>540</height>
 | 
			
		||||
   </rect>
 | 
			
		||||
  </property>
 | 
			
		||||
  <property name="windowTitle">
 | 
			
		||||
   <string>Configure Input</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="inputLayout"/>
 | 
			
		||||
   </item>
 | 
			
		||||
   <item>
 | 
			
		||||
    <layout class="QHBoxLayout" name="horizontalLayout">
 | 
			
		||||
     <item>
 | 
			
		||||
      <widget class="QDialogButtonBox" name="buttonBox">
 | 
			
		||||
       <property name="standardButtons">
 | 
			
		||||
        <set>QDialogButtonBox::Ok</set>
 | 
			
		||||
       </property>
 | 
			
		||||
      </widget>
 | 
			
		||||
     </item>
 | 
			
		||||
    </layout>
 | 
			
		||||
   </item>
 | 
			
		||||
  </layout>
 | 
			
		||||
 </widget>
 | 
			
		||||
 <resources/>
 | 
			
		||||
 <connections>
 | 
			
		||||
  <connection>
 | 
			
		||||
   <sender>buttonBox</sender>
 | 
			
		||||
   <signal>accepted()</signal>
 | 
			
		||||
   <receiver>ConfigureInputDialog</receiver>
 | 
			
		||||
   <slot>accept()</slot>
 | 
			
		||||
  </connection>
 | 
			
		||||
 </connections>
 | 
			
		||||
</ui>
 | 
			
		||||
@ -11,6 +11,7 @@
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// VFS includes must be before glad as they will conflict with Windows file api, which uses defines.
 | 
			
		||||
#include "applets/controller.h"
 | 
			
		||||
#include "applets/error.h"
 | 
			
		||||
#include "applets/profile_select.h"
 | 
			
		||||
#include "applets/software_keyboard.h"
 | 
			
		||||
@ -19,7 +20,9 @@
 | 
			
		||||
#include "configuration/configure_per_game.h"
 | 
			
		||||
#include "core/file_sys/vfs.h"
 | 
			
		||||
#include "core/file_sys/vfs_real.h"
 | 
			
		||||
#include "core/frontend/applets/controller.h"
 | 
			
		||||
#include "core/frontend/applets/general_frontend.h"
 | 
			
		||||
#include "core/frontend/applets/software_keyboard.h"
 | 
			
		||||
#include "core/hle/service/acc/profile_manager.h"
 | 
			
		||||
#include "core/hle/service/am/applet_ae.h"
 | 
			
		||||
#include "core/hle/service/am/applet_oe.h"
 | 
			
		||||
@ -84,7 +87,6 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
 | 
			
		||||
#include "core/file_sys/romfs.h"
 | 
			
		||||
#include "core/file_sys/savedata_factory.h"
 | 
			
		||||
#include "core/file_sys/submission_package.h"
 | 
			
		||||
#include "core/frontend/applets/software_keyboard.h"
 | 
			
		||||
#include "core/hle/kernel/process.h"
 | 
			
		||||
#include "core/hle/service/am/am.h"
 | 
			
		||||
#include "core/hle/service/filesystem/filesystem.h"
 | 
			
		||||
@ -283,6 +285,23 @@ GMainWindow::~GMainWindow() {
 | 
			
		||||
        delete render_window;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GMainWindow::ControllerSelectorReconfigureControllers(
 | 
			
		||||
    const Core::Frontend::ControllerParameters& parameters) {
 | 
			
		||||
    QtControllerSelectorDialog dialog(this, parameters, input_subsystem.get());
 | 
			
		||||
    dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
 | 
			
		||||
                          Qt::WindowSystemMenuHint);
 | 
			
		||||
    dialog.setWindowModality(Qt::WindowModal);
 | 
			
		||||
    dialog.exec();
 | 
			
		||||
 | 
			
		||||
    emit ControllerSelectorReconfigureFinished();
 | 
			
		||||
 | 
			
		||||
    // Don't forget to apply settings.
 | 
			
		||||
    Settings::Apply();
 | 
			
		||||
    config->Save();
 | 
			
		||||
 | 
			
		||||
    UpdateStatusButtons();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GMainWindow::ProfileSelectorSelectProfile() {
 | 
			
		||||
    const Service::Account::ProfileManager manager;
 | 
			
		||||
    int index = 0;
 | 
			
		||||
@ -291,10 +310,12 @@ void GMainWindow::ProfileSelectorSelectProfile() {
 | 
			
		||||
        dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
 | 
			
		||||
                              Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint);
 | 
			
		||||
        dialog.setWindowModality(Qt::WindowModal);
 | 
			
		||||
 | 
			
		||||
        if (dialog.exec() == QDialog::Rejected) {
 | 
			
		||||
            emit ProfileSelectorFinishedSelection(std::nullopt);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        index = dialog.GetIndex();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -966,13 +987,14 @@ bool GMainWindow::LoadROM(const QString& filename) {
 | 
			
		||||
    system.SetFilesystem(vfs);
 | 
			
		||||
 | 
			
		||||
    system.SetAppletFrontendSet({
 | 
			
		||||
        nullptr,                                     // Parental Controls
 | 
			
		||||
        std::make_unique<QtErrorDisplay>(*this),     //
 | 
			
		||||
        nullptr,                                     // Photo Viewer
 | 
			
		||||
        std::make_unique<QtProfileSelector>(*this),  //
 | 
			
		||||
        std::make_unique<QtSoftwareKeyboard>(*this), //
 | 
			
		||||
        std::make_unique<QtWebBrowser>(*this),       //
 | 
			
		||||
        nullptr,                                     // E-Commerce
 | 
			
		||||
        std::make_unique<QtControllerSelector>(*this), // Controller Selector
 | 
			
		||||
        nullptr,                                       // E-Commerce
 | 
			
		||||
        std::make_unique<QtErrorDisplay>(*this),       // Error Display
 | 
			
		||||
        nullptr,                                       // Parental Controls
 | 
			
		||||
        nullptr,                                       // Photo Viewer
 | 
			
		||||
        std::make_unique<QtProfileSelector>(*this),    // Profile Selector
 | 
			
		||||
        std::make_unique<QtSoftwareKeyboard>(*this),   // Software Keyboard
 | 
			
		||||
        std::make_unique<QtWebBrowser>(*this),         // Web Browser
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    system.RegisterHostThread();
 | 
			
		||||
@ -2047,6 +2069,7 @@ void GMainWindow::OnStartGame() {
 | 
			
		||||
 | 
			
		||||
    emu_thread->SetRunning(true);
 | 
			
		||||
 | 
			
		||||
    qRegisterMetaType<Core::Frontend::ControllerParameters>("Core::Frontend::ControllerParameters");
 | 
			
		||||
    qRegisterMetaType<Core::Frontend::SoftwareKeyboardParameters>(
 | 
			
		||||
        "Core::Frontend::SoftwareKeyboardParameters");
 | 
			
		||||
    qRegisterMetaType<Core::System::ResultStatus>("Core::System::ResultStatus");
 | 
			
		||||
 | 
			
		||||
@ -37,6 +37,7 @@ enum class InstalledEntryType;
 | 
			
		||||
class GameListPlaceholder;
 | 
			
		||||
 | 
			
		||||
namespace Core::Frontend {
 | 
			
		||||
struct ControllerParameters;
 | 
			
		||||
struct SoftwareKeyboardParameters;
 | 
			
		||||
} // namespace Core::Frontend
 | 
			
		||||
 | 
			
		||||
@ -116,9 +117,12 @@ signals:
 | 
			
		||||
 | 
			
		||||
    void UpdateInstallProgress();
 | 
			
		||||
 | 
			
		||||
    void ControllerSelectorReconfigureFinished();
 | 
			
		||||
 | 
			
		||||
    void ErrorDisplayFinished();
 | 
			
		||||
 | 
			
		||||
    void ProfileSelectorFinishedSelection(std::optional<Common::UUID> uuid);
 | 
			
		||||
 | 
			
		||||
    void SoftwareKeyboardFinishedText(std::optional<std::u16string> text);
 | 
			
		||||
    void SoftwareKeyboardFinishedCheckDialog();
 | 
			
		||||
 | 
			
		||||
@ -127,6 +131,8 @@ signals:
 | 
			
		||||
 | 
			
		||||
public slots:
 | 
			
		||||
    void OnLoadComplete();
 | 
			
		||||
    void ControllerSelectorReconfigureControllers(
 | 
			
		||||
        const Core::Frontend::ControllerParameters& parameters);
 | 
			
		||||
    void ErrorDisplayDisplayError(QString body);
 | 
			
		||||
    void ProfileSelectorSelectProfile();
 | 
			
		||||
    void SoftwareKeyboardGetText(const Core::Frontend::SoftwareKeyboardParameters& parameters);
 | 
			
		||||
 | 
			
		||||