mirror of
https://github.com/PCSX2/pcsx2.git
synced 2026-08-26 07:34:35 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c8c7ac45d1 | ||
|
|
14181ec70d | ||
|
|
b20e5a1e01 | ||
|
|
64d222a1e4 | ||
|
|
e4554fe9ca | ||
|
|
8ec736789c | ||
|
|
9a323a9a8d | ||
|
|
298e626b6e | ||
|
|
af7308e395 | ||
|
|
7c80fcacba | ||
|
|
beb23efa88 | ||
|
|
1b65f5f164 | ||
|
|
bb336f1bc7 | ||
|
|
36d386b451 | ||
|
|
9199f48a3c | ||
|
|
5c88c585a0 | ||
|
|
771b1490d2 | ||
|
|
4bbdbf6332 | ||
|
|
7dc10fbe46 | ||
|
|
90ca83bd96 | ||
|
|
4ee92fc637 | ||
|
|
1d39488061 | ||
|
|
d87cd32ff4 | ||
|
|
2a50ae905d | ||
|
|
f536584d7a | ||
|
|
fa3bd58b7f | ||
|
|
1f5d2c49fc | ||
|
|
3e585c3438 | ||
|
|
c23e792f68 | ||
|
|
02d3c93c2c | ||
|
|
a07ef0f5ee | ||
|
|
e415251f30 | ||
|
|
ddbc143178 | ||
|
|
d54715a9c3 | ||
|
|
eb9507707d | ||
|
|
3377de1fe3 | ||
|
|
b5807e0788 | ||
|
|
c86e82039a | ||
|
|
999b2267c0 | ||
|
|
fbf9585b5a | ||
|
|
470365644f | ||
|
|
7b3847cc5c | ||
|
|
2b0e1a1dec | ||
|
|
316e140329 | ||
|
|
02c4c3b03d | ||
|
|
e5405e191b | ||
|
|
839ea61d55 | ||
|
|
02f27f8cbc | ||
|
|
35b5138593 | ||
|
|
809c5ed051 | ||
|
|
412451f9d6 | ||
|
|
35802f2089 | ||
|
|
8f6f0f8401 | ||
|
|
44d95badc4 | ||
|
|
d622faba17 | ||
|
|
b5945d3d5c | ||
|
|
52cd6fb1dd | ||
|
|
04681babf1 | ||
|
|
e63c068720 | ||
|
|
fb5b465a4e | ||
|
|
59ea3c7949 | ||
|
|
6f5306dbdc | ||
|
|
b5388fdf2f | ||
|
|
d2904c1fd5 | ||
|
|
7718feedd5 | ||
|
|
56add277f9 | ||
|
|
86f772ad38 | ||
|
|
24c99551c7 | ||
|
|
9441d2a33a | ||
|
|
3922091a58 | ||
|
|
1107ce8fd8 | ||
|
|
3d10cd1adf | ||
|
|
02ac3943f2 | ||
|
|
44b672b6f5 | ||
|
|
0239d8350d | ||
|
|
bada5fe941 | ||
|
|
6db871958e | ||
|
|
0b557fe265 | ||
|
|
ce08627396 | ||
|
|
200ec5dcfb | ||
|
|
8a6f55a63e | ||
|
|
e327f5e6f0 | ||
|
|
5849726913 | ||
|
|
e063613a7f | ||
|
|
48d2cb4975 | ||
|
|
59412b1673 | ||
|
|
d1a235272e | ||
|
|
7db9627ff6 | ||
|
|
83550cd153 | ||
|
|
77471bd9d6 | ||
|
|
0e94211ff1 | ||
|
|
f6e7bba354 | ||
|
|
b2255e5b27 | ||
|
|
7b493ff4c8 | ||
|
|
aeef163349 | ||
|
|
26f2352059 | ||
|
|
67e38d8de2 |
@@ -40,8 +40,6 @@
|
||||
'GameDB':
|
||||
- '**/GameIndex.*'
|
||||
'Installer | Package':
|
||||
- 'nsis/*'
|
||||
- 'nsis/**/*'
|
||||
- 'build.sh'
|
||||
|
||||
# Tools / Features
|
||||
|
||||
@@ -37,6 +37,7 @@ allowed_game_fixes = [
|
||||
"VUSyncHack",
|
||||
"VUOverflowHack",
|
||||
"XGKickHack",
|
||||
"BlitInternalFPSHack",
|
||||
]
|
||||
allowed_gs_hw_fixes = [
|
||||
"autoFlush",
|
||||
|
||||
@@ -68,6 +68,7 @@ oprofile_data/
|
||||
/.vscode*
|
||||
|
||||
/bin/**/*.dll
|
||||
/bin/**/*.dmp
|
||||
/bin/**/*.exp
|
||||
/bin/**/*.ilk
|
||||
/bin/**/*.lib
|
||||
|
||||
+524
-386
File diff suppressed because it is too large
Load Diff
@@ -47,10 +47,10 @@
|
||||
03000000c82d00000130000000000000,8BitDo SF30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
|
||||
03000000c82d00000060000000000000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
|
||||
03000000c82d00000061000000000000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
|
||||
03000000102800000900000000000000,8BitDo SFC30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
|
||||
03000000c82d000021ab000000000000,8BitDo SFC30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
|
||||
03000000c82d00003028000000000000,8BitDo SFC30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
|
||||
03000000c82d00000030000000000000,8BitDo SN30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
|
||||
03000000102800000900000000000000,8BitDo SFC30,a:b1,b:b0,back:b10,leftshoulder:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
|
||||
03000000c82d000021ab000000000000,8BitDo SFC30,a:b1,b:b0,back:b10,leftshoulder:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
|
||||
03000000c82d00003028000000000000,8BitDo SFC30,a:b1,b:b0,back:b10,leftshoulder:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
|
||||
03000000c82d00000030000000000000,8BitDo SN30,a:b1,b:b0,back:b10,leftshoulder:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
|
||||
03000000c82d00001290000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
|
||||
03000000c82d000020ab000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
|
||||
03000000c82d00004028000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows,
|
||||
@@ -63,7 +63,7 @@
|
||||
03000000c82d00000260000000000000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
|
||||
03000000c82d00000261000000000000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
|
||||
03000000a00500003232000000000000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows,
|
||||
03000000c82d00001890000000000000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
|
||||
03000000c82d00001890000000000000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows,
|
||||
03000000c82d00003032000000000000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows,
|
||||
030000008f0e00001200000000000000,Acme GA02,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Windows,
|
||||
03000000c01100000355000000000000,Acrux,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
@@ -91,7 +91,7 @@
|
||||
03000000120c0000100e000000000000,Armor 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000490b00004406000000000000,ASCII Seamic Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,
|
||||
03000000869800002500000000000000,Astro C40 TR PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000a30c00002700000000000000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a3,lefty:a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,
|
||||
03000000a30c00002700000000000000,Astro City Mini,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,
|
||||
03000000a30c00002800000000000000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a3,lefty:a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,
|
||||
03000000e4150000103f000000000000,Batarang,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
|
||||
03000000d6200000e557000000000000,Batarang PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
@@ -117,7 +117,7 @@
|
||||
030000006b1400000103000000000000,Bigben PS3 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows,
|
||||
03000000120c0000200e000000000000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000120c0000210e000000000000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000120c0000310c000000000000,Brook Super Converter,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,
|
||||
03000000120c0000310c000000000000,Brook Super Converter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,
|
||||
03000000d81d00000b00000000000000,Buffalo BSGP1601 Series,a:b5,b:b3,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b13,x:b4,y:b2,platform:Windows,
|
||||
030000005b1c00002400000000000000,Capcom Home Arcade Controller,a:b3,b:b4,back:b7,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b6,x:b0,y:b1,platform:Windows,
|
||||
030000005b1c00002500000000000000,Capcom Home Arcade Controller,a:b3,b:b4,back:b7,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b6,x:b0,y:b1,platform:Windows,
|
||||
@@ -178,7 +178,7 @@
|
||||
03000000151900004000000000000000,Flydigi Vader 2,a:b11,b:b10,back:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,leftstick:b1,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b0,righttrigger:b4,rightx:a3,righty:a4,start:b2,x:b9,y:b8,platform:Windows,
|
||||
03000000b40400001124000000000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b4,paddle2:b5,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b2,y:b3,platform:Windows,
|
||||
03000000b40400001224000000000000,Flydigi Vader 2 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b15,paddle2:b16,paddle3:b17,paddle4:b18,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Windows,
|
||||
030000008305000000a0000000000000,G08XU,a:b0,b:b1,back:b4,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b5,x:b2,y:b3,platform:Windows,
|
||||
030000008305000000a0000000000000,G08XU,a:b0,b:b1,back:b4,leftshoulder:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b7,start:b5,x:b2,y:b3,platform:Windows,
|
||||
0300000066f700000100000000000000,Game VIB Joystick,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Windows,
|
||||
03000000260900002625000000000000,GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,lefttrigger:a4,leftx:a0,lefty:a1,righttrigger:a5,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Windows,
|
||||
03000000341a000005f7000000000000,GameCube Controller,a:b2,b:b3,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b1,y:b0,platform:Windows,
|
||||
@@ -186,7 +186,7 @@
|
||||
03000000790000004718000000000000,GameCube Controller,a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows,
|
||||
03000000790000004618000000000000,GameCube Controller Adapter,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows,
|
||||
030000008f0e00000d31000000000000,Gamepad 3 Turbo,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000280400000140000000000000,GamePad Pro,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000280400000140000000000000,GamePad Pro,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,dpdown:+a1,dpleft:-a0,dpright:+a3,dpup:-a4,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000ac0500003d03000000000000,GameSir G3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
|
||||
03000000ac0500005b05000000000000,GameSir G3w,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
|
||||
03000000ac0500002d02000000000000,GameSir G4,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
|
||||
@@ -211,13 +211,11 @@
|
||||
030000004f04000026b3000000000000,GP XID,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
|
||||
0300000079000000d418000000000000,GPD Win,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
|
||||
03000000c6240000025b000000000000,GPX,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
|
||||
030000007d0400000540000000000000,Gravis Eliminator Pro,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
|
||||
030000007d0400000540000000000000,Gravis Eliminator Pro,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
|
||||
030000008f0e00000610000000000000,GreenAsia,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a5,righty:a2,start:b11,x:b3,y:b0,platform:Windows,
|
||||
03000000ac0500006b05000000000000,GT2a,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
|
||||
03000000341a00000302000000000000,Hama Scorpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
030000000d0f00004900000000000000,Hatsune Miku Sho PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
030000000d0f0000a500000000000000,Hori Miku Project Diva X HD PS4 Controller,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,platform:Windows,
|
||||
030000000d0f0000a600000000000000,Hori Miku Project Diva X HD PS4 Controller,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,
|
||||
030000001008000001e1000000000000,Havit HV G60,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b0,platform:Windows,
|
||||
030000000d0f00000c00000000000000,HEXT,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
|
||||
03000000d81400000862000000000000,HitBox Edition Cthulhu,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b4,rightshoulder:b7,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows,
|
||||
@@ -233,7 +231,6 @@
|
||||
030000000d0f00008600000000000000,Hori Fighting Commander Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
|
||||
030000000d0f0000ba00000000000000,Hori Fighting Commander Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
|
||||
030000000d0f00001000000000000000,Hori Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
|
||||
030000000f0d00000010000000000000,Hori Fightstick 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
|
||||
030000000d0f00003200000000000000,Hori Fightstick 3W,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
|
||||
030000000d0f0000c000000000000000,Hori Fightstick 4,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
|
||||
030000000d0f00000d00000000000000,Hori Fightstick EX2,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,
|
||||
@@ -244,6 +241,8 @@
|
||||
030000000d0f00002100000000000000,Hori Fightstick V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
|
||||
030000000d0f00002700000000000000,Hori Fightstick V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
|
||||
030000000d0f0000a000000000000000,Hori Grip TAC4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b13,x:b0,y:b3,platform:Windows,
|
||||
030000000d0f0000a500000000000000,Hori Miku Project Diva X HD PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
|
||||
030000000d0f0000a600000000000000,Hori Miku Project Diva X HD PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
030000000d0f00000101000000000000,Hori Mini Hatsune Miku FT,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
030000000d0f00005400000000000000,Hori Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
030000000d0f00000900000000000000,Hori Pad 3 Turbo,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
@@ -285,7 +284,7 @@
|
||||
030000000d0f00006700000000000000,Horipad One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
|
||||
030000000d0f0000dc00000000000000,Horipad Switch,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
|
||||
030000008f0e00001330000000000000,HuiJia SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b9,x:b3,y:b0,platform:Windows,
|
||||
03000000790000004e95000000000000,Hyperkin N64 Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a5,righty:a2,start:b9,platform:Windows,
|
||||
03000000790000004e95000000000000,Hyperkin N64 Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a5,righty:a2,start:b9,platform:Windows,
|
||||
03000000d81d00000e00000000000000,iBuffalo AC02 Arcade Joystick,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b11,righttrigger:b3,rightx:a2,righty:a5,start:b8,x:b4,y:b5,platform:Windows,
|
||||
03000000d81d00000f00000000000000,iBuffalo BSGP1204 Series,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
|
||||
03000000d81d00001000000000000000,iBuffalo BSGP1204P Series,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
|
||||
@@ -293,9 +292,10 @@
|
||||
03000000696400006964000000000000,iDroidCon Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000b50700001403000000000000,Impact Black,a:b2,b:b3,back:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,
|
||||
030000006f0e00002401000000000000,Injustice Fightstick PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000830500005130000000000000,InterAct ActionPad,a:b0,b:b1,back:b8,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,
|
||||
03000000830500005130000000000000,InterAct ActionPad,a:b0,b:b1,back:b8,leftshoulder:b6,lefttrigger:b7,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,
|
||||
03000000ef0500000300000000000000,InterAct AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Windows,
|
||||
03000000fd0500000230000000000000,InterAct AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a5,start:b11,x:b0,y:b1,platform:Windows,
|
||||
03000000fd0500000030000000000000,Interact GoPad,a:b3,b:b4,x:b0,y:b1,leftshoulder:b6,rightshoulder:b2,leftx:a0,lefty:a1,lefttrigger:b7,righttrigger:b5,platform:Windows,
|
||||
03000000fd0500003902000000000000,InterAct Hammerhead,a:b3,b:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b2,lefttrigger:b8,rightshoulder:b7,rightstick:b5,righttrigger:b9,start:b10,x:b0,y:b1,platform:Windows,
|
||||
03000000fd0500002a26000000000000,InterAct Hammerhead FX,a:b3,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b0,y:b1,platform:Windows,
|
||||
03000000fd0500002f26000000000000,InterAct Hammerhead FX,a:b4,b:b5,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b1,y:b2,platform:Windows,
|
||||
@@ -344,7 +344,6 @@
|
||||
03000000380700008483000000000000,Mad Catz Fightstick TE S PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000380700008134000000000000,Mad Catz Fightstick TE2 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b7,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b4,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000380700008184000000000000,Mad Catz Fightstick TE2 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,leftstick:b10,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
|
||||
78696e70757403000000000000000000,Mad Catz Fightstick TES,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Windows,
|
||||
03000000380700006252000000000000,Mad Catz Micro CTRLR,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000380700008232000000000000,Mad Catz PlayStation Brawlpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000380700008731000000000000,Mad Catz PlayStation Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
@@ -365,11 +364,12 @@
|
||||
0300000079000000d218000000000000,Mayflash Magic NS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
|
||||
03000000d620000010a7000000000000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
030000008f0e00001030000000000000,Mayflash Sega Saturn Adapter,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b5,rightshoulder:b2,righttrigger:b7,start:b9,x:b3,y:b4,platform:Windows,
|
||||
0300000025090000e803000000000000,Mayflash Wii Classic Controller,a:b1,b:b0,back:b8,dpdown:b13,dpleft:b12,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows,
|
||||
03000000790000000018000000000000,Mayflash WiiU Pro Adapter,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
0300000025090000e803000000000000,Mayflash Wii Classic Adapter,a:b1,b:b0,back:b8,dpdown:b13,dpleft:b12,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows,
|
||||
03000000790000000318000000000000,Mayflash Wii DolphinBar,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Windows,
|
||||
03000000790000000018000000000000,Mayflash Wii U Pro Adapter,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000790000002418000000000000,Mega Drive Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,rightshoulder:b2,start:b9,x:b3,y:b4,platform:Windows,
|
||||
0300000079000000ae18000000000000,Mega Drive Controller,a:b0,b:b1,back:b7,dpdown:b14,dpleft:b15,dpright:b13,dpup:b2,rightshoulder:b6,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,
|
||||
03000000c0160000990a000000000000,Mega Drive Controller,a:b0,b:b1,leftx:a0,lefty:a1,righttrigger:b2,start:b3,platform:Windows,
|
||||
03000000c0160000990a000000000000,Mega Drive Controller,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,righttrigger:b2,start:b3,platform:Windows,
|
||||
030000005e0400002800000000000000,Microsoft Dual Strike,a:b3,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,rightx:a0,righty:a1~,start:b5,x:b1,y:b0,platform:Windows,
|
||||
030000005e0400000300000000000000,Microsoft SideWinder,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows,
|
||||
030000005e0400000700000000000000,Microsoft SideWinder,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,
|
||||
@@ -389,6 +389,7 @@
|
||||
03000000c62400001b89000000000000,Moga XP5X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
|
||||
03000000efbe0000edfe000000000000,Monect Virtual Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Windows,
|
||||
03000000250900006688000000000000,MP-8866 Super Dual Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
|
||||
03000000091200004488000000000000,MUSIA PlayStation 2 Input Display,a:b0,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b6,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b7,righttrigger:b11,rightx:a2,righty:a3,start:b5,x:b1,y:b3,platform:Windows,
|
||||
03000000f70600000100000000000000,N64 Adaptoid,+rightx:b2,+righty:b1,-rightx:b4,-righty:b5,a:b0,b:b3,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,platform:Windows,
|
||||
030000006b140000010c000000000000,Nacon GC 400ES,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
|
||||
030000006b1400001106000000000000,Nacon Revolution 3 PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
|
||||
@@ -399,9 +400,8 @@
|
||||
0300000038070000efbe000000000000,NEO SE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
|
||||
0300000092120000474e000000000000,NeoGeo X Arcade Stick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b3,y:b2,platform:Windows,
|
||||
03000000921200004b46000000000000,NES 2 port Adapter,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b11,platform:Windows,
|
||||
03000000000f00000100000000000000,NES Controller,a:b1,b:b0,back:b2,leftx:a0,lefty:a1,start:b3,platform:Windows,
|
||||
03000000571d00002100000000000000,NES Controller,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Windows,
|
||||
03000000921200004346000000000000,NES Controller,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Windows,
|
||||
03000000000f00000100000000000000,NES Controller,a:b1,b:b0,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Windows,
|
||||
03000000921200004346000000000000,NES Controller,a:b0,b:b1,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Windows,
|
||||
03000000790000004518000000000000,NEXILUX GameCube Controller Adapter,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows,
|
||||
030000001008000001e5000000000000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Windows,
|
||||
03000000050b00000045000000000000,Nexus,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Windows,
|
||||
@@ -503,7 +503,7 @@
|
||||
03000000222c00000023000000000000,Qanba Obsidian Arcade Stick PS4,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
|
||||
030000008a2400006682000000000000,R1 Mobile Controller,a:b3,b:b1,back:b7,leftx:a0,lefty:a1,start:b6,x:b4,y:b0,platform:Windows,
|
||||
03000000086700006626000000000000,RadioShack,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows,
|
||||
03000000ff1100004733000000000000,Ramox FPS Controller,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,lefttrigger:b6,righttrigger:b7,platform:Windows,
|
||||
03000000ff1100004733000000000000,Ramox FPS Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b0,platform:Windows,
|
||||
030000009b2800002300000000000000,Raphnet 3DO Adapter,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b2,start:b3,platform:Windows,
|
||||
030000009b2800006900000000000000,Raphnet 3DO Adapter,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b2,start:b3,platform:Windows,
|
||||
030000009b2800000800000000000000,Raphnet Dreamcast Adapter,a:b2,b:b1,dpdown:b5,dpleft:b6,dpright:b7,dpup:b4,lefttrigger:a2,leftx:a0,righttrigger:a3,righty:a1,start:b3,x:b10,y:b9,platform:Windows,
|
||||
@@ -511,12 +511,12 @@
|
||||
030000009b2800006000000000000000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows,
|
||||
030000009b2800001800000000000000,Raphnet Jaguar Adapter,a:b2,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b10,start:b3,x:b11,y:b12,platform:Windows,
|
||||
030000009b2800000200000000000000,Raphnet NES Adapter,a:b7,b:b6,back:b5,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,start:b4,platform:Windows,
|
||||
030000009b2800004400000000000000,Raphnet PS1 and PS2 Adapter,a:b1,b:b2,x:b0,y:b3,back:b5,start:b4,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:b12,dpdown:b13,dpleft:b14,dpright:b15,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b8,righttrigger:b9,platform:Windows,
|
||||
030000009b2800004400000000000000,Raphnet PS1 and PS2 Adapter,a:b1,b:b2,back:b5,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b9,rightx:a3,righty:a4,start:b4,x:b0,y:b3,platform:Windows,
|
||||
030000009b2800004300000000000000,Raphnet Saturn,a:b0,b:b1,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows,
|
||||
030000009b2800000500000000000000,Raphnet Saturn Adapter 2.0,a:b1,b:b2,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows,
|
||||
030000009b2800000500000000000000,Raphnet Saturn Adapter 2.0,a:b1,b:b2,leftshoulder:b6,lefttrigger:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows,
|
||||
030000009b2800000300000000000000,Raphnet SNES Adapter,a:b0,b:b4,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows,
|
||||
030000009b2800005600000000000000,Raphnet SNES Adapter,a:b1,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Windows,
|
||||
030000009b2800005700000000000000,Raphnet SNES Adapter,a:b1,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Windows,
|
||||
030000009b2800005600000000000000,Raphnet SNES Adapter,a:b1,b:b4,back:b2,leftshoulder:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Windows,
|
||||
030000009b2800005700000000000000,Raphnet SNES Adapter,a:b1,b:b4,back:b2,leftshoulder:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Windows,
|
||||
030000009b2800001e00000000000000,Raphnet Vectrex Adapter,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a1,lefty:a2,x:b2,y:b3,platform:Windows,
|
||||
030000009b2800002b00000000000000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Windows,
|
||||
030000009b2800002c00000000000000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Windows,
|
||||
@@ -532,12 +532,13 @@
|
||||
03000000321500000910000000000000,Razer Raiju UE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000321500000011000000000000,Razer Raion PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000321500000009000000000000,Razer Serval,+lefty:+a2,-lefty:-a1,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,leftx:a0,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
|
||||
03000000921200004547000000000000,Retro Bit Sega Genesis Controller Adapter,a:b0,b:b1,x:b3,y:b4,start:b6,rightshoulder:b5,dpup:-a1,dpdown:+a1,dpleft:-a0,dpright:+a0,lefttrigger:b7,righttrigger:b2,platform:Windows,
|
||||
03000000790000001100000000000000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000830500006020000000000000,Retro Controller,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b8,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows,
|
||||
03000000bd12000013d0000000000000,Retrolink Sega Saturn Classic Controller,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b5,lefttrigger:b6,rightshoulder:b2,righttrigger:b7,start:b8,x:b3,y:b4,platform:Windows,
|
||||
03000000bd12000015d0000000000000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows,
|
||||
0300000000f000000300000000000000,RetroUSB RetroPad,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows,
|
||||
0300000000f00000f100000000000000,RetroUSB Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows,
|
||||
0300000000f000000300000000000000,RetroUSB RetroPad,a:b1,b:b5,back:b2,leftshoulder:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows,
|
||||
0300000000f00000f100000000000000,RetroUSB Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows,
|
||||
03000000830500000960000000000000,Revenger,a:b0,b:b1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b3,x:b4,y:b5,platform:Windows,
|
||||
030000006b140000010d000000000000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
|
||||
030000006b140000020d000000000000,Revolution Pro Controller 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
|
||||
@@ -579,25 +580,25 @@
|
||||
03000000411200004550000000000000,Sanwa Micro Grip Pro,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a1,righty:a2,start:b9,x:b1,y:b3,platform:Windows,
|
||||
03000000c01100004150000000000000,Sanwa Micro Grip Pro,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows,
|
||||
03000000c01100004450000000000000,Sanwa Online Grip,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b8,rightstick:b11,righttrigger:b9,rightx:a3,righty:a2,start:b14,x:b3,y:b4,platform:Windows,
|
||||
03000000730700000401000000000000,Sanwa PlayOnline Mobile,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Windows,
|
||||
03000000730700000401000000000000,Sanwa PlayOnline Mobile,a:b0,b:b1,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Windows,
|
||||
03000000830500006120000000000000,Sanwa Smart Grip II,a:b0,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,x:b1,y:b3,platform:Windows,
|
||||
03000000c01100000051000000000000,Satechi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows,
|
||||
030000004f04000028b3000000000000,Score A,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000952e00002577000000000000,Scuf PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000a30c00002500000000000000,Sega Genesis Mini 3B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,platform:Windows,
|
||||
03000000a30c00002400000000000000,Sega Mega Drive Mini 6B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows,
|
||||
0300000000050000289b000000000000,Sega Saturn Adapter,a:b1,b:b2,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows,
|
||||
0300000000f000000800000000000000,Sega Saturn Controller,a:b1,b:b2,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b3,start:b0,x:b5,y:b6,platform:Windows,
|
||||
0300000000050000289b000000000000,Sega Saturn Adapter,a:b1,b:b2,leftshoulder:b6,lefttrigger:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows,
|
||||
0300000000f000000800000000000000,Sega Saturn Controller,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b7,righttrigger:b3,start:b0,x:b5,y:b6,platform:Windows,
|
||||
03000000730700000601000000000000,Sega Saturn Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows,
|
||||
03000000b40400000a01000000000000,Sega Saturn Controller,a:b0,b:b1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows,
|
||||
03000000b40400000a01000000000000,Sega Saturn Controller,a:b0,b:b1,leftshoulder:b6,lefttrigger:b7,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows,
|
||||
030000003b07000004a1000000000000,SFX,a:b0,b:b2,back:b7,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b5,start:b8,x:b1,y:b3,platform:Windows,
|
||||
03000000f82100001900000000000000,Shogun Bros Chameleon X1,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
|
||||
03000000120c00001c1e000000000000,SnakeByte 4S PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
|
||||
0300000003040000c197000000000000,SNES Controller,a:b0,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows,
|
||||
03000000571d00002000000000000000,SNES Controller,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows,
|
||||
0300000081170000960a000000000000,SNES Controller,a:b4,b:b0,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b5,y:b1,platform:Windows,
|
||||
0300000003040000c197000000000000,SNES Controller,a:b0,b:b4,back:b2,leftshoulder:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows,
|
||||
0300000081170000960a000000000000,SNES Controller,a:b4,b:b0,back:b2,leftshoulder:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b7,start:b3,x:b5,y:b1,platform:Windows,
|
||||
03000000811700009d0a000000000000,SNES Controller,a:b0,b:b4,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows,
|
||||
030000008b2800000300000000000000,SNES Controller,a:b0,b:b4,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows,
|
||||
03000000921200004653000000000000,SNES Controller,a:b0,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows,
|
||||
03000000921200004653000000000000,SNES Controller,a:b0,b:b4,back:b2,leftshoulder:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows,
|
||||
03000000ff000000cb01000000000000,Sony PlayStation Portable,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows,
|
||||
03000000341a00000208000000000000,Speedlink 6555,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:-a4,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a3,righty:a2,start:b7,x:b2,y:b3,platform:Windows,
|
||||
03000000341a00000908000000000000,Speedlink 6566,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
|
||||
@@ -611,18 +612,20 @@
|
||||
03000000110100001914000000000000,SteelSeries,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftstick:b13,lefttrigger:b6,leftx:a0,lefty:a1,rightstick:b14,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
|
||||
03000000381000001214000000000000,SteelSeries Free,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Windows,
|
||||
03000000110100003114000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
|
||||
03000000381000003014000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
|
||||
03000000381000003114000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
|
||||
03000000381000001814000000000000,SteelSeries Stratus XL,a:b0,b:b1,back:b18,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b19,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b2,y:b3,platform:Windows,
|
||||
03000000790000001c18000000000000,STK 7024X,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
|
||||
03000000381000003014000000000000,Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
|
||||
03000000381000003114000000000000,Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
|
||||
03000000380700003847000000000000,Street Fighter Fightstick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b11,start:b7,x:b2,y:b3,platform:Windows,
|
||||
030000001f08000001e4000000000000,Super Famicom Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows,
|
||||
030000001f08000001e4000000000000,Super Famicom Controller,a:b2,b:b1,back:b8,leftshoulder:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows,
|
||||
03000000790000000418000000000000,Super Famicom Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b33,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows,
|
||||
03000000341200001300000000000000,Super Racer,a:b2,b:b3,back:b8,leftshoulder:b5,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b7,x:b0,y:b1,platform:Windows,
|
||||
03000000d620000011a7000000000000,Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
030000000d0f0000f600000000000000,Switch Hori,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
|
||||
030000000d0f0000f600000000000000,Switch Hori Pad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
|
||||
03000000457500002211000000000000,Szmy Power PC Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
030000004f0400000ab1000000000000,T16000M,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b10,x:b2,y:b3,platform:Windows,
|
||||
030000000d0f00007b00000000000000,TAC GEAR,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000e40a00000207000000000000,Taito Egret II Mini Controller,a:b4,b:b2,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b9,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Windows,
|
||||
03000000d814000001a0000000000000,TE Kitty,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000fa1900000706000000000000,Team 5,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
|
||||
03000000b50700001203000000000000,Techmobility X6-38V,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows,
|
||||
@@ -640,6 +643,8 @@
|
||||
030000006d04000088ca000000000000,Thunderpad,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows,
|
||||
03000000666600000488000000000000,TigerGame PlayStation Adapter,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows,
|
||||
030000004f04000007d0000000000000,TMini,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000571d00002100000000000000,Tomee NES Controller Adapter,a:b1,b:b0,back:b2,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,start:b3,platform:Windows,
|
||||
03000000571d00002000000000000000,Tomee SNES Controller Adapter,a:b0,b:b1,back:b6,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows,
|
||||
03000000d62000006000000000000000,Tournament PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000c01100000055000000000000,Tronsmart,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
|
||||
030000005f140000c501000000000000,Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows,
|
||||
@@ -668,7 +673,7 @@
|
||||
030000006f0e00000702000000000000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows,
|
||||
0300000034120000adbe000000000000,vJoy Device,a:b0,b:b1,back:b15,dpdown:b6,dpleft:b7,dpright:b8,dpup:b5,guide:b16,leftshoulder:b9,leftstick:b13,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b14,righttrigger:b12,rightx:a3,righty:a4,start:b4,x:b2,y:b3,platform:Windows,
|
||||
03000000120c0000ab57000000000000,Warrior Joypad JS083,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
|
||||
030000007e0500003003000000000000,WiiU Pro,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,leftshoulder:b6,leftstick:b11,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b12,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows,
|
||||
030000007e0500003003000000000000,Wii U Pro,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,leftshoulder:b6,leftstick:b11,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b12,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows,
|
||||
0300000032150000030a000000000000,Wildcat,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
|
||||
0300000032150000140a000000000000,Wolverine,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows,
|
||||
030000002e160000efbe000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,rightshoulder:b5,righttrigger:b11,start:b7,x:b2,y:b3,platform:Windows,
|
||||
@@ -724,7 +729,6 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
030000007d0400000340000000000000,Xterminator Digital Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:-a4,lefttrigger:+a4,leftx:a0,lefty:a1,paddle1:b7,paddle2:b6,rightshoulder:b5,rightstick:b9,righttrigger:b2,rightx:a3,righty:a5,start:b8,x:b3,y:b4,platform:Windows,
|
||||
03000000790000004f18000000000000,ZDT Android Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows,
|
||||
03000000120c0000101e000000000000,Zeroplus P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,
|
||||
03000000091200004488000000000000,MUSIA PlayStation 2 Input Display,a:b0,b:b2,y:b3,x:b1,start:b5,back:b4,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b10,righttrigger:b11,platform:Windows,
|
||||
|
||||
# Mac OS X
|
||||
030000008f0e00000300000009010000,2In1 Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,
|
||||
@@ -732,8 +736,9 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000c82d00000531000000020000,8BitDo Adapter 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
|
||||
03000000c82d00000090000001000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
|
||||
03000000c82d00001038000000010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
|
||||
03000000a30c00002400000006020000,8BitDo M30,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,guide:b9,leftshoulder:b6,lefttrigger:b5,rightshoulder:b4,righttrigger:b7,start:b8,x:b3,y:b0,platform:Mac OS X,
|
||||
03000000c82d00000650000001000000,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Mac OS X,
|
||||
03000000c82d00005106000000010000,8BitDo M30,a:b1,b:b0,back:b10,guide:b2,leftshoulder:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,start:b11,x:b4,y:b3,platform:Mac OS X,
|
||||
03000000c82d00005106000000010000,8BitDo M30,a:b1,b:b0,back:b10,guide:b2,leftshoulder:b6,lefttrigger:a5,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b7,righttrigger:a4,start:b11,x:b4,y:b3,platform:Mac OS X,
|
||||
03000000c82d00001590000001000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
|
||||
03000000c82d00006528000000010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
|
||||
030000003512000012ab000001000000,8BitDo NES30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
|
||||
@@ -748,8 +753,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000c82d00000231000001000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
|
||||
03000000c82d00000331000001000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
|
||||
03000000c82d00000431000001000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
|
||||
03000000102800000900000000000000,8BitDo SFC30 Joystick,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
|
||||
03000000c82d00001290000001000000,8BitDo SN30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
|
||||
03000000102800000900000000000000,8BitDo SFC30 Joystick,a:b1,b:b0,back:b10,leftshoulder:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
|
||||
03000000c82d00001290000001000000,8BitDo SN30,a:b1,b:b0,back:b10,leftshoulder:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
|
||||
03000000c82d00004028000000010000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
|
||||
03000000c82d00000160000001000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
|
||||
03000000c82d00000161000000010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Mac OS X,
|
||||
@@ -757,11 +762,11 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000c82d00000261000000010000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X,
|
||||
03000000a00500003232000008010000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X,
|
||||
03000000a00500003232000009010000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X,
|
||||
03000000c82d00001890000001000000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
|
||||
03000000c82d00001890000001000000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
|
||||
03000000c82d00003032000000010000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a31,start:b11,x:b4,y:b3,platform:Mac OS X,
|
||||
03000000491900001904000001010000,Amazon Luna Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Mac OS X,
|
||||
03000000710100001904000000010000,Amazon Luna Controller,a:b0,b:b1,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Mac OS X,
|
||||
03000000a30c00002700000003030000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a3,lefty:a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X,
|
||||
03000000a30c00002700000003030000,Astro City Mini,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X,
|
||||
03000000a30c00002800000003030000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a3,lefty:a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X,
|
||||
03000000050b00000045000031000000,ASUS Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,
|
||||
03000000c62400001a89000000010000,BDA MOGA XP5-X Plus,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b6,leftstick:b15,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b16,righttrigger:a4,rightx:a2,righty:a3,start:b13,x:b3,y:b4,platform:Mac OS X,
|
||||
@@ -781,7 +786,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,
|
||||
03000000c01100000140000000010000,GameStop PS4 Fun Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
030000006f0e00000102000000000000,GameStop Xbox 360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
|
||||
030000007d0400000540000001010000,Gravis Eliminator Pro,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
030000007d0400000540000001010000,Gravis Eliminator Pro,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
03000000280400000140000000020000,Gravis Gamepad Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
030000008f0e00000300000007010000,GreenAsia Joystick,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Mac OS X,
|
||||
030000000d0f00002d00000000100000,Hori Fighting Commander 3 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
@@ -792,15 +797,17 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
030000000d0f00008400000000010000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
030000000d0f00008500000000010000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
030000000d0f00004d00000000000000,Hori Gem Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
030000000d0f00003801000008010000,Hori PC Engine Mini Controller,a:b1,b:b2,back:b8,start:b9,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,platform:Mac OS X,
|
||||
030000000d0f00003801000008010000,Hori PC Engine Mini Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,platform:Mac OS X,
|
||||
030000000d0f00009200000000010000,Hori Pokken Tournament DX Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
030000000d0f00006e00000000010000,Horipad 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
030000000d0f00006600000000010000,Horipad 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
030000000d0f00006600000000000000,Horipad FPS Plus 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
030000000d0f0000ee00000000010000,Horipad Mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
030000008f0e00001330000011010000,HuiJia SNES Controller,a:b4,b:b2,back:b16,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b12,rightshoulder:b14,start:b18,x:b6,y:b0,platform:Mac OS X,
|
||||
03000000830500006020000000000000,iBuffalo Gamepad,a:b1,b:b0,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Mac OS X,
|
||||
03000000790000004e95000000010000,Hyperkin N64 Controller Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a5,righty:a2,start:b9,platform:Mac OS X,
|
||||
03000000830500006020000000000000,iBuffalo Gamepad,a:b1,b:b0,back:b6,leftshoulder:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Mac OS X,
|
||||
03000000ef0500000300000000020000,InterAct AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Mac OS X,
|
||||
03000000fd0500000030000010010000,Interact GoPad,a:b3,b:b4,x:b0,y:b1,leftshoulder:b6,rightshoulder:b2,leftx:a0,lefty:a1,lefttrigger:b7,righttrigger:b5,platform:Mac OS X,
|
||||
030000007e0500000620000001000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Mac OS X,
|
||||
030000007e0500000720000001000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Mac OS X,
|
||||
03000000242f00002d00000007010000,JYS Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,
|
||||
@@ -823,9 +830,10 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000242f00007300000000020000,Mayflash Magic NS,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,platform:Mac OS X,
|
||||
0300000079000000d218000026010000,Mayflash Magic NS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,
|
||||
03000000d620000010a7000003010000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
0300000025090000e803000000000000,Mayflash Wii Classic Controller,a:b1,b:b0,back:b8,dpdown:b13,dpleft:b12,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Mac OS X,
|
||||
03000000790000000018000000010000,Mayflash Wii U Pro Controller Adapter,a:b4,b:b8,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b16,leftstick:b40,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,rightstick:b44,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b12,platform:Mac OS X,
|
||||
03000000790000000018000000000000,Mayflash WiiU Pro Adapter,a:b4,b:b8,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b16,leftstick:b40,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,rightstick:b44,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b12,platform:Mac OS X,
|
||||
0300000025090000e803000000000000,Mayflash Wii Classic Adapter,a:b1,b:b0,back:b8,dpdown:b13,dpleft:b12,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Mac OS X,
|
||||
03000000790000000318000000010000,Mayflash Wii DolphinBar,a:b8,b:b12,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b44,leftshoulder:b16,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b4,platform:Mac OS X,
|
||||
03000000790000000018000000000000,Mayflash Wii U Pro Adapter,a:b4,b:b8,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b16,leftstick:b40,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,rightstick:b44,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b12,platform:Mac OS X,
|
||||
03000000790000000018000000010000,Mayflash Wii U Pro Adapter,a:b4,b:b8,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b16,leftstick:b40,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,rightstick:b44,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b12,platform:Mac OS X,
|
||||
030000005e0400002800000002010000,Microsoft Dual Strike,a:b3,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,rightx:a0,righty:a1~,start:b5,x:b1,y:b0,platform:Mac OS X,
|
||||
030000005e0400002700000001010000,Microsoft SideWinder Plug and Play,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b4,righttrigger:b5,x:b2,y:b3,platform:Mac OS X,
|
||||
03000000d62000007162000001000000,Moga Pro 2,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Mac OS X,
|
||||
@@ -843,7 +851,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000550900001472000025050000,NVIDIA Controller,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Mac OS X,
|
||||
030000006f0e00000901000002010000,PDP Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
030000008f0e00000300000000000000,Piranha Xtreme PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Mac OS X,
|
||||
030000004c050000da0c000000010000,PlayStation Classic Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X,
|
||||
030000004c050000da0c000000010000,PlayStation Classic Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X,
|
||||
030000004c0500003713000000010000,PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
03000000d62000006dca000000010000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
03000000100800000300000006010000,PS2 Adapter,a:b2,b:b1,back:b8,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a4,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X,
|
||||
@@ -866,6 +874,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000321500000009000000020000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X,
|
||||
030000003215000000090000163a0000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X,
|
||||
0300000032150000030a000000000000,Razer Wildcat,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
|
||||
030000000d0f0000c100000072050000,Retro Bit Sega Genesis 6B Controller,a:b2,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b8,rightshoulder:b6,righttrigger:b7,start:b9,x:b3,y:b0,platform:Mac OS X,
|
||||
03000000921200004547000000020000,Retro Bit Sega Genesis Controller Adapter,a:b0,b:b2,x:b6,y:b8,start:b12,rightshoulder:b10,dpup:-a2,dpdown:+a2,dpleft:-a0,dpright:+a0,lefttrigger:b14,righttrigger:b4,platform:Mac OS X,
|
||||
03000000790000001100000000000000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
03000000790000001100000005010000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b4,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
03000000830500006020000000010000,Retro Controller,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b8,righttrigger:b9,start:b7,x:b2,y:b3,platform:Mac OS X,
|
||||
@@ -873,30 +883,36 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
030000006b140000010d000000010000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
030000006b140000130d000000010000,Revolution Pro Controller 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
03000000c6240000fefa000000000000,Rock Candy PS3,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
|
||||
03000000730700000401000000010000,Sanwa PlayOnline Mobile,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Mac OS X,
|
||||
03000000730700000401000000010000,Sanwa PlayOnline Mobile,a:b0,b:b1,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Mac OS X,
|
||||
03000000a30c00002500000006020000,Sega Genesis Mini 3B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,platform:Mac OS X,
|
||||
03000000811700007e05000000000000,Sega Saturn,a:b2,b:b4,dpdown:b16,dpleft:b15,dpright:b14,dpup:b17,leftshoulder:b8,lefttrigger:a5,leftx:a0,lefty:a2,rightshoulder:b9,righttrigger:a4,start:b13,x:b0,y:b6,platform:Mac OS X,
|
||||
03000000b40400000a01000000000000,Sega Saturn,a:b0,b:b1,back:b5,guide:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Mac OS X,
|
||||
030000003512000021ab000000000000,SFC30 Joystick,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
|
||||
03000000b40400000a01000000000000,Sega Saturn,a:b0,b:b1,back:b5,guide:b2,leftshoulder:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Mac OS X,
|
||||
030000003512000021ab000000000000,SFC30 Joystick,a:b1,b:b0,back:b10,leftshoulder:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X,
|
||||
0300000000f00000f100000000000000,SNES RetroPort,a:b2,b:b3,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b5,rightshoulder:b7,start:b6,x:b0,y:b1,platform:Mac OS X,
|
||||
030000004c050000a00b000000000000,Sony DualShock 4 Adapter,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
030000004c050000cc09000000000000,Sony DualShock 4 V2,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
03000000d11800000094000000010000,Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X,
|
||||
030000005e0400008e02000001000000,Steam Virtual Gamepad,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
|
||||
03000000110100002014000000000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b12,x:b2,y:b3,platform:Mac OS X,
|
||||
03000000110100002014000000000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X,
|
||||
03000000110100002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X,
|
||||
03000000381000002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X,
|
||||
05000000484944204465766963650000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b15,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b14,x:b2,y:b3,platform:Mac OS X,
|
||||
050000004e696d6275732b0000000000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b15,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b14,x:b2,y:b3,platform:Mac OS X,
|
||||
050000004e696d6275732b008b000000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b15,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b14,x:b2,y:b3,platform:Mac OS X,
|
||||
05000000556e6b6e6f776e2048494400,SteelSeries Nimbus Plus,a:b0,b:b1,back:b15,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b14,x:b2,y:b3,platform:Mac OS X,
|
||||
03000000381000003014000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
|
||||
03000000381000003114000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X,
|
||||
03000000110100001714000000000000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X,
|
||||
03000000110100001714000020010000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X,
|
||||
030000000d0f0000f600000000010000,Switch Hori Pad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X,
|
||||
03000000457500002211000000010000,SZMY Power PC Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
030000004f04000015b3000000000000,Thrustmaster Dual Analog 3.2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Mac OS X,
|
||||
030000004f0400000ed0000000020000,ThrustMaster eSwap Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Mac OS X,
|
||||
03000000571d00002100000021000000,Tomee NES Controller Adapter,a:b1,b:b0,back:b2,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,start:b3,platform:Mac OS X,
|
||||
03000000bd12000015d0000000010000,Tomee Retro Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,
|
||||
03000000bd12000015d0000000000000,Tomee SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X,
|
||||
03000000571d00002000000021000000,Tomee SNES Controller Adapter,a:b0,b:b1,back:b6,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Mac OS X,
|
||||
03000000100800000100000000000000,Twin USB Joystick,a:b4,b:b2,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b12,leftstick:b20,lefttrigger:b8,leftx:a0,lefty:a2,rightshoulder:b14,rightstick:b22,righttrigger:b10,rightx:a6,righty:a4,start:b18,x:b6,y:b0,platform:Mac OS X,
|
||||
030000006f0e00000302000025040000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
030000006f0e00000702000003060000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
@@ -920,6 +936,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
030000005e040000130b000001050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
|
||||
030000005e040000130b000005050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
|
||||
030000005e040000130b000009050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
|
||||
030000005e040000130b000013050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X,
|
||||
03000000172700004431000029010000,XiaoMi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Mac OS X,
|
||||
03000000120c0000100e000000010000,Zeroplus P4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
03000000120c0000101e000000010000,Zeroplus P4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X,
|
||||
@@ -934,7 +951,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
05000000c82d00005106000000010000,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Linux,
|
||||
03000000c82d00001590000011010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
|
||||
05000000c82d00006528000000010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
|
||||
03000000008000000210000011010000,8BitDo NES30,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000008000000210000011010000,8BitDo NES30,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000c82d00000310000011010000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b9,righttrigger:b8,start:b11,x:b3,y:b4,platform:Linux,
|
||||
05000000c82d00008010000000010000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b9,righttrigger:b8,start:b11,x:b3,y:b4,platform:Linux,
|
||||
03000000022000000090000011010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
|
||||
@@ -951,9 +968,9 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
05000000c82d00000061000000010000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
|
||||
030000003512000012ab000010010000,8BitDo SFC30,a:b2,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Linux,
|
||||
030000003512000021ab000010010000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
|
||||
03000000c82d000021ab000010010000,8BitDo SFC30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
|
||||
05000000102800000900000000010000,8BitDo SFC30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
|
||||
05000000c82d00003028000000010000,8BitDo SFC30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
|
||||
03000000c82d000021ab000010010000,8BitDo SFC30,a:b1,b:b0,back:b10,leftshoulder:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
|
||||
05000000102800000900000000010000,8BitDo SFC30,a:b1,b:b0,back:b10,leftshoulder:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
|
||||
05000000c82d00003028000000010000,8BitDo SFC30,a:b1,b:b0,back:b10,leftshoulder:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
|
||||
03000000c82d00000160000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Linux,
|
||||
03000000c82d00000160000011010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
|
||||
03000000c82d00000161000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Linux,
|
||||
@@ -963,9 +980,9 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000c82d00000260000011010000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
|
||||
05000000c82d00000261000000010000,8BitDo SN30 Pro+,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
|
||||
05000000202800000900000000010000,8BitDo SNES30,a:b1,b:b0,back:b10,dpdown:b122,dpleft:b119,dpright:b120,dpup:b117,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
|
||||
05000000a00500003232000001000000,8BitDo Zero,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux,
|
||||
05000000a00500003232000001000000,8BitDo Zero,a:b0,b:b1,back:b10,leftshoulder:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux,
|
||||
05000000a00500003232000008010000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux,
|
||||
03000000c82d00001890000011010000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
|
||||
03000000c82d00001890000011010000,8BitDo Zero 2,a:b1,b:b0,back:b10,leftshoulder:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux,
|
||||
050000005e040000e002000030110000,8BitDo Zero 2,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux,
|
||||
05000000c82d00003032000000010000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux,
|
||||
03000000c01100000355000011010000,Acrux Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
@@ -979,7 +996,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000491900001904000011010000,Amazon Luna Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Linux,
|
||||
05000000710100001904000000010000,Amazon Luna Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux,
|
||||
03000000790000003018000011010000,Arcade Fightstick F300,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000a30c00002700000011010000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
|
||||
03000000a30c00002700000011010000,Astro City Mini,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
|
||||
03000000a30c00002800000011010000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
|
||||
05000000050b00000045000031000000,Asus Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Linux,
|
||||
05000000050b00000045000040000000,Asus Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Linux,
|
||||
@@ -1031,14 +1048,14 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000451300000010000010010000,Genius Maxfire Grandias 12,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
|
||||
03000000f0250000c183000010010000,Goodbetterbest Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
0300000079000000d418000000010000,GPD Win 2 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000007d0400000540000000010000,Gravis Eliminator Pro,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000280400000140000000010000,Gravis Pro,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
|
||||
030000007d0400000540000000010000,Gravis Eliminator Pro,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000280400000140000000010000,Gravis Pro,a:b1,b:b2,back:b8,leftshoulder:b4,lefttrigger:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
|
||||
030000008f0e00000610000000010000,GreenAsia Electronics Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Linux,
|
||||
030000008f0e00001200000010010000,GreenAsia Joystick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux,
|
||||
0500000047532067616d657061640000,GS gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
|
||||
03000000f0250000c383000010010000,GT VX2,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
|
||||
06000000adde0000efbe000002010000,Hidromancer Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
03000000d81400000862000011010000,HitBox PS3 PC Analog Mode,a:b1,b:b2,back:b8,guide:b9,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b12,x:b0,y:b3,platform:Linux,
|
||||
03000000d81400000862000011010000,HitBox PS3 PC Analog Mode,a:b1,b:b2,back:b8,guide:b9,leftshoulder:b4,lefttrigger:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b5,righttrigger:b7,start:b12,x:b0,y:b3,platform:Linux,
|
||||
03000000c9110000f055000011010000,HJC Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
|
||||
03000000632500002605000010010000,HJDX,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
030000000d0f00000d00000000010000,Hori,a:b0,b:b6,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b3,rightshoulder:b7,start:b9,x:b1,y:b2,platform:Linux,
|
||||
@@ -1055,6 +1072,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
030000000d0f00003801000011010000,Hori PC Engine Mini Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,platform:Linux,
|
||||
030000000d0f00009200000011010000,Hori Pokken Tournament DX Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
|
||||
030000000d0f0000aa00000011010000,Hori Real Arcade Pro,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
|
||||
030000000d0f00001100000011010000,Hori Real Arcade Pro 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
030000000d0f00002200000011010000,Hori Real Arcade Pro 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux,
|
||||
030000000d0f00006a00000011010000,Hori Real Arcade Pro 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
|
||||
030000000d0f00006b00000011010000,Hori Real Arcade Pro 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
@@ -1068,12 +1086,13 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000341a000005f7000010010000,HuiJia GameCube Controller Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Linux,
|
||||
030000008f0e00001330000010010000,HuiJia SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b9,x:b3,y:b0,platform:Linux,
|
||||
03000000242e00008816000001010000,Hyperkin X91,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
03000000830500006020000010010000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux,
|
||||
050000006964726f69643a636f6e0000,idroidcon Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000b50700001503000010010000,Impact,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux,
|
||||
03000000d80400008200000003000000,IMS PCU0,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b5,x:b3,y:b2,platform:Linux,
|
||||
03000000120c00000500000010010000,InterAct AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Linux,
|
||||
03000000ef0500000300000000010000,InterAct AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Linux,
|
||||
03000000fd0500000030000000010000,InterAct GoPad I73000,a:b3,b:b4,back:b6,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,start:b7,x:b0,y:b1,platform:Linux,
|
||||
03000000fd0500000030000000010000,InterAct GoPad,a:b3,b:b4,x:b0,y:b1,leftshoulder:b6,rightshoulder:b2,leftx:a0,lefty:a1,lefttrigger:b7,righttrigger:b5,platform:Linux,
|
||||
03000000fd0500002a26000000010000,InterAct HammerHead FX,a:b3,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b2,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b5,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Linux,
|
||||
0500000049190000020400001b010000,Ipega PG 9069,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b161,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
03000000632500007505000011010000,Ipega PG 9099,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
|
||||
@@ -1123,12 +1142,13 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
0300000079000000d218000011010000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000d620000010a7000011010000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000242f0000f700000001010000,Mayflash Magic S Pro,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
0300000025090000e803000001010000,Mayflash Wii Classic Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:a4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:a5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux,
|
||||
0300000025090000e803000001010000,Mayflash Wii Classic Adapter,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:a4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:a5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux,
|
||||
03000000790000000318000011010000,Mayflash Wii DolphinBar,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Linux,
|
||||
03000000b50700001203000010010000,Mega World Logic 3 Controller,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux,
|
||||
03000000780000000600000010010000,Microntek Joystick,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux,
|
||||
030000005e0400002800000000010000,Microsoft Dual Strike,a:b3,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,rightx:a0,righty:a1~,start:b5,x:b1,y:b0,platform:Linux,
|
||||
030000005e0400000e00000000010000,Microsoft SideWinder,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Linux,
|
||||
030000005e0400000700000000010000,Microsoft SideWinder Gamepad,a:b0,b:b1,back:b8,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Linux,
|
||||
030000005e0400000700000000010000,Microsoft SideWinder Gamepad,a:b0,b:b1,back:b8,leftshoulder:b6,lefttrigger:b7,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Linux,
|
||||
030000005e0400002700000000010000,Microsoft SideWinder Plug and Play,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b4,righttrigger:b5,x:b2,y:b3,platform:Linux,
|
||||
030000005e0400008502000000010000,Microsoft Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux,
|
||||
030000005e0400008e02000001000000,Microsoft Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.1,dpleft:h0.2,dpright:h0.8,dpup:h0.4,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
@@ -1155,7 +1175,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
05000000c62400002a89000000010000,MOGA XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b22,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
05000000c62400001a89000000010000,MOGA XP5X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
03000000250900006688000000010000,MP8866 Super Dual Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux,
|
||||
030000005e0400008e02000010020000,MSI GC20 V2,a:b0,b:b1,y:b3,x:b2,start:b7,back:b6,guide:b8,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:b12,dpleft:b14,dpdown:b13,dpright:b15,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux,
|
||||
030000005e0400008e02000010020000,MSI GC20 V2,a:b0,b:b1,back:b6,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000006b1400000906000014010000,Nacon Asymmetric Wireless PS4 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000006b140000010c000010010000,Nacon GC 400ES,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
|
||||
03000000853200000706000012010000,Nacon GC-100,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
@@ -1164,7 +1184,6 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
0300000092120000474e000000010000,NeoGeo X Arcade Stick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b3,y:b2,platform:Linux,
|
||||
03000000790000004518000010010000,Nexilux GameCube Controller Adapter,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Linux,
|
||||
030000001008000001e5000010010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Linux,
|
||||
050000004e696d6275732b0000000000,Nimbus Plus,a:b0,b:b1,back:b10,guide:b11,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b12,x:b2,y:b3,platform:Linux,
|
||||
060000007e0500003713000000000000,Nintendo 3DS,a:b0,b:b1,back:b8,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux,
|
||||
030000007e0500003703000000016800,Nintendo GameCube Controller,a:b0,b:b2,dpdown:b6,dpleft:b4,dpright:b5,dpup:b7,lefttrigger:a4,leftx:a0,lefty:a1~,rightshoulder:b9,righttrigger:a5,rightx:a2,righty:a3~,start:b8,x:b1,y:b3,platform:Linux,
|
||||
03000000790000004618000010010000,Nintendo GameCube Controller Adapter,a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a5~,righty:a2~,start:b9,x:b2,y:b3,platform:Linux,
|
||||
@@ -1256,6 +1275,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
050000004c050000e60c000000810000,PS5 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux,
|
||||
03000000300f00001211000011010000,Qanba Arcade Joystick,a:b2,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b9,x:b1,y:b3,platform:Linux,
|
||||
03000000300f00001210000010010000,Qanba Joystick Plus,a:b0,b:b1,back:b8,leftshoulder:b5,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b6,start:b9,x:b2,y:b3,platform:Linux,
|
||||
03000000222c00000223000011010000,Qanba Obsidian Arcade Joystick (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000222c00000023000011010000,Qanba Obsidian Arcade Joystick (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux,
|
||||
030000009b2800000300000001010000,Raphnet 4nes4snes,a:b0,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Linux,
|
||||
030000009b2800004200000001010000,Raphnet Dual NES Adapter,a:b0,b:b1,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Linux,
|
||||
030000009b2800003200000001010000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux,
|
||||
@@ -1299,8 +1320,8 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
03000000a30c00002500000011010000,Sega Genesis Mini 3B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,platform:Linux,
|
||||
03000000790000001100000011010000,Sega Saturn,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b4,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000790000002201000011010000,Sega Saturn,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,start:b9,x:b2,y:b3,platform:Linux,
|
||||
03000000b40400000a01000000010000,Sega Saturn,a:b0,b:b1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Linux,
|
||||
030000001f08000001e4000010010000,SFC Controller,a:b2,b:b1,back:b8,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Linux,
|
||||
03000000b40400000a01000000010000,Sega Saturn,a:b0,b:b1,leftshoulder:b6,lefttrigger:b7,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Linux,
|
||||
030000001f08000001e4000010010000,SFC Controller,a:b2,b:b1,back:b8,leftshoulder:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Linux,
|
||||
03000000632500002305000010010000,ShanWan Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
|
||||
03000000f025000021c1000010010000,Shanwan Gioteck PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
|
||||
03000000632500007505000010010000,Shanwan PS3 PC,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
|
||||
@@ -1314,7 +1335,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
030000005e0400008e02000020200000,SpeedLink Xeox Pro Analog,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
03000000d11800000094000011010000,Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux,
|
||||
03000000de2800000112000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
|
||||
03000000de2800000112000011010000,Steam Controller,a:b2,b:b3,x:b4,y:b5,back:b10,guide:b12,start:b11,leftstick:b13,rightstick:b14,leftshoulder:b6,rightshoulder:b7,dpup:-a5,dpdown:+a5,dpleft:-a4,dpright:+a4,paddle1:b15,paddle2:b16,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a7,righttrigger:a6,platform:Linux,
|
||||
03000000de2800000112000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:+a5,dpleft:-a4,dpright:+a4,dpup:-a5,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,paddle1:b15,paddle2:b16,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux,
|
||||
03000000de2800000211000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
|
||||
03000000de2800000211000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:b18,dpleft:b19,dpright:b20,dpup:b17,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b16,paddle2:b15,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux,
|
||||
03000000de2800004211000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
|
||||
@@ -1324,14 +1345,15 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
|
||||
05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
|
||||
05000000de2800000611000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux,
|
||||
03000000de280000ff11000001000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
050000004e696d6275732b0000000000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b10,guide:b11,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b12,x:b2,y:b3,platform:Linux,
|
||||
03000000381000003014000075010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
03000000381000003114000075010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
0500000011010000311400001b010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b32,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
05000000110100001914000009010000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
|
||||
03000000ad1b000038f0000090040000,Street Fighter IV Fightstick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux,
|
||||
030000003b07000004a1000000010000,Suncom SFX Plus,a:b0,b:b2,back:b7,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b5,start:b8,x:b1,y:b3,platform:Linux,
|
||||
030000003b07000004a1000000010000,Suncom SFX Plus,a:b0,b:b2,back:b7,leftshoulder:b6,lefttrigger:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b9,righttrigger:b5,start:b8,x:b1,y:b3,platform:Linux,
|
||||
03000000666600000488000000010000,Super Joy Box 5 Pro,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux,
|
||||
0300000000f00000f100000000010000,Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux,
|
||||
0300000000f00000f100000000010000,Super RetroPort,a:b1,b:b5,back:b2,leftshoulder:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux,
|
||||
030000008f0e00000d31000010010000,SZMY Power 3 Turbo,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
03000000457500002211000010010000,SZMY Power Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux,
|
||||
030000008f0e00001431000010010000,SZMY Power PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
|
||||
|
||||
@@ -135,12 +135,10 @@ PS_OUTPUT ps_filter_complex(PS_INPUT input) // triangular
|
||||
{
|
||||
PS_OUTPUT output;
|
||||
|
||||
float2 texdim, halfpixel;
|
||||
Texture.GetDimensions(texdim.x, texdim.y);
|
||||
if (ddy(input.t.y) * input.t.y > 0.5)
|
||||
output.c = sample_c(input.t);
|
||||
else
|
||||
output.c = (0.9 - 0.4 * cos(2 * PI * input.t.y * texdim.y)) * sample_c(float2(input.t.x, (floor(input.t.y * texdim.y) + 0.5) / texdim.y));
|
||||
float2 texdim;
|
||||
Texture.GetDimensions(texdim.x, texdim.y);
|
||||
|
||||
output.c = (0.9 - 0.4 * cos(2 * PI * input.t.y * texdim.y)) * sample_c(float2(input.t.x, (floor(input.t.y * texdim.y) + 0.5) / texdim.y));
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
@@ -119,18 +119,10 @@ void ps_filter_triangular() // triangular
|
||||
#ifdef ps_filter_complex
|
||||
void ps_filter_complex()
|
||||
{
|
||||
|
||||
const float PI = 3.14159265359f;
|
||||
|
||||
vec2 texdim = vec2(textureSize(TextureSampler, 0));
|
||||
|
||||
vec4 c;
|
||||
if (dFdy(PSin_t.y) * PSin_t.y > 0.5f) {
|
||||
c = sample_c();
|
||||
} else {
|
||||
float factor = (0.9f - 0.4f * cos(2.0f * PI * PSin_t.y * texdim.y));
|
||||
c = factor * texture(TextureSampler, vec2(PSin_t.x, (floor(PSin_t.y * texdim.y) + 0.5f) / texdim.y));
|
||||
}
|
||||
float factor = (0.9f - 0.4f * cos(2.0f * PI * PSin_t.y * texdim.y));
|
||||
vec4 c = factor * texture(TextureSampler, vec2(PSin_t.x, (floor(PSin_t.y * texdim.y) + 0.5f) / texdim.y));
|
||||
|
||||
SV_Target0 = c;
|
||||
}
|
||||
|
||||
@@ -106,10 +106,8 @@ void ps_filter_complex() // triangular
|
||||
{
|
||||
const float PI = 3.14159265359f;
|
||||
vec2 texdim = vec2(textureSize(samp0, 0));
|
||||
if (dFdy(v_tex.y) * v_tex.y > 0.5)
|
||||
o_col0 = sample_c(v_tex);
|
||||
else
|
||||
o_col0 = (0.9 - 0.4 * cos(2 * PI * v_tex.y * texdim.y)) * sample_c(vec2(v_tex.x, (floor(v_tex.y * texdim.y) + 0.5) / texdim.y));
|
||||
|
||||
o_col0 = (0.9 - 0.4 * cos(2 * PI * v_tex.y * texdim.y)) * sample_c(vec2(v_tex.x, (floor(v_tex.y * texdim.y) + 0.5) / texdim.y));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -158,9 +158,11 @@ for ARG in "$@"; do
|
||||
--rel|--release ) flags="$flags -DCMAKE_BUILD_TYPE=Release" ; build="$root/build_rel";;
|
||||
--prof ) flags="$flags -DCMAKE_BUILD_TYPE=RelWithDebInfo"; build="$root/build_prof";;
|
||||
--strip ) flags="$flags -DCMAKE_BUILD_STRIP=TRUE" ;;
|
||||
--use-system-yaml ) flags="$flags -DUSE_SYSTEM_YAML=TRUE" ;;
|
||||
--asan ) flags="$flags -DUSE_ASAN=TRUE" ;;
|
||||
--gtk2 ) flags="$flags -DGTK2_API=TRUE" ;;
|
||||
--qt6 ) flags="$flags -DQT_BUILD=TRUE" ;;
|
||||
--use-system ) flags="$flags -DUSE_SYSTEM_LIBS=ON" ;;
|
||||
--use-bundled ) flags="$flags -DUSE_SYSTEM_LIBS=OFF" ;;
|
||||
--lto ) flags="$flags -DCMAKE_INTERPROCEDURAL_OPTIMIZATION=TRUE" ;;
|
||||
--pgo-optimize ) flags="$flags -DUSE_PGO_OPTIMIZE=TRUE" ;;
|
||||
--pgo-generate ) flags="$flags -DUSE_PGO_GENERATE=TRUE" ;;
|
||||
@@ -185,13 +187,15 @@ for ARG in "$@"; do
|
||||
echo
|
||||
echo "** Distribution Compatibilities **"
|
||||
echo "--no-portaudio : Skip portaudio for SPU2."
|
||||
echo "--use-system-yaml : Use system rapidyaml library."
|
||||
echo
|
||||
echo "** Expert Developer option **"
|
||||
echo "--gtk2 : use GTK 2 instead of GTK 3."
|
||||
echo "--qt6 : Experimental qt 6 ui."
|
||||
echo "--no-trans : Don't regenerate mo files when building."
|
||||
echo "--strip : Strip binaries to save a small amount of space."
|
||||
echo "--clang : Build with Clang/llvm."
|
||||
echo "--use-system : Only use system libs."
|
||||
echo "--use-bundled : Only use bundled libs."
|
||||
echo "--intel : Build with ICC (Intel compiler)."
|
||||
echo "--lto : Use Link Time Optimization."
|
||||
echo "--pgo-generate : Executable will generate profiling information when run."
|
||||
|
||||
+13
-11
@@ -284,7 +284,7 @@ void Texture::TransitionSubresourceToState(ID3D12GraphicsCommandList* cmdlist, u
|
||||
cmdlist->ResourceBarrier(1, &barrier);
|
||||
}
|
||||
|
||||
bool Texture::BeginStreamUpdate(u32 level, u32 x, u32 y, u32 width, u32 height, void** out_data, u32* out_data_pitch)
|
||||
ID3D12GraphicsCommandList* Texture::BeginStreamUpdate(ID3D12GraphicsCommandList* cmdlist, u32 level, u32 x, u32 y, u32 width, u32 height, void** out_data, u32* out_data_pitch)
|
||||
{
|
||||
const u32 copy_pitch = Common::AlignUpPow2(width * GetTexelSize(m_format), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
|
||||
const u32 upload_size = copy_pitch * height;
|
||||
@@ -297,16 +297,19 @@ bool Texture::BeginStreamUpdate(u32 level, u32 x, u32 y, u32 width, u32 height,
|
||||
if (!g_d3d12_context->GetTextureStreamBuffer().ReserveMemory(upload_size, D3D12_TEXTURE_DATA_PLACEMENT_ALIGNMENT))
|
||||
{
|
||||
Console.Error("Failed to reserve %u bytes for %ux%u upload", upload_size, width, height);
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// cmdlist change
|
||||
return g_d3d12_context->GetInitCommandList();
|
||||
}
|
||||
|
||||
*out_data = g_d3d12_context->GetTextureStreamBuffer().GetCurrentHostPointer();
|
||||
*out_data_pitch = copy_pitch;
|
||||
return true;
|
||||
return cmdlist;
|
||||
}
|
||||
|
||||
void Texture::EndStreamUpdate(u32 level, u32 x, u32 y, u32 width, u32 height)
|
||||
void Texture::EndStreamUpdate(ID3D12GraphicsCommandList* cmdlist, u32 level, u32 x, u32 y, u32 width, u32 height)
|
||||
{
|
||||
const u32 copy_pitch = Common::AlignUpPow2(width * GetTexelSize(m_format), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
|
||||
const u32 upload_size = copy_pitch * height;
|
||||
@@ -315,10 +318,10 @@ void Texture::EndStreamUpdate(u32 level, u32 x, u32 y, u32 width, u32 height)
|
||||
const u32 sb_offset = sb.GetCurrentOffset();
|
||||
sb.CommitMemory(upload_size);
|
||||
|
||||
CopyFromBuffer(level, x, y, width, height, copy_pitch, sb.GetBuffer(), sb_offset);
|
||||
CopyFromBuffer(cmdlist, level, x, y, width, height, copy_pitch, sb.GetBuffer(), sb_offset);
|
||||
}
|
||||
|
||||
void Texture::CopyFromBuffer(u32 level, u32 x, u32 y, u32 width, u32 height, u32 pitch, ID3D12Resource* buffer, u32 buffer_offset)
|
||||
void Texture::CopyFromBuffer(ID3D12GraphicsCommandList* cmdlist, u32 level, u32 x, u32 y, u32 width, u32 height, u32 pitch, ID3D12Resource* buffer, u32 buffer_offset)
|
||||
{
|
||||
D3D12_TEXTURE_COPY_LOCATION src;
|
||||
src.pResource = buffer;
|
||||
@@ -337,7 +340,6 @@ void Texture::CopyFromBuffer(u32 level, u32 x, u32 y, u32 width, u32 height, u32
|
||||
|
||||
const D3D12_BOX src_box{0u, 0u, 0u, width, height, 1u};
|
||||
const D3D12_RESOURCE_STATES old_state = m_state;
|
||||
ID3D12GraphicsCommandList* cmdlist = g_d3d12_context->GetCommandList();
|
||||
TransitionToState(cmdlist, D3D12_RESOURCE_STATE_COPY_DEST);
|
||||
cmdlist->CopyTextureRegion(&dst, x, y, 0, &src, &src_box);
|
||||
TransitionToState(cmdlist, old_state);
|
||||
@@ -381,7 +383,7 @@ static ID3D12Resource* CreateStagingBuffer(u32 height, const void* data, u32 pit
|
||||
return resource.get();
|
||||
}
|
||||
|
||||
bool Texture::LoadData(u32 level, u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch)
|
||||
bool Texture::LoadData(ID3D12GraphicsCommandList* cmdlist, u32 level, u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch)
|
||||
{
|
||||
const u32 texel_size = GetTexelSize(m_format);
|
||||
const u32 upload_pitch = Common::AlignUpPow2(width * texel_size, D3D12_TEXTURE_DATA_PITCH_ALIGNMENT);
|
||||
@@ -392,17 +394,17 @@ bool Texture::LoadData(u32 level, u32 x, u32 y, u32 width, u32 height, const voi
|
||||
if (!staging_buffer)
|
||||
return false;
|
||||
|
||||
CopyFromBuffer(level, x, y, width, height, upload_pitch, staging_buffer, 0);
|
||||
CopyFromBuffer(cmdlist, level, x, y, width, height, upload_pitch, staging_buffer, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
void* write_ptr;
|
||||
u32 write_pitch;
|
||||
if (!BeginStreamUpdate(level, x, y, width, height, &write_ptr, &write_pitch))
|
||||
if (!(cmdlist = BeginStreamUpdate(cmdlist, level, x, y, width, height, &write_ptr, &write_pitch)))
|
||||
return false;
|
||||
|
||||
StringUtil::StrideMemCpy(write_ptr, write_pitch, data, pitch, std::min(pitch, upload_pitch), height);
|
||||
EndStreamUpdate(level, x, y, width, height);
|
||||
EndStreamUpdate(cmdlist, level, x, y, width, height);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -74,10 +74,10 @@ namespace D3D12
|
||||
Texture& operator=(Texture&& texture);
|
||||
|
||||
// NOTE: Does not handle compressed formats.
|
||||
bool BeginStreamUpdate(u32 level, u32 x, u32 y, u32 width, u32 height, void** out_data, u32* out_data_pitch);
|
||||
void EndStreamUpdate(u32 level, u32 x, u32 y, u32 width, u32 height);
|
||||
bool LoadData(u32 level, u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch);
|
||||
void CopyFromBuffer(u32 level, u32 x, u32 y, u32 width, u32 height, u32 pitch, ID3D12Resource* buffer, u32 buffer_offset);
|
||||
ID3D12GraphicsCommandList* BeginStreamUpdate(ID3D12GraphicsCommandList* cmdlist, u32 level, u32 x, u32 y, u32 width, u32 height, void** out_data, u32* out_data_pitch);
|
||||
void EndStreamUpdate(ID3D12GraphicsCommandList* cmdlist, u32 level, u32 x, u32 y, u32 width, u32 height);
|
||||
bool LoadData(ID3D12GraphicsCommandList* cmdlist, u32 level, u32 x, u32 y, u32 width, u32 height, const void* data, u32 pitch);
|
||||
void CopyFromBuffer(ID3D12GraphicsCommandList* cmdlist, u32 level, u32 x, u32 y, u32 width, u32 height, u32 pitch, ID3D12Resource* buffer, u32 buffer_offset);
|
||||
|
||||
private:
|
||||
static bool CreateSRVDescriptor(ID3D12Resource* resource, u32 levels, DXGI_FORMAT format, DescriptorHandle* dh);
|
||||
|
||||
@@ -138,7 +138,7 @@ void pxOnAssertFail(const char* file, int line, const char* func, const char* ms
|
||||
fputs(full_msg, stderr);
|
||||
fputs("\nAborting application.\n", stderr);
|
||||
fflush(stderr);
|
||||
abort();
|
||||
AbortWithMessage(full_msg);
|
||||
#endif
|
||||
|
||||
ResumeThreads(handle);
|
||||
|
||||
+142
-19
@@ -13,10 +13,10 @@
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "common/PrecompiledHeader.h"
|
||||
|
||||
#include "common/GL/ContextWGL.h"
|
||||
#include "common/Assertions.h"
|
||||
#include "common/Console.h"
|
||||
#include "ContextWGL.h"
|
||||
#include "common/ScopedGuard.h"
|
||||
|
||||
static void* GetProcAddressCallback(const char* name)
|
||||
{
|
||||
@@ -43,8 +43,7 @@ namespace GL
|
||||
if (m_rc)
|
||||
wglDeleteContext(m_rc);
|
||||
|
||||
if (m_dc)
|
||||
ReleaseDC(GetHWND(), m_dc);
|
||||
ReleaseDC();
|
||||
}
|
||||
|
||||
std::unique_ptr<Context> ContextWGL::Create(const WindowInfo& wi, const Version* versions_to_try,
|
||||
@@ -66,7 +65,7 @@ namespace GL
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Error("PBuffer not implemented");
|
||||
Console.Error("ContextWGL must always start with a valid surface.");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -102,11 +101,7 @@ namespace GL
|
||||
{
|
||||
const bool was_current = (wglGetCurrentContext() == m_rc);
|
||||
|
||||
if (m_dc)
|
||||
{
|
||||
ReleaseDC(GetHWND(), m_dc);
|
||||
m_dc = {};
|
||||
}
|
||||
ReleaseDC();
|
||||
|
||||
m_wi = new_wi;
|
||||
if (!InitializeDC())
|
||||
@@ -187,7 +182,7 @@ namespace GL
|
||||
return context;
|
||||
}
|
||||
|
||||
bool ContextWGL::InitializeDC()
|
||||
HDC ContextWGL::GetDCAndSetPixelFormat(HWND hwnd)
|
||||
{
|
||||
PIXELFORMATDESCRIPTOR pfd = {};
|
||||
pfd.nSize = sizeof(pfd);
|
||||
@@ -200,26 +195,154 @@ namespace GL
|
||||
pfd.cBlueBits = 8;
|
||||
pfd.cColorBits = 24;
|
||||
|
||||
m_dc = GetDC(GetHWND());
|
||||
if (!m_dc)
|
||||
HDC hDC = ::GetDC(hwnd);
|
||||
if (!hDC)
|
||||
{
|
||||
Console.Error("GetDC() failed: 0x%08X", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
const int pf = ChoosePixelFormat(m_dc, &pfd);
|
||||
if (pf == 0)
|
||||
if (!m_pixel_format.has_value())
|
||||
{
|
||||
Console.Error("ChoosePixelFormat() failed: 0x%08X", GetLastError());
|
||||
return false;
|
||||
const int pf = ChoosePixelFormat(hDC, &pfd);
|
||||
if (pf == 0)
|
||||
{
|
||||
Console.Error("ChoosePixelFormat() failed: 0x%08X", GetLastError());
|
||||
::ReleaseDC(hwnd, hDC);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_pixel_format = pf;
|
||||
}
|
||||
|
||||
if (!SetPixelFormat(m_dc, pf, &pfd))
|
||||
if (!SetPixelFormat(hDC, m_pixel_format.value(), &pfd))
|
||||
{
|
||||
Console.Error("SetPixelFormat() failed: 0x%08X", GetLastError());
|
||||
::ReleaseDC(hwnd, hDC);
|
||||
return {};
|
||||
}
|
||||
|
||||
return hDC;
|
||||
}
|
||||
|
||||
bool ContextWGL::InitializeDC()
|
||||
{
|
||||
if (m_wi.type == WindowInfo::Type::Win32)
|
||||
{
|
||||
m_dc = GetDCAndSetPixelFormat(GetHWND());
|
||||
if (!m_dc)
|
||||
{
|
||||
Console.Error("Failed to get DC for window");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (m_wi.type == WindowInfo::Type::Surfaceless)
|
||||
{
|
||||
return CreatePBuffer();
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Error("Unknown window info type %u", static_cast<unsigned>(m_wi.type));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void ContextWGL::ReleaseDC()
|
||||
{
|
||||
if (m_pbuffer)
|
||||
{
|
||||
wglReleasePbufferDCARB(m_pbuffer, m_dc);
|
||||
m_dc = {};
|
||||
|
||||
wglDestroyPbufferARB(m_pbuffer);
|
||||
m_pbuffer = {};
|
||||
|
||||
::ReleaseDC(m_dummy_window, m_dummy_dc);
|
||||
m_dummy_dc = {};
|
||||
|
||||
DestroyWindow(m_dummy_window);
|
||||
m_dummy_window = {};
|
||||
}
|
||||
else if (m_dc)
|
||||
{
|
||||
::ReleaseDC(GetHWND(), m_dc);
|
||||
m_dc = {};
|
||||
}
|
||||
}
|
||||
|
||||
bool ContextWGL::CreatePBuffer()
|
||||
{
|
||||
static bool window_class_registered = false;
|
||||
static const wchar_t* window_class_name = L"ContextWGLPBuffer";
|
||||
|
||||
if (!window_class_registered)
|
||||
{
|
||||
WNDCLASSEXW wc = {};
|
||||
wc.cbSize = sizeof(WNDCLASSEXW);
|
||||
wc.style = 0;
|
||||
wc.lpfnWndProc = DefWindowProcW;
|
||||
wc.cbClsExtra = 0;
|
||||
wc.cbWndExtra = 0;
|
||||
wc.hInstance = GetModuleHandle(nullptr);
|
||||
wc.hIcon = NULL;
|
||||
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
|
||||
wc.lpszMenuName = NULL;
|
||||
wc.lpszClassName = window_class_name;
|
||||
wc.hIconSm = NULL;
|
||||
|
||||
if (!RegisterClassExW(&wc))
|
||||
{
|
||||
Console.Error("(ContextWGL::CreatePBuffer) RegisterClassExW() failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
window_class_registered = true;
|
||||
}
|
||||
|
||||
HWND hwnd = CreateWindowExW(0, window_class_name, window_class_name, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
|
||||
if (!hwnd)
|
||||
{
|
||||
Console.Error("(ContextWGL::CreatePBuffer) CreateWindowEx() failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
ScopedGuard hwnd_guard([hwnd]() { DestroyWindow(hwnd); });
|
||||
|
||||
HDC hdc = GetDCAndSetPixelFormat(hwnd);
|
||||
if (!hdc)
|
||||
return false;
|
||||
|
||||
ScopedGuard hdc_guard([hdc, hwnd]() { ::ReleaseDC(hwnd, hdc); });
|
||||
|
||||
static constexpr const int pb_attribs[] = {0, 0};
|
||||
|
||||
pxAssertRel(m_pixel_format.has_value(), "Has pixel format for pbuffer");
|
||||
HPBUFFERARB pbuffer = wglCreatePbufferARB(hdc, m_pixel_format.value(), 1, 1, pb_attribs);
|
||||
if (!pbuffer)
|
||||
{
|
||||
Console.Error("(ContextWGL::CreatePBuffer) wglCreatePbufferARB() failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
ScopedGuard pbuffer_guard([pbuffer]() { wglDestroyPbufferARB(pbuffer); });
|
||||
|
||||
m_dc = wglGetPbufferDCARB(pbuffer);
|
||||
if (!m_dc)
|
||||
{
|
||||
Console.Error("(ContextWGL::CreatePbuffer) wglGetPbufferDCARB() failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_dummy_window = hwnd;
|
||||
m_dummy_dc = hdc;
|
||||
m_pbuffer = pbuffer;
|
||||
|
||||
pbuffer_guard.Cancel();
|
||||
hdc_guard.Cancel();
|
||||
hwnd_guard.Cancel();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#include <optional>
|
||||
|
||||
namespace GL
|
||||
{
|
||||
@@ -48,12 +49,24 @@ namespace GL
|
||||
private:
|
||||
__fi HWND GetHWND() const { return static_cast<HWND>(m_wi.window_handle); }
|
||||
|
||||
HDC GetDCAndSetPixelFormat(HWND hwnd);
|
||||
|
||||
bool Initialize(const Version* versions_to_try, size_t num_versions_to_try);
|
||||
bool InitializeDC();
|
||||
void ReleaseDC();
|
||||
bool CreatePBuffer();
|
||||
bool CreateAnyContext(HGLRC share_context, bool make_current);
|
||||
bool CreateVersionContext(const Version& version, HGLRC share_context, bool make_current);
|
||||
|
||||
HDC m_dc = {};
|
||||
HGLRC m_rc = {};
|
||||
|
||||
// Can't change pixel format once it's set for a RC.
|
||||
std::optional<int> m_pixel_format;
|
||||
|
||||
// Dummy window for creating a PBuffer off when we're surfaceless.
|
||||
HWND m_dummy_window = {};
|
||||
HDC m_dummy_dc = {};
|
||||
HPBUFFERARB m_pbuffer = {};
|
||||
};
|
||||
} // namespace GL
|
||||
@@ -160,6 +160,8 @@ extern u64 GetPhysicalMemory();
|
||||
extern u32 ShortSpin();
|
||||
/// Number of ns to spin for before sleeping a thread
|
||||
extern const u32 SPIN_TIME_NS;
|
||||
/// Like C abort() but adds the given message to the crashlog
|
||||
[[noreturn]] void AbortWithMessage(const char* msg);
|
||||
|
||||
extern std::string GetOSVersionString();
|
||||
|
||||
|
||||
@@ -71,3 +71,31 @@ static u32 GetSpinTime()
|
||||
}
|
||||
|
||||
const u32 SPIN_TIME_NS = GetSpinTime();
|
||||
|
||||
#ifdef __APPLE__
|
||||
// https://alastairs-place.net/blog/2013/01/10/interesting-os-x-crash-report-tidbits/
|
||||
// https://opensource.apple.com/source/WebKit2/WebKit2-7608.3.10.0.3/Platform/spi/Cocoa/CrashReporterClientSPI.h.auto.html
|
||||
struct crash_info_t
|
||||
{
|
||||
u64 version;
|
||||
u64 message;
|
||||
u64 signature;
|
||||
u64 backtrace;
|
||||
u64 message2;
|
||||
u64 reserved;
|
||||
u64 reserved2;
|
||||
};
|
||||
#define CRASH_ANNOTATION __attribute__((section("__DATA,__crash_info")))
|
||||
#define CRASH_VERSION 4
|
||||
extern "C" crash_info_t gCRAnnotations CRASH_ANNOTATION = { CRASH_VERSION };
|
||||
#endif
|
||||
|
||||
void AbortWithMessage(const char* msg)
|
||||
{
|
||||
#ifdef __APPLE__
|
||||
gCRAnnotations.message = reinterpret_cast<size_t>(msg);
|
||||
// Some macOS's seem to have issues displaying non-static `message`s, so throw it in here too
|
||||
gCRAnnotations.backtrace = gCRAnnotations.message;
|
||||
#endif
|
||||
abort();
|
||||
}
|
||||
|
||||
@@ -42,11 +42,12 @@ public:
|
||||
virtual void SetBoolValue(const char* section, const char* key, bool value) = 0;
|
||||
virtual void SetStringValue(const char* section, const char* key, const char* value) = 0;
|
||||
|
||||
virtual std::vector<std::string> GetStringList(const char* section, const char* key) = 0;
|
||||
virtual std::vector<std::string> GetStringList(const char* section, const char* key) const = 0;
|
||||
virtual void SetStringList(const char* section, const char* key, const std::vector<std::string>& items) = 0;
|
||||
virtual bool RemoveFromStringList(const char* section, const char* key, const char* item) = 0;
|
||||
virtual bool AddToStringList(const char* section, const char* key, const char* item) = 0;
|
||||
|
||||
virtual bool ContainsValue(const char* section, const char* key) const = 0;
|
||||
virtual void DeleteValue(const char* section, const char* key) = 0;
|
||||
virtual void ClearSection(const char* section) = 0;
|
||||
|
||||
@@ -153,4 +154,67 @@ public:
|
||||
{
|
||||
value.has_value() ? SetStringValue(section, key, value.value()) : DeleteValue(section, key);
|
||||
}
|
||||
|
||||
__fi void CopyBoolValue(const SettingsInterface& si, const char* section, const char* key)
|
||||
{
|
||||
bool value;
|
||||
if (si.GetBoolValue(section, key, &value))
|
||||
SetBoolValue(section, key, value);
|
||||
else
|
||||
DeleteValue(section, key);
|
||||
}
|
||||
|
||||
__fi void CopyIntValue(const SettingsInterface& si, const char* section, const char* key)
|
||||
{
|
||||
int value;
|
||||
if (si.GetIntValue(section, key, &value))
|
||||
SetIntValue(section, key, value);
|
||||
else
|
||||
DeleteValue(section, key);
|
||||
}
|
||||
|
||||
__fi void CopyUIntValue(const SettingsInterface& si, const char* section, const char* key)
|
||||
{
|
||||
uint value;
|
||||
if (si.GetUIntValue(section, key, &value))
|
||||
SetUIntValue(section, key, value);
|
||||
else
|
||||
DeleteValue(section, key);
|
||||
}
|
||||
|
||||
__fi void CopyFloatValue(const SettingsInterface& si, const char* section, const char* key)
|
||||
{
|
||||
float value;
|
||||
if (si.GetFloatValue(section, key, &value))
|
||||
SetFloatValue(section, key, value);
|
||||
else
|
||||
DeleteValue(section, key);
|
||||
}
|
||||
|
||||
__fi void CopyDoubleValue(const SettingsInterface& si, const char* section, const char* key)
|
||||
{
|
||||
double value;
|
||||
if (si.GetDoubleValue(section, key, &value))
|
||||
SetDoubleValue(section, key, value);
|
||||
else
|
||||
DeleteValue(section, key);
|
||||
}
|
||||
|
||||
__fi void CopyStringValue(const SettingsInterface& si, const char* section, const char* key)
|
||||
{
|
||||
std::string value;
|
||||
if (si.GetStringValue(section, key, &value))
|
||||
SetStringValue(section, key, value.c_str());
|
||||
else
|
||||
DeleteValue(section, key);
|
||||
}
|
||||
|
||||
__fi void CopyStringListValue(const SettingsInterface& si, const char* section, const char* key)
|
||||
{
|
||||
std::vector<std::string> value(si.GetStringList(section, key));
|
||||
if (!value.empty())
|
||||
SetStringList(section, key, value);
|
||||
else
|
||||
DeleteValue(section, key);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -634,8 +634,14 @@ namespace Vulkan
|
||||
vkGetDeviceQueue(m_device, m_present_queue_family_index, 0, &m_present_queue);
|
||||
}
|
||||
|
||||
m_gpu_timing_supported = (queue_family_properties[m_graphics_queue_family_index].timestampValidBits > 0);
|
||||
DevCon.WriteLn("GPU timing is %s", m_gpu_timing_supported ? "supported" : "not supported");
|
||||
m_gpu_timing_supported = (m_device_properties.limits.timestampComputeAndGraphics != 0 &&
|
||||
queue_family_properties[m_graphics_queue_family_index].timestampValidBits > 0 &&
|
||||
m_device_properties.limits.timestampPeriod > 0);
|
||||
DevCon.WriteLn("GPU timing is %s (TS=%u TS valid bits=%u, TS period=%f)",
|
||||
m_gpu_timing_supported ? "supported" : "not supported",
|
||||
static_cast<u32>(m_device_properties.limits.timestampComputeAndGraphics),
|
||||
queue_family_properties[m_graphics_queue_family_index].timestampValidBits,
|
||||
m_device_properties.limits.timestampPeriod);
|
||||
|
||||
ProcessDeviceExtensions();
|
||||
return true;
|
||||
@@ -845,6 +851,7 @@ namespace Vulkan
|
||||
if (res != VK_SUCCESS)
|
||||
{
|
||||
LOG_VULKAN_ERROR(res, "vkCreateQueryPool failed: ");
|
||||
m_gpu_timing_supported = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -959,9 +966,10 @@ namespace Vulkan
|
||||
return time;
|
||||
}
|
||||
|
||||
void Context::SetEnableGPUTiming(bool enabled)
|
||||
bool Context::SetEnableGPUTiming(bool enabled)
|
||||
{
|
||||
m_gpu_timing_enabled = enabled && m_gpu_timing_supported;
|
||||
return (enabled == m_gpu_timing_enabled);
|
||||
}
|
||||
|
||||
void Context::WaitForCommandBufferCompletion(u32 index)
|
||||
@@ -1199,8 +1207,8 @@ namespace Vulkan
|
||||
// if we didn't write the timestamp at the start of the cmdbuffer (just enabled timing), the first TS will be zero
|
||||
if (timestamps[0] > 0)
|
||||
{
|
||||
const u64 ns_diff = (timestamps[1] - timestamps[0]) * static_cast<u64>(m_device_properties.limits.timestampPeriod);
|
||||
m_accumulated_gpu_time += static_cast<double>(ns_diff) / 1000000.0;
|
||||
const double ns_diff = (timestamps[1] - timestamps[0]) * static_cast<double>(m_device_properties.limits.timestampPeriod);
|
||||
m_accumulated_gpu_time += ns_diff / 1000000.0;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -221,7 +221,7 @@ namespace Vulkan
|
||||
void WaitForGPUIdle();
|
||||
|
||||
float GetAndResetAccumulatedGPUTime();
|
||||
void SetEnableGPUTiming(bool enabled);
|
||||
bool SetEnableGPUTiming(bool enabled);
|
||||
|
||||
private:
|
||||
Context(VkInstance instance, VkPhysicalDevice physical_device);
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
<PropertyGroup>
|
||||
<MocDefines></MocDefines>
|
||||
<MocDefines Condition="!$(Configuration.Contains(Debug))">-DQT_NO_DEBUG -DNDEBUG $(MocDefines)</MocDefines>
|
||||
<MocIncludes>"-I$(QtIncludeDir)" "-I$(SolutionDir)pcsx2" "-I$(SolutionDir)" -I.</MocIncludes>
|
||||
<MocIncludes>-I"$(QtIncludeDir)." -I"$(SolutionDir)pcsx2" "-I$(SolutionDir)." -I.</MocIncludes>
|
||||
</PropertyGroup>
|
||||
<Target Name="QtMoc"
|
||||
BeforeTargets="ClCompile"
|
||||
|
||||
@@ -60,12 +60,16 @@ target_sources(pcsx2-qt PRIVATE
|
||||
Settings/ControllerSettingsDialog.cpp
|
||||
Settings/ControllerSettingsDialog.h
|
||||
Settings/ControllerSettingsDialog.ui
|
||||
Settings/ControllerSettingWidgetBinder.h
|
||||
Settings/CreateMemoryCardDialog.cpp
|
||||
Settings/CreateMemoryCardDialog.h
|
||||
Settings/CreateMemoryCardDialog.ui
|
||||
Settings/EmulationSettingsWidget.cpp
|
||||
Settings/EmulationSettingsWidget.h
|
||||
Settings/EmulationSettingsWidget.ui
|
||||
Settings/FolderSettingsWidget.cpp
|
||||
Settings/FolderSettingsWidget.h
|
||||
Settings/FolderSettingsWidget.ui
|
||||
Settings/GameFixSettingsWidget.cpp
|
||||
Settings/GameFixSettingsWidget.h
|
||||
Settings/GameFixSettingsWidget.ui
|
||||
|
||||
+152
-30
@@ -21,6 +21,7 @@
|
||||
#include "EmuThread.h"
|
||||
#include "MainWindow.h"
|
||||
#include "QtHost.h"
|
||||
#include "QtUtils.h"
|
||||
|
||||
#include "pcsx2/GS/GSIntrin.h" // _BitScanForward
|
||||
|
||||
@@ -33,7 +34,9 @@
|
||||
#include <QtGui/QWindowStateChangeEvent>
|
||||
#include <cmath>
|
||||
|
||||
#if !defined(_WIN32) && !defined(APPLE)
|
||||
#if defined(_WIN32)
|
||||
#include "common/RedtapeWindows.h"
|
||||
#elif !defined(APPLE)
|
||||
#include <qpa/qplatformnativeinterface.h>
|
||||
#endif
|
||||
|
||||
@@ -50,7 +53,13 @@ DisplayWidget::DisplayWidget(QWidget* parent)
|
||||
setMouseTracking(true);
|
||||
}
|
||||
|
||||
DisplayWidget::~DisplayWidget() = default;
|
||||
DisplayWidget::~DisplayWidget()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (m_clip_mouse_enabled)
|
||||
ClipCursor(nullptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
qreal DisplayWidget::devicePixelRatioFromScreen() const
|
||||
{
|
||||
@@ -110,27 +119,96 @@ std::optional<WindowInfo> DisplayWidget::getWindowInfo()
|
||||
return wi;
|
||||
}
|
||||
|
||||
void DisplayWidget::setRelativeMode(bool enabled)
|
||||
void DisplayWidget::updateRelativeMode(bool master_enable)
|
||||
{
|
||||
if (m_relative_mouse_enabled == enabled)
|
||||
bool relative_mode = master_enable && InputManager::HasPointerAxisBinds();
|
||||
|
||||
#ifdef _WIN32
|
||||
// prefer ClipCursor() over warping movement when we're using raw input
|
||||
bool clip_cursor = relative_mode && false /*InputManager::IsUsingRawInput()*/;
|
||||
if (m_relative_mouse_enabled == relative_mode && m_clip_mouse_enabled == clip_cursor)
|
||||
return;
|
||||
|
||||
if (enabled)
|
||||
{
|
||||
m_relative_mouse_start_position = QCursor::pos();
|
||||
DevCon.WriteLn("updateRelativeMode(): relative=%s, clip=%s", relative_mode ? "yes" : "no", clip_cursor ? "yes" : "no");
|
||||
|
||||
const QPoint center_pos = mapToGlobal(QPoint(width() / 2, height() / 2));
|
||||
QCursor::setPos(center_pos);
|
||||
m_relative_mouse_last_position = center_pos;
|
||||
if (!clip_cursor && m_clip_mouse_enabled)
|
||||
{
|
||||
m_clip_mouse_enabled = false;
|
||||
ClipCursor(nullptr);
|
||||
}
|
||||
#else
|
||||
if (m_relative_mouse_enabled == relative_mode)
|
||||
return;
|
||||
|
||||
DevCon.WriteLn("updateRelativeMode(): relative=%s", relative_mode ? "yes" : "no");
|
||||
#endif
|
||||
|
||||
if (relative_mode)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
m_relative_mouse_enabled = !clip_cursor;
|
||||
m_clip_mouse_enabled = clip_cursor;
|
||||
#else
|
||||
m_relative_mouse_enabled = true;
|
||||
#endif
|
||||
m_relative_mouse_start_pos = QCursor::pos();
|
||||
updateCenterPos();
|
||||
grabMouse();
|
||||
}
|
||||
else
|
||||
else if (m_relative_mouse_enabled)
|
||||
{
|
||||
QCursor::setPos(m_relative_mouse_start_position);
|
||||
m_relative_mouse_enabled = false;
|
||||
QCursor::setPos(m_relative_mouse_start_pos);
|
||||
releaseMouse();
|
||||
}
|
||||
|
||||
m_relative_mouse_enabled = enabled;
|
||||
}
|
||||
|
||||
void DisplayWidget::updateCursor(bool master_enable)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
const bool hide = master_enable && (m_should_hide_cursor || m_relative_mouse_enabled || m_clip_mouse_enabled);
|
||||
#else
|
||||
const bool hide = master_enable && (m_should_hide_cursor || m_relative_mouse_enabled);
|
||||
#endif
|
||||
if (m_cursor_hidden == hide)
|
||||
return;
|
||||
|
||||
m_cursor_hidden = hide;
|
||||
if (hide)
|
||||
setCursor(Qt::BlankCursor);
|
||||
else
|
||||
unsetCursor();
|
||||
}
|
||||
|
||||
void DisplayWidget::updateCenterPos()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (m_clip_mouse_enabled)
|
||||
{
|
||||
RECT rc;
|
||||
if (GetWindowRect(reinterpret_cast<HWND>(winId()), &rc))
|
||||
ClipCursor(&rc);
|
||||
}
|
||||
else if (m_relative_mouse_enabled)
|
||||
{
|
||||
RECT rc;
|
||||
if (GetWindowRect(reinterpret_cast<HWND>(winId()), &rc))
|
||||
{
|
||||
m_relative_mouse_center_pos.setX(((rc.right - rc.left) / 2) + rc.left);
|
||||
m_relative_mouse_center_pos.setY(((rc.bottom - rc.top) / 2) + rc.top);
|
||||
SetCursorPos(m_relative_mouse_center_pos.x(), m_relative_mouse_center_pos.y());
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (m_relative_mouse_enabled)
|
||||
{
|
||||
// we do a round trip here because these coordinates are dpi-unscaled
|
||||
m_relative_mouse_center_pos = mapToGlobal(QPoint((width() + 1) / 2, (height() + 1) / 2));
|
||||
QCursor::setPos(m_relative_mouse_center_pos);
|
||||
m_relative_mouse_center_pos = QCursor::pos();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
QPaintEngine* DisplayWidget::paintEngine() const
|
||||
@@ -157,7 +235,8 @@ bool DisplayWidget::event(QEvent* event)
|
||||
// but I can't think of a better way of handling it, and there doesn't appear to be
|
||||
// any window flag which changes this behavior that I can see.
|
||||
|
||||
const int key = key_event->key();
|
||||
const u32 key = QtUtils::KeyEventToCode(key_event);
|
||||
const Qt::KeyboardModifiers modifiers = key_event->modifiers();
|
||||
const bool pressed = (key_event->type() == QEvent::KeyPress);
|
||||
const auto it = std::find(m_keys_pressed_with_modifiers.begin(), m_keys_pressed_with_modifiers.end(), key);
|
||||
if (it != m_keys_pressed_with_modifiers.end())
|
||||
@@ -167,12 +246,15 @@ bool DisplayWidget::event(QEvent* event)
|
||||
else
|
||||
m_keys_pressed_with_modifiers.erase(it);
|
||||
}
|
||||
else if (key_event->modifiers() != Qt::NoModifier && pressed)
|
||||
else if (modifiers != Qt::NoModifier && modifiers != Qt::KeypadModifier && pressed)
|
||||
{
|
||||
m_keys_pressed_with_modifiers.push_back(key);
|
||||
}
|
||||
|
||||
emit windowKeyEvent(key, pressed);
|
||||
Host::RunOnCPUThread([key, pressed]() {
|
||||
InputManager::InvokeEvents(InputManager::MakeHostKeyboardKey(key), static_cast<float>(pressed));
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -184,22 +266,39 @@ bool DisplayWidget::event(QEvent* event)
|
||||
{
|
||||
const qreal dpr = devicePixelRatioFromScreen();
|
||||
const QPoint mouse_pos = mouse_event->pos();
|
||||
const int scaled_x = static_cast<int>(static_cast<qreal>(mouse_pos.x()) * dpr);
|
||||
const int scaled_y = static_cast<int>(static_cast<qreal>(mouse_pos.y()) * dpr);
|
||||
|
||||
windowMouseMoveEvent(scaled_x, scaled_y);
|
||||
const float scaled_x = static_cast<float>(static_cast<qreal>(mouse_pos.x()) * dpr);
|
||||
const float scaled_y = static_cast<float>(static_cast<qreal>(mouse_pos.y()) * dpr);
|
||||
InputManager::UpdatePointerAbsolutePosition(0, scaled_x, scaled_y);
|
||||
}
|
||||
else
|
||||
{
|
||||
const QPoint center_pos = mapToGlobal(QPoint((width() + 1) / 2, (height() + 1) / 2));
|
||||
const QPoint mouse_pos = mapToGlobal(mouse_event->pos());
|
||||
// On windows, we use winapi here. The reason being that the coordinates in QCursor
|
||||
// are un-dpi-scaled, so we lose precision at higher desktop scalings.
|
||||
float dx = 0.0f, dy = 0.0f;
|
||||
|
||||
const int dx = mouse_pos.x() - center_pos.x();
|
||||
const int dy = mouse_pos.y() - center_pos.y();
|
||||
m_relative_mouse_last_position.setX(m_relative_mouse_last_position.x() + dx);
|
||||
m_relative_mouse_last_position.setY(m_relative_mouse_last_position.y() + dy);
|
||||
windowMouseMoveEvent(m_relative_mouse_last_position.x(), m_relative_mouse_last_position.y());
|
||||
QCursor::setPos(center_pos);
|
||||
#ifndef _WIN32
|
||||
const QPoint mouse_pos = QCursor::pos();
|
||||
if (mouse_pos != m_relative_mouse_center_pos)
|
||||
{
|
||||
dx = static_cast<float>(mouse_pos.x() - m_relative_mouse_center_pos.x());
|
||||
dy = static_cast<float>(mouse_pos.y() - m_relative_mouse_center_pos.y());
|
||||
QCursor::setPos(m_relative_mouse_center_pos);
|
||||
}
|
||||
#else
|
||||
POINT mouse_pos;
|
||||
if (GetCursorPos(&mouse_pos))
|
||||
{
|
||||
dx = static_cast<float>(mouse_pos.x - m_relative_mouse_center_pos.x());
|
||||
dy = static_cast<float>(mouse_pos.y - m_relative_mouse_center_pos.y());
|
||||
SetCursorPos(m_relative_mouse_center_pos.x(), m_relative_mouse_center_pos.y());
|
||||
}
|
||||
#endif
|
||||
|
||||
if (dx != 0.0f)
|
||||
InputManager::UpdatePointerRelativeDelta(0, InputPointerAxis::X, dx);
|
||||
if (dy != 0.0f)
|
||||
InputManager::UpdatePointerRelativeDelta(0, InputPointerAxis::Y, dy);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -211,10 +310,16 @@ bool DisplayWidget::event(QEvent* event)
|
||||
{
|
||||
unsigned long button_index;
|
||||
if (_BitScanForward(&button_index, static_cast<u32>(static_cast<const QMouseEvent*>(event)->button())))
|
||||
emit windowMouseButtonEvent(static_cast<int>(button_index + 1u), event->type() != QEvent::MouseButtonRelease);
|
||||
{
|
||||
Host::RunOnCPUThread([button_index, pressed = (event->type() != QEvent::MouseButtonRelease)]() {
|
||||
InputManager::InvokeEvents(InputManager::MakePointerButtonKey(0, button_index), static_cast<float>(pressed));
|
||||
});
|
||||
}
|
||||
|
||||
// don't toggle fullscreen when we're bound.. that wouldn't end well.
|
||||
if (event->type() == QEvent::MouseButtonDblClick &&
|
||||
static_cast<const QMouseEvent*>(event)->button() == Qt::LeftButton &&
|
||||
!InputManager::HasAnyBindingsForKey(InputManager::MakePointerButtonKey(0, 0)) &&
|
||||
Host::GetBoolSettingValue("UI", "DoubleClickTogglesFullscreen", true))
|
||||
{
|
||||
g_emu_thread->toggleFullscreen();
|
||||
@@ -225,8 +330,18 @@ bool DisplayWidget::event(QEvent* event)
|
||||
|
||||
case QEvent::Wheel:
|
||||
{
|
||||
const QWheelEvent* wheel_event = static_cast<QWheelEvent*>(event);
|
||||
emit windowMouseWheelEvent(wheel_event->angleDelta());
|
||||
// wheel delta is 120 as in winapi
|
||||
const QPoint delta_angle(static_cast<QWheelEvent*>(event)->angleDelta());
|
||||
constexpr float DELTA = 120.0f;
|
||||
|
||||
const float dx = std::clamp(static_cast<float>(delta_angle.x()) / DELTA, -1.0f, 1.0f);
|
||||
if (dx != 0.0f)
|
||||
InputManager::UpdatePointerRelativeDelta(0, InputPointerAxis::WheelX, dx);
|
||||
|
||||
const float dy = std::clamp(static_cast<float>(delta_angle.y()) / DELTA, -1.0f, 1.0f);
|
||||
if (dy != 0.0f)
|
||||
InputManager::UpdatePointerRelativeDelta(0, InputPointerAxis::WheelY, dy);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -249,6 +364,13 @@ bool DisplayWidget::event(QEvent* event)
|
||||
emit windowResizedEvent(scaled_width, scaled_height, dpr);
|
||||
}
|
||||
|
||||
updateCenterPos();
|
||||
return true;
|
||||
}
|
||||
|
||||
case QEvent::Move:
|
||||
{
|
||||
updateCenterPos();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -30,30 +30,37 @@ public:
|
||||
|
||||
QPaintEngine* paintEngine() const override;
|
||||
|
||||
__fi void setShouldHideCursor(bool hide) { m_should_hide_cursor = hide; }
|
||||
|
||||
int scaledWindowWidth() const;
|
||||
int scaledWindowHeight() const;
|
||||
qreal devicePixelRatioFromScreen() const;
|
||||
|
||||
std::optional<WindowInfo> getWindowInfo();
|
||||
|
||||
void setRelativeMode(bool enabled);
|
||||
void updateRelativeMode(bool master_enable);
|
||||
void updateCursor(bool master_enable);
|
||||
|
||||
Q_SIGNALS:
|
||||
void windowFocusEvent();
|
||||
void windowResizedEvent(int width, int height, float scale);
|
||||
void windowRestoredEvent();
|
||||
void windowKeyEvent(int key_code, bool pressed);
|
||||
void windowMouseMoveEvent(int x, int y);
|
||||
void windowMouseButtonEvent(int button, bool pressed);
|
||||
void windowMouseWheelEvent(const QPoint& angle_delta);
|
||||
|
||||
protected:
|
||||
bool event(QEvent* event) override;
|
||||
|
||||
private:
|
||||
QPoint m_relative_mouse_start_position{};
|
||||
QPoint m_relative_mouse_last_position{};
|
||||
void updateCenterPos();
|
||||
|
||||
QPoint m_relative_mouse_start_pos{};
|
||||
QPoint m_relative_mouse_center_pos{};
|
||||
bool m_relative_mouse_enabled = false;
|
||||
#ifdef _WIN32
|
||||
bool m_clip_mouse_enabled = false;
|
||||
#endif
|
||||
bool m_should_hide_cursor = false;
|
||||
bool m_cursor_hidden = false;
|
||||
|
||||
std::vector<int> m_keys_pressed_with_modifiers;
|
||||
|
||||
u32 m_last_window_width = 0;
|
||||
|
||||
+23
-38
@@ -47,7 +47,6 @@
|
||||
#include "QtUtils.h"
|
||||
|
||||
EmuThread* g_emu_thread = nullptr;
|
||||
WindowInfo g_gs_window_info;
|
||||
|
||||
static std::unique_ptr<HostDisplay> s_host_display;
|
||||
|
||||
@@ -412,6 +411,17 @@ void EmuThread::reloadGameSettings()
|
||||
}
|
||||
}
|
||||
|
||||
void EmuThread::updateEmuFolders()
|
||||
{
|
||||
if (!isOnEmuThread())
|
||||
{
|
||||
QMetaObject::invokeMethod(this, &EmuThread::updateEmuFolders, Qt::QueuedConnection);
|
||||
return;
|
||||
}
|
||||
|
||||
Host::Internal::UpdateEmuFolders();
|
||||
}
|
||||
|
||||
void EmuThread::loadOurSettings()
|
||||
{
|
||||
m_verbose_status = Host::GetBaseBoolSettingValue("UI", "VerboseStatusBar", false);
|
||||
@@ -419,6 +429,8 @@ void EmuThread::loadOurSettings()
|
||||
|
||||
void EmuThread::checkForSettingChanges()
|
||||
{
|
||||
QMetaObject::invokeMethod(g_main_window, &MainWindow::checkForSettingChanges, Qt::QueuedConnection);
|
||||
|
||||
if (VMManager::HasValidVM())
|
||||
{
|
||||
const bool render_to_main = Host::GetBaseBoolSettingValue("UI", "RenderToMainWindow", true);
|
||||
@@ -504,11 +516,12 @@ void EmuThread::reloadInputSources()
|
||||
|
||||
std::unique_lock<std::mutex> lock = Host::GetSettingsLock();
|
||||
SettingsInterface* si = Host::GetSettingsInterface();
|
||||
SettingsInterface* bindings_si = Host::GetSettingsInterfaceForBindings();
|
||||
InputManager::ReloadSources(*si, lock);
|
||||
|
||||
// skip loading bindings if we're not running, since it'll get done on startup anyway
|
||||
if (VMManager::HasValidVM())
|
||||
InputManager::ReloadBindings(*si);
|
||||
InputManager::ReloadBindings(*si, *bindings_si);
|
||||
}
|
||||
|
||||
void EmuThread::reloadInputBindings()
|
||||
@@ -525,7 +538,8 @@ void EmuThread::reloadInputBindings()
|
||||
|
||||
auto lock = Host::GetSettingsLock();
|
||||
SettingsInterface* si = Host::GetSettingsInterface();
|
||||
InputManager::ReloadBindings(*si);
|
||||
SettingsInterface* bindings_si = Host::GetSettingsInterfaceForBindings();
|
||||
InputManager::ReloadBindings(*si, *bindings_si);
|
||||
}
|
||||
|
||||
void EmuThread::requestDisplaySize(float scale)
|
||||
@@ -583,29 +597,11 @@ void EmuThread::connectDisplaySignals(DisplayWidget* widget)
|
||||
connect(widget, &DisplayWidget::windowFocusEvent, this, &EmuThread::onDisplayWindowFocused);
|
||||
connect(widget, &DisplayWidget::windowResizedEvent, this, &EmuThread::onDisplayWindowResized);
|
||||
// connect(widget, &DisplayWidget::windowRestoredEvent, this, &EmuThread::redrawDisplayWindow);
|
||||
connect(widget, &DisplayWidget::windowKeyEvent, this, &EmuThread::onDisplayWindowKeyEvent);
|
||||
connect(widget, &DisplayWidget::windowMouseMoveEvent, this, &EmuThread::onDisplayWindowMouseMoveEvent);
|
||||
connect(widget, &DisplayWidget::windowMouseButtonEvent, this, &EmuThread::onDisplayWindowMouseButtonEvent);
|
||||
connect(widget, &DisplayWidget::windowMouseWheelEvent, this, &EmuThread::onDisplayWindowMouseWheelEvent);
|
||||
}
|
||||
|
||||
void EmuThread::onDisplayWindowMouseMoveEvent(int x, int y) {}
|
||||
|
||||
void EmuThread::onDisplayWindowMouseButtonEvent(int button, bool pressed)
|
||||
{
|
||||
InputManager::InvokeEvents(InputManager::MakeHostMouseButtonKey(button), pressed ? 1.0f : 0.0f);
|
||||
}
|
||||
|
||||
void EmuThread::onDisplayWindowMouseWheelEvent(const QPoint& delta_angle) {}
|
||||
|
||||
void EmuThread::onDisplayWindowKeyEvent(int key, bool pressed)
|
||||
{
|
||||
InputManager::InvokeEvents(InputManager::MakeHostKeyboardKey(key), pressed ? 1.0f : 0.0f);
|
||||
}
|
||||
|
||||
void EmuThread::onDisplayWindowResized(int width, int height, float scale)
|
||||
{
|
||||
if (!VMManager::HasValidVM())
|
||||
if (!s_host_display)
|
||||
return;
|
||||
|
||||
GetMTGS().ResizeDisplayWindow(width, height, scale);
|
||||
@@ -681,8 +677,6 @@ HostDisplay* EmuThread::acquireHostDisplay(HostDisplay::RenderAPI api)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
g_gs_window_info = s_host_display->GetWindowInfo();
|
||||
|
||||
Console.WriteLn(Color_StrongGreen, "%s Graphics Driver Info:", HostDisplay::RenderAPIToString(s_host_display->GetRenderAPI()));
|
||||
Console.Indent().WriteLn(s_host_display->GetDriverInfo());
|
||||
|
||||
@@ -693,17 +687,8 @@ void EmuThread::releaseHostDisplay()
|
||||
{
|
||||
ImGuiManager::Shutdown();
|
||||
|
||||
if (s_host_display)
|
||||
{
|
||||
s_host_display->DestroyRenderSurface();
|
||||
s_host_display->DestroyRenderDevice();
|
||||
}
|
||||
|
||||
g_gs_window_info = WindowInfo();
|
||||
|
||||
emit onDestroyDisplayRequested();
|
||||
|
||||
s_host_display.reset();
|
||||
emit onDestroyDisplayRequested();
|
||||
}
|
||||
|
||||
HostDisplay* Host::GetHostDisplay()
|
||||
@@ -967,7 +952,7 @@ SysMtgsThread& GetMTGS()
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
BEGIN_HOTKEY_LIST(g_host_hotkeys)
|
||||
DEFINE_HOTKEY("ShutdownVM", "System", "Shut Down Virtual Machine", [](bool pressed) {
|
||||
DEFINE_HOTKEY("ShutdownVM", "System", "Shut Down Virtual Machine", [](s32 pressed) {
|
||||
if (!pressed)
|
||||
{
|
||||
// run it on the host thread, that way we get the confirm prompt (if enabled)
|
||||
@@ -975,16 +960,16 @@ DEFINE_HOTKEY("ShutdownVM", "System", "Shut Down Virtual Machine", [](bool press
|
||||
Q_ARG(bool, true), Q_ARG(bool, true), Q_ARG(bool, true));
|
||||
}
|
||||
})
|
||||
DEFINE_HOTKEY("TogglePause", "System", "Toggle Pause", [](bool pressed) {
|
||||
DEFINE_HOTKEY("TogglePause", "System", "Toggle Pause", [](s32 pressed) {
|
||||
if (!pressed)
|
||||
g_emu_thread->setVMPaused(VMManager::GetState() != VMState::Paused);
|
||||
})
|
||||
DEFINE_HOTKEY("ToggleFullscreen", "General", "Toggle Fullscreen", [](bool pressed) {
|
||||
DEFINE_HOTKEY("ToggleFullscreen", "General", "Toggle Fullscreen", [](s32 pressed) {
|
||||
if (!pressed)
|
||||
g_emu_thread->toggleFullscreen();
|
||||
})
|
||||
// Input Recording Hot Keys
|
||||
DEFINE_HOTKEY("InputRecToggleMode", "Input Recording", "Toggle Recording Mode", [](bool pressed) {
|
||||
DEFINE_HOTKEY("InputRecToggleMode", "Input Recording", "Toggle Recording Mode", [](s32 pressed) {
|
||||
if (!pressed) // ?? - not pressed so it is on key up?
|
||||
{
|
||||
g_InputRecordingControls.RecordModeToggle();
|
||||
|
||||
@@ -70,6 +70,7 @@ public Q_SLOTS:
|
||||
void setSurfaceless(bool surfaceless);
|
||||
void applySettings();
|
||||
void reloadGameSettings();
|
||||
void updateEmuFolders();
|
||||
void toggleSoftwareRendering();
|
||||
void switchRenderer(GSRendererType renderer);
|
||||
void changeDisc(const QString& path);
|
||||
@@ -142,12 +143,8 @@ private:
|
||||
private Q_SLOTS:
|
||||
void stopInThread();
|
||||
void doBackgroundControllerPoll();
|
||||
void onDisplayWindowMouseMoveEvent(int x, int y);
|
||||
void onDisplayWindowMouseButtonEvent(int button, bool pressed);
|
||||
void onDisplayWindowMouseWheelEvent(const QPoint& delta_angle);
|
||||
void onDisplayWindowResized(int width, int height, float scale);
|
||||
void onDisplayWindowFocused();
|
||||
void onDisplayWindowKeyEvent(int key, bool pressed);
|
||||
|
||||
private:
|
||||
QThread* m_ui_thread;
|
||||
|
||||
@@ -92,6 +92,7 @@ void GameListWidget::initialize()
|
||||
m_table_view->horizontalHeader()->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
m_table_view->verticalHeader()->hide();
|
||||
m_table_view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
|
||||
m_table_view->setVerticalScrollMode(QAbstractItemView::ScrollMode::ScrollPerPixel);
|
||||
|
||||
loadTableViewColumnVisibilitySettings();
|
||||
loadTableViewColumnSortSettings();
|
||||
@@ -119,6 +120,8 @@ void GameListWidget::initialize()
|
||||
m_list_view->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
m_list_view->setFrameStyle(QFrame::NoFrame);
|
||||
m_list_view->setSpacing(m_model->getCoverArtSpacing());
|
||||
m_list_view->setVerticalScrollMode(QAbstractItemView::ScrollMode::ScrollPerPixel);
|
||||
|
||||
updateListFont();
|
||||
|
||||
connect(m_list_view->selectionModel(), &QItemSelectionModel::currentChanged, this,
|
||||
|
||||
+6
-5
@@ -26,12 +26,13 @@
|
||||
|
||||
#include "CDVD/CDVD.h"
|
||||
#include "Frontend/GameList.h"
|
||||
#include "Frontend/LogSink.h"
|
||||
|
||||
#include "common/CrashHandler.h"
|
||||
|
||||
static void PrintCommandLineVersion()
|
||||
{
|
||||
QtHost::InitializeEarlyConsole();
|
||||
Host::InitializeEarlyConsole();
|
||||
std::fprintf(stderr, "%s\n", (QtHost::GetAppNameAndVersion() + QtHost::GetAppConfigSuffix()).toUtf8().constData());
|
||||
std::fprintf(stderr, "https://pcsx2.net/\n");
|
||||
std::fprintf(stderr, "\n");
|
||||
@@ -143,7 +144,7 @@ static bool ParseCommandLineOptions(int argc, char* argv[], std::shared_ptr<VMBo
|
||||
}
|
||||
else if (CHECK_ARG("-earlyconsolelog"))
|
||||
{
|
||||
QtHost::InitializeEarlyConsole();
|
||||
Host::InitializeEarlyConsole();
|
||||
continue;
|
||||
}
|
||||
else if (CHECK_ARG("--"))
|
||||
@@ -153,7 +154,7 @@ static bool ParseCommandLineOptions(int argc, char* argv[], std::shared_ptr<VMBo
|
||||
}
|
||||
else if (argv[i][0] == '-')
|
||||
{
|
||||
QtHost::InitializeEarlyConsole();
|
||||
Host::InitializeEarlyConsole();
|
||||
std::fprintf(stderr, "Unknown parameter: '%s'", argv[i]);
|
||||
return false;
|
||||
}
|
||||
@@ -172,7 +173,7 @@ static bool ParseCommandLineOptions(int argc, char* argv[], std::shared_ptr<VMBo
|
||||
// or disc, we don't want to actually start.
|
||||
if (autoboot && !autoboot->source_type.has_value() && autoboot->filename.empty() && autoboot->elf_override.empty())
|
||||
{
|
||||
QtHost::InitializeEarlyConsole();
|
||||
Host::InitializeEarlyConsole();
|
||||
Console.Warning("Skipping autoboot due to no boot parameters.");
|
||||
autoboot.reset();
|
||||
}
|
||||
@@ -181,7 +182,7 @@ static bool ParseCommandLineOptions(int argc, char* argv[], std::shared_ptr<VMBo
|
||||
// scanning the game list).
|
||||
if (QtHost::InBatchMode() && !autoboot)
|
||||
{
|
||||
QtHost::InitializeEarlyConsole();
|
||||
Host::InitializeEarlyConsole();
|
||||
Console.Warning("Disabling batch mode, because we have no autoboot.");
|
||||
QtHost::SetBatchMode(false);
|
||||
}
|
||||
|
||||
+60
-8
@@ -29,6 +29,7 @@
|
||||
|
||||
#include "pcsx2/CDVD/CDVDaccess.h"
|
||||
#include "pcsx2/Frontend/GameList.h"
|
||||
#include "pcsx2/Frontend/LogSink.h"
|
||||
#include "pcsx2/GSDumpReplayer.h"
|
||||
#include "pcsx2/HostDisplay.h"
|
||||
#include "pcsx2/HostSettings.h"
|
||||
@@ -210,6 +211,7 @@ void MainWindow::connectSignals()
|
||||
connect(m_ui.actionAudioSettings, &QAction::triggered, [this]() { doSettings("Audio"); });
|
||||
connect(m_ui.actionMemoryCardSettings, &QAction::triggered, [this]() { doSettings("Memory Cards"); });
|
||||
connect(m_ui.actionDEV9Settings, &QAction::triggered, [this]() { doSettings("Network & HDD"); });
|
||||
connect(m_ui.actionFolderSettings, &QAction::triggered, [this]() { doSettings("Folders"); });
|
||||
connect(
|
||||
m_ui.actionControllerSettings, &QAction::triggered, [this]() { doControllerSettings(ControllerSettingsDialog::Category::GlobalSettings); });
|
||||
connect(m_ui.actionHotkeySettings, &QAction::triggered, [this]() { doControllerSettings(ControllerSettingsDialog::Category::HotkeySettings); });
|
||||
@@ -766,6 +768,11 @@ bool MainWindow::isRenderingToMain() const
|
||||
return (m_display_widget && m_display_widget->parent() == this);
|
||||
}
|
||||
|
||||
bool MainWindow::shouldHideMouseCursor() const
|
||||
{
|
||||
return isRenderingFullscreen() && Host::GetBoolSettingValue("UI", "HideMouseCursor", false);
|
||||
}
|
||||
|
||||
void MainWindow::switchToGameListView()
|
||||
{
|
||||
if (centralWidget() == m_game_list_widget)
|
||||
@@ -843,11 +850,11 @@ bool MainWindow::requestShutdown(bool allow_confirm /* = true */, bool allow_sav
|
||||
if (!VMManager::HasValidVM())
|
||||
return true;
|
||||
|
||||
// if we don't have a crc, we can't save state
|
||||
// If we don't have a crc, we can't save state.
|
||||
allow_save_to_state &= (m_current_game_crc != 0);
|
||||
bool save_state = allow_save_to_state && EmuConfig.SaveStateOnShutdown;
|
||||
|
||||
// only confirm on UI thread because we need to display a msgbox
|
||||
// Only confirm on UI thread because we need to display a msgbox.
|
||||
if (allow_confirm && !GSDumpReplayer::IsReplayingDump() && Host::GetBaseBoolSettingValue("UI", "ConfirmShutdown", true))
|
||||
{
|
||||
VMLock lock(pauseAndLockVM());
|
||||
@@ -868,20 +875,23 @@ bool MainWindow::requestShutdown(bool allow_confirm /* = true */, bool allow_sav
|
||||
return false;
|
||||
|
||||
save_state = save_cb->isChecked();
|
||||
|
||||
// Don't switch back to fullscreen when we're shutting down anyway.
|
||||
lock.cancelResume();
|
||||
}
|
||||
|
||||
g_emu_thread->shutdownVM(save_state);
|
||||
|
||||
if (block_until_done || QtHost::InBatchMode())
|
||||
{
|
||||
// we need to yield here, since the display gets destroyed
|
||||
// We need to yield here, since the display gets destroyed.
|
||||
while (VMManager::GetState() != VMState::Shutdown)
|
||||
QApplication::processEvents(QEventLoop::ExcludeUserInputEvents, 1);
|
||||
}
|
||||
|
||||
if (QtHost::InBatchMode())
|
||||
{
|
||||
// closing the window should shut down everything.
|
||||
// Closing the window should shut down everything.
|
||||
close();
|
||||
}
|
||||
|
||||
@@ -897,6 +907,12 @@ void MainWindow::requestExit()
|
||||
close();
|
||||
}
|
||||
|
||||
void MainWindow::checkForSettingChanges()
|
||||
{
|
||||
if (m_display_widget)
|
||||
m_display_widget->updateRelativeMode(m_vm_valid && !m_vm_paused);
|
||||
}
|
||||
|
||||
void Host::InvalidateSaveStateCache()
|
||||
{
|
||||
QMetaObject::invokeMethod(g_main_window, &MainWindow::invalidateSaveStateCache, Qt::QueuedConnection);
|
||||
@@ -1241,7 +1257,7 @@ void MainWindow::onThemeChangedFromSettings()
|
||||
|
||||
void MainWindow::onLoggingOptionChanged()
|
||||
{
|
||||
QtHost::UpdateLogging();
|
||||
Host::UpdateLogging();
|
||||
}
|
||||
|
||||
void MainWindow::onInputRecNewActionTriggered()
|
||||
@@ -1354,6 +1370,11 @@ void MainWindow::onVMPaused()
|
||||
updateWindowTitle();
|
||||
updateStatusBarWidgetVisibility();
|
||||
m_status_fps_widget->setText(tr("Paused"));
|
||||
if (m_display_widget)
|
||||
{
|
||||
m_display_widget->updateRelativeMode(false);
|
||||
m_display_widget->updateCursor(false);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::onVMResumed()
|
||||
@@ -1370,7 +1391,11 @@ void MainWindow::onVMResumed()
|
||||
updateStatusBarWidgetVisibility();
|
||||
m_status_fps_widget->setText(m_last_fps_status);
|
||||
if (m_display_widget)
|
||||
{
|
||||
m_display_widget->updateRelativeMode(true);
|
||||
m_display_widget->updateCursor(true);
|
||||
m_display_widget->setFocus();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::onVMStopped()
|
||||
@@ -1381,7 +1406,16 @@ void MainWindow::onVMStopped()
|
||||
updateEmulationActions(false, false);
|
||||
updateWindowTitle();
|
||||
updateStatusBarWidgetVisibility();
|
||||
switchToGameListView();
|
||||
|
||||
if (m_display_widget)
|
||||
{
|
||||
m_display_widget->updateRelativeMode(false);
|
||||
m_display_widget->updateCursor(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
switchToGameListView();
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::onGameChanged(const QString& path, const QString& serial, const QString& name, quint32 crc)
|
||||
@@ -1554,6 +1588,10 @@ DisplayWidget* MainWindow::createDisplay(bool fullscreen, bool render_to_main)
|
||||
updateWindowTitle();
|
||||
m_display_widget->setFocus();
|
||||
|
||||
m_display_widget->setShouldHideCursor(shouldHideMouseCursor());
|
||||
m_display_widget->updateRelativeMode(m_vm_valid && !m_vm_paused);
|
||||
m_display_widget->updateCursor(m_vm_valid && !m_vm_paused);
|
||||
|
||||
host_display->DoneRenderContextCurrent();
|
||||
return m_display_widget;
|
||||
}
|
||||
@@ -1597,6 +1635,11 @@ DisplayWidget* MainWindow::updateDisplay(bool fullscreen, bool render_to_main, b
|
||||
container->showNormal();
|
||||
}
|
||||
|
||||
m_display_widget->setFocus();
|
||||
m_display_widget->setShouldHideCursor(shouldHideMouseCursor());
|
||||
m_display_widget->updateRelativeMode(m_vm_valid && !m_vm_paused);
|
||||
m_display_widget->updateCursor(m_vm_valid && !m_vm_paused);
|
||||
|
||||
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
||||
return m_display_widget;
|
||||
}
|
||||
@@ -1676,6 +1719,9 @@ DisplayWidget* MainWindow::updateDisplay(bool fullscreen, bool render_to_main, b
|
||||
|
||||
updateWindowTitle();
|
||||
m_display_widget->setFocus();
|
||||
m_display_widget->setShouldHideCursor(shouldHideMouseCursor());
|
||||
m_display_widget->updateRelativeMode(m_vm_valid && !m_vm_paused);
|
||||
m_display_widget->updateCursor(m_vm_valid && !m_vm_paused);
|
||||
|
||||
QSignalBlocker blocker(m_ui.actionFullscreen);
|
||||
m_ui.actionFullscreen->setChecked(fullscreen);
|
||||
@@ -2045,7 +2091,7 @@ void MainWindow::populateLoadStateMenu(QMenu* menu, const QString& filename, con
|
||||
if (!FileSystem::StatFile(state_filename.c_str(), &sd))
|
||||
continue;
|
||||
|
||||
action = menu->addAction(tr("Save Slot %1 (%2)").arg(i).arg(formatTimestampForSaveStateMenu(sd.ModificationTime)));
|
||||
action = menu->addAction(tr("Load Slot %1 (%2)").arg(i).arg(formatTimestampForSaveStateMenu(sd.ModificationTime)));
|
||||
connect(action, &QAction::triggered, [this, i]() { loadSaveStateSlot(i); });
|
||||
}
|
||||
}
|
||||
@@ -2171,7 +2217,7 @@ MainWindow::VMLock::VMLock(VMLock&& lock)
|
||||
, m_was_fullscreen(lock.m_was_fullscreen)
|
||||
{
|
||||
lock.m_dialog_parent = nullptr;
|
||||
lock.m_was_paused = false;
|
||||
lock.m_was_paused = true;
|
||||
lock.m_was_fullscreen = false;
|
||||
}
|
||||
|
||||
@@ -2183,3 +2229,9 @@ MainWindow::VMLock::~VMLock()
|
||||
g_emu_thread->setVMPaused(false);
|
||||
}
|
||||
|
||||
void MainWindow::VMLock::cancelResume()
|
||||
{
|
||||
m_was_paused = true;
|
||||
m_was_fullscreen = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -93,6 +93,7 @@ public Q_SLOTS:
|
||||
void runOnUIThread(const std::function<void()>& func);
|
||||
bool requestShutdown(bool allow_confirm = true, bool allow_save_to_state = true, bool block_until_done = false);
|
||||
void requestExit();
|
||||
void checkForSettingChanges();
|
||||
|
||||
private Q_SLOTS:
|
||||
void onUpdateCheckComplete();
|
||||
@@ -184,6 +185,7 @@ private:
|
||||
bool isShowingGameList() const;
|
||||
bool isRenderingFullscreen() const;
|
||||
bool isRenderingToMain() const;
|
||||
bool shouldHideMouseCursor() const;
|
||||
void switchToGameListView();
|
||||
void switchToEmulationView();
|
||||
|
||||
|
||||
@@ -93,6 +93,7 @@
|
||||
<addaction name="actionAudioSettings"/>
|
||||
<addaction name="actionMemoryCardSettings"/>
|
||||
<addaction name="actionDEV9Settings"/>
|
||||
<addaction name="actionFolderSettings"/>
|
||||
<addaction name="actionControllerSettings"/>
|
||||
<addaction name="actionHotkeySettings"/>
|
||||
<addaction name="separator"/>
|
||||
@@ -570,6 +571,15 @@
|
||||
<string>&Network && HDD</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionFolderSettings">
|
||||
<property name="icon">
|
||||
<iconset theme="folder-open-line">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Folders</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionViewToolbar">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
|
||||
+2
-365
@@ -38,6 +38,7 @@
|
||||
#include "pcsx2/DebugTools/Debug.h"
|
||||
#include "pcsx2/Frontend/GameList.h"
|
||||
#include "pcsx2/Frontend/INISettingsInterface.h"
|
||||
#include "pcsx2/Frontend/LogSink.h"
|
||||
#include "pcsx2/HostSettings.h"
|
||||
#include "pcsx2/PAD/Host/PAD.h"
|
||||
|
||||
@@ -227,14 +228,6 @@ void QtHost::SetDataDirectory()
|
||||
EmuFolders::DataRoot = EmuFolders::AppRoot;
|
||||
}
|
||||
|
||||
void QtHost::UpdateFolders()
|
||||
{
|
||||
// TODO: This should happen with the VM thread paused.
|
||||
auto lock = Host::GetSettingsLock();
|
||||
EmuFolders::LoadConfig(*s_base_settings_interface.get());
|
||||
EmuFolders::EnsureFoldersExist();
|
||||
}
|
||||
|
||||
bool QtHost::InitializeConfig()
|
||||
{
|
||||
if (!SetCriticalFolders())
|
||||
@@ -260,7 +253,7 @@ bool QtHost::InitializeConfig()
|
||||
// TODO: Handle reset to defaults if load fails.
|
||||
EmuFolders::LoadConfig(*s_base_settings_interface.get());
|
||||
EmuFolders::EnsureFoldersExist();
|
||||
QtHost::UpdateLogging();
|
||||
Host::UpdateLogging();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -511,359 +504,3 @@ void QtHost::HookSignals()
|
||||
std::signal(SIGINT, SignalHandler);
|
||||
std::signal(SIGTERM, SignalHandler);
|
||||
}
|
||||
|
||||
// Used on both Windows and Linux.
|
||||
#ifdef _WIN32
|
||||
static const wchar_t s_console_colors[][ConsoleColors_Count] = {
|
||||
#define CC(x) L ## x
|
||||
#else
|
||||
static const char s_console_colors[][ConsoleColors_Count] = {
|
||||
#define CC(x) x
|
||||
#endif
|
||||
CC("\033[0m"), // default
|
||||
CC("\033[30m\033[1m"), // black
|
||||
CC("\033[32m"), // green
|
||||
CC("\033[31m"), // red
|
||||
CC("\033[34m"), // blue
|
||||
CC("\033[35m"), // magenta
|
||||
CC("\033[35m"), // orange (FIXME)
|
||||
CC("\033[37m"), // gray
|
||||
CC("\033[36m"), // cyan
|
||||
CC("\033[33m"), // yellow
|
||||
CC("\033[37m"), // white
|
||||
CC("\033[30m\033[1m"), // strong black
|
||||
CC("\033[31m\033[1m"), // strong red
|
||||
CC("\033[32m\033[1m"), // strong green
|
||||
CC("\033[34m\033[1m"), // strong blue
|
||||
CC("\033[35m\033[1m"), // strong magenta
|
||||
CC("\033[35m\033[1m"), // strong orange (FIXME)
|
||||
CC("\033[37m\033[1m"), // strong gray
|
||||
CC("\033[36m\033[1m"), // strong cyan
|
||||
CC("\033[33m\033[1m"), // strong yellow
|
||||
CC("\033[37m\033[1m") // strong white
|
||||
};
|
||||
#undef CC
|
||||
|
||||
static Common::Timer::Value s_log_start_timestamp = Common::Timer::GetCurrentValue();
|
||||
static bool s_log_timestamps = false;
|
||||
static std::mutex s_log_mutex;
|
||||
|
||||
// Replacement for Console so we actually get output to our console window on Windows.
|
||||
#ifdef _WIN32
|
||||
|
||||
static bool s_debugger_attached = false;
|
||||
static bool s_console_handle_set = false;
|
||||
static bool s_console_allocated = false;
|
||||
static HANDLE s_console_handle = INVALID_HANDLE_VALUE;
|
||||
static HANDLE s_old_console_stdin = NULL;
|
||||
static HANDLE s_old_console_stdout = NULL;
|
||||
static HANDLE s_old_console_stderr = NULL;
|
||||
|
||||
static BOOL WINAPI ConsoleCtrlHandler(DWORD dwCtrlType)
|
||||
{
|
||||
Console.WriteLn("Handler %u", dwCtrlType);
|
||||
if (dwCtrlType != CTRL_C_EVENT)
|
||||
return FALSE;
|
||||
|
||||
SignalHandler(SIGTERM);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static bool EnableVirtualTerminalProcessing(HANDLE hConsole)
|
||||
{
|
||||
if (hConsole == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
|
||||
DWORD old_mode;
|
||||
if (!GetConsoleMode(hConsole, &old_mode))
|
||||
return false;
|
||||
|
||||
// already enabled?
|
||||
if (old_mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING)
|
||||
return true;
|
||||
|
||||
return SetConsoleMode(hConsole, old_mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void ConsoleQt_SetTitle(const char* title)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
SetConsoleTitleW(StringUtil::UTF8StringToWideString(title).c_str());
|
||||
#else
|
||||
std::fprintf(stdout, "\033]0;%s\007", title);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void ConsoleQt_DoSetColor(ConsoleColors color)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (s_console_handle == INVALID_HANDLE_VALUE)
|
||||
return;
|
||||
|
||||
const wchar_t* colortext = s_console_colors[static_cast<u32>(color)];
|
||||
DWORD written;
|
||||
WriteConsoleW(s_console_handle, colortext, std::wcslen(colortext), &written, nullptr);
|
||||
#else
|
||||
const char* colortext = s_console_colors[static_cast<u32>(color)];
|
||||
std::fputs(colortext, stdout);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void ConsoleQt_DoWrite(const char* fmt)
|
||||
{
|
||||
std::unique_lock lock(s_log_mutex);
|
||||
|
||||
#ifdef _WIN32
|
||||
if (s_console_handle != INVALID_HANDLE_VALUE || s_debugger_attached)
|
||||
{
|
||||
// TODO: Put this on the stack.
|
||||
std::wstring wfmt(StringUtil::UTF8StringToWideString(fmt));
|
||||
|
||||
if (s_debugger_attached)
|
||||
OutputDebugStringW(wfmt.c_str());
|
||||
|
||||
if (s_console_handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
DWORD written;
|
||||
WriteConsoleW(s_console_handle, wfmt.c_str(), static_cast<DWORD>(wfmt.length()), &written, nullptr);
|
||||
}
|
||||
}
|
||||
#else
|
||||
std::fputs(fmt, stdout);
|
||||
std::fputc('\n', stdout);
|
||||
#endif
|
||||
|
||||
if (emuLog)
|
||||
{
|
||||
std::fputs(fmt, emuLog);
|
||||
}
|
||||
}
|
||||
|
||||
static void ConsoleQt_DoWriteLn(const char* fmt)
|
||||
{
|
||||
std::unique_lock lock(s_log_mutex);
|
||||
|
||||
// find time since start of process, but save a syscall if we're not writing timestamps
|
||||
float message_time = s_log_timestamps ?
|
||||
static_cast<float>(
|
||||
Common::Timer::ConvertValueToSeconds(Common::Timer::GetCurrentValue() - s_log_start_timestamp)) :
|
||||
0.0f;
|
||||
|
||||
// split newlines up
|
||||
const char* start = fmt;
|
||||
do
|
||||
{
|
||||
const char* end = std::strchr(start, '\n');
|
||||
|
||||
std::string_view line;
|
||||
if (end)
|
||||
{
|
||||
line = std::string_view(start, end - start);
|
||||
start = end + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
line = std::string_view(start);
|
||||
start = nullptr;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
if (s_console_handle != INVALID_HANDLE_VALUE || s_debugger_attached)
|
||||
{
|
||||
// TODO: Put this on the stack.
|
||||
std::wstring wfmt(StringUtil::UTF8StringToWideString(line));
|
||||
|
||||
if (s_debugger_attached)
|
||||
{
|
||||
// VS already timestamps logs (at least with the productivity power tools).
|
||||
if (!wfmt.empty())
|
||||
OutputDebugStringW(wfmt.c_str());
|
||||
OutputDebugStringW(L"\n");
|
||||
}
|
||||
|
||||
if (s_console_handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
DWORD written;
|
||||
if (s_log_timestamps)
|
||||
{
|
||||
wchar_t timestamp_text[128];
|
||||
const int timestamp_len = _swprintf(timestamp_text, L"[%10.4f] ", message_time);
|
||||
WriteConsoleW(s_console_handle, timestamp_text, static_cast<DWORD>(timestamp_len), &written, nullptr);
|
||||
}
|
||||
|
||||
if (!wfmt.empty())
|
||||
WriteConsoleW(s_console_handle, wfmt.c_str(), static_cast<DWORD>(wfmt.length()), &written, nullptr);
|
||||
|
||||
WriteConsoleW(s_console_handle, L"\n", 1, &written, nullptr);
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (s_log_timestamps)
|
||||
{
|
||||
std::fprintf(stdout, "[%10.4f] %.*s\n", message_time, static_cast<int>(line.length()), line.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!line.empty())
|
||||
std::fwrite(line.data(), line.length(), 1, stdout);
|
||||
std::fputc('\n', stdout);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (emuLog)
|
||||
{
|
||||
if (s_log_timestamps)
|
||||
{
|
||||
std::fprintf(emuLog, "[%10.4f] %.*s\n", message_time, static_cast<int>(line.length()), line.data());
|
||||
}
|
||||
else
|
||||
{
|
||||
std::fwrite(line.data(), line.length(), 1, emuLog);
|
||||
std::fputc('\n', emuLog);
|
||||
}
|
||||
}
|
||||
} while (start);
|
||||
}
|
||||
|
||||
static void ConsoleQt_Newline()
|
||||
{
|
||||
ConsoleQt_DoWriteLn("");
|
||||
}
|
||||
|
||||
static const IConsoleWriter ConsoleWriter_WinQt =
|
||||
{
|
||||
ConsoleQt_DoWrite,
|
||||
ConsoleQt_DoWriteLn,
|
||||
ConsoleQt_DoSetColor,
|
||||
|
||||
ConsoleQt_DoWrite,
|
||||
ConsoleQt_Newline,
|
||||
ConsoleQt_SetTitle,
|
||||
};
|
||||
|
||||
static void UpdateLoggingSinks(bool system_console, bool file_log)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
const bool debugger_attached = IsDebuggerPresent();
|
||||
s_debugger_attached = debugger_attached;
|
||||
if (system_console)
|
||||
{
|
||||
if (!s_console_handle_set)
|
||||
{
|
||||
s_old_console_stdin = GetStdHandle(STD_INPUT_HANDLE);
|
||||
s_old_console_stdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
s_old_console_stderr = GetStdHandle(STD_ERROR_HANDLE);
|
||||
|
||||
bool handle_valid = (GetConsoleWindow() != NULL);
|
||||
if (!handle_valid)
|
||||
{
|
||||
s_console_allocated = AttachConsole(ATTACH_PARENT_PROCESS) || AllocConsole();
|
||||
handle_valid = (GetConsoleWindow() != NULL);
|
||||
}
|
||||
|
||||
if (handle_valid)
|
||||
{
|
||||
s_console_handle = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
if (s_console_handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
s_console_handle_set = true;
|
||||
SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE);
|
||||
|
||||
// This gets us unix-style coloured output.
|
||||
EnableVirtualTerminalProcessing(GetStdHandle(STD_OUTPUT_HANDLE));
|
||||
EnableVirtualTerminalProcessing(GetStdHandle(STD_ERROR_HANDLE));
|
||||
|
||||
// Redirect stdout/stderr.
|
||||
std::FILE* fp;
|
||||
freopen_s(&fp, "CONIN$", "r", stdin);
|
||||
freopen_s(&fp, "CONOUT$", "w", stdout);
|
||||
freopen_s(&fp, "CONOUT$", "w", stderr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// just in case it fails
|
||||
system_console = s_console_handle_set;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (s_console_handle_set)
|
||||
{
|
||||
s_console_handle_set = false;
|
||||
SetConsoleCtrlHandler(ConsoleCtrlHandler, FALSE);
|
||||
|
||||
// redirect stdout/stderr back to null.
|
||||
std::FILE* fp;
|
||||
freopen_s(&fp, "NUL:", "w", stderr);
|
||||
freopen_s(&fp, "NUL:", "w", stdout);
|
||||
freopen_s(&fp, "NUL:", "w", stdin);
|
||||
|
||||
// release console and restore state
|
||||
SetStdHandle(STD_INPUT_HANDLE, s_old_console_stdin);
|
||||
SetStdHandle(STD_OUTPUT_HANDLE, s_old_console_stdout);
|
||||
SetStdHandle(STD_ERROR_HANDLE, s_old_console_stderr);
|
||||
s_old_console_stdin = NULL;
|
||||
s_old_console_stdout = NULL;
|
||||
s_old_console_stderr = NULL;
|
||||
if (s_console_allocated)
|
||||
{
|
||||
s_console_allocated = false;
|
||||
FreeConsole();
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
const bool debugger_attached = false;
|
||||
#endif
|
||||
|
||||
if (file_log)
|
||||
{
|
||||
if (!emuLog)
|
||||
{
|
||||
emuLogName = Path::Combine(EmuFolders::Logs, "emulog.txt");
|
||||
emuLog = FileSystem::OpenCFile(emuLogName.c_str(), "wb");
|
||||
file_log = (emuLog != nullptr);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (emuLog)
|
||||
{
|
||||
std::fclose(emuLog);
|
||||
emuLog = nullptr;
|
||||
emuLogName = {};
|
||||
}
|
||||
}
|
||||
|
||||
// Discard logs completely if there's no sinks.
|
||||
if (debugger_attached || system_console || file_log)
|
||||
Console_SetActiveHandler(ConsoleWriter_WinQt);
|
||||
else
|
||||
Console_SetActiveHandler(ConsoleWriter_Null);
|
||||
}
|
||||
|
||||
void QtHost::InitializeEarlyConsole()
|
||||
{
|
||||
UpdateLoggingSinks(true, false);
|
||||
}
|
||||
|
||||
void QtHost::UpdateLogging()
|
||||
{
|
||||
const bool system_console_enabled = Host::GetBaseBoolSettingValue("Logging", "EnableSystemConsole", false);
|
||||
const bool file_logging_enabled = Host::GetBaseBoolSettingValue("Logging", "EnableFileLogging", false);
|
||||
|
||||
s_log_timestamps = Host::GetBaseBoolSettingValue("Logging", "EnableTimestamps", true);
|
||||
|
||||
const bool any_logging_sinks = system_console_enabled || file_logging_enabled;
|
||||
DevConWriterEnabled = any_logging_sinks && (IsDevBuild || Host::GetBaseBoolSettingValue("Logging", "EnableVerbose", false));
|
||||
SysConsole.eeConsole.Enabled = any_logging_sinks && Host::GetBaseBoolSettingValue("Logging", "EnableEEConsole", false);
|
||||
SysConsole.iopConsole.Enabled = any_logging_sinks && Host::GetBaseBoolSettingValue("Logging", "EnableIOPConsole", false);
|
||||
|
||||
// Input Recording Logs
|
||||
SysConsole.recordingConsole.Enabled = any_logging_sinks && Host::GetBaseBoolSettingValue("Logging", "EnableInputRecordingLogs", true);
|
||||
SysConsole.controlInfo.Enabled = any_logging_sinks && Host::GetBaseBoolSettingValue("Logging", "EnableControllerLogs", false);
|
||||
|
||||
UpdateLoggingSinks(system_console_enabled, file_logging_enabled);
|
||||
}
|
||||
|
||||
@@ -40,12 +40,6 @@ namespace QtHost
|
||||
bool Initialize();
|
||||
void Shutdown();
|
||||
|
||||
void UpdateFolders();
|
||||
void UpdateLogging();
|
||||
|
||||
/// Initializes early console logging (for printing command line arguments).
|
||||
void InitializeEarlyConsole();
|
||||
|
||||
/// Sets batch mode (exit after game shutdown).
|
||||
bool InBatchMode();
|
||||
void SetBatchMode(bool enabled);
|
||||
|
||||
+36
-5
@@ -15,8 +15,14 @@
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "QtUtils.h"
|
||||
|
||||
#include "pcsx2/Frontend/InputManager.h"
|
||||
|
||||
#include "common/StringUtil.h"
|
||||
|
||||
#include <QtGui/QKeyEvent>
|
||||
|
||||
struct KeyCodeName
|
||||
{
|
||||
int code;
|
||||
@@ -465,10 +471,18 @@ static constexpr KeyCodeName s_qt_key_names[] = {
|
||||
|
||||
std::optional<u32> InputManager::ConvertHostKeyboardStringToCode(const std::string_view& str)
|
||||
{
|
||||
std::string compare_name(str);
|
||||
u32 modifier_bits = 0;
|
||||
if (StringUtil::StartsWith(compare_name, "Numpad"))
|
||||
{
|
||||
compare_name = compare_name.substr(6);
|
||||
modifier_bits |= Qt::KeypadModifier;
|
||||
}
|
||||
|
||||
for (const KeyCodeName& name : s_qt_key_names)
|
||||
{
|
||||
if (str == name.name)
|
||||
return static_cast<u32>(name.code);
|
||||
if (compare_name == name.name)
|
||||
return static_cast<u32>(name.code) | modifier_bits;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
@@ -476,11 +490,28 @@ std::optional<u32> InputManager::ConvertHostKeyboardStringToCode(const std::stri
|
||||
|
||||
std::optional<std::string> InputManager::ConvertHostKeyboardCodeToString(u32 code)
|
||||
{
|
||||
std::optional<std::string> ret;
|
||||
|
||||
const u32 modifier_bits = (code & Qt::KeyboardModifierMask);
|
||||
const u32 masked_code = (code & ~Qt::KeyboardModifierMask);
|
||||
|
||||
for (const KeyCodeName& name : s_qt_key_names)
|
||||
{
|
||||
if (static_cast<int>(code) == name.code)
|
||||
return std::string(name.name);
|
||||
if (static_cast<int>(masked_code) == name.code)
|
||||
{
|
||||
if (modifier_bits & Qt::KeypadModifier)
|
||||
ret = fmt::format("Numpad{}", name.name);
|
||||
else
|
||||
ret = std::string(name.name);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
return ret;
|
||||
}
|
||||
|
||||
u32 QtUtils::KeyEventToCode(const QKeyEvent* ev)
|
||||
{
|
||||
return static_cast<u32>(ev->key()) | (static_cast<u32>(ev->modifiers()) & static_cast<u32>(Qt::KeypadModifier));
|
||||
}
|
||||
|
||||
+11
-534
@@ -133,540 +133,6 @@ namespace QtUtils
|
||||
ResizeColumnsForView(view, widths);
|
||||
}
|
||||
|
||||
static const std::map<int, QString> s_qt_key_names = {
|
||||
{Qt::Key_Escape, QStringLiteral("Escape")},
|
||||
{Qt::Key_Tab, QStringLiteral("Tab")},
|
||||
{Qt::Key_Backtab, QStringLiteral("Backtab")},
|
||||
{Qt::Key_Backspace, QStringLiteral("Backspace")},
|
||||
{Qt::Key_Return, QStringLiteral("Return")},
|
||||
{Qt::Key_Enter, QStringLiteral("Enter")},
|
||||
{Qt::Key_Insert, QStringLiteral("Insert")},
|
||||
{Qt::Key_Delete, QStringLiteral("Delete")},
|
||||
{Qt::Key_Pause, QStringLiteral("Pause")},
|
||||
{Qt::Key_Print, QStringLiteral("Print")},
|
||||
{Qt::Key_SysReq, QStringLiteral("SysReq")},
|
||||
{Qt::Key_Clear, QStringLiteral("Clear")},
|
||||
{Qt::Key_Home, QStringLiteral("Home")},
|
||||
{Qt::Key_End, QStringLiteral("End")},
|
||||
{Qt::Key_Left, QStringLiteral("Left")},
|
||||
{Qt::Key_Up, QStringLiteral("Up")},
|
||||
{Qt::Key_Right, QStringLiteral("Right")},
|
||||
{Qt::Key_Down, QStringLiteral("Down")},
|
||||
{Qt::Key_PageUp, QStringLiteral("PageUp")},
|
||||
{Qt::Key_PageDown, QStringLiteral("PageDown")},
|
||||
{Qt::Key_Shift, QStringLiteral("Shift")},
|
||||
{Qt::Key_Control, QStringLiteral("Control")},
|
||||
{Qt::Key_Meta, QStringLiteral("Meta")},
|
||||
{Qt::Key_Alt, QStringLiteral("Alt")},
|
||||
{Qt::Key_CapsLock, QStringLiteral("CapsLock")},
|
||||
{Qt::Key_NumLock, QStringLiteral("NumLock")},
|
||||
{Qt::Key_ScrollLock, QStringLiteral("ScrollLock")},
|
||||
{Qt::Key_F1, QStringLiteral("F1")},
|
||||
{Qt::Key_F2, QStringLiteral("F2")},
|
||||
{Qt::Key_F3, QStringLiteral("F3")},
|
||||
{Qt::Key_F4, QStringLiteral("F4")},
|
||||
{Qt::Key_F5, QStringLiteral("F5")},
|
||||
{Qt::Key_F6, QStringLiteral("F6")},
|
||||
{Qt::Key_F7, QStringLiteral("F7")},
|
||||
{Qt::Key_F8, QStringLiteral("F8")},
|
||||
{Qt::Key_F9, QStringLiteral("F9")},
|
||||
{Qt::Key_F10, QStringLiteral("F10")},
|
||||
{Qt::Key_F11, QStringLiteral("F11")},
|
||||
{Qt::Key_F12, QStringLiteral("F12")},
|
||||
{Qt::Key_F13, QStringLiteral("F13")},
|
||||
{Qt::Key_F14, QStringLiteral("F14")},
|
||||
{Qt::Key_F15, QStringLiteral("F15")},
|
||||
{Qt::Key_F16, QStringLiteral("F16")},
|
||||
{Qt::Key_F17, QStringLiteral("F17")},
|
||||
{Qt::Key_F18, QStringLiteral("F18")},
|
||||
{Qt::Key_F19, QStringLiteral("F19")},
|
||||
{Qt::Key_F20, QStringLiteral("F20")},
|
||||
{Qt::Key_F21, QStringLiteral("F21")},
|
||||
{Qt::Key_F22, QStringLiteral("F22")},
|
||||
{Qt::Key_F23, QStringLiteral("F23")},
|
||||
{Qt::Key_F24, QStringLiteral("F24")},
|
||||
{Qt::Key_F25, QStringLiteral("F25")},
|
||||
{Qt::Key_F26, QStringLiteral("F26")},
|
||||
{Qt::Key_F27, QStringLiteral("F27")},
|
||||
{Qt::Key_F28, QStringLiteral("F28")},
|
||||
{Qt::Key_F29, QStringLiteral("F29")},
|
||||
{Qt::Key_F30, QStringLiteral("F30")},
|
||||
{Qt::Key_F31, QStringLiteral("F31")},
|
||||
{Qt::Key_F32, QStringLiteral("F32")},
|
||||
{Qt::Key_F33, QStringLiteral("F33")},
|
||||
{Qt::Key_F34, QStringLiteral("F34")},
|
||||
{Qt::Key_F35, QStringLiteral("F35")},
|
||||
{Qt::Key_Super_L, QStringLiteral("Super_L")},
|
||||
{Qt::Key_Super_R, QStringLiteral("Super_R")},
|
||||
{Qt::Key_Menu, QStringLiteral("Menu")},
|
||||
{Qt::Key_Hyper_L, QStringLiteral("Hyper_L")},
|
||||
{Qt::Key_Hyper_R, QStringLiteral("Hyper_R")},
|
||||
{Qt::Key_Help, QStringLiteral("Help")},
|
||||
{Qt::Key_Direction_L, QStringLiteral("Direction_L")},
|
||||
{Qt::Key_Direction_R, QStringLiteral("Direction_R")},
|
||||
{Qt::Key_Space, QStringLiteral("Space")},
|
||||
{Qt::Key_Any, QStringLiteral("Any")},
|
||||
{Qt::Key_Exclam, QStringLiteral("Exclam")},
|
||||
{Qt::Key_QuoteDbl, QStringLiteral("QuoteDbl")},
|
||||
{Qt::Key_NumberSign, QStringLiteral("NumberSign")},
|
||||
{Qt::Key_Dollar, QStringLiteral("Dollar")},
|
||||
{Qt::Key_Percent, QStringLiteral("Percent")},
|
||||
{Qt::Key_Ampersand, QStringLiteral("Ampersand")},
|
||||
{Qt::Key_Apostrophe, QStringLiteral("Apostrophe")},
|
||||
{Qt::Key_ParenLeft, QStringLiteral("ParenLeft")},
|
||||
{Qt::Key_ParenRight, QStringLiteral("ParenRight")},
|
||||
{Qt::Key_Asterisk, QStringLiteral("Asterisk")},
|
||||
{Qt::Key_Plus, QStringLiteral("Plus")},
|
||||
{Qt::Key_Comma, QStringLiteral("Comma")},
|
||||
{Qt::Key_Minus, QStringLiteral("Minus")},
|
||||
{Qt::Key_Period, QStringLiteral("Period")},
|
||||
{Qt::Key_Slash, QStringLiteral("Slash")},
|
||||
{Qt::Key_0, QStringLiteral("0")},
|
||||
{Qt::Key_1, QStringLiteral("1")},
|
||||
{Qt::Key_2, QStringLiteral("2")},
|
||||
{Qt::Key_3, QStringLiteral("3")},
|
||||
{Qt::Key_4, QStringLiteral("4")},
|
||||
{Qt::Key_5, QStringLiteral("5")},
|
||||
{Qt::Key_6, QStringLiteral("6")},
|
||||
{Qt::Key_7, QStringLiteral("7")},
|
||||
{Qt::Key_8, QStringLiteral("8")},
|
||||
{Qt::Key_9, QStringLiteral("9")},
|
||||
{Qt::Key_Colon, QStringLiteral("Colon")},
|
||||
{Qt::Key_Semicolon, QStringLiteral("Semicolon")},
|
||||
{Qt::Key_Less, QStringLiteral("Less")},
|
||||
{Qt::Key_Equal, QStringLiteral("Equal")},
|
||||
{Qt::Key_Greater, QStringLiteral("Greater")},
|
||||
{Qt::Key_Question, QStringLiteral("Question")},
|
||||
{Qt::Key_At, QStringLiteral("At")},
|
||||
{Qt::Key_A, QStringLiteral("A")},
|
||||
{Qt::Key_B, QStringLiteral("B")},
|
||||
{Qt::Key_C, QStringLiteral("C")},
|
||||
{Qt::Key_D, QStringLiteral("D")},
|
||||
{Qt::Key_E, QStringLiteral("E")},
|
||||
{Qt::Key_F, QStringLiteral("F")},
|
||||
{Qt::Key_G, QStringLiteral("G")},
|
||||
{Qt::Key_H, QStringLiteral("H")},
|
||||
{Qt::Key_I, QStringLiteral("I")},
|
||||
{Qt::Key_J, QStringLiteral("J")},
|
||||
{Qt::Key_K, QStringLiteral("K")},
|
||||
{Qt::Key_L, QStringLiteral("L")},
|
||||
{Qt::Key_M, QStringLiteral("M")},
|
||||
{Qt::Key_N, QStringLiteral("N")},
|
||||
{Qt::Key_O, QStringLiteral("O")},
|
||||
{Qt::Key_P, QStringLiteral("P")},
|
||||
{Qt::Key_Q, QStringLiteral("Q")},
|
||||
{Qt::Key_R, QStringLiteral("R")},
|
||||
{Qt::Key_S, QStringLiteral("S")},
|
||||
{Qt::Key_T, QStringLiteral("T")},
|
||||
{Qt::Key_U, QStringLiteral("U")},
|
||||
{Qt::Key_V, QStringLiteral("V")},
|
||||
{Qt::Key_W, QStringLiteral("W")},
|
||||
{Qt::Key_X, QStringLiteral("X")},
|
||||
{Qt::Key_Y, QStringLiteral("Y")},
|
||||
{Qt::Key_Z, QStringLiteral("Z")},
|
||||
{Qt::Key_BracketLeft, QStringLiteral("BracketLeft")},
|
||||
{Qt::Key_Backslash, QStringLiteral("Backslash")},
|
||||
{Qt::Key_BracketRight, QStringLiteral("BracketRight")},
|
||||
{Qt::Key_AsciiCircum, QStringLiteral("AsciiCircum")},
|
||||
{Qt::Key_Underscore, QStringLiteral("Underscore")},
|
||||
{Qt::Key_QuoteLeft, QStringLiteral("QuoteLeft")},
|
||||
{Qt::Key_BraceLeft, QStringLiteral("BraceLeft")},
|
||||
{Qt::Key_Bar, QStringLiteral("Bar")},
|
||||
{Qt::Key_BraceRight, QStringLiteral("BraceRight")},
|
||||
{Qt::Key_AsciiTilde, QStringLiteral("AsciiTilde")},
|
||||
{Qt::Key_nobreakspace, QStringLiteral("nobreakspace")},
|
||||
{Qt::Key_exclamdown, QStringLiteral("exclamdown")},
|
||||
{Qt::Key_cent, QStringLiteral("cent")},
|
||||
{Qt::Key_sterling, QStringLiteral("sterling")},
|
||||
{Qt::Key_currency, QStringLiteral("currency")},
|
||||
{Qt::Key_yen, QStringLiteral("yen")},
|
||||
{Qt::Key_brokenbar, QStringLiteral("brokenbar")},
|
||||
{Qt::Key_section, QStringLiteral("section")},
|
||||
{Qt::Key_diaeresis, QStringLiteral("diaeresis")},
|
||||
{Qt::Key_copyright, QStringLiteral("copyright")},
|
||||
{Qt::Key_ordfeminine, QStringLiteral("ordfeminine")},
|
||||
{Qt::Key_guillemotleft, QStringLiteral("guillemotleft")},
|
||||
{Qt::Key_notsign, QStringLiteral("notsign")},
|
||||
{Qt::Key_hyphen, QStringLiteral("hyphen")},
|
||||
{Qt::Key_registered, QStringLiteral("registered")},
|
||||
{Qt::Key_macron, QStringLiteral("macron")},
|
||||
{Qt::Key_degree, QStringLiteral("degree")},
|
||||
{Qt::Key_plusminus, QStringLiteral("plusminus")},
|
||||
{Qt::Key_twosuperior, QStringLiteral("twosuperior")},
|
||||
{Qt::Key_threesuperior, QStringLiteral("threesuperior")},
|
||||
{Qt::Key_acute, QStringLiteral("acute")},
|
||||
{Qt::Key_mu, QStringLiteral("mu")},
|
||||
{Qt::Key_paragraph, QStringLiteral("paragraph")},
|
||||
{Qt::Key_periodcentered, QStringLiteral("periodcentered")},
|
||||
{Qt::Key_cedilla, QStringLiteral("cedilla")},
|
||||
{Qt::Key_onesuperior, QStringLiteral("onesuperior")},
|
||||
{Qt::Key_masculine, QStringLiteral("masculine")},
|
||||
{Qt::Key_guillemotright, QStringLiteral("guillemotright")},
|
||||
{Qt::Key_onequarter, QStringLiteral("onequarter")},
|
||||
{Qt::Key_onehalf, QStringLiteral("onehalf")},
|
||||
{Qt::Key_threequarters, QStringLiteral("threequarters")},
|
||||
{Qt::Key_questiondown, QStringLiteral("questiondown")},
|
||||
{Qt::Key_Agrave, QStringLiteral("Agrave")},
|
||||
{Qt::Key_Aacute, QStringLiteral("Aacute")},
|
||||
{Qt::Key_Acircumflex, QStringLiteral("Acircumflex")},
|
||||
{Qt::Key_Atilde, QStringLiteral("Atilde")},
|
||||
{Qt::Key_Adiaeresis, QStringLiteral("Adiaeresis")},
|
||||
{Qt::Key_Aring, QStringLiteral("Aring")},
|
||||
{Qt::Key_AE, QStringLiteral("AE")},
|
||||
{Qt::Key_Ccedilla, QStringLiteral("Ccedilla")},
|
||||
{Qt::Key_Egrave, QStringLiteral("Egrave")},
|
||||
{Qt::Key_Eacute, QStringLiteral("Eacute")},
|
||||
{Qt::Key_Ecircumflex, QStringLiteral("Ecircumflex")},
|
||||
{Qt::Key_Ediaeresis, QStringLiteral("Ediaeresis")},
|
||||
{Qt::Key_Igrave, QStringLiteral("Igrave")},
|
||||
{Qt::Key_Iacute, QStringLiteral("Iacute")},
|
||||
{Qt::Key_Icircumflex, QStringLiteral("Icircumflex")},
|
||||
{Qt::Key_Idiaeresis, QStringLiteral("Idiaeresis")},
|
||||
{Qt::Key_ETH, QStringLiteral("ETH")},
|
||||
{Qt::Key_Ntilde, QStringLiteral("Ntilde")},
|
||||
{Qt::Key_Ograve, QStringLiteral("Ograve")},
|
||||
{Qt::Key_Oacute, QStringLiteral("Oacute")},
|
||||
{Qt::Key_Ocircumflex, QStringLiteral("Ocircumflex")},
|
||||
{Qt::Key_Otilde, QStringLiteral("Otilde")},
|
||||
{Qt::Key_Odiaeresis, QStringLiteral("Odiaeresis")},
|
||||
{Qt::Key_multiply, QStringLiteral("multiply")},
|
||||
{Qt::Key_Ooblique, QStringLiteral("Ooblique")},
|
||||
{Qt::Key_Ugrave, QStringLiteral("Ugrave")},
|
||||
{Qt::Key_Uacute, QStringLiteral("Uacute")},
|
||||
{Qt::Key_Ucircumflex, QStringLiteral("Ucircumflex")},
|
||||
{Qt::Key_Udiaeresis, QStringLiteral("Udiaeresis")},
|
||||
{Qt::Key_Yacute, QStringLiteral("Yacute")},
|
||||
{Qt::Key_THORN, QStringLiteral("THORN")},
|
||||
{Qt::Key_ssharp, QStringLiteral("ssharp")},
|
||||
{Qt::Key_division, QStringLiteral("division")},
|
||||
{Qt::Key_ydiaeresis, QStringLiteral("ydiaeresis")},
|
||||
{Qt::Key_AltGr, QStringLiteral("AltGr")},
|
||||
{Qt::Key_Multi_key, QStringLiteral("Multi_key")},
|
||||
{Qt::Key_Codeinput, QStringLiteral("Codeinput")},
|
||||
{Qt::Key_SingleCandidate, QStringLiteral("SingleCandidate")},
|
||||
{Qt::Key_MultipleCandidate, QStringLiteral("MultipleCandidate")},
|
||||
{Qt::Key_PreviousCandidate, QStringLiteral("PreviousCandidate")},
|
||||
{Qt::Key_Mode_switch, QStringLiteral("Mode_switch")},
|
||||
{Qt::Key_Kanji, QStringLiteral("Kanji")},
|
||||
{Qt::Key_Muhenkan, QStringLiteral("Muhenkan")},
|
||||
{Qt::Key_Henkan, QStringLiteral("Henkan")},
|
||||
{Qt::Key_Romaji, QStringLiteral("Romaji")},
|
||||
{Qt::Key_Hiragana, QStringLiteral("Hiragana")},
|
||||
{Qt::Key_Katakana, QStringLiteral("Katakana")},
|
||||
{Qt::Key_Hiragana_Katakana, QStringLiteral("Hiragana_Katakana")},
|
||||
{Qt::Key_Zenkaku, QStringLiteral("Zenkaku")},
|
||||
{Qt::Key_Hankaku, QStringLiteral("Hankaku")},
|
||||
{Qt::Key_Zenkaku_Hankaku, QStringLiteral("Zenkaku_Hankaku")},
|
||||
{Qt::Key_Touroku, QStringLiteral("Touroku")},
|
||||
{Qt::Key_Massyo, QStringLiteral("Massyo")},
|
||||
{Qt::Key_Kana_Lock, QStringLiteral("Kana_Lock")},
|
||||
{Qt::Key_Kana_Shift, QStringLiteral("Kana_Shift")},
|
||||
{Qt::Key_Eisu_Shift, QStringLiteral("Eisu_Shift")},
|
||||
{Qt::Key_Eisu_toggle, QStringLiteral("Eisu_toggle")},
|
||||
{Qt::Key_Hangul, QStringLiteral("Hangul")},
|
||||
{Qt::Key_Hangul_Start, QStringLiteral("Hangul_Start")},
|
||||
{Qt::Key_Hangul_End, QStringLiteral("Hangul_End")},
|
||||
{Qt::Key_Hangul_Hanja, QStringLiteral("Hangul_Hanja")},
|
||||
{Qt::Key_Hangul_Jamo, QStringLiteral("Hangul_Jamo")},
|
||||
{Qt::Key_Hangul_Romaja, QStringLiteral("Hangul_Romaja")},
|
||||
{Qt::Key_Hangul_Jeonja, QStringLiteral("Hangul_Jeonja")},
|
||||
{Qt::Key_Hangul_Banja, QStringLiteral("Hangul_Banja")},
|
||||
{Qt::Key_Hangul_PreHanja, QStringLiteral("Hangul_PreHanja")},
|
||||
{Qt::Key_Hangul_PostHanja, QStringLiteral("Hangul_PostHanja")},
|
||||
{Qt::Key_Hangul_Special, QStringLiteral("Hangul_Special")},
|
||||
{Qt::Key_Dead_Grave, QStringLiteral("Dead_Grave")},
|
||||
{Qt::Key_Dead_Acute, QStringLiteral("Dead_Acute")},
|
||||
{Qt::Key_Dead_Circumflex, QStringLiteral("Dead_Circumflex")},
|
||||
{Qt::Key_Dead_Tilde, QStringLiteral("Dead_Tilde")},
|
||||
{Qt::Key_Dead_Macron, QStringLiteral("Dead_Macron")},
|
||||
{Qt::Key_Dead_Breve, QStringLiteral("Dead_Breve")},
|
||||
{Qt::Key_Dead_Abovedot, QStringLiteral("Dead_Abovedot")},
|
||||
{Qt::Key_Dead_Diaeresis, QStringLiteral("Dead_Diaeresis")},
|
||||
{Qt::Key_Dead_Abovering, QStringLiteral("Dead_Abovering")},
|
||||
{Qt::Key_Dead_Doubleacute, QStringLiteral("Dead_Doubleacute")},
|
||||
{Qt::Key_Dead_Caron, QStringLiteral("Dead_Caron")},
|
||||
{Qt::Key_Dead_Cedilla, QStringLiteral("Dead_Cedilla")},
|
||||
{Qt::Key_Dead_Ogonek, QStringLiteral("Dead_Ogonek")},
|
||||
{Qt::Key_Dead_Iota, QStringLiteral("Dead_Iota")},
|
||||
{Qt::Key_Dead_Voiced_Sound, QStringLiteral("Dead_Voiced_Sound")},
|
||||
{Qt::Key_Dead_Semivoiced_Sound, QStringLiteral("Dead_Semivoiced_Sound")},
|
||||
{Qt::Key_Dead_Belowdot, QStringLiteral("Dead_Belowdot")},
|
||||
{Qt::Key_Dead_Hook, QStringLiteral("Dead_Hook")},
|
||||
{Qt::Key_Dead_Horn, QStringLiteral("Dead_Horn")},
|
||||
{Qt::Key_Back, QStringLiteral("Back")},
|
||||
{Qt::Key_Forward, QStringLiteral("Forward")},
|
||||
{Qt::Key_Stop, QStringLiteral("Stop")},
|
||||
{Qt::Key_Refresh, QStringLiteral("Refresh")},
|
||||
{Qt::Key_VolumeDown, QStringLiteral("VolumeDown")},
|
||||
{Qt::Key_VolumeMute, QStringLiteral("VolumeMute")},
|
||||
{Qt::Key_VolumeUp, QStringLiteral("VolumeUp")},
|
||||
{Qt::Key_BassBoost, QStringLiteral("BassBoost")},
|
||||
{Qt::Key_BassUp, QStringLiteral("BassUp")},
|
||||
{Qt::Key_BassDown, QStringLiteral("BassDown")},
|
||||
{Qt::Key_TrebleUp, QStringLiteral("TrebleUp")},
|
||||
{Qt::Key_TrebleDown, QStringLiteral("TrebleDown")},
|
||||
{Qt::Key_MediaPlay, QStringLiteral("MediaPlay")},
|
||||
{Qt::Key_MediaStop, QStringLiteral("MediaStop")},
|
||||
{Qt::Key_MediaPrevious, QStringLiteral("MediaPrevious")},
|
||||
{Qt::Key_MediaNext, QStringLiteral("MediaNext")},
|
||||
{Qt::Key_MediaRecord, QStringLiteral("MediaRecord")},
|
||||
{Qt::Key_MediaPause, QStringLiteral("MediaPause")},
|
||||
{Qt::Key_MediaTogglePlayPause, QStringLiteral("MediaTogglePlayPause")},
|
||||
{Qt::Key_HomePage, QStringLiteral("HomePage")},
|
||||
{Qt::Key_Favorites, QStringLiteral("Favorites")},
|
||||
{Qt::Key_Search, QStringLiteral("Search")},
|
||||
{Qt::Key_Standby, QStringLiteral("Standby")},
|
||||
{Qt::Key_OpenUrl, QStringLiteral("OpenUrl")},
|
||||
{Qt::Key_LaunchMail, QStringLiteral("LaunchMail")},
|
||||
{Qt::Key_LaunchMedia, QStringLiteral("LaunchMedia")},
|
||||
{Qt::Key_Launch0, QStringLiteral("Launch0")},
|
||||
{Qt::Key_Launch1, QStringLiteral("Launch1")},
|
||||
{Qt::Key_Launch2, QStringLiteral("Launch2")},
|
||||
{Qt::Key_Launch3, QStringLiteral("Launch3")},
|
||||
{Qt::Key_Launch4, QStringLiteral("Launch4")},
|
||||
{Qt::Key_Launch5, QStringLiteral("Launch5")},
|
||||
{Qt::Key_Launch6, QStringLiteral("Launch6")},
|
||||
{Qt::Key_Launch7, QStringLiteral("Launch7")},
|
||||
{Qt::Key_Launch8, QStringLiteral("Launch8")},
|
||||
{Qt::Key_Launch9, QStringLiteral("Launch9")},
|
||||
{Qt::Key_LaunchA, QStringLiteral("LaunchA")},
|
||||
{Qt::Key_LaunchB, QStringLiteral("LaunchB")},
|
||||
{Qt::Key_LaunchC, QStringLiteral("LaunchC")},
|
||||
{Qt::Key_LaunchD, QStringLiteral("LaunchD")},
|
||||
{Qt::Key_LaunchE, QStringLiteral("LaunchE")},
|
||||
{Qt::Key_LaunchF, QStringLiteral("LaunchF")},
|
||||
{Qt::Key_MonBrightnessUp, QStringLiteral("MonBrightnessUp")},
|
||||
{Qt::Key_MonBrightnessDown, QStringLiteral("MonBrightnessDown")},
|
||||
{Qt::Key_KeyboardLightOnOff, QStringLiteral("KeyboardLightOnOff")},
|
||||
{Qt::Key_KeyboardBrightnessUp, QStringLiteral("KeyboardBrightnessUp")},
|
||||
{Qt::Key_KeyboardBrightnessDown, QStringLiteral("KeyboardBrightnessDown")},
|
||||
{Qt::Key_PowerOff, QStringLiteral("PowerOff")},
|
||||
{Qt::Key_WakeUp, QStringLiteral("WakeUp")},
|
||||
{Qt::Key_Eject, QStringLiteral("Eject")},
|
||||
{Qt::Key_ScreenSaver, QStringLiteral("ScreenSaver")},
|
||||
{Qt::Key_WWW, QStringLiteral("WWW")},
|
||||
{Qt::Key_Memo, QStringLiteral("Memo")},
|
||||
{Qt::Key_LightBulb, QStringLiteral("LightBulb")},
|
||||
{Qt::Key_Shop, QStringLiteral("Shop")},
|
||||
{Qt::Key_History, QStringLiteral("History")},
|
||||
{Qt::Key_AddFavorite, QStringLiteral("AddFavorite")},
|
||||
{Qt::Key_HotLinks, QStringLiteral("HotLinks")},
|
||||
{Qt::Key_BrightnessAdjust, QStringLiteral("BrightnessAdjust")},
|
||||
{Qt::Key_Finance, QStringLiteral("Finance")},
|
||||
{Qt::Key_Community, QStringLiteral("Community")},
|
||||
{Qt::Key_AudioRewind, QStringLiteral("AudioRewind")},
|
||||
{Qt::Key_BackForward, QStringLiteral("BackForward")},
|
||||
{Qt::Key_ApplicationLeft, QStringLiteral("ApplicationLeft")},
|
||||
{Qt::Key_ApplicationRight, QStringLiteral("ApplicationRight")},
|
||||
{Qt::Key_Book, QStringLiteral("Book")},
|
||||
{Qt::Key_CD, QStringLiteral("CD")},
|
||||
{Qt::Key_Calculator, QStringLiteral("Calculator")},
|
||||
{Qt::Key_ToDoList, QStringLiteral("ToDoList")},
|
||||
{Qt::Key_ClearGrab, QStringLiteral("ClearGrab")},
|
||||
{Qt::Key_Close, QStringLiteral("Close")},
|
||||
{Qt::Key_Copy, QStringLiteral("Copy")},
|
||||
{Qt::Key_Cut, QStringLiteral("Cut")},
|
||||
{Qt::Key_Display, QStringLiteral("Display")},
|
||||
{Qt::Key_DOS, QStringLiteral("DOS")},
|
||||
{Qt::Key_Documents, QStringLiteral("Documents")},
|
||||
{Qt::Key_Excel, QStringLiteral("Excel")},
|
||||
{Qt::Key_Explorer, QStringLiteral("Explorer")},
|
||||
{Qt::Key_Game, QStringLiteral("Game")},
|
||||
{Qt::Key_Go, QStringLiteral("Go")},
|
||||
{Qt::Key_iTouch, QStringLiteral("iTouch")},
|
||||
{Qt::Key_LogOff, QStringLiteral("LogOff")},
|
||||
{Qt::Key_Market, QStringLiteral("Market")},
|
||||
{Qt::Key_Meeting, QStringLiteral("Meeting")},
|
||||
{Qt::Key_MenuKB, QStringLiteral("MenuKB")},
|
||||
{Qt::Key_MenuPB, QStringLiteral("MenuPB")},
|
||||
{Qt::Key_MySites, QStringLiteral("MySites")},
|
||||
{Qt::Key_News, QStringLiteral("News")},
|
||||
{Qt::Key_OfficeHome, QStringLiteral("OfficeHome")},
|
||||
{Qt::Key_Option, QStringLiteral("Option")},
|
||||
{Qt::Key_Paste, QStringLiteral("Paste")},
|
||||
{Qt::Key_Phone, QStringLiteral("Phone")},
|
||||
{Qt::Key_Calendar, QStringLiteral("Calendar")},
|
||||
{Qt::Key_Reply, QStringLiteral("Reply")},
|
||||
{Qt::Key_Reload, QStringLiteral("Reload")},
|
||||
{Qt::Key_RotateWindows, QStringLiteral("RotateWindows")},
|
||||
{Qt::Key_RotationPB, QStringLiteral("RotationPB")},
|
||||
{Qt::Key_RotationKB, QStringLiteral("RotationKB")},
|
||||
{Qt::Key_Save, QStringLiteral("Save")},
|
||||
{Qt::Key_Send, QStringLiteral("Send")},
|
||||
{Qt::Key_Spell, QStringLiteral("Spell")},
|
||||
{Qt::Key_SplitScreen, QStringLiteral("SplitScreen")},
|
||||
{Qt::Key_Support, QStringLiteral("Support")},
|
||||
{Qt::Key_TaskPane, QStringLiteral("TaskPane")},
|
||||
{Qt::Key_Terminal, QStringLiteral("Terminal")},
|
||||
{Qt::Key_Tools, QStringLiteral("Tools")},
|
||||
{Qt::Key_Travel, QStringLiteral("Travel")},
|
||||
{Qt::Key_Video, QStringLiteral("Video")},
|
||||
{Qt::Key_Word, QStringLiteral("Word")},
|
||||
{Qt::Key_Xfer, QStringLiteral("Xfer")},
|
||||
{Qt::Key_ZoomIn, QStringLiteral("ZoomIn")},
|
||||
{Qt::Key_ZoomOut, QStringLiteral("ZoomOut")},
|
||||
{Qt::Key_Away, QStringLiteral("Away")},
|
||||
{Qt::Key_Messenger, QStringLiteral("Messenger")},
|
||||
{Qt::Key_WebCam, QStringLiteral("WebCam")},
|
||||
{Qt::Key_MailForward, QStringLiteral("MailForward")},
|
||||
{Qt::Key_Pictures, QStringLiteral("Pictures")},
|
||||
{Qt::Key_Music, QStringLiteral("Music")},
|
||||
{Qt::Key_Battery, QStringLiteral("Battery")},
|
||||
{Qt::Key_Bluetooth, QStringLiteral("Bluetooth")},
|
||||
{Qt::Key_WLAN, QStringLiteral("WLAN")},
|
||||
{Qt::Key_UWB, QStringLiteral("UWB")},
|
||||
{Qt::Key_AudioForward, QStringLiteral("AudioForward")},
|
||||
{Qt::Key_AudioRepeat, QStringLiteral("AudioRepeat")},
|
||||
{Qt::Key_AudioRandomPlay, QStringLiteral("AudioRandomPlay")},
|
||||
{Qt::Key_Subtitle, QStringLiteral("Subtitle")},
|
||||
{Qt::Key_AudioCycleTrack, QStringLiteral("AudioCycleTrack")},
|
||||
{Qt::Key_Time, QStringLiteral("Time")},
|
||||
{Qt::Key_Hibernate, QStringLiteral("Hibernate")},
|
||||
{Qt::Key_View, QStringLiteral("View")},
|
||||
{Qt::Key_TopMenu, QStringLiteral("TopMenu")},
|
||||
{Qt::Key_PowerDown, QStringLiteral("PowerDown")},
|
||||
{Qt::Key_Suspend, QStringLiteral("Suspend")},
|
||||
{Qt::Key_ContrastAdjust, QStringLiteral("ContrastAdjust")},
|
||||
{Qt::Key_LaunchG, QStringLiteral("LaunchG")},
|
||||
{Qt::Key_LaunchH, QStringLiteral("LaunchH")},
|
||||
{Qt::Key_TouchpadToggle, QStringLiteral("TouchpadToggle")},
|
||||
{Qt::Key_TouchpadOn, QStringLiteral("TouchpadOn")},
|
||||
{Qt::Key_TouchpadOff, QStringLiteral("TouchpadOff")},
|
||||
{Qt::Key_MicMute, QStringLiteral("MicMute")},
|
||||
{Qt::Key_Red, QStringLiteral("Red")},
|
||||
{Qt::Key_Green, QStringLiteral("Green")},
|
||||
{Qt::Key_Yellow, QStringLiteral("Yellow")},
|
||||
{Qt::Key_Blue, QStringLiteral("Blue")},
|
||||
{Qt::Key_ChannelUp, QStringLiteral("ChannelUp")},
|
||||
{Qt::Key_ChannelDown, QStringLiteral("ChannelDown")},
|
||||
{Qt::Key_Guide, QStringLiteral("Guide")},
|
||||
{Qt::Key_Info, QStringLiteral("Info")},
|
||||
{Qt::Key_Settings, QStringLiteral("Settings")},
|
||||
{Qt::Key_MicVolumeUp, QStringLiteral("MicVolumeUp")},
|
||||
{Qt::Key_MicVolumeDown, QStringLiteral("MicVolumeDown")},
|
||||
{Qt::Key_New, QStringLiteral("New")},
|
||||
{Qt::Key_Open, QStringLiteral("Open")},
|
||||
{Qt::Key_Find, QStringLiteral("Find")},
|
||||
{Qt::Key_Undo, QStringLiteral("Undo")},
|
||||
{Qt::Key_Redo, QStringLiteral("Redo")},
|
||||
{Qt::Key_MediaLast, QStringLiteral("MediaLast")},
|
||||
{Qt::Key_Select, QStringLiteral("Select")},
|
||||
{Qt::Key_Yes, QStringLiteral("Yes")},
|
||||
{Qt::Key_No, QStringLiteral("No")},
|
||||
{Qt::Key_Cancel, QStringLiteral("Cancel")},
|
||||
{Qt::Key_Printer, QStringLiteral("Printer")},
|
||||
{Qt::Key_Execute, QStringLiteral("Execute")},
|
||||
{Qt::Key_Sleep, QStringLiteral("Sleep")},
|
||||
{Qt::Key_Play, QStringLiteral("Play")},
|
||||
{Qt::Key_Zoom, QStringLiteral("Zoom")},
|
||||
{Qt::Key_Exit, QStringLiteral("Exit")},
|
||||
{Qt::Key_Context1, QStringLiteral("Context1")},
|
||||
{Qt::Key_Context2, QStringLiteral("Context2")},
|
||||
{Qt::Key_Context3, QStringLiteral("Context3")},
|
||||
{Qt::Key_Context4, QStringLiteral("Context4")},
|
||||
{Qt::Key_Call, QStringLiteral("Call")},
|
||||
{Qt::Key_Hangup, QStringLiteral("Hangup")},
|
||||
{Qt::Key_Flip, QStringLiteral("Flip")},
|
||||
{Qt::Key_ToggleCallHangup, QStringLiteral("ToggleCallHangup")},
|
||||
{Qt::Key_VoiceDial, QStringLiteral("VoiceDial")},
|
||||
{Qt::Key_LastNumberRedial, QStringLiteral("LastNumberRedial")},
|
||||
{Qt::Key_Camera, QStringLiteral("Camera")},
|
||||
{Qt::Key_CameraFocus, QStringLiteral("CameraFocus")}};
|
||||
|
||||
struct QtKeyModifierEntry
|
||||
{
|
||||
Qt::KeyboardModifier mod;
|
||||
Qt::Key key;
|
||||
QString name;
|
||||
};
|
||||
|
||||
static const std::array<QtKeyModifierEntry, 5> s_qt_key_modifiers = {
|
||||
{{Qt::ShiftModifier, Qt::Key_Shift, QStringLiteral("Shift")},
|
||||
{Qt::ControlModifier, Qt::Key_Control, QStringLiteral("Control")},
|
||||
{Qt::AltModifier, Qt::Key_Alt, QStringLiteral("Alt")},
|
||||
{Qt::MetaModifier, Qt::Key_Meta, QStringLiteral("Meta")},
|
||||
{Qt::KeypadModifier, static_cast<Qt::Key>(0), QStringLiteral("Keypad")}}};
|
||||
|
||||
QString GetKeyIdentifier(int key)
|
||||
{
|
||||
const auto it = s_qt_key_names.find(key);
|
||||
return it == s_qt_key_names.end() ? QString() : it->second;
|
||||
}
|
||||
|
||||
std::optional<int> GetKeyIdForIdentifier(const QString& key_identifier)
|
||||
{
|
||||
for (const auto& it : s_qt_key_names)
|
||||
{
|
||||
if (it.second == key_identifier)
|
||||
return it.first;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
QString KeyEventToString(int key, Qt::KeyboardModifiers mods)
|
||||
{
|
||||
QString key_name = GetKeyIdentifier(key);
|
||||
if (key_name.isEmpty())
|
||||
return {};
|
||||
|
||||
QString ret;
|
||||
for (const QtKeyModifierEntry& mod : s_qt_key_modifiers)
|
||||
{
|
||||
if (mods & mod.mod && key != mod.key)
|
||||
{
|
||||
ret.append(mod.name);
|
||||
ret.append('+');
|
||||
}
|
||||
}
|
||||
|
||||
ret.append(key_name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::optional<int> ParseKeyString(const QString& key_str)
|
||||
{
|
||||
const QStringList sections = key_str.split('+');
|
||||
std::optional<int> key_id = GetKeyIdForIdentifier(sections.last());
|
||||
if (!key_id)
|
||||
return std::nullopt;
|
||||
|
||||
int ret = key_id.value();
|
||||
|
||||
if (sections.size() > 1)
|
||||
{
|
||||
const int num_modifiers = sections.size() - 1;
|
||||
for (int i = 0; i < num_modifiers; i++)
|
||||
{
|
||||
for (const QtKeyModifierEntry& mod : s_qt_key_modifiers)
|
||||
{
|
||||
if (sections[i] == mod.name)
|
||||
{
|
||||
ret |= static_cast<int>(mod.mod);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int KeyEventToInt(int key, Qt::KeyboardModifiers mods)
|
||||
{
|
||||
int val = key;
|
||||
if (mods != 0)
|
||||
{
|
||||
for (const QtKeyModifierEntry& mod : s_qt_key_modifiers)
|
||||
{
|
||||
if (mods & mod.mod && key != mod.key)
|
||||
val |= static_cast<int>(mod.mod);
|
||||
}
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
void OpenURL(QWidget* parent, const QUrl& qurl)
|
||||
{
|
||||
if (!QDesktopServices::openUrl(qurl))
|
||||
@@ -690,4 +156,15 @@ namespace QtUtils
|
||||
{
|
||||
return str.empty() ? QString() : QString::fromUtf8(str.data(), str.size());
|
||||
}
|
||||
|
||||
void SetWidgetFontForInheritedSetting(QWidget* widget, bool inherited)
|
||||
{
|
||||
if (widget->font().italic() != inherited)
|
||||
{
|
||||
QFont new_font(widget->font());
|
||||
new_font.setItalic(inherited);
|
||||
widget->setFont(new_font);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace QtUtils
|
||||
|
||||
+6
-14
@@ -50,20 +50,9 @@ namespace QtUtils
|
||||
void ResizeColumnsForTableView(QTableView* view, const std::initializer_list<int>& widths);
|
||||
void ResizeColumnsForTreeView(QTreeView* view, const std::initializer_list<int>& widths);
|
||||
|
||||
/// Returns a string identifier for a Qt key ID.
|
||||
QString GetKeyIdentifier(int key);
|
||||
|
||||
/// Returns the integer Qt key ID for an identifier.
|
||||
std::optional<int> GetKeyIdForIdentifier(const QString& key_identifier);
|
||||
|
||||
/// Stringizes a key event.
|
||||
QString KeyEventToString(int key, Qt::KeyboardModifiers mods);
|
||||
|
||||
/// Returns an integer id for a stringized key event. Modifiers are in the upper bits.
|
||||
std::optional<int> ParseKeyString(const QString& key_str);
|
||||
|
||||
/// Returns a key id for a key event, including any modifiers.
|
||||
int KeyEventToInt(int key, Qt::KeyboardModifiers mods);
|
||||
/// Returns a key id for a key event, including any modifiers that we need (e.g. Keypad).
|
||||
/// NOTE: Defined in QtKeyCodes.cpp, not QtUtils.cpp.
|
||||
u32 KeyEventToCode(const QKeyEvent* ev);
|
||||
|
||||
/// Opens a URL with the default handler.
|
||||
void OpenURL(QWidget* parent, const QUrl& qurl);
|
||||
@@ -76,4 +65,7 @@ namespace QtUtils
|
||||
|
||||
/// Converts a std::string_view to a QString safely.
|
||||
QString StringViewToQString(const std::string_view& str);
|
||||
|
||||
/// Sets a widget to italics if the setting value is inherited.
|
||||
void SetWidgetFontForInheritedSetting(QWidget* widget, bool inherited);
|
||||
} // namespace QtUtils
|
||||
@@ -20,17 +20,23 @@
|
||||
|
||||
#include <QtCore/QtCore>
|
||||
#include <QtGui/QAction>
|
||||
#include <QtWidgets/QAbstractButton>
|
||||
#include <QtWidgets/QCheckBox>
|
||||
#include <QtWidgets/QComboBox>
|
||||
#include <QtWidgets/QDoubleSpinBox>
|
||||
#include <QtWidgets/QFileDialog>
|
||||
#include <QtWidgets/QLineEdit>
|
||||
#include <QtWidgets/QSlider>
|
||||
#include <QtWidgets/QSpinBox>
|
||||
|
||||
#include "common/Path.h"
|
||||
|
||||
#include "pcsx2/Config.h"
|
||||
#include "pcsx2/HostSettings.h"
|
||||
|
||||
#include "EmuThread.h"
|
||||
#include "QtHost.h"
|
||||
#include "QtUtils.h"
|
||||
#include "Settings/SettingsDialog.h"
|
||||
|
||||
namespace SettingWidgetBinder
|
||||
@@ -228,7 +234,7 @@ namespace SettingWidgetBinder
|
||||
static std::optional<QString> getNullableStringValue(const QCheckBox* widget)
|
||||
{
|
||||
return (widget->checkState() == Qt::PartiallyChecked) ?
|
||||
std::nullopt :
|
||||
std::nullopt :
|
||||
std::optional<QString>(widget->isChecked() ? QStringLiteral("1") : QStringLiteral("0"));
|
||||
}
|
||||
static void setNullableStringValue(QCheckBox* widget, std::optional<QString> value)
|
||||
@@ -769,4 +775,70 @@ namespace SettingWidgetBinder
|
||||
}
|
||||
}
|
||||
|
||||
template <typename WidgetType>
|
||||
static void BindWidgetToFolderSetting(SettingsInterface* sif, WidgetType* widget,
|
||||
QAbstractButton* browse_button, QAbstractButton* open_button, QAbstractButton* reset_button,
|
||||
std::string section, std::string key, std::string default_value)
|
||||
{
|
||||
using Accessor = SettingAccessor<WidgetType>;
|
||||
|
||||
std::string current_path(Host::GetBaseStringSettingValue(section.c_str(), key.c_str(), default_value.c_str()));
|
||||
if (!Path::IsAbsolute(current_path))
|
||||
current_path = Path::Combine(EmuFolders::DataRoot, current_path);
|
||||
|
||||
const QString value(QString::fromStdString(current_path));
|
||||
Accessor::setStringValue(widget, value);
|
||||
|
||||
// if we're doing per-game settings, disable the widget, we only allow folder changes in the base config
|
||||
if (sif)
|
||||
{
|
||||
widget->setEnabled(false);
|
||||
if (browse_button)
|
||||
browse_button->setEnabled(false);
|
||||
if (reset_button)
|
||||
reset_button->setEnabled(false);
|
||||
return;
|
||||
}
|
||||
|
||||
Accessor::connectValueChanged(widget, [widget, section = std::move(section), key = std::move(key)]() {
|
||||
const std::string new_value(Accessor::getStringValue(widget).toStdString());
|
||||
if (!new_value.empty())
|
||||
{
|
||||
std::string relative_path(Path::MakeRelative(new_value, EmuFolders::DataRoot));
|
||||
QtHost::SetBaseStringSettingValue(section.c_str(), key.c_str(), relative_path.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
QtHost::RemoveBaseSettingValue(section.c_str(), key.c_str());
|
||||
}
|
||||
|
||||
g_emu_thread->updateEmuFolders();
|
||||
});
|
||||
|
||||
if (browse_button)
|
||||
{
|
||||
QObject::connect(browse_button, &QAbstractButton::clicked, browse_button, [widget, key]() {
|
||||
const QString path(QDir::toNativeSeparators(QFileDialog::getExistingDirectory(QtUtils::GetRootWidget(widget),
|
||||
qApp->translate("SettingWidgetBinder", "Select folder for %1").arg(QString::fromStdString(key)))));
|
||||
if (path.isEmpty())
|
||||
return;
|
||||
|
||||
Accessor::setStringValue(widget, path);
|
||||
});
|
||||
}
|
||||
if (open_button)
|
||||
{
|
||||
QObject::connect(open_button, &QAbstractButton::clicked, open_button, [widget]() {
|
||||
QString path(Accessor::getStringValue(widget));
|
||||
if (!path.isEmpty())
|
||||
QtUtils::OpenURL(QtUtils::GetRootWidget(widget), QUrl::fromLocalFile(path));
|
||||
});
|
||||
}
|
||||
if (reset_button)
|
||||
{
|
||||
QObject::connect(reset_button, &QAbstractButton::clicked, reset_button, [widget, default_value = std::move(default_value)]() {
|
||||
Accessor::setStringValue(widget, QString::fromStdString(Path::Combine(EmuFolders::AppRoot, default_value)));
|
||||
});
|
||||
}
|
||||
}
|
||||
} // namespace SettingWidgetBinder
|
||||
|
||||
@@ -38,28 +38,17 @@ BIOSSettingsWidget::BIOSSettingsWidget(SettingsDialog* dialog, QWidget* parent)
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.fastBoot, "EmuCore", "EnableFastBoot", true);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.patchRegion, "EmuCore", "PatchBios", false);
|
||||
SettingWidgetBinder::BindWidgetToEnumSetting(sif, m_ui.regionComboBox, "EmuCore", "PatchRegion", BiosZoneStrings, BiosZoneBytes, BiosZoneBytes[0]);
|
||||
SettingWidgetBinder::BindWidgetToFolderSetting(sif, m_ui.searchDirectory, m_ui.browseSearchDirectory, m_ui.openSearchDirectory,
|
||||
m_ui.resetSearchDirectory, "Folders", "Bios", "bios");
|
||||
|
||||
dialog->registerWidgetHelp(m_ui.patchRegion, tr("Patch Region"),tr("Unchecked"),
|
||||
dialog->registerWidgetHelp(m_ui.patchRegion, tr("Patch Region"), tr("Unchecked"),
|
||||
tr("Patches the BIOS region byte in ROM. Not recommended unless you really know what you're doing."));
|
||||
dialog->registerWidgetHelp(m_ui.fastBoot, tr("Fast Boot"), tr("Unchecked"),
|
||||
tr("Patches the BIOS to skip the console's boot animation."));
|
||||
|
||||
updateSearchDirectory();
|
||||
refreshList();
|
||||
|
||||
connect(m_ui.searchDirectory, &QLineEdit::textChanged, [this](const QString& text) {
|
||||
QtHost::SetBaseStringSettingValue("Folders", "Bios", text.toUtf8().constData());
|
||||
QtHost::UpdateFolders();
|
||||
refreshList();
|
||||
});
|
||||
connect(m_ui.resetSearchDirectory, &QPushButton::clicked, [this]() {
|
||||
QtHost::RemoveBaseSettingValue("Folders", "Bios");
|
||||
QtHost::UpdateFolders();
|
||||
updateSearchDirectory();
|
||||
refreshList();
|
||||
});
|
||||
connect(m_ui.browseSearchDirectory, &QPushButton::clicked, this, &BIOSSettingsWidget::browseSearchDirectory);
|
||||
connect(m_ui.openSearchDirectory, &QPushButton::clicked, this, &BIOSSettingsWidget::openSearchDirectory);
|
||||
connect(m_ui.searchDirectory, &QLineEdit::textChanged, this, &BIOSSettingsWidget::refreshList);
|
||||
connect(m_ui.refresh, &QPushButton::clicked, this, &BIOSSettingsWidget::refreshList);
|
||||
connect(m_ui.fileList, &QTreeWidget::currentItemChanged, this, &BIOSSettingsWidget::listItemChanged);
|
||||
|
||||
@@ -89,27 +78,6 @@ void BIOSSettingsWidget::refreshList()
|
||||
m_refresh_thread->start();
|
||||
}
|
||||
|
||||
void BIOSSettingsWidget::browseSearchDirectory()
|
||||
{
|
||||
QString directory = QDir::toNativeSeparators(QFileDialog::getExistingDirectory(
|
||||
QtUtils::GetRootWidget(this), tr("Select Directory"), m_ui.searchDirectory->text()));
|
||||
if (directory.isEmpty())
|
||||
return;
|
||||
|
||||
m_ui.searchDirectory->setText(directory);
|
||||
}
|
||||
|
||||
void BIOSSettingsWidget::openSearchDirectory()
|
||||
{
|
||||
QtUtils::OpenURL(this, QUrl::fromLocalFile(m_ui.searchDirectory->text()));
|
||||
}
|
||||
|
||||
void BIOSSettingsWidget::updateSearchDirectory()
|
||||
{
|
||||
// this will generate a full path
|
||||
m_ui.searchDirectory->setText(QString::fromStdString(EmuFolders::Bios));
|
||||
}
|
||||
|
||||
void BIOSSettingsWidget::listRefreshed(const QVector<BIOSInfo>& items)
|
||||
{
|
||||
const std::string selected_bios(Host::GetBaseStringSettingValue("Filenames", "BIOS"));
|
||||
|
||||
@@ -47,9 +47,6 @@ public:
|
||||
|
||||
private Q_SLOTS:
|
||||
void refreshList();
|
||||
void browseSearchDirectory();
|
||||
void openSearchDirectory();
|
||||
void updateSearchDirectory();
|
||||
|
||||
void listItemChanged(const QTreeWidgetItem* current, const QTreeWidgetItem* previous);
|
||||
void listRefreshed(const QVector<BIOSInfo>& items);
|
||||
|
||||
@@ -188,7 +188,7 @@
|
||||
</layout>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="resources/resources.qrc"/>
|
||||
<include location="../resources/resources.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>834</width>
|
||||
<width>833</width>
|
||||
<height>560</height>
|
||||
</rect>
|
||||
</property>
|
||||
@@ -61,35 +61,14 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="loadProfile">
|
||||
<property name="text">
|
||||
<string>Load Profile</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="folder-open-line">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="saveProfile">
|
||||
<property name="text">
|
||||
<string>Save Profile</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="save-3-line">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="clearBindings">
|
||||
<property name="text">
|
||||
<string>Clear Bindings</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="file-reduce-line"/>
|
||||
<iconset theme="file-reduce-line">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -623,10 +623,10 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1" rowspan="2" colspan="4">
|
||||
<item row="2" column="3" rowspan="2" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox_30">
|
||||
<property name="title">
|
||||
<string>Axis Scale</string>
|
||||
<string>Analog Sensitivity</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
@@ -642,7 +642,33 @@
|
||||
<item>
|
||||
<widget class="QLabel" name="AxisScaleLabel">
|
||||
<property name="text">
|
||||
<string>1.0x</string>
|
||||
<string>100%</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1" rowspan="2" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox_33">
|
||||
<property name="title">
|
||||
<string>Analog Deadzone</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QSlider" name="Deadzone">
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="DeadzoneLabel">
|
||||
<property name="text">
|
||||
<string>0%</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -19,19 +19,18 @@
|
||||
#include <QtWidgets/QMessageBox>
|
||||
#include <algorithm>
|
||||
|
||||
#include "ControllerBindingWidgets.h"
|
||||
#include "ControllerSettingsDialog.h"
|
||||
#include "Settings/ControllerBindingWidgets.h"
|
||||
#include "Settings/ControllerSettingsDialog.h"
|
||||
#include "Settings/ControllerSettingWidgetBinder.h"
|
||||
#include "Settings/SettingsDialog.h"
|
||||
#include "EmuThread.h"
|
||||
#include "QtUtils.h"
|
||||
#include "SettingWidgetBinder.h"
|
||||
#include "SettingsDialog.h"
|
||||
|
||||
#include "common/StringUtil.h"
|
||||
#include "pcsx2/HostSettings.h"
|
||||
#include "pcsx2/PAD/Host/PAD.h"
|
||||
|
||||
#include "SettingWidgetBinder.h"
|
||||
|
||||
ControllerBindingWidget::ControllerBindingWidget(QWidget* parent, ControllerSettingsDialog* dialog, u32 port)
|
||||
: QWidget(parent)
|
||||
, m_dialog(dialog)
|
||||
@@ -42,7 +41,9 @@ ControllerBindingWidget::ControllerBindingWidget(QWidget* parent, ControllerSett
|
||||
populateControllerTypes();
|
||||
onTypeChanged();
|
||||
|
||||
SettingWidgetBinder::BindWidgetToStringSetting(nullptr, m_ui.controllerType, m_config_section, "Type", "None");
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileString(m_dialog->getProfileSettingsInterface(),
|
||||
m_ui.controllerType, m_config_section, "Type", PAD::GetDefaultPadType(port));
|
||||
|
||||
connect(m_ui.controllerType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &ControllerBindingWidget::onTypeChanged);
|
||||
connect(m_ui.automaticBinding, &QPushButton::clicked, this, &ControllerBindingWidget::doAutomaticBinding);
|
||||
connect(m_ui.clearBindings, &QPushButton::clicked, this, &ControllerBindingWidget::doClearBindings);
|
||||
@@ -50,6 +51,11 @@ ControllerBindingWidget::ControllerBindingWidget(QWidget* parent, ControllerSett
|
||||
|
||||
ControllerBindingWidget::~ControllerBindingWidget() = default;
|
||||
|
||||
QIcon ControllerBindingWidget::getIcon() const
|
||||
{
|
||||
return m_current_widget->getIcon();
|
||||
}
|
||||
|
||||
void ControllerBindingWidget::populateControllerTypes()
|
||||
{
|
||||
for (const auto& [name, display_name] : PAD::GetControllerTypeNames())
|
||||
@@ -58,15 +64,16 @@ void ControllerBindingWidget::populateControllerTypes()
|
||||
|
||||
void ControllerBindingWidget::onTypeChanged()
|
||||
{
|
||||
if (m_current_widget)
|
||||
const bool is_initializing = (m_current_widget == nullptr);
|
||||
m_controller_type = m_dialog->getStringValue(m_config_section.c_str(), "Type", PAD::GetDefaultPadType(m_port_number));
|
||||
|
||||
if (!is_initializing)
|
||||
{
|
||||
m_ui.verticalLayout->removeWidget(m_current_widget);
|
||||
delete m_current_widget;
|
||||
m_current_widget = nullptr;
|
||||
}
|
||||
|
||||
m_controller_type = Host::GetBaseStringSettingValue(m_config_section.c_str(), "Type");
|
||||
|
||||
const int index = m_ui.controllerType->findData(QString::fromStdString(m_controller_type));
|
||||
if (index >= 0 && index != m_ui.controllerType->currentIndex())
|
||||
{
|
||||
@@ -80,6 +87,10 @@ void ControllerBindingWidget::onTypeChanged()
|
||||
m_current_widget = new ControllerBindingWidget_Base(this);
|
||||
|
||||
m_ui.verticalLayout->addWidget(m_current_widget, 1);
|
||||
|
||||
// no need to do this on first init, only changes
|
||||
if (!is_initializing)
|
||||
m_dialog->updateListDescription(m_port_number, this);
|
||||
}
|
||||
|
||||
void ControllerBindingWidget::doAutomaticBinding()
|
||||
@@ -110,15 +121,20 @@ void ControllerBindingWidget::doAutomaticBinding()
|
||||
void ControllerBindingWidget::doClearBindings()
|
||||
{
|
||||
if (QMessageBox::question(QtUtils::GetRootWidget(this), tr("Clear Bindings"),
|
||||
tr("Are you sure you want to clear all bindings for this controller? This action cannot be undone.")) != QMessageBox::Yes)
|
||||
tr("Are you sure you want to clear all bindings for this controller? This action cannot be undone.")) != QMessageBox::Yes)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_dialog->isEditingGlobalSettings())
|
||||
{
|
||||
auto lock = Host::GetSettingsLock();
|
||||
PAD::ClearPortBindings(*Host::Internal::GetBaseSettingsLayer(), m_port_number);
|
||||
}
|
||||
else
|
||||
{
|
||||
PAD::ClearPortBindings(*m_dialog->getProfileSettingsInterface(), m_port_number);
|
||||
}
|
||||
|
||||
saveAndRefresh();
|
||||
}
|
||||
@@ -134,10 +150,17 @@ void ControllerBindingWidget::doDeviceAutomaticBinding(const QString& device)
|
||||
}
|
||||
|
||||
bool result;
|
||||
if (m_dialog->isEditingGlobalSettings())
|
||||
{
|
||||
auto lock = Host::GetSettingsLock();
|
||||
result = PAD::MapController(*Host::Internal::GetBaseSettingsLayer(), m_port_number, mapping);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = PAD::MapController(*m_dialog->getProfileSettingsInterface(), m_port_number, mapping);
|
||||
m_dialog->getProfileSettingsInterface()->Save();
|
||||
g_emu_thread->reloadInputBindings();
|
||||
}
|
||||
|
||||
// force a refresh after mapping
|
||||
if (result)
|
||||
@@ -162,11 +185,17 @@ ControllerBindingWidget_Base::~ControllerBindingWidget_Base()
|
||||
{
|
||||
}
|
||||
|
||||
QIcon ControllerBindingWidget_Base::getIcon() const
|
||||
{
|
||||
return QIcon::fromTheme("artboard-2-line");
|
||||
}
|
||||
|
||||
void ControllerBindingWidget_Base::initBindingWidgets()
|
||||
{
|
||||
const std::string& type = getControllerType();
|
||||
const std::string& config_section = getConfigSection();
|
||||
std::vector<std::string> bindings(PAD::GetControllerBinds(type));
|
||||
SettingsInterface* sif = getDialog()->getProfileSettingsInterface();
|
||||
|
||||
for (std::string& binding : bindings)
|
||||
{
|
||||
@@ -178,7 +207,7 @@ void ControllerBindingWidget_Base::initBindingWidgets()
|
||||
continue;
|
||||
}
|
||||
|
||||
widget->setKey(config_section, std::move(binding));
|
||||
widget->initialize(sif, config_section, std::move(binding));
|
||||
}
|
||||
|
||||
const PAD::VibrationCapabilities vibe_caps = PAD::GetControllerVibrationCapabilities(type);
|
||||
@@ -209,6 +238,21 @@ void ControllerBindingWidget_Base::initBindingWidgets()
|
||||
break;
|
||||
}
|
||||
|
||||
if (QSlider* widget = findChild<QSlider*>(QStringLiteral("Deadzone")); widget)
|
||||
{
|
||||
const float range = static_cast<float>(widget->maximum());
|
||||
QLabel* label = findChild<QLabel*>(QStringLiteral("DeadzoneLabel"));
|
||||
if (label)
|
||||
{
|
||||
connect(widget, &QSlider::valueChanged, this, [range, label](int value) {
|
||||
label->setText(tr("%1%").arg((static_cast<float>(value) / range) * 100.0f, 0, 'f', 0));
|
||||
});
|
||||
}
|
||||
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileNormalized(sif, widget, config_section, "Deadzone", range,
|
||||
PAD::DEFAULT_STICK_DEADZONE);
|
||||
}
|
||||
|
||||
if (QSlider* widget = findChild<QSlider*>(QStringLiteral("AxisScale")); widget)
|
||||
{
|
||||
// position 1.0f at the halfway point
|
||||
@@ -217,17 +261,18 @@ void ControllerBindingWidget_Base::initBindingWidgets()
|
||||
if (label)
|
||||
{
|
||||
connect(widget, &QSlider::valueChanged, this, [range, label](int value) {
|
||||
label->setText(tr("%1x").arg(static_cast<float>(value) / range, 0, 'f', 2));
|
||||
label->setText(tr("%1%").arg((static_cast<float>(value) / range) * 100.0f, 0, 'f', 0));
|
||||
});
|
||||
}
|
||||
|
||||
SettingWidgetBinder::BindWidgetToNormalizedSetting(nullptr, widget, config_section, "AxisScale", range, 1.0f);
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileNormalized(sif, widget, config_section, "AxisScale", range,
|
||||
PAD::DEFAULT_STICK_SCALE);
|
||||
}
|
||||
|
||||
if (QDoubleSpinBox* widget = findChild<QDoubleSpinBox*>(QStringLiteral("SmallMotorScale")); widget)
|
||||
SettingWidgetBinder::BindWidgetToFloatSetting(nullptr, widget, config_section, "SmallMotorScale", 1.0f);
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileFloat(sif, widget, config_section, "SmallMotorScale", 1.0f);
|
||||
if (QDoubleSpinBox* widget = findChild<QDoubleSpinBox*>(QStringLiteral("LargeMotorScale")); widget)
|
||||
SettingWidgetBinder::BindWidgetToFloatSetting(nullptr, widget, config_section, "LargeMotorScale", 1.0f);
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileFloat(sif, widget, config_section, "LargeMotorScale", 1.0f);
|
||||
}
|
||||
|
||||
ControllerBindingWidget_DualShock2::ControllerBindingWidget_DualShock2(ControllerBindingWidget* parent)
|
||||
@@ -241,6 +286,11 @@ ControllerBindingWidget_DualShock2::~ControllerBindingWidget_DualShock2()
|
||||
{
|
||||
}
|
||||
|
||||
QIcon ControllerBindingWidget_DualShock2::getIcon() const
|
||||
{
|
||||
return QIcon::fromTheme("gamepad-line");
|
||||
}
|
||||
|
||||
ControllerBindingWidget_Base* ControllerBindingWidget_DualShock2::createInstance(ControllerBindingWidget* parent)
|
||||
{
|
||||
return new ControllerBindingWidget_DualShock2(parent);
|
||||
|
||||
@@ -32,6 +32,8 @@ public:
|
||||
ControllerBindingWidget(QWidget* parent, ControllerSettingsDialog* dialog, u32 port);
|
||||
~ControllerBindingWidget();
|
||||
|
||||
QIcon getIcon() const;
|
||||
|
||||
__fi ControllerSettingsDialog* getDialog() const { return m_dialog; }
|
||||
__fi const std::string& getConfigSection() const { return m_config_section; }
|
||||
__fi const std::string& getControllerType() const { return m_controller_type; }
|
||||
@@ -71,6 +73,8 @@ public:
|
||||
__fi const std::string& getControllerType() const { return static_cast<ControllerBindingWidget*>(parent())->getControllerType(); }
|
||||
__fi u32 getPortNumber() const { return static_cast<ControllerBindingWidget*>(parent())->getPortNumber(); }
|
||||
|
||||
virtual QIcon getIcon() const;
|
||||
|
||||
protected:
|
||||
void initBindingWidgets();
|
||||
};
|
||||
@@ -83,6 +87,8 @@ public:
|
||||
ControllerBindingWidget_DualShock2(ControllerBindingWidget* parent);
|
||||
~ControllerBindingWidget_DualShock2();
|
||||
|
||||
QIcon getIcon() const override;
|
||||
|
||||
static ControllerBindingWidget_Base* createInstance(ControllerBindingWidget* parent);
|
||||
|
||||
private:
|
||||
|
||||
@@ -18,19 +18,53 @@
|
||||
#include "Frontend/InputManager.h"
|
||||
#include "Settings/ControllerGlobalSettingsWidget.h"
|
||||
#include "Settings/ControllerSettingsDialog.h"
|
||||
#include "Settings/ControllerSettingWidgetBinder.h"
|
||||
#include "QtUtils.h"
|
||||
#include "SettingWidgetBinder.h"
|
||||
|
||||
ControllerGlobalSettingsWidget::ControllerGlobalSettingsWidget(QWidget* parent, ControllerSettingsDialog* dialog)
|
||||
: QWidget(parent)
|
||||
, m_dialog(dialog)
|
||||
{
|
||||
m_ui.setupUi(this);
|
||||
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.enableSDLSource, "InputSources", "SDL", true);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.enableSDLEnhancedMode, "InputSources", "SDLControllerEnhancedMode", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.enableXInputSource, "InputSources", "XInput", false);
|
||||
SettingsInterface* sif = dialog->getProfileSettingsInterface();
|
||||
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableSDLSource, "InputSources", "SDL", true);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableSDLEnhancedMode, "InputSources", "SDLControllerEnhancedMode", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.enableXInputSource, "InputSources", "XInput", false);
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.multitapPort1, "Pad", "MultitapPort1", false);
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.multitapPort2, "Pad", "MultitapPort2", false);
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.pointerXInvert, "Pad", "PointerXInvert", false);
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileBool(sif, m_ui.pointerYInvert, "Pad", "PointerYInvert", false);
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileFloat(sif, m_ui.pointerXScale, "Pad", "PointerXScale", 8.0f);
|
||||
ControllerSettingWidgetBinder::BindWidgetToInputProfileFloat(sif, m_ui.pointerYScale, "Pad", "PointerYScale", 8.0f);
|
||||
|
||||
if (dialog->isEditingProfile())
|
||||
{
|
||||
m_ui.useProfileHotkeyBindings->setChecked(m_dialog->getBoolValue("Pad", "UseProfileHotkeyBindings", false));
|
||||
connect(m_ui.useProfileHotkeyBindings, &QCheckBox::stateChanged, this, [this](int new_state) {
|
||||
m_dialog->setBoolValue("Pad", "UseProfileHotkeyBindings", (new_state == Qt::Checked));
|
||||
emit bindingSetupChanged();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
// remove profile options from the UI.
|
||||
m_ui.mainLayout->removeWidget(m_ui.profileSettings);
|
||||
m_ui.profileSettings->deleteLater();
|
||||
m_ui.profileSettings = nullptr;
|
||||
}
|
||||
|
||||
connect(m_ui.enableSDLSource, &QCheckBox::stateChanged, this, &ControllerGlobalSettingsWidget::updateSDLOptionsEnabled);
|
||||
for (QCheckBox* cb : {m_ui.multitapPort1, m_ui.multitapPort2})
|
||||
connect(cb, &QCheckBox::stateChanged, this, [this]() { emit bindingSetupChanged(); });
|
||||
|
||||
connect(m_ui.pointerXScale, &QSlider::valueChanged, this, [this](int value) { m_ui.pointerXScaleLabel->setText(QStringLiteral("%1").arg(value)); });
|
||||
connect(m_ui.pointerYScale, &QSlider::valueChanged, this, [this](int value) { m_ui.pointerYScaleLabel->setText(QStringLiteral("%1").arg(value)); });
|
||||
m_ui.pointerXScaleLabel->setText(QStringLiteral("%1").arg(m_ui.pointerXScale->value()));
|
||||
m_ui.pointerYScaleLabel->setText(QStringLiteral("%1").arg(m_ui.pointerYScale->value()));
|
||||
|
||||
updateSDLOptionsEnabled();
|
||||
}
|
||||
|
||||
|
||||
@@ -35,8 +35,12 @@ public:
|
||||
void addDeviceToList(const QString& identifier, const QString& name);
|
||||
void removeDeviceFromList(const QString& identifier);
|
||||
|
||||
Q_SIGNALS:
|
||||
void bindingSetupChanged();
|
||||
|
||||
private:
|
||||
void updateSDLOptionsEnabled();
|
||||
|
||||
Ui::ControllerGlobalSettingsWidget m_ui;
|
||||
ControllerSettingsDialog* m_dialog;
|
||||
};
|
||||
|
||||
@@ -7,13 +7,13 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>900</width>
|
||||
<height>500</height>
|
||||
<height>675</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="1,0">
|
||||
<layout class="QGridLayout" name="mainLayout" columnstretch="1,0">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
@@ -26,122 +26,273 @@
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>SDL Input Source</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>The SDL input source supports most controllers, and provides advanced functionality for DualShock 4 / DualSense pads in Bluetooth mode (Vibration / LED Control).</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="enableSDLSource">
|
||||
<property name="text">
|
||||
<string>Enable SDL Input Source</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="enableSDLEnhancedMode">
|
||||
<property name="text">
|
||||
<string>DualShock 4 / DualSense Enhanced Mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>XInput Source</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>The XInput source provides support for XBox 360 / XBox One / XBox Series controllers, and third party controllers which implement the XInput protocol.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="enableXInputSource">
|
||||
<property name="text">
|
||||
<string>Enable XInput Input Source</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_4">
|
||||
<property name="title">
|
||||
<string>Controller Multitap</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>The multitap enables up to 8 controllers to be connected to the console. Each multitap provides 4 ports. Multitap is not supported by all games. (NOT YET IMPLEMENTED)</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="multitapPort1">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Multitap on Console Port 1</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="multitapPort2">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Multitap on Console Port 2</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
<item row="0" column="0">
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>SDL Input Source</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>The SDL input source supports most controllers, and provides advanced functionality for DualShock 4 / DualSense pads in Bluetooth mode (Vibration / LED Control).</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="enableSDLSource">
|
||||
<property name="text">
|
||||
<string>Enable SDL Input Source</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="enableSDLEnhancedMode">
|
||||
<property name="text">
|
||||
<string>DualShock 4 / DualSense Enhanced Mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>XInput Source</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>The XInput source provides support for XBox 360 / XBox One / XBox Series controllers, and third party controllers which implement the XInput protocol.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="enableXInputSource">
|
||||
<property name="text">
|
||||
<string>Enable XInput Input Source</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QGroupBox" name="groupBox_5">
|
||||
<property name="title">
|
||||
<string>Mouse/Pointer Source</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_6">
|
||||
<item row="2" column="1">
|
||||
<widget class="QSlider" name="pointerYScale">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>150</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>30</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="4">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Using raw input improves precision when you bind controller sticks to the mouse pointer. Also enables multiple mice to be used.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="3">
|
||||
<widget class="QCheckBox" name="pointerYInvert">
|
||||
<property name="text">
|
||||
<string>Invert</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLabel" name="pointerXScaleLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>10</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QCheckBox" name="pointerXInvert">
|
||||
<property name="text">
|
||||
<string>Invert</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Vertical Sensitivity:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSlider" name="pointerXScale">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>150</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>30</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QLabel" name="pointerYScaleLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>10</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Horizontal Sensitivity:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QGroupBox" name="groupBox_4">
|
||||
<property name="title">
|
||||
<string>Controller Multitap</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_4">
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>The multitap enables up to 8 controllers to be connected to the console. Each multitap provides 4 ports. Multitap is not supported by all games.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="multitapPort1">
|
||||
<property name="text">
|
||||
<string>Multitap on Console Port 1</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="multitapPort2">
|
||||
<property name="text">
|
||||
<string>Multitap on Console Port 2</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QGroupBox" name="profileSettings">
|
||||
<property name="title">
|
||||
<string>Profile Settings</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_5">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>When this option is enabled, hotkeys can be set in this input profile, and will be used instead of the global hotkeys. By default, hotkeys are always shared between all profiles.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="useProfileHotkeyBindings">
|
||||
<property name="text">
|
||||
<string>Use Per-Profile Hotkeys</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>45</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="1" rowspan="6">
|
||||
<widget class="QGroupBox" name="groupBox_3">
|
||||
<property name="title">
|
||||
<string>Detected Devices</string>
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <type_traits>
|
||||
|
||||
#include <QtCore/QtCore>
|
||||
#include <QtGui/QAction>
|
||||
#include <QtWidgets/QCheckBox>
|
||||
#include <QtWidgets/QComboBox>
|
||||
#include <QtWidgets/QDoubleSpinBox>
|
||||
#include <QtWidgets/QLineEdit>
|
||||
#include <QtWidgets/QSlider>
|
||||
#include <QtWidgets/QSpinBox>
|
||||
|
||||
#include "pcsx2/HostSettings.h"
|
||||
|
||||
#include "EmuThread.h"
|
||||
#include "QtHost.h"
|
||||
|
||||
#include "SettingWidgetBinder.h"
|
||||
|
||||
/// This nastyness is required because input profiles aren't overlaid settings like the rest of them, it's
|
||||
/// input profile *or* global, not both.
|
||||
namespace ControllerSettingWidgetBinder
|
||||
{
|
||||
/// Interface specific method of BindWidgetToBoolSetting().
|
||||
template <typename WidgetType>
|
||||
static void BindWidgetToInputProfileBool(SettingsInterface* sif, WidgetType* widget, std::string section, std::string key, bool default_value)
|
||||
{
|
||||
using Accessor = SettingWidgetBinder::SettingAccessor<WidgetType>;
|
||||
|
||||
if (sif)
|
||||
{
|
||||
const bool value = sif->GetBoolValue(section.c_str(), key.c_str(), default_value);
|
||||
Accessor::setBoolValue(widget, value);
|
||||
|
||||
Accessor::connectValueChanged(widget, [sif, widget, section = std::move(section), key = std::move(key)]() {
|
||||
const bool new_value = Accessor::getBoolValue(widget);
|
||||
sif->SetBoolValue(section.c_str(), key.c_str(), new_value);
|
||||
sif->Save();
|
||||
g_emu_thread->reloadGameSettings();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
const bool value = Host::GetBaseBoolSettingValue(section.c_str(), key.c_str(), default_value);
|
||||
Accessor::setBoolValue(widget, value);
|
||||
|
||||
Accessor::connectValueChanged(widget, [widget, section = std::move(section), key = std::move(key)]() {
|
||||
const bool new_value = Accessor::getBoolValue(widget);
|
||||
QtHost::SetBaseBoolSettingValue(section.c_str(), key.c_str(), new_value);
|
||||
g_emu_thread->applySettings();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Interface specific method of BindWidgetToFloatSetting().
|
||||
template <typename WidgetType>
|
||||
static void BindWidgetToInputProfileFloat(SettingsInterface* sif, WidgetType* widget, std::string section, std::string key, float default_value)
|
||||
{
|
||||
using Accessor = SettingWidgetBinder::SettingAccessor<WidgetType>;
|
||||
|
||||
if (sif)
|
||||
{
|
||||
const float value = sif->GetFloatValue(section.c_str(), key.c_str(), default_value);
|
||||
Accessor::setFloatValue(widget, value);
|
||||
|
||||
Accessor::connectValueChanged(widget, [sif, widget, section = std::move(section), key = std::move(key)]() {
|
||||
const float new_value = Accessor::getFloatValue(widget);
|
||||
sif->SetFloatValue(section.c_str(), key.c_str(), new_value);
|
||||
sif->Save();
|
||||
g_emu_thread->reloadGameSettings();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
const float value = Host::GetBaseFloatSettingValue(section.c_str(), key.c_str(), default_value);
|
||||
Accessor::setFloatValue(widget, value);
|
||||
|
||||
Accessor::connectValueChanged(widget, [widget, section = std::move(section), key = std::move(key)]() {
|
||||
const float new_value = Accessor::getFloatValue(widget);
|
||||
QtHost::SetBaseFloatSettingValue(section.c_str(), key.c_str(), new_value);
|
||||
g_emu_thread->applySettings();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Interface specific method of BindWidgetToNormalizedSetting().
|
||||
template <typename WidgetType>
|
||||
static void BindWidgetToInputProfileNormalized(
|
||||
SettingsInterface* sif, WidgetType* widget, std::string section, std::string key, float range, float default_value)
|
||||
{
|
||||
using Accessor = SettingWidgetBinder::SettingAccessor<WidgetType>;
|
||||
|
||||
|
||||
if (sif)
|
||||
{
|
||||
const float value = sif->GetFloatValue(section.c_str(), key.c_str(), default_value);
|
||||
Accessor::setIntValue(widget, static_cast<int>(value * range));
|
||||
|
||||
Accessor::connectValueChanged(widget, [sif, widget, section = std::move(section), key = std::move(key), range]() {
|
||||
const int new_value = Accessor::getIntValue(widget);
|
||||
sif->SetFloatValue(section.c_str(), key.c_str(), static_cast<float>(new_value) / range);
|
||||
sif->Save();
|
||||
g_emu_thread->reloadGameSettings();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
const float value = Host::GetBaseFloatSettingValue(section.c_str(), key.c_str(), default_value);
|
||||
Accessor::setIntValue(widget, static_cast<int>(value * range));
|
||||
|
||||
Accessor::connectValueChanged(widget, [widget, section = std::move(section), key = std::move(key), range]() {
|
||||
const float new_value = (static_cast<float>(Accessor::getIntValue(widget)) / range);
|
||||
QtHost::SetBaseFloatSettingValue(section.c_str(), key.c_str(), new_value);
|
||||
g_emu_thread->applySettings();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// Interface specific method of BindWidgetToStringSetting().
|
||||
template <typename WidgetType>
|
||||
static void BindWidgetToInputProfileString(
|
||||
SettingsInterface* sif, WidgetType* widget, std::string section, std::string key, std::string default_value = std::string())
|
||||
{
|
||||
using Accessor = SettingWidgetBinder::SettingAccessor<WidgetType>;
|
||||
|
||||
if (sif)
|
||||
{
|
||||
const QString value(QString::fromStdString(sif->GetStringValue(section.c_str(), key.c_str(), default_value.c_str())));
|
||||
|
||||
Accessor::setStringValue(widget, value);
|
||||
|
||||
Accessor::connectValueChanged(widget, [widget, sif, section = std::move(section), key = std::move(key)]() {
|
||||
const QString new_value = Accessor::getStringValue(widget);
|
||||
if (!new_value.isEmpty())
|
||||
sif->SetStringValue(section.c_str(), key.c_str(), new_value.toUtf8().constData());
|
||||
else
|
||||
sif->DeleteValue(section.c_str(), key.c_str());
|
||||
|
||||
sif->Save();
|
||||
g_emu_thread->reloadGameSettings();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
const QString value(QString::fromStdString(Host::GetBaseStringSettingValue(section.c_str(), key.c_str(), default_value.c_str())));
|
||||
|
||||
Accessor::setStringValue(widget, value);
|
||||
|
||||
Accessor::connectValueChanged(widget, [widget, section = std::move(section), key = std::move(key)]() {
|
||||
const QString new_value = Accessor::getStringValue(widget);
|
||||
if (!new_value.isEmpty())
|
||||
QtHost::SetBaseStringSettingValue(section.c_str(), key.c_str(), new_value.toUtf8().constData());
|
||||
else
|
||||
QtHost::RemoveBaseSettingValue(section.c_str(), key.c_str());
|
||||
|
||||
g_emu_thread->applySettings();
|
||||
});
|
||||
}
|
||||
}
|
||||
} // namespace ControllerSettingWidgetBinder
|
||||
@@ -22,9 +22,21 @@
|
||||
#include "Settings/ControllerBindingWidgets.h"
|
||||
#include "Settings/HotkeySettingsWidget.h"
|
||||
|
||||
#include "pcsx2/Frontend/INISettingsInterface.h"
|
||||
#include "pcsx2/PAD/Host/PAD.h"
|
||||
#include "pcsx2/Sio.h"
|
||||
#include "pcsx2/VMManager.h"
|
||||
|
||||
#include "common/Assertions.h"
|
||||
#include "common/FileSystem.h"
|
||||
|
||||
#include <array>
|
||||
#include <QtWidgets/QInputDialog>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
#include <QtWidgets/QTextEdit>
|
||||
|
||||
static constexpr const std::array<char, 4> s_mtap_slot_names = {{'A', 'B', 'C', 'D'}};
|
||||
|
||||
ControllerSettingsDialog::ControllerSettingsDialog(QWidget* parent /* = nullptr */)
|
||||
: QDialog(parent)
|
||||
{
|
||||
@@ -32,21 +44,17 @@ ControllerSettingsDialog::ControllerSettingsDialog(QWidget* parent /* = nullptr
|
||||
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
|
||||
m_global_settings = new ControllerGlobalSettingsWidget(m_ui.settingsContainer, this);
|
||||
m_ui.settingsContainer->insertWidget(0, m_global_settings);
|
||||
|
||||
for (u32 i = 0; i < MAX_PORTS; i++)
|
||||
{
|
||||
m_port_bindings[i] = new ControllerBindingWidget(m_ui.settingsContainer, this, i);
|
||||
m_ui.settingsContainer->insertWidget(i + 1, m_port_bindings[i]);
|
||||
}
|
||||
|
||||
m_hotkey_settings = new HotkeySettingsWidget(m_ui.settingsContainer, this);
|
||||
m_ui.settingsContainer->insertWidget(3, m_hotkey_settings);
|
||||
refreshProfileList();
|
||||
createWidgets();
|
||||
|
||||
m_ui.settingsCategory->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||
connect(m_ui.settingsCategory, &QListWidget::currentRowChanged, this, &ControllerSettingsDialog::onCategoryCurrentRowChanged);
|
||||
connect(m_ui.currentProfile, &QComboBox::currentIndexChanged, this, &ControllerSettingsDialog::onCurrentProfileChanged);
|
||||
connect(m_ui.buttonBox, &QDialogButtonBox::rejected, this, &ControllerSettingsDialog::close);
|
||||
connect(m_ui.newProfile, &QPushButton::clicked, this, &ControllerSettingsDialog::onNewProfileClicked);
|
||||
connect(m_ui.loadProfile, &QPushButton::clicked, this, &ControllerSettingsDialog::onLoadProfileClicked);
|
||||
connect(m_ui.deleteProfile, &QPushButton::clicked, this, &ControllerSettingsDialog::onDeleteProfileClicked);
|
||||
connect(m_ui.restoreDefaults, &QPushButton::clicked, this, &ControllerSettingsDialog::onRestoreDefaultsClicked);
|
||||
|
||||
connect(g_emu_thread, &EmuThread::onInputDevicesEnumerated, this, &ControllerSettingsDialog::onInputDevicesEnumerated);
|
||||
connect(g_emu_thread, &EmuThread::onInputDeviceConnected, this, &ControllerSettingsDialog::onInputDeviceConnected);
|
||||
@@ -87,6 +95,123 @@ void ControllerSettingsDialog::onCategoryCurrentRowChanged(int row)
|
||||
m_ui.settingsContainer->setCurrentIndex(row);
|
||||
}
|
||||
|
||||
void ControllerSettingsDialog::onCurrentProfileChanged(int index)
|
||||
{
|
||||
switchProfile((index == 0) ? 0 : m_ui.currentProfile->itemText(index));
|
||||
}
|
||||
|
||||
void ControllerSettingsDialog::onNewProfileClicked()
|
||||
{
|
||||
const QString profile_name(QInputDialog::getText(this, tr("Create Input Profile"), tr("Enter the name for the new input profile:")));
|
||||
if (profile_name.isEmpty())
|
||||
return;
|
||||
|
||||
std::string profile_path(VMManager::GetInputProfilePath(profile_name.toStdString()));
|
||||
if (FileSystem::FileExists(profile_path.c_str()))
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), tr("A profile with the name '%1' already exists.").arg(profile_name));
|
||||
return;
|
||||
}
|
||||
|
||||
const int res = QMessageBox::question(this, tr("Create Input Profile"),
|
||||
tr("Do you want to copy all bindings from the currently-selected profile to the new profile? Selecting No will create a completely empty profile."),
|
||||
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
|
||||
if (res == QMessageBox::Cancel)
|
||||
return;
|
||||
|
||||
INISettingsInterface temp_si(std::move(profile_path));
|
||||
if (res == QMessageBox::Yes)
|
||||
{
|
||||
// copy from global or the current profile
|
||||
if (!m_profile_interface)
|
||||
{
|
||||
// from global
|
||||
auto lock = Host::GetSettingsLock();
|
||||
PAD::CopyConfiguration(&temp_si, *Host::Internal::GetBaseSettingsLayer(), true, true, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// from profile
|
||||
const bool copy_hotkey_bindings = m_profile_interface->GetBoolValue("Pad", "UseProfileHotkeyBindings", false);
|
||||
temp_si.SetBoolValue("Pad", "UseProfileHotkeyBindings", copy_hotkey_bindings);
|
||||
PAD::CopyConfiguration(&temp_si, *m_profile_interface, true, true, copy_hotkey_bindings);
|
||||
}
|
||||
}
|
||||
|
||||
if (!temp_si.Save())
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), tr("Failed to save the new profile to '%1'.").arg(QString::fromStdString(temp_si.GetFileName())));
|
||||
return;
|
||||
}
|
||||
|
||||
refreshProfileList();
|
||||
switchProfile(profile_name);
|
||||
}
|
||||
|
||||
void ControllerSettingsDialog::onLoadProfileClicked()
|
||||
{
|
||||
if (QMessageBox::question(this, tr("Load Input Profile"),
|
||||
tr("Are you sure you want to load the input profile named '%1'?\n\n"
|
||||
"All current global bindings will be removed, and the profile bindings loaded.\n\n"
|
||||
"You cannot undo this action.")
|
||||
.arg(m_profile_name)) != QMessageBox::Yes)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
auto lock = Host::GetSettingsLock();
|
||||
PAD::CopyConfiguration(Host::Internal::GetBaseSettingsLayer(), *m_profile_interface, true, true, false);
|
||||
QtHost::QueueSettingsSave();
|
||||
}
|
||||
|
||||
// make it visible
|
||||
switchProfile({});
|
||||
}
|
||||
|
||||
void ControllerSettingsDialog::onDeleteProfileClicked()
|
||||
{
|
||||
if (QMessageBox::question(this, tr("Delete Input Profile"),
|
||||
tr("Are you sure you want to delete the input profile named '%1'?\n\n"
|
||||
"You cannot undo this action.")
|
||||
.arg(m_profile_name)) != QMessageBox::Yes)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::string profile_path(VMManager::GetInputProfilePath(m_profile_name.toStdString()));
|
||||
if (!FileSystem::DeleteFilePath(profile_path.c_str()))
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), tr("Failed to delete '%1'.").arg(QString::fromStdString(profile_path)));
|
||||
return;
|
||||
}
|
||||
|
||||
// switch back to global
|
||||
refreshProfileList();
|
||||
switchProfile({});
|
||||
}
|
||||
|
||||
void ControllerSettingsDialog::onRestoreDefaultsClicked()
|
||||
{
|
||||
if (QMessageBox::question(this, tr("Restore Defaults"),
|
||||
tr("Are you sure you want to restore the default controller configuration?\n\n"
|
||||
"All shared bindings and configuration will be lost, but your input profiles will remain.\n\n"
|
||||
"You cannot undo this action.")) != QMessageBox::Yes)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// actually restore it
|
||||
{
|
||||
auto lock = Host::GetSettingsLock();
|
||||
PAD::SetDefaultConfig(*Host::Internal::GetBaseSettingsLayer());
|
||||
QtHost::QueueSettingsSave();
|
||||
}
|
||||
|
||||
// reload all settings
|
||||
switchProfile({});
|
||||
}
|
||||
|
||||
void ControllerSettingsDialog::onInputDevicesEnumerated(const QList<QPair<QString, QString>>& devices)
|
||||
{
|
||||
m_device_list = devices;
|
||||
@@ -128,3 +253,213 @@ void ControllerSettingsDialog::onVibrationMotorsEnumerated(const QList<InputBind
|
||||
m_vibration_motors.push_back(QString::fromStdString(key_str));
|
||||
}
|
||||
}
|
||||
|
||||
bool ControllerSettingsDialog::getBoolValue(const char* section, const char* key, bool default_value) const
|
||||
{
|
||||
if (m_profile_interface)
|
||||
return m_profile_interface->GetBoolValue(section, key, default_value);
|
||||
else
|
||||
return Host::GetBaseBoolSettingValue(section, key, default_value);
|
||||
}
|
||||
|
||||
std::string ControllerSettingsDialog::getStringValue(const char* section, const char* key, const char* default_value) const
|
||||
{
|
||||
std::string value;
|
||||
if (m_profile_interface)
|
||||
value = m_profile_interface->GetStringValue(section, key, default_value);
|
||||
else
|
||||
value = Host::GetBaseStringSettingValue(section, key, default_value);
|
||||
return value;
|
||||
}
|
||||
|
||||
void ControllerSettingsDialog::setBoolValue(const char* section, const char* key, bool value)
|
||||
{
|
||||
if (m_profile_interface)
|
||||
{
|
||||
m_profile_interface->SetBoolValue(section, key, value);
|
||||
m_profile_interface->Save();
|
||||
g_emu_thread->reloadGameSettings();
|
||||
}
|
||||
else
|
||||
{
|
||||
QtHost::SetBaseBoolSettingValue(section, key, value);
|
||||
g_emu_thread->applySettings();
|
||||
}
|
||||
}
|
||||
|
||||
void ControllerSettingsDialog::setStringValue(const char* section, const char* key, const char* value)
|
||||
{
|
||||
if (m_profile_interface)
|
||||
{
|
||||
m_profile_interface->SetStringValue(section, key, value);
|
||||
m_profile_interface->Save();
|
||||
g_emu_thread->reloadGameSettings();
|
||||
}
|
||||
else
|
||||
{
|
||||
QtHost::SetBaseStringSettingValue(key, section, value);
|
||||
g_emu_thread->applySettings();
|
||||
}
|
||||
}
|
||||
|
||||
void ControllerSettingsDialog::clearSettingValue(const char* section, const char* key)
|
||||
{
|
||||
if (m_profile_interface)
|
||||
{
|
||||
m_profile_interface->DeleteValue(section, key);
|
||||
m_profile_interface->Save();
|
||||
g_emu_thread->reloadGameSettings();
|
||||
}
|
||||
else
|
||||
{
|
||||
QtHost::RemoveBaseSettingValue(section, key);
|
||||
g_emu_thread->applySettings();
|
||||
}
|
||||
}
|
||||
|
||||
void ControllerSettingsDialog::createWidgets()
|
||||
{
|
||||
QSignalBlocker sb(m_ui.settingsContainer);
|
||||
QSignalBlocker sb2(m_ui.settingsCategory);
|
||||
|
||||
while (m_ui.settingsContainer->count() > 0)
|
||||
{
|
||||
QWidget* widget = m_ui.settingsContainer->widget(m_ui.settingsContainer->count() - 1);
|
||||
m_ui.settingsContainer->removeWidget(widget);
|
||||
widget->deleteLater();
|
||||
}
|
||||
|
||||
m_ui.settingsCategory->clear();
|
||||
|
||||
m_global_settings = nullptr;
|
||||
m_hotkey_settings = nullptr;
|
||||
|
||||
{
|
||||
// global settings
|
||||
QListWidgetItem* item = new QListWidgetItem();
|
||||
item->setText(tr("Global Settings"));
|
||||
item->setIcon(QIcon::fromTheme("settings-3-line"));
|
||||
m_ui.settingsCategory->addItem(item);
|
||||
m_ui.settingsCategory->setCurrentRow(0);
|
||||
m_global_settings = new ControllerGlobalSettingsWidget(m_ui.settingsContainer, this);
|
||||
m_ui.settingsContainer->addWidget(m_global_settings);
|
||||
connect(m_global_settings, &ControllerGlobalSettingsWidget::bindingSetupChanged, this, &ControllerSettingsDialog::createWidgets);
|
||||
for (const QPair<QString, QString>& dev : m_device_list)
|
||||
m_global_settings->addDeviceToList(dev.first, dev.second);
|
||||
}
|
||||
|
||||
// load mtap settings
|
||||
const std::array<bool, 2> mtap_enabled = {{getBoolValue("Pad", "MultitapPort1", false),
|
||||
getBoolValue("Pad", "MultitapPort2", false)}};
|
||||
|
||||
// we reorder things a little to make it look less silly for mtap
|
||||
static constexpr const std::array<u32, MAX_PORTS> mtap_port_order = {{0, 2, 3, 4, 1, 5, 6, 7}};
|
||||
|
||||
// create the ports
|
||||
for (u32 global_slot : mtap_port_order)
|
||||
{
|
||||
const bool is_mtap_port = sioPadIsMultitapSlot(global_slot);
|
||||
const auto [port, slot] = sioConvertPadToPortAndSlot(global_slot);
|
||||
if (is_mtap_port && !mtap_enabled[port])
|
||||
continue;
|
||||
|
||||
m_port_bindings[global_slot] = new ControllerBindingWidget(m_ui.settingsContainer, this, global_slot);
|
||||
m_ui.settingsContainer->addWidget(m_port_bindings[global_slot]);
|
||||
|
||||
const PAD::ControllerInfo* ci = PAD::GetControllerInfo(m_port_bindings[global_slot]->getControllerType());
|
||||
const QString display_name(ci ? QString::fromUtf8(ci->display_name) : QStringLiteral("Unknown"));
|
||||
|
||||
QListWidgetItem* item = new QListWidgetItem();
|
||||
item->setText(mtap_enabled[port] ?
|
||||
(tr("Controller Port %1%2\n%3").arg(port + 1).arg(s_mtap_slot_names[slot]).arg(display_name)) :
|
||||
tr("Controller Port %1\n%2").arg(port + 1).arg(display_name));
|
||||
item->setIcon(m_port_bindings[global_slot]->getIcon());
|
||||
item->setData(Qt::UserRole, QVariant(global_slot));
|
||||
m_ui.settingsCategory->addItem(item);
|
||||
}
|
||||
|
||||
// only add hotkeys if we're editing global settings
|
||||
if (!m_profile_interface || m_profile_interface->GetBoolValue("Pad", "UseProfileHotkeyBindings", false))
|
||||
{
|
||||
QListWidgetItem* item = new QListWidgetItem();
|
||||
item->setText(tr("Hotkeys"));
|
||||
item->setIcon(QIcon::fromTheme("keyboard-line"));
|
||||
m_ui.settingsCategory->addItem(item);
|
||||
m_hotkey_settings = new HotkeySettingsWidget(m_ui.settingsContainer, this);
|
||||
m_ui.settingsContainer->addWidget(m_hotkey_settings);
|
||||
}
|
||||
|
||||
m_ui.loadProfile->setEnabled(isEditingProfile());
|
||||
m_ui.deleteProfile->setEnabled(isEditingProfile());
|
||||
m_ui.restoreDefaults->setEnabled(isEditingGlobalSettings());
|
||||
}
|
||||
|
||||
void ControllerSettingsDialog::updateListDescription(u32 global_slot, ControllerBindingWidget* widget)
|
||||
{
|
||||
for (int i = 0; i < m_ui.settingsCategory->count(); i++)
|
||||
{
|
||||
QListWidgetItem* item = m_ui.settingsCategory->item(i);
|
||||
const QVariant data(item->data(Qt::UserRole));
|
||||
if (data.type() == QVariant::UInt && data.toUInt() == global_slot)
|
||||
{
|
||||
const bool is_mtap_port = sioPadIsMultitapSlot(global_slot);
|
||||
const auto [port, slot] = sioConvertPadToPortAndSlot(global_slot);
|
||||
const bool mtap_enabled = getBoolValue("Pad", (port == 0) ? "MultitapPort1" : "MultitapPort2", false);
|
||||
|
||||
const PAD::ControllerInfo* ci = PAD::GetControllerInfo(widget->getControllerType());
|
||||
const QString display_name(ci ? QString::fromUtf8(ci->display_name) : QStringLiteral("Unknown"));
|
||||
|
||||
item->setText(mtap_enabled ?
|
||||
(tr("Controller Port %1%2\n%3").arg(port + 1).arg(s_mtap_slot_names[slot]).arg(display_name)) :
|
||||
tr("Controller Port %1\n%2").arg(port + 1).arg(display_name));
|
||||
item->setIcon(widget->getIcon());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
void ControllerSettingsDialog::refreshProfileList()
|
||||
{
|
||||
const std::vector<std::string> names(PAD::GetInputProfileNames());
|
||||
|
||||
QSignalBlocker sb(m_ui.currentProfile);
|
||||
m_ui.currentProfile->clear();
|
||||
m_ui.currentProfile->addItem(tr("Shared"));
|
||||
if (isEditingGlobalSettings())
|
||||
m_ui.currentProfile->setCurrentIndex(0);
|
||||
|
||||
for (const std::string& name : names)
|
||||
{
|
||||
const QString qname(QString::fromStdString(name));
|
||||
m_ui.currentProfile->addItem(qname);
|
||||
if (qname == m_profile_name)
|
||||
m_ui.currentProfile->setCurrentIndex(m_ui.currentProfile->count() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
void ControllerSettingsDialog::switchProfile(const QString& name)
|
||||
{
|
||||
QSignalBlocker sb(m_ui.currentProfile);
|
||||
|
||||
if (!name.isEmpty())
|
||||
{
|
||||
std::string path(VMManager::GetInputProfilePath(name.toStdString()));
|
||||
if (!FileSystem::FileExists(path.c_str()))
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), tr("The input profile named '%1' cannot be found.").arg(name));
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_ptr<INISettingsInterface> sif(std::make_unique<INISettingsInterface>(std::move(path)));
|
||||
sif->Load();
|
||||
m_profile_interface = std::move(sif);
|
||||
m_ui.currentProfile->setCurrentIndex(m_ui.currentProfile->findText(name));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_profile_interface.reset();
|
||||
m_ui.currentProfile->setCurrentIndex(0);
|
||||
}
|
||||
|
||||
m_profile_name = name;
|
||||
createWidgets();
|
||||
}
|
||||
|
||||
@@ -22,11 +22,14 @@
|
||||
#include <QtCore/QStringList>
|
||||
#include <QtWidgets/QDialog>
|
||||
#include <array>
|
||||
#include <string>
|
||||
|
||||
class ControllerGlobalSettingsWidget;
|
||||
class ControllerBindingWidget;
|
||||
class HotkeySettingsWidget;
|
||||
|
||||
class SettingsInterface;
|
||||
|
||||
class ControllerSettingsDialog final : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -42,29 +45,57 @@ public:
|
||||
|
||||
enum : u32
|
||||
{
|
||||
MAX_PORTS = 2
|
||||
MAX_PORTS = 8
|
||||
};
|
||||
|
||||
ControllerSettingsDialog(QWidget* parent = nullptr);
|
||||
~ControllerSettingsDialog();
|
||||
|
||||
HotkeySettingsWidget* getHotkeySettingsWidget() const { return m_hotkey_settings; }
|
||||
__fi HotkeySettingsWidget* getHotkeySettingsWidget() const { return m_hotkey_settings; }
|
||||
|
||||
__fi const QList<QPair<QString, QString>>& getDeviceList() const { return m_device_list; }
|
||||
__fi const QStringList& getVibrationMotors() const { return m_vibration_motors; }
|
||||
|
||||
__fi bool isEditingGlobalSettings() const { return m_profile_name.isEmpty(); }
|
||||
__fi bool isEditingProfile() const { return !m_profile_name.isEmpty(); }
|
||||
__fi SettingsInterface* getProfileSettingsInterface() { return m_profile_interface.get(); }
|
||||
|
||||
void updateListDescription(u32 global_slot, ControllerBindingWidget* widget);
|
||||
|
||||
// Helper functions for updating setting values globally or in the profile.
|
||||
bool getBoolValue(const char* section, const char* key, bool default_value) const;
|
||||
std::string getStringValue(const char* section, const char* key, const char* default_value) const;
|
||||
void setBoolValue(const char* section, const char* key, bool value);
|
||||
void setStringValue(const char* section, const char* key, const char* value);
|
||||
void clearSettingValue(const char* section, const char* key);
|
||||
|
||||
Q_SIGNALS:
|
||||
void inputProfileSwitched();
|
||||
|
||||
public Q_SLOTS:
|
||||
void setCategory(Category category);
|
||||
|
||||
private Q_SLOTS:
|
||||
void onCategoryCurrentRowChanged(int row);
|
||||
void onCurrentProfileChanged(int index);
|
||||
void onNewProfileClicked();
|
||||
void onLoadProfileClicked();
|
||||
void onDeleteProfileClicked();
|
||||
void onRestoreDefaultsClicked();
|
||||
|
||||
void onInputDevicesEnumerated(const QList<QPair<QString, QString>>& devices);
|
||||
void onInputDeviceConnected(const QString& identifier, const QString& device_name);
|
||||
void onInputDeviceDisconnected(const QString& identifier);
|
||||
void onVibrationMotorsEnumerated(const QList<InputBindingKey>& motors);
|
||||
|
||||
void createWidgets();
|
||||
|
||||
private:
|
||||
static QIcon getIconForType(const std::string& type);
|
||||
|
||||
void refreshProfileList();
|
||||
void switchProfile(const QString& name);
|
||||
|
||||
Ui::ControllerSettingsDialog m_ui;
|
||||
|
||||
ControllerGlobalSettingsWidget* m_global_settings = nullptr;
|
||||
@@ -73,4 +104,7 @@ private:
|
||||
|
||||
QList<QPair<QString, QString>> m_device_list;
|
||||
QStringList m_vibration_motors;
|
||||
|
||||
QString m_profile_name;
|
||||
std::unique_ptr<SettingsInterface> m_profile_interface;
|
||||
};
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1274</width>
|
||||
<height>668</height>
|
||||
<width>1276</width>
|
||||
<height>672</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
@@ -22,7 +22,7 @@
|
||||
<property name="windowTitle">
|
||||
<string>PCSX2 Controller Settings</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout" columnstretch="0,0">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QListWidget" name="settingsCategory">
|
||||
<property name="sizePolicy">
|
||||
@@ -49,42 +49,6 @@
|
||||
<height>32</height>
|
||||
</size>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Global Settings</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="settings-3-line">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Controller 1</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="gamepad-line">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Controller 2</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="gamepad-line">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Hotkeys</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="keyboard-line">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
@@ -95,23 +59,74 @@
|
||||
<height>620</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="page"/>
|
||||
<widget class="QWidget" name="page_3"/>
|
||||
<widget class="QWidget" name="page_4"/>
|
||||
<widget class="QWidget" name="page_5"/>
|
||||
<widget class="QWidget" name="page_6"/>
|
||||
<widget class="QWidget" name="page_2"/>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Close</set>
|
||||
</property>
|
||||
</widget>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Profile:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="currentProfile"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="newProfile">
|
||||
<property name="text">
|
||||
<string>New Profile</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="file-add-line">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="loadProfile">
|
||||
<property name="text">
|
||||
<string>Load Profile</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="folder-open-line"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="deleteProfile">
|
||||
<property name="text">
|
||||
<string>Delete Profile</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="file-reduce-line">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="restoreDefaults">
|
||||
<property name="text">
|
||||
<string>Restore Defaults</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="restart-line"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Close</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
||||
@@ -60,20 +60,16 @@ CreateMemoryCardDialog::~CreateMemoryCardDialog() = default;
|
||||
|
||||
void CreateMemoryCardDialog::nameTextChanged()
|
||||
{
|
||||
const QString controlName(m_ui.name->text());
|
||||
QString controlName(m_ui.name->text());
|
||||
const int cursorPos = m_ui.name->cursorPosition();
|
||||
|
||||
QString nameWithoutExtension;
|
||||
if (controlName.endsWith(QStringLiteral(".ps2")))
|
||||
nameWithoutExtension = controlName.left(controlName.size() - 4);
|
||||
else
|
||||
nameWithoutExtension = controlName;
|
||||
controlName.replace(".", "");
|
||||
|
||||
QSignalBlocker sb(m_ui.name);
|
||||
if (nameWithoutExtension.isEmpty())
|
||||
if (controlName.isEmpty())
|
||||
m_ui.name->setText(QString());
|
||||
else
|
||||
m_ui.name->setText(nameWithoutExtension + QStringLiteral(".ps2"));
|
||||
m_ui.name->setText(controlName);
|
||||
|
||||
m_ui.name->setCursorPosition(cursorPos);
|
||||
updateState();
|
||||
@@ -99,7 +95,7 @@ void CreateMemoryCardDialog::restoreDefaults()
|
||||
|
||||
void CreateMemoryCardDialog::updateState()
|
||||
{
|
||||
const bool okay = (m_ui.name->text().length() > 4);
|
||||
const bool okay = (m_ui.name->text().length() > 0);
|
||||
|
||||
m_ui.buttonBox->button(QDialogButtonBox::Ok)->setEnabled(okay);
|
||||
#ifdef _WIN32
|
||||
@@ -109,8 +105,20 @@ void CreateMemoryCardDialog::updateState()
|
||||
|
||||
void CreateMemoryCardDialog::createCard()
|
||||
{
|
||||
const QString name(m_ui.name->text());
|
||||
const std::string nameStr(name.toStdString());
|
||||
QString name(m_ui.name->text());
|
||||
std::string nameStr;
|
||||
|
||||
if (m_fileType == MemoryCardFileType::PS1)
|
||||
{
|
||||
name += QStringLiteral(".mcr");
|
||||
}
|
||||
else
|
||||
{
|
||||
name += QStringLiteral(".ps2");
|
||||
}
|
||||
|
||||
nameStr = name.toStdString();
|
||||
|
||||
if (FileMcd_GetCardInfo(nameStr).has_value())
|
||||
{
|
||||
QMessageBox::critical(this, tr("Create Memory Card"),
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include <QtWidgets/QMessageBox>
|
||||
#include <algorithm>
|
||||
|
||||
#include "FolderSettingsWidget.h"
|
||||
#include "SettingWidgetBinder.h"
|
||||
#include "SettingsDialog.h"
|
||||
|
||||
FolderSettingsWidget::FolderSettingsWidget(SettingsDialog* dialog, QWidget* parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
SettingsInterface* sif = dialog->getSettingsInterface();
|
||||
|
||||
m_ui.setupUi(this);
|
||||
|
||||
SettingWidgetBinder::BindWidgetToFolderSetting(sif, m_ui.cache, m_ui.cacheBrowse, m_ui.cacheOpen, m_ui.cacheReset, "Folders", "Cache", "cache");
|
||||
SettingWidgetBinder::BindWidgetToFolderSetting(sif, m_ui.covers, m_ui.coversBrowse, m_ui.coversOpen, m_ui.coversReset, "Folders", "Covers", "covers");
|
||||
SettingWidgetBinder::BindWidgetToFolderSetting(sif, m_ui.snapshots, m_ui.snapshotsBrowse, m_ui.snapshotsOpen, m_ui.snapshotsReset, "Folders", "Snapshots", "snaps");
|
||||
SettingWidgetBinder::BindWidgetToFolderSetting(sif, m_ui.saveStates, m_ui.saveStatesBrowse, m_ui.saveStatesOpen, m_ui.saveStatesReset, "Folders", "SaveStates", "sstates");
|
||||
}
|
||||
|
||||
FolderSettingsWidget::~FolderSettingsWidget() = default;
|
||||
@@ -0,0 +1,34 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QtWidgets/QWidget>
|
||||
|
||||
#include "ui_FolderSettingsWidget.h"
|
||||
|
||||
class SettingsDialog;
|
||||
|
||||
class FolderSettingsWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
FolderSettingsWidget(SettingsDialog* dialog, QWidget* parent);
|
||||
~FolderSettingsWidget();
|
||||
|
||||
private:
|
||||
Ui::FolderSettingsWidget m_ui;
|
||||
};
|
||||
@@ -0,0 +1,208 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>FolderSettingsWidget</class>
|
||||
<widget class="QWidget" name="FolderSettingsWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>648</width>
|
||||
<height>487</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_3">
|
||||
<property name="title">
|
||||
<string>Cache Directory</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLineEdit" name="cache"/>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QPushButton" name="cacheBrowse">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="cacheOpen">
|
||||
<property name="text">
|
||||
<string>Open...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QPushButton" name="cacheReset">
|
||||
<property name="text">
|
||||
<string>Reset</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="4">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Used for storing shaders, gzip indices, and game list data.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_4">
|
||||
<property name="title">
|
||||
<string>Covers Directory</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_4">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLineEdit" name="covers"/>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QPushButton" name="coversBrowse">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="coversOpen">
|
||||
<property name="text">
|
||||
<string>Open...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QPushButton" name="coversReset">
|
||||
<property name="text">
|
||||
<string>Reset</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="4">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Used for storing covers in the game grid/Big Picture UIs.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Snapshots Directory</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLineEdit" name="snapshots"/>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QPushButton" name="snapshotsBrowse">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="snapshotsOpen">
|
||||
<property name="text">
|
||||
<string>Open...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QPushButton" name="snapshotsReset">
|
||||
<property name="text">
|
||||
<string>Reset</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="4">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Used for screenshots and saving GS dumps.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Save States Directory</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLineEdit" name="saveStates"/>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QPushButton" name="saveStatesBrowse">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="saveStatesOpen">
|
||||
<property name="text">
|
||||
<string>Open...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QPushButton" name="saveStatesReset">
|
||||
<property name="text">
|
||||
<string>Reset</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="4">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Used for storing save states.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>132</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="../resources/resources.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -47,6 +47,7 @@ GameFixSettingsWidget::GameFixSettingsWidget(SettingsDialog* dialog, QWidget* pa
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.VUSyncHack, "EmuCore/Gamefixes", "VUSyncHack", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.VUOverflowHack, "EmuCore/Gamefixes", "VUOverflowHack", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.XgKickHack, "EmuCore/Gamefixes", "XgKickHack", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.BlitInternalFPSHack, "EmuCore/Gamefixes", "BlitInternalFPSHack", false);
|
||||
}
|
||||
|
||||
GameFixSettingsWidget::~GameFixSettingsWidget() = default;
|
||||
|
||||
@@ -141,6 +141,13 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="BlitInternalFPSHack">
|
||||
<property name="text">
|
||||
<string>Force Blit Internal FPS Detection (When auto-detection fails)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -18,11 +18,14 @@
|
||||
#include "common/StringUtil.h"
|
||||
|
||||
#include "Frontend/GameList.h"
|
||||
#include "PAD/Host/PAD.h"
|
||||
|
||||
#include "GameSummaryWidget.h"
|
||||
#include "SettingsDialog.h"
|
||||
#include "QtHost.h"
|
||||
|
||||
GameSummaryWidget::GameSummaryWidget(const GameList::Entry* entry, SettingsDialog* dialog, QWidget* parent)
|
||||
: m_dialog(dialog)
|
||||
{
|
||||
m_ui.setupUi(this);
|
||||
|
||||
@@ -39,6 +42,8 @@ GameSummaryWidget::GameSummaryWidget(const GameList::Entry* entry, SettingsDialo
|
||||
}
|
||||
|
||||
populateUi(entry);
|
||||
|
||||
connect(m_ui.inputProfile, &QComboBox::currentIndexChanged, this, &GameSummaryWidget::onInputProfileChanged);
|
||||
}
|
||||
|
||||
GameSummaryWidget::~GameSummaryWidget() = default;
|
||||
@@ -52,4 +57,21 @@ void GameSummaryWidget::populateUi(const GameList::Entry* entry)
|
||||
m_ui.type->setCurrentIndex(static_cast<int>(entry->type));
|
||||
m_ui.region->setCurrentIndex(static_cast<int>(entry->region));
|
||||
m_ui.compatibility->setCurrentIndex(static_cast<int>(entry->compatibility_rating));
|
||||
|
||||
for (const std::string& name : PAD::GetInputProfileNames())
|
||||
m_ui.inputProfile->addItem(QString::fromStdString(name));
|
||||
|
||||
std::optional<std::string> profile(m_dialog->getStringValue("EmuCore", "InputProfileName", std::nullopt));
|
||||
if (profile.has_value())
|
||||
m_ui.inputProfile->setCurrentIndex(m_ui.inputProfile->findText(QString::fromStdString(profile.value())));
|
||||
else
|
||||
m_ui.inputProfile->setCurrentIndex(0);
|
||||
}
|
||||
|
||||
void GameSummaryWidget::onInputProfileChanged(int index)
|
||||
{
|
||||
if (index == 0)
|
||||
m_dialog->setStringSettingValue("EmuCore", "InputProfileName", std::nullopt);
|
||||
else
|
||||
m_dialog->setStringSettingValue("EmuCore", "InputProfileName", m_ui.inputProfile->itemText(index).toUtf8());
|
||||
}
|
||||
|
||||
@@ -37,5 +37,8 @@ public:
|
||||
private:
|
||||
void populateUi(const GameList::Entry* entry);
|
||||
|
||||
void onInputProfileChanged(int index);
|
||||
|
||||
Ui::GameSummaryWidget m_ui;
|
||||
SettingsDialog* m_dialog;
|
||||
};
|
||||
|
||||
@@ -82,6 +82,65 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Type:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QComboBox" name="type">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>PS2 Disc</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources/resources.qrc">
|
||||
<normaloff>:/icons/media-optical-24.png</normaloff>:/icons/media-optical-24.png</iconset>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>PS1 Disc</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources/resources.qrc">
|
||||
<normaloff>:/icons/media-optical-24.png</normaloff>:/icons/media-optical-24.png</iconset>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>ELF (PS2 Executable)</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources/resources.qrc">
|
||||
<normaloff>:/icons/applications-system-24.png</normaloff>:/icons/applications-system-24.png</iconset>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Playlist</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources/resources.qrc">
|
||||
<normaloff>:/icons/address-book-new-22.png</normaloff>:/icons/address-book-new-22.png</iconset>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
@@ -94,6 +153,12 @@
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
@@ -251,24 +316,17 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QComboBox" name="compatibility">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
@@ -301,62 +359,44 @@
|
||||
<property name="text">
|
||||
<string>Perfect</string>
|
||||
</property>
|
||||
</item>z
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<item row="8" column="1">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QComboBox" name="inputProfile">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Shared</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Type:</string>
|
||||
<string>Input Profile:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QComboBox" name="type">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>PS2 Disc</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources/resources.qrc">
|
||||
<normaloff>:/icons/media-optical-24.png</normaloff>:/icons/media-optical-24.png</iconset>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>PS1 Disc</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources/resources.qrc">
|
||||
<normaloff>:/icons/media-optical-24.png</normaloff>:/icons/media-optical-24.png</iconset>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>ELF (PS2 Executable)</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources/resources.qrc">
|
||||
<normaloff>:/icons/applications-system-24.png</normaloff>:/icons/applications-system-24.png</iconset>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Playlist</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources/resources.qrc">
|
||||
<normaloff>:/icons/address-book-new-22.png</normaloff>:/icons/address-book-new-22.png</iconset>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources>
|
||||
|
||||
@@ -86,6 +86,12 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
|
||||
m_ui.setupUi(this);
|
||||
|
||||
// start hidden, fixup in updateRendererDependentOptions()
|
||||
m_ui.hardwareRendererGroup->setVisible(false);
|
||||
m_ui.verticalLayout->removeWidget(m_ui.hardwareRendererGroup);
|
||||
m_ui.softwareRendererGroup->setVisible(false);
|
||||
m_ui.verticalLayout->removeWidget(m_ui.softwareRendererGroup);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Global Settings
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@@ -105,6 +111,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.integerScaling, "EmuCore/GS", "IntegerScaling", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.PCRTCOffsets, "EmuCore/GS", "pcrtc_offsets", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.PCRTCOverscan, "EmuCore/GS", "pcrtc_overscan", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.PCRTCAntiBlur, "EmuCore/GS", "pcrtc_antiblur", true);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.DisableInterlaceOffset, "EmuCore/GS", "disable_interlace_offset", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.internalResolutionScreenshots, "EmuCore/GS", "InternalResolutionScreenshots", false);
|
||||
SettingWidgetBinder::BindWidgetToFloatSetting(sif, m_ui.zoom, "EmuCore/GS", "Zoom", 100.0f);
|
||||
@@ -208,6 +215,8 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsDialog* dialog, QWidget*
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.loadTextureReplacements, "EmuCore/GS", "LoadTextureReplacements", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.loadTextureReplacementsAsync, "EmuCore/GS", "LoadTextureReplacementsAsync", true);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.precacheTextureReplacements, "EmuCore/GS", "PrecacheTextureReplacements", false);
|
||||
SettingWidgetBinder::BindWidgetToFolderSetting(sif, m_ui.texturesDirectory, m_ui.texturesBrowse, m_ui.texturesOpen, m_ui.texturesReset,
|
||||
"Folders", "Textures", "textures");
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Advanced Settings
|
||||
@@ -537,7 +546,7 @@ void GraphicsSettingsWidget::updateRendererDependentOptions()
|
||||
const int current_tab = m_hardware_renderer_visible ? m_ui.hardwareRendererGroup->currentIndex() : m_ui.softwareRendererGroup->currentIndex();
|
||||
|
||||
// move advanced tab to the correct parent
|
||||
static constexpr std::array<const char*, 3> move_tab_names = {{"Display", "On-Screen Display", "Advanced"}};
|
||||
static constexpr std::array<const char*, 3> move_tab_names = {{"Display", "OSD", "Advanced"}};
|
||||
const std::array<QWidget*, 3> move_tab_pointers = {{m_ui.gameDisplayTab, m_ui.osdTab, m_ui.advancedTab}};
|
||||
for (size_t i = 0; i < move_tab_pointers.size(); i++)
|
||||
{
|
||||
@@ -564,7 +573,7 @@ void GraphicsSettingsWidget::updateRendererDependentOptions()
|
||||
{
|
||||
// map first two tabs over, skip hacks
|
||||
m_ui.verticalLayout->insertWidget(1, m_ui.hardwareRendererGroup);
|
||||
m_ui.hardwareRendererGroup->setCurrentIndex((current_tab < 2) ? current_tab : (current_tab + 2));
|
||||
m_ui.hardwareRendererGroup->setCurrentIndex((current_tab < 2) ? current_tab : (current_tab + 3));
|
||||
}
|
||||
|
||||
m_hardware_renderer_visible = is_hardware;
|
||||
@@ -684,5 +693,6 @@ void GraphicsSettingsWidget::updateRendererDependentOptions()
|
||||
}
|
||||
|
||||
m_ui.enableHWFixes->setEnabled(is_hardware);
|
||||
onEnableHardwareFixesChanged();
|
||||
if (is_hardware)
|
||||
onEnableHardwareFixesChanged();
|
||||
}
|
||||
|
||||
@@ -31,8 +31,6 @@ public:
|
||||
GraphicsSettingsWidget(SettingsDialog* dialog, QWidget* parent);
|
||||
~GraphicsSettingsWidget();
|
||||
|
||||
void updateRendererDependentOptions();
|
||||
|
||||
Q_SIGNALS:
|
||||
void fullscreenModesChanged(const QStringList& modes);
|
||||
|
||||
@@ -48,11 +46,12 @@ private Q_SLOTS:
|
||||
|
||||
private:
|
||||
GSRendererType getEffectiveRenderer() const;
|
||||
void updateRendererDependentOptions();
|
||||
|
||||
SettingsDialog* m_dialog;
|
||||
|
||||
Ui::GraphicsSettingsWidget m_ui;
|
||||
|
||||
bool m_hardware_renderer_visible = true;
|
||||
bool m_software_renderer_visible = true;
|
||||
bool m_hardware_renderer_visible = false;
|
||||
bool m_software_renderer_visible = false;
|
||||
};
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>566</width>
|
||||
<width>657</width>
|
||||
<height>890</height>
|
||||
</rect>
|
||||
</property>
|
||||
@@ -323,6 +323,19 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QCheckBox" name="PCRTCAntiBlur">
|
||||
<property name="toolTip">
|
||||
<string>Enables internal Anti-Blur hacks. LEss accurate to PS2 rendering but will make a lot of games look less blurry.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Anti-Blur</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+S</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
@@ -900,9 +913,120 @@
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab">
|
||||
<attribute name="title">
|
||||
<string>Texture Replacement</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_6">
|
||||
<property name="title">
|
||||
<string>Search Directory</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_4">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLineEdit" name="texturesDirectory"/>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QPushButton" name="texturesBrowse">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="texturesOpen">
|
||||
<property name="text">
|
||||
<string>Open...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QPushButton" name="texturesReset">
|
||||
<property name="text">
|
||||
<string>Reset</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="4">
|
||||
<widget class="QLabel" name="label_38">
|
||||
<property name="text">
|
||||
<string>PCSX2 will dump and load texture replacements from this directory.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Options</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_8">
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="dumpReplaceableTextures">
|
||||
<property name="text">
|
||||
<string>Dump Textures</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="dumpReplaceableMipmaps">
|
||||
<property name="text">
|
||||
<string>Dump Mipmaps</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="dumpTexturesWithFMVActive">
|
||||
<property name="text">
|
||||
<string>Dump FMV Textures</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="loadTextureReplacementsAsync">
|
||||
<property name="text">
|
||||
<string>Async Texture Loading</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="loadTextureReplacements">
|
||||
<property name="text">
|
||||
<string>Load Textures</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QCheckBox" name="precacheTextureReplacements">
|
||||
<property name="text">
|
||||
<string>Precache Textures</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_4">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QGroupBox" name="osdTab">
|
||||
<attribute name="title">
|
||||
<string>On-Screen Display</string>
|
||||
<string>OSD</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
@@ -1274,57 +1398,6 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Texture Replacement</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_8">
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="dumpReplaceableTextures">
|
||||
<property name="text">
|
||||
<string>Dump Textures</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="dumpReplaceableMipmaps">
|
||||
<property name="text">
|
||||
<string>Dump Mipmaps</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="loadTextureReplacementsAsync">
|
||||
<property name="text">
|
||||
<string>Async Texture Loading</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QCheckBox" name="precacheTextureReplacements">
|
||||
<property name="text">
|
||||
<string>Precache Textures</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="loadTextureReplacements">
|
||||
<property name="text">
|
||||
<string>Load Textures</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="dumpTexturesWithFMVActive">
|
||||
<property name="text">
|
||||
<string>Dump FMV Textures</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
HotkeySettingsWidget::HotkeySettingsWidget(QWidget* parent, ControllerSettingsDialog* dialog)
|
||||
: QWidget(parent)
|
||||
, m_dialog(dialog)
|
||||
{
|
||||
createUi();
|
||||
}
|
||||
@@ -79,6 +80,6 @@ void HotkeySettingsWidget::createButtons()
|
||||
const int target_row = layout->count() / 2;
|
||||
|
||||
layout->addWidget(new QLabel(qApp->translate("Hotkeys", hotkey->display_name), container), target_row, 0);
|
||||
layout->addWidget(new InputBindingWidget(container, "Hotkeys", hotkey->name), target_row, 1);
|
||||
layout->addWidget(new InputBindingWidget(container, m_dialog->getProfileSettingsInterface(), "Hotkeys", hotkey->name), target_row, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ private:
|
||||
void createUi();
|
||||
void createButtons();
|
||||
|
||||
ControllerSettingsDialog* m_dialog;
|
||||
QTabWidget* m_tab_widget;
|
||||
|
||||
struct Category
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#include "EmuThread.h"
|
||||
#include "QtHost.h"
|
||||
#include "QtUtils.h"
|
||||
#include "Settings/InputBindingDialog.h"
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtGui/QKeyEvent>
|
||||
@@ -25,9 +26,10 @@
|
||||
// _BitScanForward()
|
||||
#include "pcsx2/GS/GSIntrin.h"
|
||||
|
||||
InputBindingDialog::InputBindingDialog(std::string section_name, std::string key_name,
|
||||
InputBindingDialog::InputBindingDialog(SettingsInterface* sif, std::string section_name, std::string key_name,
|
||||
std::vector<std::string> bindings, QWidget* parent)
|
||||
: QDialog(parent)
|
||||
, m_sif(sif)
|
||||
, m_section_name(std::move(section_name))
|
||||
, m_key_name(std::move(key_name))
|
||||
, m_bindings(std::move(bindings))
|
||||
@@ -54,7 +56,7 @@ bool InputBindingDialog::eventFilter(QObject* watched, QEvent* event)
|
||||
const QEvent::Type event_type = event->type();
|
||||
|
||||
// if the key is being released, set the input
|
||||
if (event_type == QEvent::KeyRelease || event_type == QEvent::MouseButtonPress)
|
||||
if (event_type == QEvent::KeyRelease || event_type == QEvent::MouseButtonRelease)
|
||||
{
|
||||
addNewBinding();
|
||||
stopListeningForInput();
|
||||
@@ -63,20 +65,46 @@ bool InputBindingDialog::eventFilter(QObject* watched, QEvent* event)
|
||||
else if (event_type == QEvent::KeyPress)
|
||||
{
|
||||
const QKeyEvent* key_event = static_cast<const QKeyEvent*>(event);
|
||||
m_new_bindings.push_back(InputManager::MakeHostKeyboardKey(key_event->key()));
|
||||
m_new_bindings.push_back(InputManager::MakeHostKeyboardKey(QtUtils::KeyEventToCode(key_event)));
|
||||
return true;
|
||||
}
|
||||
else if (event_type == QEvent::MouseButtonPress)
|
||||
else if (event_type == QEvent::MouseButtonPress || event_type == QEvent::MouseButtonDblClick)
|
||||
{
|
||||
// double clicks get triggered if we click bind, then click again quickly.
|
||||
unsigned long button_index;
|
||||
if (_BitScanForward(&button_index, static_cast<u32>(static_cast<const QMouseEvent*>(event)->button())))
|
||||
m_new_bindings.push_back(InputManager::MakeHostMouseButtonKey(button_index));
|
||||
m_new_bindings.push_back(InputManager::MakePointerButtonKey(0, button_index));
|
||||
return true;
|
||||
}
|
||||
else if (event_type == QEvent::MouseButtonDblClick)
|
||||
else if (event_type == QEvent::MouseMove)
|
||||
{
|
||||
// just eat double clicks
|
||||
return true;
|
||||
// if we've moved more than a decent distance from the center of the widget, bind it.
|
||||
// this is so we don't accidentally bind to the mouse if you bump it while reaching for your pad.
|
||||
static constexpr const s32 THRESHOLD = 50;
|
||||
const QPoint diff(static_cast<QMouseEvent*>(event)->globalPos() - m_input_listen_start_position);
|
||||
bool has_one = false;
|
||||
|
||||
if (std::abs(diff.x()) >= THRESHOLD)
|
||||
{
|
||||
InputBindingKey key(InputManager::MakePointerAxisKey(0, InputPointerAxis::X));
|
||||
key.negative = (diff.x() < 0);
|
||||
m_new_bindings.push_back(key);
|
||||
has_one = true;
|
||||
}
|
||||
if (std::abs(diff.y()) >= THRESHOLD)
|
||||
{
|
||||
InputBindingKey key(InputManager::MakePointerAxisKey(0, InputPointerAxis::Y));
|
||||
key.negative = (diff.y() < 0);
|
||||
m_new_bindings.push_back(key);
|
||||
has_one = true;
|
||||
}
|
||||
|
||||
if (has_one)
|
||||
{
|
||||
addNewBinding();
|
||||
stopListeningForInput();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -97,6 +125,7 @@ void InputBindingDialog::onInputListenTimerTimeout()
|
||||
void InputBindingDialog::startListeningForInput(u32 timeout_in_seconds)
|
||||
{
|
||||
m_new_bindings.clear();
|
||||
m_input_listen_start_position = QCursor::pos();
|
||||
m_input_listen_timer = new QTimer(this);
|
||||
m_input_listen_timer->setSingleShot(false);
|
||||
m_input_listen_timer->start(1000);
|
||||
@@ -113,6 +142,7 @@ void InputBindingDialog::startListeningForInput(u32 timeout_in_seconds)
|
||||
installEventFilter(this);
|
||||
grabKeyboard();
|
||||
grabMouse();
|
||||
setMouseTracking(true);
|
||||
hookInputManager();
|
||||
}
|
||||
|
||||
@@ -130,6 +160,7 @@ void InputBindingDialog::stopListeningForInput()
|
||||
unhookInputManager();
|
||||
releaseMouse();
|
||||
releaseKeyboard();
|
||||
setMouseTracking(false);
|
||||
removeEventFilter(this);
|
||||
}
|
||||
|
||||
@@ -186,12 +217,23 @@ void InputBindingDialog::updateList()
|
||||
|
||||
void InputBindingDialog::saveListToSettings()
|
||||
{
|
||||
if (!m_bindings.empty())
|
||||
QtHost::SetBaseStringListSettingValue(m_section_name.c_str(), m_key_name.c_str(), m_bindings);
|
||||
if (m_sif)
|
||||
{
|
||||
if (!m_bindings.empty())
|
||||
m_sif->SetStringList(m_section_name.c_str(), m_key_name.c_str(), m_bindings);
|
||||
else
|
||||
m_sif->DeleteValue(m_section_name.c_str(), m_key_name.c_str());
|
||||
m_sif->Save();
|
||||
g_emu_thread->reloadGameSettings();
|
||||
}
|
||||
else
|
||||
QtHost::RemoveBaseSettingValue(m_section_name.c_str(), m_key_name.c_str());
|
||||
|
||||
g_emu_thread->reloadInputBindings();
|
||||
{
|
||||
if (!m_bindings.empty())
|
||||
QtHost::SetBaseStringListSettingValue(m_section_name.c_str(), m_key_name.c_str(), m_bindings);
|
||||
else
|
||||
QtHost::RemoveBaseSettingValue(m_section_name.c_str(), m_key_name.c_str());
|
||||
g_emu_thread->reloadInputBindings();
|
||||
}
|
||||
}
|
||||
|
||||
void InputBindingDialog::inputManagerHookCallback(InputBindingKey key, float value)
|
||||
|
||||
@@ -21,12 +21,14 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class SettingsInterface;
|
||||
|
||||
class InputBindingDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
InputBindingDialog(std::string section_name, std::string key_name, std::vector<std::string> bindings, QWidget* parent);
|
||||
InputBindingDialog(SettingsInterface* sif, std::string section_name, std::string key_name, std::vector<std::string> bindings, QWidget* parent);
|
||||
~InputBindingDialog();
|
||||
|
||||
protected Q_SLOTS:
|
||||
@@ -58,6 +60,7 @@ protected:
|
||||
|
||||
Ui::InputBindingDialog m_ui;
|
||||
|
||||
SettingsInterface* m_sif;
|
||||
std::string m_section_name;
|
||||
std::string m_key_name;
|
||||
std::vector<std::string> m_bindings;
|
||||
@@ -65,4 +68,5 @@ protected:
|
||||
|
||||
QTimer* m_input_listen_timer = nullptr;
|
||||
u32 m_input_listen_remaining_seconds = 0;
|
||||
QPoint m_input_listen_start_position{};
|
||||
};
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <QtGui/QKeyEvent>
|
||||
#include <QtGui/QMouseEvent>
|
||||
#include <QtWidgets/QInputDialog>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
#include <cmath>
|
||||
#include <sstream>
|
||||
|
||||
@@ -39,7 +40,7 @@ InputBindingWidget::InputBindingWidget(QWidget* parent)
|
||||
connect(this, &QPushButton::clicked, this, &InputBindingWidget::onClicked);
|
||||
}
|
||||
|
||||
InputBindingWidget::InputBindingWidget(QWidget* parent, std::string section_name, std::string key_name)
|
||||
InputBindingWidget::InputBindingWidget(QWidget* parent, SettingsInterface* sif, std::string section_name, std::string key_name)
|
||||
: QPushButton(parent)
|
||||
{
|
||||
setMinimumWidth(225);
|
||||
@@ -47,7 +48,7 @@ InputBindingWidget::InputBindingWidget(QWidget* parent, std::string section_name
|
||||
|
||||
connect(this, &QPushButton::clicked, this, &InputBindingWidget::onClicked);
|
||||
|
||||
setKey(std::move(section_name), std::move(key_name));
|
||||
initialize(sif, std::move(section_name), std::move(key_name));
|
||||
}
|
||||
|
||||
InputBindingWidget::~InputBindingWidget()
|
||||
@@ -55,12 +56,12 @@ InputBindingWidget::~InputBindingWidget()
|
||||
Q_ASSERT(!isListeningForInput());
|
||||
}
|
||||
|
||||
void InputBindingWidget::setKey(std::string section_name, std::string key_name)
|
||||
void InputBindingWidget::initialize(SettingsInterface* sif, std::string section_name, std::string key_name)
|
||||
{
|
||||
m_sif = sif;
|
||||
m_section_name = std::move(section_name);
|
||||
m_key_name = std::move(key_name);
|
||||
m_bindings = Host::GetBaseStringListSetting(m_section_name.c_str(), m_key_name.c_str());
|
||||
updateText();
|
||||
reloadBinding();
|
||||
}
|
||||
|
||||
void InputBindingWidget::updateText()
|
||||
@@ -105,7 +106,7 @@ bool InputBindingWidget::eventFilter(QObject* watched, QEvent* event)
|
||||
const QEvent::Type event_type = event->type();
|
||||
|
||||
// if the key is being released, set the input
|
||||
if (event_type == QEvent::KeyRelease || event_type == QEvent::MouseButtonPress)
|
||||
if (event_type == QEvent::KeyRelease || event_type == QEvent::MouseButtonRelease)
|
||||
{
|
||||
setNewBinding();
|
||||
stopListeningForInput();
|
||||
@@ -114,20 +115,46 @@ bool InputBindingWidget::eventFilter(QObject* watched, QEvent* event)
|
||||
else if (event_type == QEvent::KeyPress)
|
||||
{
|
||||
const QKeyEvent* key_event = static_cast<const QKeyEvent*>(event);
|
||||
m_new_bindings.push_back(InputManager::MakeHostKeyboardKey(key_event->key()));
|
||||
m_new_bindings.push_back(InputManager::MakeHostKeyboardKey(QtUtils::KeyEventToCode(key_event)));
|
||||
return true;
|
||||
}
|
||||
else if (event_type == QEvent::MouseButtonPress)
|
||||
else if (event_type == QEvent::MouseButtonPress || event_type == QEvent::MouseButtonDblClick)
|
||||
{
|
||||
// double clicks get triggered if we click bind, then click again quickly.
|
||||
unsigned long button_index;
|
||||
if (_BitScanForward(&button_index, static_cast<u32>(static_cast<const QMouseEvent*>(event)->button())))
|
||||
m_new_bindings.push_back(InputManager::MakeHostMouseButtonKey(button_index));
|
||||
m_new_bindings.push_back(InputManager::MakePointerButtonKey(0, button_index));
|
||||
return true;
|
||||
}
|
||||
else if (event_type == QEvent::MouseButtonDblClick)
|
||||
else if (event_type == QEvent::MouseMove)
|
||||
{
|
||||
// just eat double clicks
|
||||
return true;
|
||||
// if we've moved more than a decent distance from the center of the widget, bind it.
|
||||
// this is so we don't accidentally bind to the mouse if you bump it while reaching for your pad.
|
||||
static constexpr const s32 THRESHOLD = 50;
|
||||
const QPoint diff(static_cast<QMouseEvent*>(event)->globalPos() - m_input_listen_start_position);
|
||||
bool has_one = false;
|
||||
|
||||
if (std::abs(diff.x()) >= THRESHOLD)
|
||||
{
|
||||
InputBindingKey key(InputManager::MakePointerAxisKey(0, InputPointerAxis::X));
|
||||
key.negative = (diff.x() < 0);
|
||||
m_new_bindings.push_back(key);
|
||||
has_one = true;
|
||||
}
|
||||
if (std::abs(diff.y()) >= THRESHOLD)
|
||||
{
|
||||
InputBindingKey key(InputManager::MakePointerAxisKey(0, InputPointerAxis::Y));
|
||||
key.negative = (diff.y() < 0);
|
||||
m_new_bindings.push_back(key);
|
||||
has_one = true;
|
||||
}
|
||||
|
||||
if (has_one)
|
||||
{
|
||||
setNewBinding();
|
||||
stopListeningForInput();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -168,8 +195,17 @@ void InputBindingWidget::setNewBinding()
|
||||
InputManager::ConvertInputBindingKeysToString(m_new_bindings.data(), m_new_bindings.size()));
|
||||
if (!new_binding.empty())
|
||||
{
|
||||
QtHost::SetBaseStringSettingValue(m_section_name.c_str(), m_key_name.c_str(), new_binding.c_str());
|
||||
g_emu_thread->reloadInputBindings();
|
||||
if (m_sif)
|
||||
{
|
||||
m_sif->SetStringValue(m_section_name.c_str(), m_key_name.c_str(), new_binding.c_str());
|
||||
m_sif->Save();
|
||||
g_emu_thread->reloadGameSettings();
|
||||
}
|
||||
else
|
||||
{
|
||||
QtHost::SetBaseStringSettingValue(m_section_name.c_str(), m_key_name.c_str(), new_binding.c_str());
|
||||
g_emu_thread->reloadInputBindings();
|
||||
}
|
||||
}
|
||||
|
||||
m_bindings.clear();
|
||||
@@ -179,14 +215,25 @@ void InputBindingWidget::setNewBinding()
|
||||
void InputBindingWidget::clearBinding()
|
||||
{
|
||||
m_bindings.clear();
|
||||
QtHost::RemoveBaseSettingValue(m_section_name.c_str(), m_key_name.c_str());
|
||||
g_emu_thread->reloadInputBindings();
|
||||
updateText();
|
||||
if (m_sif)
|
||||
{
|
||||
m_sif->DeleteValue(m_section_name.c_str(), m_key_name.c_str());
|
||||
m_sif->Save();
|
||||
g_emu_thread->reloadGameSettings();
|
||||
}
|
||||
else
|
||||
{
|
||||
QtHost::RemoveBaseSettingValue(m_section_name.c_str(), m_key_name.c_str());
|
||||
g_emu_thread->reloadInputBindings();
|
||||
}
|
||||
reloadBinding();
|
||||
}
|
||||
|
||||
void InputBindingWidget::reloadBinding()
|
||||
{
|
||||
m_bindings = Host::GetBaseStringListSetting(m_section_name.c_str(), m_key_name.c_str());
|
||||
m_bindings = m_sif ?
|
||||
m_sif->GetStringList(m_section_name.c_str(), m_key_name.c_str()) :
|
||||
Host::GetBaseStringListSetting(m_section_name.c_str(), m_key_name.c_str());
|
||||
updateText();
|
||||
}
|
||||
|
||||
@@ -219,6 +266,7 @@ void InputBindingWidget::onInputListenTimerTimeout()
|
||||
void InputBindingWidget::startListeningForInput(u32 timeout_in_seconds)
|
||||
{
|
||||
m_new_bindings.clear();
|
||||
m_input_listen_start_position = QCursor::pos();
|
||||
m_input_listen_timer = new QTimer(this);
|
||||
m_input_listen_timer->setSingleShot(false);
|
||||
m_input_listen_timer->start(1000);
|
||||
@@ -231,17 +279,19 @@ void InputBindingWidget::startListeningForInput(u32 timeout_in_seconds)
|
||||
installEventFilter(this);
|
||||
grabKeyboard();
|
||||
grabMouse();
|
||||
setMouseTracking(true);
|
||||
hookInputManager();
|
||||
}
|
||||
|
||||
void InputBindingWidget::stopListeningForInput()
|
||||
{
|
||||
updateText();
|
||||
reloadBinding();
|
||||
delete m_input_listen_timer;
|
||||
m_input_listen_timer = nullptr;
|
||||
std::vector<InputBindingKey>().swap(m_new_bindings);
|
||||
|
||||
unhookInputManager();
|
||||
setMouseTracking(false);
|
||||
releaseMouse();
|
||||
releaseKeyboard();
|
||||
removeEventFilter(this);
|
||||
@@ -293,7 +343,7 @@ void InputBindingWidget::unhookInputManager()
|
||||
|
||||
void InputBindingWidget::openDialog()
|
||||
{
|
||||
InputBindingDialog binding_dialog(m_section_name, m_key_name, m_bindings, QtUtils::GetRootWidget(this));
|
||||
InputBindingDialog binding_dialog(m_sif, m_section_name, m_key_name, m_bindings, QtUtils::GetRootWidget(this));
|
||||
binding_dialog.exec();
|
||||
reloadBinding();
|
||||
}
|
||||
@@ -342,7 +392,14 @@ void InputVibrationBindingWidget::onClicked()
|
||||
const QString current(QString::fromStdString(m_binding));
|
||||
QStringList input_options(m_dialog->getVibrationMotors());
|
||||
if (!current.isEmpty() && input_options.indexOf(current) < 0)
|
||||
{
|
||||
input_options.append(current);
|
||||
}
|
||||
else if (input_options.isEmpty())
|
||||
{
|
||||
QMessageBox::critical(QtUtils::GetRootWidget(this), tr("Error"), tr("No devices with vibration motors were detected."));
|
||||
return;
|
||||
}
|
||||
|
||||
QInputDialog input_dialog(this);
|
||||
input_dialog.setWindowTitle(full_key);
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
class QTimer;
|
||||
|
||||
class ControllerSettingsDialog;
|
||||
class SettingsInterface;
|
||||
|
||||
class InputBindingWidget : public QPushButton
|
||||
{
|
||||
@@ -29,10 +30,10 @@ class InputBindingWidget : public QPushButton
|
||||
|
||||
public:
|
||||
InputBindingWidget(QWidget* parent);
|
||||
InputBindingWidget(QWidget* parent, std::string section_name, std::string key_name);
|
||||
InputBindingWidget(QWidget* parent, SettingsInterface* sif, std::string section_name, std::string key_name);
|
||||
~InputBindingWidget();
|
||||
|
||||
void setKey(std::string section_name, std::string key_name);
|
||||
void initialize(SettingsInterface* sif, std::string section_name, std::string key_name);
|
||||
|
||||
public Q_SLOTS:
|
||||
void clearBinding();
|
||||
@@ -65,12 +66,14 @@ protected:
|
||||
void hookInputManager();
|
||||
void unhookInputManager();
|
||||
|
||||
SettingsInterface* m_sif = nullptr;
|
||||
std::string m_section_name;
|
||||
std::string m_key_name;
|
||||
std::vector<std::string> m_bindings;
|
||||
std::vector<InputBindingKey> m_new_bindings;
|
||||
QTimer* m_input_listen_timer = nullptr;
|
||||
u32 m_input_listen_remaining_seconds = 0;
|
||||
QPoint m_input_listen_start_position{};
|
||||
};
|
||||
|
||||
class InputVibrationBindingWidget : public QPushButton
|
||||
|
||||
@@ -117,7 +117,6 @@ InterfaceSettingsWidget::InterfaceSettingsWidget(SettingsDialog* dialog, QWidget
|
||||
m_ui.pauseOnStart->setDisabled(true);
|
||||
m_ui.pauseOnFocusLoss->setDisabled(true);
|
||||
m_ui.disableWindowResizing->setDisabled(true);
|
||||
m_ui.hideMouseCursor->setDisabled(true);
|
||||
m_ui.language->setDisabled(true);
|
||||
}
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="hideMouseCursor">
|
||||
<property name="text">
|
||||
<string>Hide Mouse Cursor</string>
|
||||
<string>Hide Cursor In Fullscreen</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include <QtGui/QDrag>
|
||||
#include <QtWidgets/QFileDialog>
|
||||
#include <QtWidgets/QInputDialog>
|
||||
#include <QtWidgets/QMenu>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
@@ -48,12 +49,14 @@ MemoryCardSettingsWidget::MemoryCardSettingsWidget(SettingsDialog* dialog, QWidg
|
||||
// this is a bit lame, but resizeEvent() isn't good enough to autosize our columns,
|
||||
// since the group box hasn't been resized at that point.
|
||||
m_ui.cardGroupBox->installEventFilter(this);
|
||||
|
||||
|
||||
SettingWidgetBinder::BindWidgetToFolderSetting(sif, m_ui.directory, m_ui.browse, m_ui.open, m_ui.reset, "Folders", "MemoryCards", "memcards");
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.autoEject, "EmuCore", "McdEnableEjection", true);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.automaticManagement, "EmuCore", "McdFolderAutoManage", true);
|
||||
|
||||
setupAdditionalUi();
|
||||
|
||||
connect(m_ui.directory, &QLineEdit::textChanged, this, &MemoryCardSettingsWidget::refresh);
|
||||
m_ui.cardList->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(m_ui.cardList, &MemoryCardListWidget::itemSelectionChanged, this, &MemoryCardSettingsWidget::updateCardActions);
|
||||
connect(m_ui.cardList, &MemoryCardListWidget::customContextMenuRequested, this, &MemoryCardSettingsWidget::listContextMenuRequested);
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>796</width>
|
||||
<width>639</width>
|
||||
<height>443</height>
|
||||
</rect>
|
||||
</property>
|
||||
@@ -58,6 +58,41 @@
|
||||
<string>Memory Cards</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Folder:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="directory"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="browse">
|
||||
<property name="text">
|
||||
<string>Browse...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="open">
|
||||
<property name="text">
|
||||
<string>Open...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="reset">
|
||||
<property name="text">
|
||||
<string>Reset</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="MemoryCardListWidget" name="cardList">
|
||||
<property name="rootIsDecorated">
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "GameListSettingsWidget.h"
|
||||
#include "GraphicsSettingsWidget.h"
|
||||
#include "DEV9SettingsWidget.h"
|
||||
#include "FolderSettingsWidget.h"
|
||||
#include "HotkeySettingsWidget.h"
|
||||
#include "InterfaceSettingsWidget.h"
|
||||
#include "MemoryCardSettingsWidget.h"
|
||||
@@ -133,6 +134,12 @@ void SettingsDialog::setupUi(const GameList::Entry* game)
|
||||
tr("<strong>Network & HDD Settings</strong><hr>These options control the network connectivity and internal HDD storage of the console.<br><br>"
|
||||
"Mouse over an option for additional information."));
|
||||
|
||||
if (!isPerGameSettings())
|
||||
{
|
||||
addWidget(m_folder_settings = new FolderSettingsWidget(this, m_ui.settingsContainer), tr("Folders"), QStringLiteral("folder-open-line"),
|
||||
tr("<strong>Folder Settings</strong><hr>These options control where PCSX2 will save runtime data files."));
|
||||
}
|
||||
|
||||
m_ui.settingsCategory->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||
m_ui.settingsCategory->setCurrentRow(0);
|
||||
m_ui.settingsContainer->setCurrentIndex(0);
|
||||
@@ -363,13 +370,13 @@ void SettingsDialog::setBoolSettingValue(const char* section, const char* key, s
|
||||
{
|
||||
value.has_value() ? m_sif->SetBoolValue(section, key, value.value()) : m_sif->DeleteValue(section, key);
|
||||
m_sif->Save();
|
||||
g_emu_thread->reloadGameSettings();
|
||||
}
|
||||
else
|
||||
{
|
||||
value.has_value() ? QtHost::SetBaseBoolSettingValue(section, key, value.value()) : QtHost::RemoveBaseSettingValue(section, key);
|
||||
g_emu_thread->applySettings();
|
||||
}
|
||||
|
||||
g_emu_thread->applySettings();
|
||||
}
|
||||
|
||||
void SettingsDialog::setIntSettingValue(const char* section, const char* key, std::optional<int> value)
|
||||
@@ -378,13 +385,13 @@ void SettingsDialog::setIntSettingValue(const char* section, const char* key, st
|
||||
{
|
||||
value.has_value() ? m_sif->SetIntValue(section, key, value.value()) : m_sif->DeleteValue(section, key);
|
||||
m_sif->Save();
|
||||
g_emu_thread->reloadGameSettings();
|
||||
}
|
||||
else
|
||||
{
|
||||
value.has_value() ? QtHost::SetBaseIntSettingValue(section, key, value.value()) : QtHost::RemoveBaseSettingValue(section, key);
|
||||
g_emu_thread->applySettings();
|
||||
}
|
||||
|
||||
g_emu_thread->applySettings();
|
||||
}
|
||||
|
||||
void SettingsDialog::setFloatSettingValue(const char* section, const char* key, std::optional<float> value)
|
||||
@@ -393,13 +400,13 @@ void SettingsDialog::setFloatSettingValue(const char* section, const char* key,
|
||||
{
|
||||
value.has_value() ? m_sif->SetFloatValue(section, key, value.value()) : m_sif->DeleteValue(section, key);
|
||||
m_sif->Save();
|
||||
g_emu_thread->reloadGameSettings();
|
||||
}
|
||||
else
|
||||
{
|
||||
value.has_value() ? QtHost::SetBaseFloatSettingValue(section, key, value.value()) : QtHost::RemoveBaseSettingValue(section, key);
|
||||
g_emu_thread->applySettings();
|
||||
}
|
||||
|
||||
g_emu_thread->applySettings();
|
||||
}
|
||||
|
||||
void SettingsDialog::setStringSettingValue(const char* section, const char* key, std::optional<const char*> value)
|
||||
@@ -408,13 +415,13 @@ void SettingsDialog::setStringSettingValue(const char* section, const char* key,
|
||||
{
|
||||
value.has_value() ? m_sif->SetStringValue(section, key, value.value()) : m_sif->DeleteValue(section, key);
|
||||
m_sif->Save();
|
||||
g_emu_thread->reloadGameSettings();
|
||||
}
|
||||
else
|
||||
{
|
||||
value.has_value() ? QtHost::SetBaseStringSettingValue(section, key, value.value()) : QtHost::RemoveBaseSettingValue(section, key);
|
||||
g_emu_thread->applySettings();
|
||||
}
|
||||
|
||||
g_emu_thread->applySettings();
|
||||
}
|
||||
|
||||
void SettingsDialog::openGamePropertiesDialog(const GameList::Entry* game, const std::string_view& serial, u32 crc)
|
||||
|
||||
@@ -39,6 +39,7 @@ class GameFixSettingsWidget;
|
||||
class GraphicsSettingsWidget;
|
||||
class AudioSettingsWidget;
|
||||
class MemoryCardSettingsWidget;
|
||||
class FolderSettingsWidget;
|
||||
class DEV9SettingsWidget;
|
||||
|
||||
class SettingsDialog final : public QDialog
|
||||
@@ -65,6 +66,7 @@ public:
|
||||
__fi GraphicsSettingsWidget* getGraphicsSettingsWidget() const { return m_graphics_settings; }
|
||||
__fi AudioSettingsWidget* getAudioSettingsWidget() const { return m_audio_settings; }
|
||||
__fi MemoryCardSettingsWidget* getMemoryCardSettingsWidget() const { return m_memory_card_settings; }
|
||||
__fi FolderSettingsWidget* getFolderSettingsWidget() const { return m_folder_settings; }
|
||||
__fi DEV9SettingsWidget* getDEV9SettingsWidget() const { return m_dev9_settings; }
|
||||
|
||||
void registerWidgetHelp(QObject* object, QString title, QString recommended_value, QString text);
|
||||
@@ -122,6 +124,7 @@ private:
|
||||
GraphicsSettingsWidget* m_graphics_settings = nullptr;
|
||||
AudioSettingsWidget* m_audio_settings = nullptr;
|
||||
MemoryCardSettingsWidget* m_memory_card_settings = nullptr;
|
||||
FolderSettingsWidget* m_folder_settings = nullptr;
|
||||
DEV9SettingsWidget* m_dev9_settings = nullptr;
|
||||
|
||||
std::array<QString, MAX_SETTINGS_WIDGETS> m_category_help_text;
|
||||
|
||||
@@ -135,6 +135,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="EarlyHardwareCheck.cpp" />
|
||||
<ClCompile Include="Settings\FolderSettingsWidget.cpp" />
|
||||
<ClCompile Include="Tools\InputRecording\NewInputRecordingDlg.cpp" />
|
||||
<ClCompile Include="Settings\BIOSSettingsWidget.cpp" />
|
||||
<ClCompile Include="Settings\ControllerBindingWidgets.cpp" />
|
||||
@@ -194,6 +195,8 @@
|
||||
<QtMoc Include="Settings\DEV9DnsHostDialog.h" />
|
||||
<QtMoc Include="Settings\DEV9SettingsWidget.h" />
|
||||
<QtMoc Include="Settings\DEV9UiCommon.h" />
|
||||
<ClInclude Include="Settings\ControllerSettingWidgetBinder.h" />
|
||||
<QtMoc Include="Settings\FolderSettingsWidget.h" />
|
||||
<ClInclude Include="Settings\HddCreateQt.h" />
|
||||
<QtMoc Include="Settings\GameSummaryWidget.h" />
|
||||
<QtMoc Include="Settings\CreateMemoryCardDialog.h" />
|
||||
@@ -237,6 +240,7 @@
|
||||
<ClCompile Include="$(IntDir)Settings\moc_InputBindingWidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)Settings\moc_AudioSettingsWidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)Settings\moc_MemoryCardSettingsWidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)Settings\moc_FolderSettingsWidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)Settings\moc_DEV9DnsHostDialog.cpp" />
|
||||
<ClCompile Include="$(IntDir)Settings\moc_DEV9SettingsWidget.cpp" />
|
||||
<ClCompile Include="$(IntDir)Settings\moc_DEV9UiCommon.cpp" />
|
||||
@@ -328,7 +332,10 @@
|
||||
<FileType>Document</FileType>
|
||||
</QtUi>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Settings\FolderSettingsWidget.ui" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<Import Project="$(SolutionDir)common\vsprops\QtCompile.targets" />
|
||||
<ImportGroup Label="ExtensionTargets" />
|
||||
</Project>
|
||||
</Project>
|
||||
@@ -217,6 +217,12 @@
|
||||
<Filter>Tools\Input Recording</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="EarlyHardwareCheck.cpp" />
|
||||
<ClCompile Include="Settings\FolderSettingsWidget.cpp">
|
||||
<Filter>Settings</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(IntDir)Settings\moc_FolderSettingsWidget.cpp">
|
||||
<Filter>moc</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Manifest Include="..\pcsx2\windows\PCSX2.manifest">
|
||||
@@ -231,6 +237,9 @@
|
||||
<ClInclude Include="Settings\HddCreateQt.h">
|
||||
<Filter>Settings</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Settings\ControllerSettingWidgetBinder.h">
|
||||
<Filter>Settings</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtMoc Include="MainWindow.h" />
|
||||
@@ -316,6 +325,7 @@
|
||||
<QtMoc Include="Tools\InputRecording\NewInputRecordingDlg.h">
|
||||
<Filter>Tools\Input Recording</Filter>
|
||||
</QtMoc>
|
||||
<QtMoc Include="Settings\FolderSettingsWidget.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<QtResource Include="resources\resources.qrc">
|
||||
@@ -392,4 +402,9 @@
|
||||
<Filter>Tools\Input Recording</Filter>
|
||||
</QtUi>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
<ItemGroup>
|
||||
<None Include="Settings\FolderSettingsWidget.ui">
|
||||
<Filter>Settings</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -27,6 +27,8 @@
|
||||
#include "gui/StringHelpers.h"
|
||||
#include "gui/wxDirName.h"
|
||||
#include <wx/stdpaths.h>
|
||||
#else
|
||||
#include "HostSettings.h"
|
||||
#endif
|
||||
|
||||
#define CLAMP(val, minval, maxval) (std::min(maxval, std::max(minval, val)))
|
||||
@@ -60,7 +62,7 @@ static Access* ReadIndexFromFile(const char* filename)
|
||||
if (std::fread(index, sizeof(Access), 1, fp.get()) != 1 ||
|
||||
datasize != static_cast<s64>(index->have) * static_cast<s64>(sizeof(Point)))
|
||||
{
|
||||
Console.Error("Error: unexpected size of gzip index, please delete it manually: '%s'.", filename);
|
||||
Console.Error("Error: Unexpected size of gzip index, please delete it manually: '%s'.", filename);
|
||||
free(index);
|
||||
return 0;
|
||||
}
|
||||
@@ -134,7 +136,7 @@ static std::string ApplyTemplate(const std::string& name, const std::string& bas
|
||||
|| !canEndWithKey && first == trimmedTemplate.length() - std::strlen(INDEX_TEMPLATE_KEY))
|
||||
{
|
||||
Console.Error("Invalid %s template '%s'.\n"
|
||||
"Template must contain exactly one '%s' and must not end with it. Abotring.",
|
||||
"Template must contain exactly one '%s' and must not end with it. Aborting.",
|
||||
name.c_str(), trimmedTemplate.c_str(), INDEX_TEMPLATE_KEY);
|
||||
return {};
|
||||
}
|
||||
@@ -182,10 +184,11 @@ static std::string iso2indexname(const std::string& isoname)
|
||||
#ifndef PCSX2_CORE
|
||||
std::string appRoot = // TODO: have only one of this in PCSX2. Right now have few...
|
||||
StringUtil::wxStringToUTF8String(((wxDirName)(wxFileName(wxStandardPaths::Get().GetExecutablePath()).GetPath())).ToString());
|
||||
return ApplyTemplate("gzip index", appRoot, EmuConfig.GzipIsoIndexTemplate, isoname, false);
|
||||
#else
|
||||
const std::string& appRoot = EmuFolders::DataRoot;
|
||||
return ApplyTemplate("gzip index", appRoot, Host::GetBaseStringSettingValue("EmuCore", "GzipIsoIndexTemplate", "$(f).pindex.tmp"), isoname, false);
|
||||
#endif
|
||||
return ApplyTemplate("gzip index", appRoot, EmuConfig.GzipIsoIndexTemplate, isoname, false);
|
||||
}
|
||||
|
||||
|
||||
@@ -288,7 +291,7 @@ void GzippedFileReader::AsyncPrefetchCancel()
|
||||
|
||||
if (!CancelIo(hOverlappedFile))
|
||||
{
|
||||
Console.Warning("canceling gz prefetch failed. following prefetching will not work.");
|
||||
Console.Warning("Canceling gz prefetch failed. Following prefetching will not work.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -342,7 +345,7 @@ bool GzippedFileReader::OkIndex()
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Error("ERROR (%d): index could not be generated for file '%s'", len, m_filename.c_str());
|
||||
Console.Error("ERROR (%d): Index could not be generated for file '%s'", len, m_filename.c_str());
|
||||
free_index(index);
|
||||
InitZstates();
|
||||
return false;
|
||||
|
||||
@@ -343,6 +343,7 @@ set(pcsx2SPU2Headers
|
||||
|
||||
# DEV9 sources
|
||||
set(pcsx2DEV9Sources
|
||||
DEV9/AdapterUtils.cpp
|
||||
DEV9/ATA/Commands/ATA_Command.cpp
|
||||
DEV9/ATA/Commands/ATA_CmdDMA.cpp
|
||||
DEV9/ATA/Commands/ATA_CmdExecuteDeviceDiag.cpp
|
||||
@@ -387,6 +388,7 @@ set(pcsx2DEV9Sources
|
||||
|
||||
# DEV9 headers
|
||||
set(pcsx2DEV9Headers
|
||||
DEV9/AdapterUtils.h
|
||||
DEV9/ATA/ATA.h
|
||||
DEV9/ATA/HddCreate.h
|
||||
DEV9/DEV9.h
|
||||
@@ -1067,6 +1069,7 @@ if(PCSX2_CORE)
|
||||
Frontend/InputManager.cpp
|
||||
Frontend/InputSource.cpp
|
||||
Frontend/LayeredSettingsInterface.cpp
|
||||
Frontend/LogSink.cpp
|
||||
GSDumpReplayer.cpp
|
||||
HostSettings.cpp
|
||||
VMManager.cpp
|
||||
@@ -1077,6 +1080,7 @@ if(PCSX2_CORE)
|
||||
Frontend/InputManager.h
|
||||
Frontend/InputSource.h
|
||||
Frontend/LayeredSettingsInterface.h
|
||||
Frontend/LogSink.h
|
||||
GSDumpReplayer.h
|
||||
HostSettings.h
|
||||
VMManager.h)
|
||||
|
||||
+5
-9
@@ -44,6 +44,7 @@ enum GamefixId
|
||||
Fix_VUSync,
|
||||
Fix_VUOverflow,
|
||||
Fix_XGKick,
|
||||
Fix_BlitInternalFPS,
|
||||
|
||||
GamefixId_COUNT
|
||||
};
|
||||
@@ -433,6 +434,7 @@ struct Pcsx2Config
|
||||
struct
|
||||
{
|
||||
bool
|
||||
PCRTCAntiBlur : 1,
|
||||
DisableInterlaceOffset : 1,
|
||||
PCRTCOffsets : 1,
|
||||
PCRTCOverscan : 1,
|
||||
@@ -501,13 +503,9 @@ struct Pcsx2Config
|
||||
// style. Useful for debugging potential bugs in the MTGS pipeline.
|
||||
bool SynchronousMTGS{false};
|
||||
bool FrameLimitEnable{true};
|
||||
bool FrameSkipEnable{false};
|
||||
|
||||
VsyncMode VsyncEnable{VsyncMode::Off};
|
||||
|
||||
int FramesToDraw{2}; // number of consecutive frames (fields) to render
|
||||
int FramesToSkip{2}; // number of consecutive frames (fields) to skip
|
||||
|
||||
double LimitScalar{1.0};
|
||||
double FramerateNTSC{59.94};
|
||||
double FrameratePAL{50.00};
|
||||
@@ -800,7 +798,8 @@ struct Pcsx2Config
|
||||
IbitHack : 1, // I bit hack. Needed to stop constant VU recompilation in some games
|
||||
VUSyncHack : 1, // Makes microVU run behind the EE to avoid VU register reading/writing sync issues. Useful for M-Bit games
|
||||
VUOverflowHack : 1, // Tries to simulate overflow flag checks (not really possible on x86 without soft floats)
|
||||
XgKickHack : 1; // Erementar Gerad, adds more delay to VU XGkick instructions. Corrects the color of some graphics, but breaks Tri-ace games and others.
|
||||
XgKickHack : 1, // Erementar Gerad, adds more delay to VU XGkick instructions. Corrects the color of some graphics, but breaks Tri-ace games and others.
|
||||
BlitInternalFPSHack : 1; // Disables privileged register write-based FPS detection.
|
||||
BITFIELD_END
|
||||
|
||||
GamefixOptions();
|
||||
@@ -887,9 +886,6 @@ struct Pcsx2Config
|
||||
// ------------------------------------------------------------------------
|
||||
struct FramerateOptions
|
||||
{
|
||||
bool SkipOnLimit{false};
|
||||
bool SkipOnTurbo{false};
|
||||
|
||||
double NominalScalar{1.0};
|
||||
double TurboScalar{2.0};
|
||||
double SlomoScalar{0.5};
|
||||
@@ -899,7 +895,7 @@ struct Pcsx2Config
|
||||
|
||||
bool operator==(const FramerateOptions& right) const
|
||||
{
|
||||
return OpEqu(SkipOnLimit) && OpEqu(SkipOnTurbo) && OpEqu(NominalScalar) && OpEqu(TurboScalar) && OpEqu(SlomoScalar);
|
||||
return OpEqu(NominalScalar) && OpEqu(TurboScalar) && OpEqu(SlomoScalar);
|
||||
}
|
||||
|
||||
bool operator!=(const FramerateOptions& right) const
|
||||
|
||||
+2
-3
@@ -233,9 +233,9 @@ static void vSyncInfoCalc(vSyncTimingInfo* info, double framesPerSecond, u32 sca
|
||||
// Jak II - random speedups
|
||||
// Shadow of Rome - FMV audio issues
|
||||
const u64 HalfFrame = Frame / 2;
|
||||
const u64 Blank = Scanline *((gsVideoMode == GS_VideoMode::NTSC ? 22 : 25) + static_cast<int>(gsIsInterlaced));
|
||||
const u64 Blank = Scanline * ((gsVideoMode == GS_VideoMode::NTSC ? 22 : 25) + static_cast<int>(gsIsInterlaced));
|
||||
const u64 Render = HalfFrame - Blank;
|
||||
const u64 GSBlank = Scanline * 3.5; // GS VBlank/CSR Swap happens roughly 3.5 Scanlines after VBlank Start
|
||||
const u64 GSBlank = Scanline * (gsVideoMode == GS_VideoMode::NTSC ? 3.5 : 3); // GS VBlank/CSR Swap happens roughly 3.5(NTSC) and 3(PAL) Scanlines after VBlank Start
|
||||
|
||||
// Important! The hRender/hBlank timers should be 50/50 for best results.
|
||||
// (this appears to be what the real EE's timing crystal does anyway)
|
||||
@@ -561,7 +561,6 @@ static __fi void frameLimitUpdateCore()
|
||||
|
||||
// Framelimiter - Measures the delta time between calls and stalls until a
|
||||
// certain amount of time passes if such time hasn't passed yet.
|
||||
// See the GS FrameSkip function for details on why this is here and not in the GS.
|
||||
static __fi void frameLimit()
|
||||
{
|
||||
// Framelimiter off in settings? Framelimiter go brrr.
|
||||
|
||||
@@ -0,0 +1,511 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include <algorithm>
|
||||
#ifdef __POSIX__
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "common/StringUtil.h"
|
||||
|
||||
#if defined(__FreeBSD__) || (__APPLE__)
|
||||
#include <sys/param.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
#include <net/route.h>
|
||||
|
||||
#include "common/Assertions.h"
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "AdapterUtils.h"
|
||||
|
||||
using namespace PacketReader::IP;
|
||||
|
||||
#ifdef _WIN32
|
||||
bool AdapterUtils::GetWin32Adapter(const std::string& name, PIP_ADAPTER_ADDRESSES adapter, std::unique_ptr<IP_ADAPTER_ADDRESSES[]>* buffer)
|
||||
{
|
||||
int neededSize = 128;
|
||||
std::unique_ptr<IP_ADAPTER_ADDRESSES[]> AdapterInfo = std::make_unique<IP_ADAPTER_ADDRESSES[]>(neededSize);
|
||||
ULONG dwBufLen = sizeof(IP_ADAPTER_ADDRESSES) * neededSize;
|
||||
|
||||
PIP_ADAPTER_ADDRESSES pAdapterInfo;
|
||||
|
||||
DWORD dwStatus = GetAdaptersAddresses(
|
||||
AF_UNSPEC,
|
||||
GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_INCLUDE_GATEWAYS,
|
||||
NULL,
|
||||
AdapterInfo.get(),
|
||||
&dwBufLen);
|
||||
|
||||
if (dwStatus == ERROR_BUFFER_OVERFLOW)
|
||||
{
|
||||
DevCon.WriteLn("DEV9: GetWin32Adapter() buffer too small, resizing");
|
||||
neededSize = dwBufLen / sizeof(IP_ADAPTER_ADDRESSES) + 1;
|
||||
AdapterInfo = std::make_unique<IP_ADAPTER_ADDRESSES[]>(neededSize);
|
||||
dwBufLen = sizeof(IP_ADAPTER_ADDRESSES) * neededSize;
|
||||
DevCon.WriteLn("DEV9: New size %i", neededSize);
|
||||
|
||||
dwStatus = GetAdaptersAddresses(
|
||||
AF_UNSPEC,
|
||||
GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_INCLUDE_GATEWAYS,
|
||||
NULL,
|
||||
AdapterInfo.get(),
|
||||
&dwBufLen);
|
||||
}
|
||||
if (dwStatus != ERROR_SUCCESS)
|
||||
return false;
|
||||
|
||||
pAdapterInfo = AdapterInfo.get();
|
||||
|
||||
do
|
||||
{
|
||||
if (strcmp(pAdapterInfo->AdapterName, name.c_str()) == 0)
|
||||
{
|
||||
*adapter = *pAdapterInfo;
|
||||
buffer->swap(AdapterInfo);
|
||||
return true;
|
||||
}
|
||||
|
||||
pAdapterInfo = pAdapterInfo->Next;
|
||||
} while (pAdapterInfo);
|
||||
return false;
|
||||
}
|
||||
bool AdapterUtils::GetWin32AdapterAuto(PIP_ADAPTER_ADDRESSES adapter, std::unique_ptr<IP_ADAPTER_ADDRESSES[]>* buffer)
|
||||
{
|
||||
int neededSize = 128;
|
||||
std::unique_ptr<IP_ADAPTER_ADDRESSES[]> AdapterInfo = std::make_unique<IP_ADAPTER_ADDRESSES[]>(neededSize);
|
||||
ULONG dwBufLen = sizeof(IP_ADAPTER_ADDRESSES) * neededSize;
|
||||
|
||||
PIP_ADAPTER_ADDRESSES pAdapter;
|
||||
|
||||
DWORD dwStatus = GetAdaptersAddresses(
|
||||
AF_UNSPEC,
|
||||
GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_INCLUDE_GATEWAYS,
|
||||
NULL,
|
||||
AdapterInfo.get(),
|
||||
&dwBufLen);
|
||||
|
||||
if (dwStatus == ERROR_BUFFER_OVERFLOW)
|
||||
{
|
||||
DevCon.WriteLn("DEV9: PCAPGetWin32Adapter() buffer too small, resizing");
|
||||
//
|
||||
neededSize = dwBufLen / sizeof(IP_ADAPTER_ADDRESSES) + 1;
|
||||
AdapterInfo = std::make_unique<IP_ADAPTER_ADDRESSES[]>(neededSize);
|
||||
dwBufLen = sizeof(IP_ADAPTER_ADDRESSES) * neededSize;
|
||||
DevCon.WriteLn("DEV9: New size %i", neededSize);
|
||||
|
||||
dwStatus = GetAdaptersAddresses(
|
||||
AF_UNSPEC,
|
||||
GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_INCLUDE_GATEWAYS,
|
||||
NULL,
|
||||
AdapterInfo.get(),
|
||||
&dwBufLen);
|
||||
}
|
||||
|
||||
if (dwStatus != ERROR_SUCCESS)
|
||||
return 0;
|
||||
|
||||
pAdapter = AdapterInfo.get();
|
||||
|
||||
do
|
||||
{
|
||||
if (pAdapter->IfType != IF_TYPE_SOFTWARE_LOOPBACK &&
|
||||
pAdapter->OperStatus == IfOperStatusUp)
|
||||
{
|
||||
//Search for an adapter with;
|
||||
//IPv4 Address
|
||||
//DNS
|
||||
//Gateway
|
||||
|
||||
bool hasIPv4 = false;
|
||||
bool hasDNS = false;
|
||||
bool hasGateway = false;
|
||||
|
||||
//IPv4
|
||||
if (GetAdapterIP(pAdapter).has_value())
|
||||
hasIPv4 = true;
|
||||
|
||||
//DNS
|
||||
if (GetDNS(pAdapter).size() > 0)
|
||||
hasDNS = true;
|
||||
|
||||
//Gateway
|
||||
if (GetGateways(pAdapter).size() > 0)
|
||||
hasGateway = true;
|
||||
|
||||
if (hasIPv4 && hasDNS && hasGateway)
|
||||
{
|
||||
*adapter = *pAdapter;
|
||||
buffer->swap(AdapterInfo);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
pAdapter = pAdapter->Next;
|
||||
} while (pAdapter);
|
||||
|
||||
return false;
|
||||
}
|
||||
#elif defined(__POSIX__)
|
||||
bool AdapterUtils::GetIfAdapter(const std::string& name, ifaddrs* adapter, ifaddrs** buffer)
|
||||
{
|
||||
ifaddrs* adapterInfo;
|
||||
ifaddrs* pAdapter;
|
||||
|
||||
int error = getifaddrs(&adapterInfo);
|
||||
if (error)
|
||||
return false;
|
||||
|
||||
pAdapter = adapterInfo;
|
||||
|
||||
do
|
||||
{
|
||||
if (pAdapter->ifa_addr->sa_family == AF_INET && strcmp(pAdapter->ifa_name, name.c_str()) == 0)
|
||||
break;
|
||||
|
||||
pAdapter = pAdapter->ifa_next;
|
||||
} while (pAdapter);
|
||||
|
||||
if (pAdapter != nullptr)
|
||||
{
|
||||
*adapter = *pAdapter;
|
||||
*buffer = adapterInfo;
|
||||
return true;
|
||||
}
|
||||
|
||||
freeifaddrs(adapterInfo);
|
||||
return false;
|
||||
}
|
||||
bool AdapterUtils::GetIfAdapterAuto(ifaddrs* adapter, ifaddrs** buffer)
|
||||
{
|
||||
ifaddrs* adapterInfo;
|
||||
ifaddrs* pAdapter;
|
||||
|
||||
int error = getifaddrs(&adapterInfo);
|
||||
if (error)
|
||||
return false;
|
||||
|
||||
pAdapter = adapterInfo;
|
||||
|
||||
do
|
||||
{
|
||||
if ((pAdapter->ifa_flags & IFF_LOOPBACK) == 0 &&
|
||||
(pAdapter->ifa_flags & IFF_UP) != 0)
|
||||
{
|
||||
//Search for an adapter with;
|
||||
//IPv4 Address
|
||||
//Gateway
|
||||
|
||||
bool hasIPv4 = false;
|
||||
bool hasGateway = false;
|
||||
|
||||
if (GetAdapterIP(pAdapter).has_value())
|
||||
hasIPv4 = true;
|
||||
|
||||
if (GetGateways(pAdapter).size() > 0)
|
||||
hasGateway = true;
|
||||
|
||||
if (hasIPv4 && hasGateway)
|
||||
{
|
||||
*adapter = *pAdapter;
|
||||
*buffer = adapterInfo;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
pAdapter = pAdapter->ifa_next;
|
||||
} while (pAdapter);
|
||||
|
||||
freeifaddrs(adapterInfo);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
//AdapterIP
|
||||
#ifdef _WIN32
|
||||
std::optional<IP_Address> AdapterUtils::GetAdapterIP(PIP_ADAPTER_ADDRESSES adapter)
|
||||
{
|
||||
PIP_ADAPTER_UNICAST_ADDRESS address = nullptr;
|
||||
if (adapter != nullptr)
|
||||
{
|
||||
address = adapter->FirstUnicastAddress;
|
||||
while (address != nullptr && address->Address.lpSockaddr->sa_family != AF_INET)
|
||||
address = address->Next;
|
||||
}
|
||||
|
||||
if (address != nullptr)
|
||||
{
|
||||
sockaddr_in* sockaddr = (sockaddr_in*)address->Address.lpSockaddr;
|
||||
return *(IP_Address*)&sockaddr->sin_addr;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
#elif defined(__POSIX__)
|
||||
std::optional<IP_Address> AdapterUtils::GetAdapterIP(ifaddrs* adapter)
|
||||
{
|
||||
sockaddr* address = nullptr;
|
||||
if (adapter != nullptr)
|
||||
{
|
||||
if (adapter->ifa_addr != nullptr && adapter->ifa_addr->sa_family == AF_INET)
|
||||
address = adapter->ifa_addr;
|
||||
}
|
||||
|
||||
if (address != nullptr)
|
||||
{
|
||||
sockaddr_in* sockaddr = (sockaddr_in*)address;
|
||||
return *(IP_Address*)&sockaddr->sin_addr;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
#endif
|
||||
|
||||
//Gateways
|
||||
#ifdef _WIN32
|
||||
std::vector<IP_Address> AdapterUtils::GetGateways(PIP_ADAPTER_ADDRESSES adapter)
|
||||
{
|
||||
if (adapter == nullptr)
|
||||
return {};
|
||||
|
||||
std::vector<IP_Address> collection;
|
||||
|
||||
PIP_ADAPTER_GATEWAY_ADDRESS address = adapter->FirstGatewayAddress;
|
||||
while (address != nullptr)
|
||||
{
|
||||
if (address->Address.lpSockaddr->sa_family == AF_INET)
|
||||
{
|
||||
sockaddr_in* sockaddr = (sockaddr_in*)address->Address.lpSockaddr;
|
||||
collection.push_back(*(IP_Address*)&sockaddr->sin_addr);
|
||||
}
|
||||
address = address->Next;
|
||||
}
|
||||
|
||||
return collection;
|
||||
}
|
||||
#elif defined(__POSIX__)
|
||||
#ifdef __linux__
|
||||
std::vector<IP_Address> AdapterUtils::GetGateways(ifaddrs* adapter)
|
||||
{
|
||||
///proc/net/route contains some information about gateway addresses,
|
||||
//and separates the information about by each interface.
|
||||
if (adapter == nullptr)
|
||||
return {};
|
||||
|
||||
std::vector<IP_Address> collection;
|
||||
std::vector<std::string> routeLines;
|
||||
std::fstream route("/proc/net/route", std::ios::in);
|
||||
if (route.fail())
|
||||
{
|
||||
route.close();
|
||||
Console.Error("DEV9: Failed to open /proc/net/route");
|
||||
return collection;
|
||||
}
|
||||
|
||||
std::string line;
|
||||
while (std::getline(route, line))
|
||||
routeLines.push_back(line);
|
||||
route.close();
|
||||
|
||||
//Columns are as follows (first-line header):
|
||||
//Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
|
||||
for (size_t i = 1; i < routeLines.size(); i++)
|
||||
{
|
||||
std::string line = routeLines[i];
|
||||
if (line.rfind(adapter->ifa_name, 0) == 0)
|
||||
{
|
||||
std::vector<std::string_view> split = StringUtil::SplitString(line, '\t', true);
|
||||
std::string gatewayIPHex{split[2]};
|
||||
int addressValue = std::stoi(gatewayIPHex, 0, 16);
|
||||
//Skip device routes without valid NextHop IP address
|
||||
if (addressValue != 0)
|
||||
{
|
||||
IP_Address gwIP = *(IP_Address*)&addressValue;
|
||||
collection.push_back(gwIP);
|
||||
}
|
||||
}
|
||||
}
|
||||
return collection;
|
||||
}
|
||||
#elif defined(__FreeBSD__) || (__APPLE__)
|
||||
std::vector<IP_Address> AdapterUtils::GetGateways(ifaddrs* adapter)
|
||||
{
|
||||
if (adapter == nullptr)
|
||||
return {};
|
||||
|
||||
std::vector<IP_Address> collection;
|
||||
|
||||
//Get index for our adapter by matching the adapter name
|
||||
int ifIndex = -1;
|
||||
|
||||
struct if_nameindex* ifNI;
|
||||
ifNI = if_nameindex();
|
||||
if (ifNI == nullptr)
|
||||
{
|
||||
Console.Error("DEV9: if_nameindex Failed");
|
||||
return collection;
|
||||
}
|
||||
|
||||
struct if_nameindex* i = ifNI;
|
||||
while (i->if_index != 0 && i->if_name != nullptr)
|
||||
{
|
||||
if (strcmp(i->if_name, adapter->ifa_name) == 0)
|
||||
{
|
||||
ifIndex = i->if_index;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if_freenameindex(ifNI);
|
||||
|
||||
//Check if we found the adapter
|
||||
if (ifIndex == -1)
|
||||
{
|
||||
Console.Error("DEV9: Failed to get index for adapter");
|
||||
return collection;
|
||||
}
|
||||
|
||||
//Find the gateway by looking though the routing information
|
||||
int name[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_DUMP, 0};
|
||||
size_t bufferLen = 0;
|
||||
|
||||
if (sysctl(name, 6, NULL, &bufferLen, NULL, 0) != 0)
|
||||
{
|
||||
Console.Error("DEV9: Failed to perform NET_RT_DUMP");
|
||||
return collection;
|
||||
}
|
||||
|
||||
//len is an estimate, double it to be safe
|
||||
bufferLen *= 2;
|
||||
std::unique_ptr<u8[]> buffer = std::make_unique<u8[]>(bufferLen);
|
||||
|
||||
if (sysctl(name, 6, buffer.get(), &bufferLen, NULL, 0) != 0)
|
||||
{
|
||||
Console.Error("DEV9: Failed to perform NET_RT_DUMP");
|
||||
return collection;
|
||||
}
|
||||
|
||||
rt_msghdr* hdr;
|
||||
for (size_t i = 0; i < bufferLen; i += hdr->rtm_msglen)
|
||||
{
|
||||
hdr = (rt_msghdr*)&buffer[i];
|
||||
|
||||
if (hdr->rtm_flags & RTF_GATEWAY && hdr->rtm_addrs & RTA_GATEWAY && (hdr->rtm_index == ifIndex))
|
||||
{
|
||||
sockaddr* sockaddrs = (sockaddr*)(hdr + 1);
|
||||
pxAssert(sockaddrs[RTAX_DST].sa_family == AF_INET);
|
||||
|
||||
//Default gateway has no destination address
|
||||
sockaddr_in* sockaddr = (sockaddr_in*)&sockaddrs[RTAX_DST];
|
||||
if (sockaddr->sin_addr.s_addr != 0)
|
||||
continue;
|
||||
|
||||
sockaddr = (sockaddr_in*)&sockaddrs[RTAX_GATEWAY];
|
||||
IP_Address gwIP = *(IP_Address*)&sockaddr->sin_addr;
|
||||
collection.push_back(gwIP);
|
||||
}
|
||||
}
|
||||
return collection;
|
||||
}
|
||||
#else
|
||||
std::vector<IP_Address> AdapterUtils::GetGateways(ifaddrs* adapter)
|
||||
{
|
||||
Console.Error("DEV9: Unsupported OS, can't find Gateway");
|
||||
return {};
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//DNS
|
||||
#ifdef _WIN32
|
||||
std::vector<IP_Address> AdapterUtils::GetDNS(PIP_ADAPTER_ADDRESSES adapter)
|
||||
{
|
||||
if (adapter == nullptr)
|
||||
return {};
|
||||
|
||||
std::vector<IP_Address> collection;
|
||||
|
||||
PIP_ADAPTER_DNS_SERVER_ADDRESS address = adapter->FirstDnsServerAddress;
|
||||
while (address != nullptr)
|
||||
{
|
||||
if (address->Address.lpSockaddr->sa_family == AF_INET)
|
||||
{
|
||||
sockaddr_in* sockaddr = (sockaddr_in*)address->Address.lpSockaddr;
|
||||
collection.push_back(*(IP_Address*)&sockaddr->sin_addr);
|
||||
}
|
||||
address = address->Next;
|
||||
}
|
||||
|
||||
return collection;
|
||||
}
|
||||
#elif defined(__POSIX__)
|
||||
std::vector<IP_Address> AdapterUtils::GetDNS(ifaddrs* adapter)
|
||||
{
|
||||
//On Linux and OSX, DNS is system wide, not adapter specific, so we can ignore adapter
|
||||
|
||||
// Parse /etc/resolv.conf for all of the "nameserver" entries.
|
||||
// These are the DNS servers the machine is configured to use.
|
||||
// On OSX, this file is not directly used by most processes for DNS
|
||||
// queries/routing, but it is automatically generated instead, with
|
||||
// the machine's DNS servers listed in it.
|
||||
if (adapter == nullptr)
|
||||
return {};
|
||||
|
||||
std::vector<IP_Address> collection;
|
||||
|
||||
std::fstream servers("/etc/resolv.conf", std::ios::in);
|
||||
if (servers.fail())
|
||||
{
|
||||
servers.close();
|
||||
Console.Error("DEV9: Failed to open /etc/resolv.conf");
|
||||
return collection;
|
||||
}
|
||||
|
||||
std::string line;
|
||||
std::vector<std::string> serversLines;
|
||||
while (std::getline(servers, line))
|
||||
serversLines.push_back(line);
|
||||
servers.close();
|
||||
|
||||
const IP_Address systemdDNS{127, 0, 0, 53};
|
||||
for (size_t i = 1; i < serversLines.size(); i++)
|
||||
{
|
||||
std::string line = serversLines[i];
|
||||
if (line.rfind("nameserver", 0) == 0)
|
||||
{
|
||||
std::vector<std::string_view> split = StringUtil::SplitString(line, '\t', true);
|
||||
if (split.size() == 1)
|
||||
split = StringUtil::SplitString(line, ' ', true);
|
||||
std::string dns{split[1]};
|
||||
|
||||
IP_Address address;
|
||||
if (inet_pton(AF_INET, dns.c_str(), &address) != 1)
|
||||
continue;
|
||||
|
||||
if (address == systemdDNS)
|
||||
Console.Error("DEV9: systemd-resolved DNS server is not supported");
|
||||
|
||||
collection.push_back(address);
|
||||
}
|
||||
}
|
||||
return collection;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,50 @@
|
||||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2022 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
* ation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <iphlpapi.h>
|
||||
#elif defined(__POSIX__)
|
||||
#include <sys/types.h>
|
||||
#include <ifaddrs.h>
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <optional>
|
||||
|
||||
#include "DEV9/PacketReader/IP/IP_Address.h"
|
||||
|
||||
namespace AdapterUtils
|
||||
{
|
||||
#ifdef _WIN32
|
||||
bool GetWin32Adapter(const std::string& name, PIP_ADAPTER_ADDRESSES adapter, std::unique_ptr<IP_ADAPTER_ADDRESSES[]>* buffer);
|
||||
bool GetWin32AdapterAuto(PIP_ADAPTER_ADDRESSES adapter, std::unique_ptr<IP_ADAPTER_ADDRESSES[]>* buffer);
|
||||
|
||||
std::optional<PacketReader::IP::IP_Address> GetAdapterIP(PIP_ADAPTER_ADDRESSES adapter);
|
||||
//Mask
|
||||
std::vector<PacketReader::IP::IP_Address> GetGateways(PIP_ADAPTER_ADDRESSES adapter);
|
||||
std::vector<PacketReader::IP::IP_Address> GetDNS(PIP_ADAPTER_ADDRESSES adapter);
|
||||
#elif defined(__POSIX__)
|
||||
bool GetIfAdapter(const std::string& name, ifaddrs* adapter, ifaddrs** buffer);
|
||||
bool GetIfAdapterAuto(ifaddrs* adapter, ifaddrs** buffer);
|
||||
|
||||
std::optional<PacketReader::IP::IP_Address> GetAdapterIP(ifaddrs* adapter);
|
||||
//Mask
|
||||
std::vector<PacketReader::IP::IP_Address> GetGateways(ifaddrs* adapter);
|
||||
std::vector<PacketReader::IP::IP_Address> GetDNS(ifaddrs* adapter);
|
||||
#endif
|
||||
}; // namespace AdapterUtils
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "DEV9/PacketReader/IP/UDP/DHCP/DHCP_Packet.h"
|
||||
|
||||
#include "DEV9/DEV9.h"
|
||||
#include "DEV9/AdapterUtils.h"
|
||||
|
||||
using namespace PacketReader;
|
||||
using namespace PacketReader::IP;
|
||||
@@ -110,195 +111,6 @@ namespace InternalServers
|
||||
AutoBroadcast(ps2IP, netmask);
|
||||
}
|
||||
|
||||
#ifdef __POSIX__
|
||||
//skipsEmpty
|
||||
std::vector<std::string> DHCP_Server::SplitString(std::string str, char delimiter)
|
||||
{
|
||||
std::vector<std::string> ret;
|
||||
size_t last = 0;
|
||||
size_t next = 0;
|
||||
std::string token;
|
||||
while ((next = str.find(delimiter, last)) != std::string::npos)
|
||||
{
|
||||
token = str.substr(last, next - last);
|
||||
if (next != last)
|
||||
ret.push_back(token);
|
||||
last = next + 1;
|
||||
}
|
||||
token = str.substr(last);
|
||||
if (next != last)
|
||||
ret.push_back(token);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#ifdef __linux__
|
||||
std::vector<IP_Address> DHCP_Server::GetGatewaysLinux(char* interfaceName)
|
||||
{
|
||||
///proc/net/route contains some information about gateway addresses,
|
||||
//and separates the information about by each interface.
|
||||
std::vector<IP_Address> collection;
|
||||
std::vector<std::string> routeLines;
|
||||
std::fstream route("/proc/net/route", std::ios::in);
|
||||
if (route.fail())
|
||||
{
|
||||
route.close();
|
||||
Console.Error("DHCP: Failed to open /proc/net/route");
|
||||
return collection;
|
||||
}
|
||||
|
||||
std::string line;
|
||||
while (std::getline(route, line))
|
||||
routeLines.push_back(line);
|
||||
route.close();
|
||||
|
||||
//Columns are as follows (first-line header):
|
||||
//Iface Destination Gateway Flags RefCnt Use Metric Mask MTU Window IRTT
|
||||
for (size_t i = 1; i < routeLines.size(); i++)
|
||||
{
|
||||
std::string line = routeLines[i];
|
||||
if (line.rfind(interfaceName, 0) == 0)
|
||||
{
|
||||
std::vector<std::string> split = SplitString(line, '\t');
|
||||
std::string gatewayIPHex = split[2];
|
||||
int addressValue = std::stoi(gatewayIPHex, 0, 16);
|
||||
//Skip device routes without valid NextHop IP address
|
||||
if (addressValue != 0)
|
||||
{
|
||||
IP_Address gwIP = *(IP_Address*)&addressValue;
|
||||
collection.push_back(gwIP);
|
||||
}
|
||||
}
|
||||
}
|
||||
return collection;
|
||||
}
|
||||
#elif defined(__FreeBSD__) || (__APPLE__)
|
||||
std::vector<IP_Address> DHCP_Server::GetGatewaysBSD(char* interfaceName)
|
||||
{
|
||||
std::vector<IP_Address> collection;
|
||||
|
||||
//Get index for our adapter by matching the adapter name
|
||||
int ifIndex = -1;
|
||||
|
||||
struct if_nameindex* ifNI;
|
||||
ifNI = if_nameindex();
|
||||
if (ifNI == nullptr)
|
||||
{
|
||||
Console.Error("DHCP: if_nameindex Failed");
|
||||
return collection;
|
||||
}
|
||||
|
||||
struct if_nameindex* i = ifNI;
|
||||
while (i->if_index != 0 && i->if_name != nullptr)
|
||||
{
|
||||
if (strcmp(i->if_name, interfaceName) == 0)
|
||||
{
|
||||
ifIndex = i->if_index;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if_freenameindex(ifNI);
|
||||
|
||||
//Check if we found the adapter
|
||||
if (ifIndex == -1)
|
||||
{
|
||||
Console.Error("DHCP: Failed to get index for adapter");
|
||||
return collection;
|
||||
}
|
||||
|
||||
//Find the gateway by looking though the routing information
|
||||
int name[] = {CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_DUMP, 0};
|
||||
size_t bufferLen = 0;
|
||||
|
||||
if (sysctl(name, 6, NULL, &bufferLen, NULL, 0) != 0)
|
||||
{
|
||||
Console.Error("DHCP: Failed to perform NET_RT_DUMP");
|
||||
return collection;
|
||||
}
|
||||
|
||||
//len is an estimate, double it to be safe
|
||||
bufferLen *= 2;
|
||||
std::unique_ptr<u8[]> buffer = std::make_unique<u8[]>(bufferLen);
|
||||
|
||||
if (sysctl(name, 6, buffer.get(), &bufferLen, NULL, 0) != 0)
|
||||
{
|
||||
Console.Error("DHCP: Failed to perform NET_RT_DUMP");
|
||||
return collection;
|
||||
}
|
||||
|
||||
rt_msghdr* hdr;
|
||||
for (size_t i = 0; i < bufferLen; i += hdr->rtm_msglen)
|
||||
{
|
||||
hdr = (rt_msghdr*)&buffer[i];
|
||||
|
||||
if (hdr->rtm_flags & RTF_GATEWAY && hdr->rtm_addrs & RTA_GATEWAY && (hdr->rtm_index == ifIndex))
|
||||
{
|
||||
sockaddr* sockaddrs = (sockaddr*)(hdr + 1);
|
||||
pxAssert(sockaddrs[RTAX_DST].sa_family == AF_INET);
|
||||
|
||||
//Default gateway has no destination address
|
||||
sockaddr_in* sockaddr = (sockaddr_in*)&sockaddrs[RTAX_DST];
|
||||
if (sockaddr->sin_addr.s_addr != 0)
|
||||
continue;
|
||||
|
||||
sockaddr = (sockaddr_in*)&sockaddrs[RTAX_GATEWAY];
|
||||
IP_Address gwIP = *(IP_Address*)&sockaddr->sin_addr;
|
||||
collection.push_back(gwIP);
|
||||
}
|
||||
}
|
||||
return collection;
|
||||
}
|
||||
#endif
|
||||
std::vector<IP_Address> DHCP_Server::GetDNSUnix()
|
||||
{
|
||||
//On Linux and OSX, DNS is system wide, not adapter specific, so we can ignore adapter
|
||||
|
||||
// Parse /etc/resolv.conf for all of the "nameserver" entries.
|
||||
// These are the DNS servers the machine is configured to use.
|
||||
// On OSX, this file is not directly used by most processes for DNS
|
||||
// queries/routing, but it is automatically generated instead, with
|
||||
// the machine's DNS servers listed in it.
|
||||
std::vector<IP_Address> collection;
|
||||
|
||||
std::fstream servers("/etc/resolv.conf", std::ios::in);
|
||||
if (servers.fail())
|
||||
{
|
||||
servers.close();
|
||||
Console.Error("DHCP: Failed to open /etc/resolv.conf");
|
||||
return collection;
|
||||
}
|
||||
|
||||
std::string line;
|
||||
std::vector<std::string> serversLines;
|
||||
while (std::getline(servers, line))
|
||||
serversLines.push_back(line);
|
||||
servers.close();
|
||||
|
||||
const IP_Address systemdDNS{127, 0, 0, 53};
|
||||
for (size_t i = 1; i < serversLines.size(); i++)
|
||||
{
|
||||
std::string line = serversLines[i];
|
||||
if (line.rfind("nameserver", 0) == 0)
|
||||
{
|
||||
std::vector<std::string> split = SplitString(line, '\t');
|
||||
if (split.size() == 1)
|
||||
split = SplitString(line, ' ');
|
||||
std::string dns = split[1];
|
||||
|
||||
IP_Address address;
|
||||
if (inet_pton(AF_INET, dns.c_str(), &address) != 1)
|
||||
continue;
|
||||
|
||||
if (address == systemdDNS)
|
||||
Console.Error("DHCP: systemd-resolved DNS server is not supported");
|
||||
|
||||
collection.push_back(address);
|
||||
}
|
||||
}
|
||||
return collection;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
void DHCP_Server::AutoNetmask(PIP_ADAPTER_ADDRESSES adapter)
|
||||
{
|
||||
@@ -316,23 +128,6 @@ namespace InternalServers
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DHCP_Server::AutoGateway(PIP_ADAPTER_ADDRESSES adapter)
|
||||
{
|
||||
if (adapter != nullptr)
|
||||
{
|
||||
PIP_ADAPTER_GATEWAY_ADDRESS address = adapter->FirstGatewayAddress;
|
||||
while (address != nullptr && address->Address.lpSockaddr->sa_family != AF_INET)
|
||||
address = address->Next;
|
||||
|
||||
if (address != nullptr)
|
||||
{
|
||||
sockaddr_in* sockaddr = (sockaddr_in*)address->Address.lpSockaddr;
|
||||
gateway = *(IP_Address*)&sockaddr->sin_addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(__POSIX__)
|
||||
void DHCP_Server::AutoNetmask(ifaddrs* adapter)
|
||||
{
|
||||
@@ -345,53 +140,28 @@ namespace InternalServers
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DHCP_Server::AutoGateway(ifaddrs* adapter)
|
||||
{
|
||||
if (adapter != nullptr)
|
||||
{
|
||||
#ifdef __linux__
|
||||
std::vector<IP_Address> gateways = GetGatewaysLinux(adapter->ifa_name);
|
||||
|
||||
if (gateways.size() > 0)
|
||||
gateway = gateways[0];
|
||||
|
||||
#elif defined(__FreeBSD__) || (__APPLE__)
|
||||
std::vector<IP_Address> gateways = GetGatewaysBSD(adapter->ifa_name);
|
||||
|
||||
if (gateways.size() > 0)
|
||||
gateway = gateways[0];
|
||||
|
||||
#else
|
||||
Console.Error("DHCP: Unsupported OS, can't find Gateway");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
void DHCP_Server::AutoDNS(PIP_ADAPTER_ADDRESSES adapter, bool autoDNS1, bool autoDNS2)
|
||||
void DHCP_Server::AutoGateway(PIP_ADAPTER_ADDRESSES adapter)
|
||||
#elif defined(__POSIX__)
|
||||
void DHCP_Server::AutoGateway(ifaddrs* adapter)
|
||||
#endif
|
||||
{
|
||||
std::vector<IP_Address> dnsIPs;
|
||||
std::vector<IP_Address> gateways = AdapterUtils::GetGateways(adapter);
|
||||
|
||||
if (adapter != nullptr)
|
||||
{
|
||||
PIP_ADAPTER_DNS_SERVER_ADDRESS address = adapter->FirstDnsServerAddress;
|
||||
while (address != nullptr)
|
||||
{
|
||||
if (address->Address.lpSockaddr->sa_family == AF_INET)
|
||||
{
|
||||
sockaddr_in* sockaddr = (sockaddr_in*)address->Address.lpSockaddr;
|
||||
dnsIPs.push_back(*(IP_Address*)&sockaddr->sin_addr);
|
||||
}
|
||||
address = address->Next;
|
||||
}
|
||||
}
|
||||
if (gateways.size() > 0)
|
||||
gateway = gateways[0];
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
void DHCP_Server::AutoDNS(PIP_ADAPTER_ADDRESSES adapter, bool autoDNS1, bool autoDNS2)
|
||||
#elif defined(__POSIX__)
|
||||
void DHCP_Server::AutoDNS(ifaddrs* adapter, bool autoDNS1, bool autoDNS2)
|
||||
{
|
||||
std::vector<IP_Address> dnsIPs = GetDNSUnix();
|
||||
#endif
|
||||
{
|
||||
std::vector<IP_Address> dnsIPs = AdapterUtils::GetDNS(adapter);
|
||||
|
||||
if (autoDNS1)
|
||||
{
|
||||
//Auto DNS1
|
||||
|
||||
@@ -61,20 +61,9 @@ namespace InternalServers
|
||||
PacketReader::IP::UDP::UDP_Packet* Recv();
|
||||
bool Send(PacketReader::IP::UDP::UDP_Packet* payload);
|
||||
|
||||
#ifdef __linux__
|
||||
static std::vector<PacketReader::IP::IP_Address> GetGatewaysLinux(char* interfaceName);
|
||||
#elif defined(__FreeBSD__) || (__APPLE__)
|
||||
static std::vector<PacketReader::IP::IP_Address> GetGatewaysBSD(char* interfaceName);
|
||||
#endif
|
||||
|
||||
~DHCP_Server();
|
||||
|
||||
private:
|
||||
#ifdef __POSIX__
|
||||
static std::vector<std::string> SplitString(std::string str, char delimiter);
|
||||
static std::vector<PacketReader::IP::IP_Address> GetDNSUnix();
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
void AutoNetmask(PIP_ADAPTER_ADDRESSES adapter);
|
||||
void AutoGateway(PIP_ADAPTER_ADDRESSES adapter);
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "DEV9/PacketReader/IP/UDP/DNS/DNS_Packet.h"
|
||||
|
||||
#include "DEV9/DEV9.h"
|
||||
#include "DEV9/AdapterUtils.h"
|
||||
|
||||
using namespace PacketReader;
|
||||
using namespace PacketReader::IP;
|
||||
@@ -101,41 +102,13 @@ namespace InternalServers
|
||||
#endif
|
||||
{
|
||||
localhostIP = {127, 0, 0, 1};
|
||||
|
||||
//Find IPv4 Address
|
||||
#ifdef _WIN32
|
||||
PIP_ADAPTER_UNICAST_ADDRESS address = nullptr;
|
||||
if (adapter != nullptr)
|
||||
{
|
||||
PIP_ADAPTER_ADDRESSES info = (PIP_ADAPTER_ADDRESSES)adapter;
|
||||
address = info->FirstUnicastAddress;
|
||||
while (address != nullptr && address->Address.lpSockaddr->sa_family != AF_INET)
|
||||
address = address->Next;
|
||||
}
|
||||
|
||||
if (address != nullptr)
|
||||
{
|
||||
sockaddr_in* sockaddr = (sockaddr_in*)address->Address.lpSockaddr;
|
||||
localhostIP = *(IP_Address*)&sockaddr->sin_addr;
|
||||
}
|
||||
std::optional<IP_Address> adapterIP = AdapterUtils::GetAdapterIP(adapter);
|
||||
if (adapterIP.has_value())
|
||||
localhostIP = adapterIP.value();
|
||||
else
|
||||
Console.Error("DEV9: Failed To Get Adapter IP");
|
||||
#elif defined(__POSIX__)
|
||||
sockaddr* address = nullptr;
|
||||
if (adapter != nullptr)
|
||||
{
|
||||
ifaddrs* info = (ifaddrs*)adapter;
|
||||
if (info->ifa_addr != nullptr && info->ifa_addr->sa_family == AF_INET)
|
||||
address = info->ifa_addr;
|
||||
}
|
||||
|
||||
if (address != nullptr)
|
||||
{
|
||||
sockaddr_in* sockaddr = (sockaddr_in*)address;
|
||||
localhostIP = *(IP_Address*)&sockaddr->sin_addr;
|
||||
}
|
||||
else
|
||||
Console.Error("DEV9: Failed To Get Adapter IP");
|
||||
#endif
|
||||
|
||||
LoadHostList();
|
||||
}
|
||||
@@ -229,7 +202,7 @@ namespace InternalServers
|
||||
bool DNS_Server::CheckHostList(std::string url, DNS_State* state)
|
||||
{
|
||||
std::transform(url.begin(), url.end(), url.begin(),
|
||||
[](unsigned char c) { return std::tolower(c); });
|
||||
[](unsigned char c) { return std::tolower(c); });
|
||||
|
||||
auto f = hosts.find(url);
|
||||
if (f != hosts.end())
|
||||
|
||||
+26
-99
@@ -37,11 +37,16 @@
|
||||
#include <stdarg.h>
|
||||
#include "pcap_io.h"
|
||||
#include "DEV9.h"
|
||||
#include "AdapterUtils.h"
|
||||
#include "net.h"
|
||||
#ifndef PCAP_NETMASK_UNKNOWN
|
||||
#define PCAP_NETMASK_UNKNOWN 0xffffffff
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#define PCAPPREFIX "\\Device\\NPF_"
|
||||
#endif
|
||||
|
||||
pcap_t* adhandle;
|
||||
pcap_dumper_t* dump_pcap = nullptr;
|
||||
char errbuf[PCAP_ERRBUF_SIZE];
|
||||
@@ -58,94 +63,6 @@ ip_address ps2_ip;
|
||||
mac_address ps2_mac;
|
||||
mac_address host_mac;
|
||||
|
||||
#ifdef _WIN32
|
||||
//IP_ADAPTER_ADDRESSES is a structure that contains ptrs to data in other regions
|
||||
//of the buffer, se we need to return both so the caller can free the buffer
|
||||
//after it's finished reading the needed data from IP_ADAPTER_ADDRESSES
|
||||
bool PCAPGetWin32Adapter(const std::string& name, PIP_ADAPTER_ADDRESSES adapter, std::unique_ptr<IP_ADAPTER_ADDRESSES[]>* buffer)
|
||||
{
|
||||
const int guidindex = strlen("\\Device\\NPF_");
|
||||
|
||||
int neededSize = 128;
|
||||
std::unique_ptr<IP_ADAPTER_ADDRESSES[]> AdapterInfo = std::make_unique<IP_ADAPTER_ADDRESSES[]>(neededSize);
|
||||
ULONG dwBufLen = sizeof(IP_ADAPTER_ADDRESSES) * neededSize;
|
||||
|
||||
PIP_ADAPTER_ADDRESSES pAdapterInfo;
|
||||
|
||||
DWORD dwStatus = GetAdaptersAddresses(
|
||||
AF_UNSPEC,
|
||||
GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_INCLUDE_GATEWAYS,
|
||||
NULL,
|
||||
AdapterInfo.get(),
|
||||
&dwBufLen);
|
||||
|
||||
if (dwStatus == ERROR_BUFFER_OVERFLOW)
|
||||
{
|
||||
DevCon.WriteLn("DEV9: GetWin32Adapter() buffer too small, resizing");
|
||||
neededSize = dwBufLen / sizeof(IP_ADAPTER_ADDRESSES) + 1;
|
||||
AdapterInfo = std::make_unique<IP_ADAPTER_ADDRESSES[]>(neededSize);
|
||||
dwBufLen = sizeof(IP_ADAPTER_ADDRESSES) * neededSize;
|
||||
DevCon.WriteLn("DEV9: New size %i", neededSize);
|
||||
|
||||
dwStatus = GetAdaptersAddresses(
|
||||
AF_UNSPEC,
|
||||
GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_INCLUDE_GATEWAYS,
|
||||
NULL,
|
||||
AdapterInfo.get(),
|
||||
&dwBufLen);
|
||||
}
|
||||
if (dwStatus != ERROR_SUCCESS)
|
||||
return false;
|
||||
|
||||
pAdapterInfo = AdapterInfo.get();
|
||||
|
||||
do
|
||||
{
|
||||
if (0 == strcmp(pAdapterInfo->AdapterName, &name.c_str()[guidindex]))
|
||||
{
|
||||
*adapter = *pAdapterInfo;
|
||||
buffer->swap(AdapterInfo);
|
||||
return true;
|
||||
}
|
||||
|
||||
pAdapterInfo = pAdapterInfo->Next;
|
||||
} while (pAdapterInfo);
|
||||
return false;
|
||||
}
|
||||
#elif defined(__POSIX__)
|
||||
//getifaddrs is not POSIX, but is supported on MAC & Linux
|
||||
bool PCAPGetIfAdapter(const std::string& name, ifaddrs* adapter, ifaddrs** buffer)
|
||||
{
|
||||
//Note, we don't support "any" adapter, but that also fails in pcap_io_init()
|
||||
ifaddrs* adapterInfo;
|
||||
ifaddrs* pAdapter;
|
||||
|
||||
int error = getifaddrs(&adapterInfo);
|
||||
if (error)
|
||||
return false;
|
||||
|
||||
pAdapter = adapterInfo;
|
||||
|
||||
do
|
||||
{
|
||||
if (pAdapter->ifa_addr != nullptr && pAdapter->ifa_addr->sa_family == AF_INET && strcmp(pAdapter->ifa_name, name.c_str()) == 0)
|
||||
break;
|
||||
|
||||
pAdapter = pAdapter->ifa_next;
|
||||
} while (pAdapter);
|
||||
|
||||
if (pAdapter != nullptr)
|
||||
{
|
||||
*adapter = *pAdapter;
|
||||
*buffer = adapterInfo;
|
||||
return true;
|
||||
}
|
||||
|
||||
freeifaddrs(adapterInfo);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Fetches the MAC address and prints it
|
||||
int GetMACAddress(const std::string& adapter, mac_address* addr)
|
||||
{
|
||||
@@ -154,7 +71,7 @@ int GetMACAddress(const std::string& adapter, mac_address* addr)
|
||||
IP_ADAPTER_ADDRESSES adapterInfo;
|
||||
std::unique_ptr<IP_ADAPTER_ADDRESSES[]> buffer;
|
||||
|
||||
if (PCAPGetWin32Adapter(adapter, &adapterInfo, &buffer))
|
||||
if (AdapterUtils::GetWin32Adapter(adapter, &adapterInfo, &buffer))
|
||||
{
|
||||
memcpy(addr, adapterInfo.PhysicalAddress, 6);
|
||||
retval = 1;
|
||||
@@ -190,8 +107,13 @@ int pcap_io_init(const std::string& adapter, bool switched, mac_address virtual_
|
||||
|
||||
pcap_io_switched = switched;
|
||||
|
||||
#ifdef _WIN32
|
||||
std::string pcapAdapter = PCAPPREFIX + adapter;
|
||||
#else
|
||||
std::string pcapAdapter = adapter;
|
||||
#endif
|
||||
/* Open the adapter */
|
||||
if ((adhandle = pcap_open_live(adapter.c_str(), // name of the device
|
||||
if ((adhandle = pcap_open_live(pcapAdapter.c_str(), // name of the device
|
||||
65536, // portion of the packet to capture.
|
||||
// 65536 grants that the whole packet will be captured on all the MACs.
|
||||
switched ? 1 : 0,
|
||||
@@ -390,7 +312,7 @@ PCAPAdapter::PCAPAdapter()
|
||||
#ifdef _WIN32
|
||||
IP_ADAPTER_ADDRESSES adapter;
|
||||
std::unique_ptr<IP_ADAPTER_ADDRESSES[]> buffer;
|
||||
if (PCAPGetWin32Adapter(EmuConfig.DEV9.EthDevice, &adapter, &buffer))
|
||||
if (AdapterUtils::GetWin32Adapter(EmuConfig.DEV9.EthDevice, &adapter, &buffer))
|
||||
InitInternalServer(&adapter);
|
||||
else
|
||||
{
|
||||
@@ -400,7 +322,7 @@ PCAPAdapter::PCAPAdapter()
|
||||
#elif defined(__POSIX__)
|
||||
ifaddrs adapter;
|
||||
ifaddrs* buffer;
|
||||
if (PCAPGetIfAdapter(EmuConfig.DEV9.EthDevice, &adapter, &buffer))
|
||||
if (AdapterUtils::GetIfAdapter(EmuConfig.DEV9.EthDevice, &adapter, &buffer))
|
||||
{
|
||||
InitInternalServer(&adapter);
|
||||
freeifaddrs(buffer);
|
||||
@@ -462,14 +384,14 @@ void PCAPAdapter::reloadSettings()
|
||||
#ifdef _WIN32
|
||||
IP_ADAPTER_ADDRESSES adapter;
|
||||
std::unique_ptr<IP_ADAPTER_ADDRESSES[]> buffer;
|
||||
if (PCAPGetWin32Adapter(EmuConfig.DEV9.EthDevice, &adapter, &buffer))
|
||||
if (AdapterUtils::GetWin32Adapter(EmuConfig.DEV9.EthDevice, &adapter, &buffer))
|
||||
ReloadInternalServer(&adapter);
|
||||
else
|
||||
ReloadInternalServer(nullptr);
|
||||
#elif defined(__POSIX__)
|
||||
ifaddrs adapter;
|
||||
ifaddrs* buffer;
|
||||
if (PCAPGetIfAdapter(EmuConfig.DEV9.EthDevice, &adapter, &buffer))
|
||||
if (AdapterUtils::GetIfAdapter(EmuConfig.DEV9.EthDevice, &adapter, &buffer))
|
||||
{
|
||||
ReloadInternalServer(&adapter);
|
||||
freeifaddrs(buffer);
|
||||
@@ -497,9 +419,7 @@ std::vector<AdapterEntry> PCAPAdapter::GetAdapters()
|
||||
pcap_if_t* d;
|
||||
|
||||
if (pcap_findalldevs(&alldevs, errbuf) == -1)
|
||||
{
|
||||
return nic;
|
||||
}
|
||||
|
||||
d = alldevs;
|
||||
while (d != NULL)
|
||||
@@ -508,12 +428,19 @@ std::vector<AdapterEntry> PCAPAdapter::GetAdapters()
|
||||
entry.type = Pcsx2Config::DEV9Options::NetApi::PCAP_Switched;
|
||||
#ifdef _WIN32
|
||||
//guid
|
||||
entry.guid = std::string(d->name);
|
||||
if (!StringUtil::StartsWith(d->name, PCAPPREFIX))
|
||||
{
|
||||
Console.Error("PCAP: Unexpected Device: ", d->name);
|
||||
d = d->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
entry.guid = std::string(&d->name[strlen(PCAPPREFIX)]);
|
||||
|
||||
IP_ADAPTER_ADDRESSES adapterInfo;
|
||||
std::unique_ptr<IP_ADAPTER_ADDRESSES[]> buffer;
|
||||
|
||||
if (PCAPGetWin32Adapter(entry.guid, &adapterInfo, &buffer))
|
||||
if (AdapterUtils::GetWin32Adapter(entry.guid, &adapterInfo, &buffer))
|
||||
entry.name = StringUtil::WideStringToUTF8String(std::wstring(adapterInfo.FriendlyName));
|
||||
else
|
||||
{
|
||||
@@ -527,7 +454,7 @@ std::vector<AdapterEntry> PCAPAdapter::GetAdapters()
|
||||
|
||||
std::unique_ptr<wchar_t[]> buf = std::make_unique<wchar_t[]>(len_buf);
|
||||
MultiByteToWideChar(CP_ACP, 0, d->description, len_desc, buf.get(), len_buf);
|
||||
|
||||
|
||||
entry.name = StringUtil::WideStringToUTF8String(std::wstring(buf.get()));
|
||||
}
|
||||
#else
|
||||
|
||||
+22
-252
@@ -17,7 +17,13 @@
|
||||
#include "common/Assertions.h"
|
||||
#include "common/StringUtil.h"
|
||||
|
||||
#ifdef __POSIX__
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <iphlpapi.h>
|
||||
#elif defined(__POSIX__)
|
||||
#include <sys/types.h>
|
||||
#include <ifaddrs.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <net/if.h>
|
||||
@@ -27,6 +33,7 @@
|
||||
#endif
|
||||
|
||||
#include "sockets.h"
|
||||
#include "AdapterUtils.h"
|
||||
#include "DEV9.h"
|
||||
|
||||
#include "Sessions/ICMP_Session/ICMP_Session.h"
|
||||
@@ -158,7 +165,7 @@ SocketAdapter::SocketAdapter()
|
||||
|
||||
if (strcmp(EmuConfig.DEV9.EthDevice.c_str(), "Auto") != 0)
|
||||
{
|
||||
foundAdapter = GetWin32SelectedAdapter(EmuConfig.DEV9.EthDevice, &adapter, &buffer);
|
||||
foundAdapter = AdapterUtils::GetWin32Adapter(EmuConfig.DEV9.EthDevice, &adapter, &buffer);
|
||||
|
||||
if (!foundAdapter)
|
||||
{
|
||||
@@ -166,17 +173,9 @@ SocketAdapter::SocketAdapter()
|
||||
return;
|
||||
}
|
||||
|
||||
PIP_ADAPTER_UNICAST_ADDRESS address = nullptr;
|
||||
|
||||
address = adapter.FirstUnicastAddress;
|
||||
while (address != nullptr && address->Address.lpSockaddr->sa_family != AF_INET)
|
||||
address = address->Next;
|
||||
|
||||
if (address != nullptr)
|
||||
{
|
||||
sockaddr_in* sockaddr = (sockaddr_in*)address->Address.lpSockaddr;
|
||||
adapterIP = *(IP_Address*)&sockaddr->sin_addr;
|
||||
}
|
||||
std::optional<IP_Address> adIP = AdapterUtils::GetAdapterIP(&adapter);
|
||||
if (adIP.has_value())
|
||||
adapterIP = adIP.value();
|
||||
else
|
||||
{
|
||||
Console.Error("DEV9: Socket: Failed To Get Adapter IP");
|
||||
@@ -185,7 +184,7 @@ SocketAdapter::SocketAdapter()
|
||||
}
|
||||
else
|
||||
{
|
||||
foundAdapter = GetWin32AutoAdapter(&adapter, &buffer);
|
||||
foundAdapter = AdapterUtils::GetWin32AdapterAuto(&adapter, &buffer);
|
||||
adapterIP = {0};
|
||||
|
||||
if (!foundAdapter)
|
||||
@@ -200,7 +199,7 @@ SocketAdapter::SocketAdapter()
|
||||
|
||||
if (strcmp(EmuConfig.DEV9.EthDevice.c_str(), "Auto") != 0)
|
||||
{
|
||||
foundAdapter = GetIfSelectedAdapter(EmuConfig.DEV9.EthDevice, &adapter, &buffer);
|
||||
foundAdapter = AdapterUtils::GetIfAdapter(EmuConfig.DEV9.EthDevice, &adapter, &buffer);
|
||||
|
||||
if (!foundAdapter)
|
||||
{
|
||||
@@ -208,16 +207,9 @@ SocketAdapter::SocketAdapter()
|
||||
return;
|
||||
}
|
||||
|
||||
sockaddr* address = nullptr;
|
||||
|
||||
if (adapter.ifa_addr != nullptr && adapter.ifa_addr->sa_family == AF_INET)
|
||||
address = adapter.ifa_addr;
|
||||
|
||||
if (address != nullptr)
|
||||
{
|
||||
sockaddr_in* sockaddr = (sockaddr_in*)address;
|
||||
adapterIP = *(IP_Address*)&sockaddr->sin_addr;
|
||||
}
|
||||
std::optional<IP_Address> adIP = AdapterUtils::GetAdapterIP(&adapter);
|
||||
if (adIP.has_value())
|
||||
adapterIP = adIP.value();
|
||||
else
|
||||
{
|
||||
Console.Error("DEV9: Socket: Failed To Get Adapter IP");
|
||||
@@ -227,7 +219,7 @@ SocketAdapter::SocketAdapter()
|
||||
}
|
||||
else
|
||||
{
|
||||
foundAdapter = GetIfAutoAdapter(&adapter, &buffer);
|
||||
foundAdapter = AdapterUtils::GetIfAdapterAuto(&adapter, &buffer);
|
||||
adapterIP = {0};
|
||||
|
||||
if (!foundAdapter)
|
||||
@@ -297,228 +289,6 @@ SocketAdapter::SocketAdapter()
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
bool SocketAdapter::GetWin32SelectedAdapter(const std::string& name, PIP_ADAPTER_ADDRESSES adapter, std::unique_ptr<IP_ADAPTER_ADDRESSES[]>* buffer)
|
||||
{
|
||||
int neededSize = 128;
|
||||
std::unique_ptr<IP_ADAPTER_ADDRESSES[]> AdapterInfo = std::make_unique<IP_ADAPTER_ADDRESSES[]>(neededSize);
|
||||
ULONG dwBufLen = sizeof(IP_ADAPTER_ADDRESSES) * neededSize;
|
||||
|
||||
PIP_ADAPTER_ADDRESSES pAdapterInfo;
|
||||
|
||||
DWORD dwStatus = GetAdaptersAddresses(
|
||||
AF_UNSPEC,
|
||||
GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_INCLUDE_GATEWAYS,
|
||||
NULL,
|
||||
AdapterInfo.get(),
|
||||
&dwBufLen);
|
||||
|
||||
if (dwStatus == ERROR_BUFFER_OVERFLOW)
|
||||
{
|
||||
DevCon.WriteLn("DEV9: GetWin32Adapter() buffer too small, resizing");
|
||||
neededSize = dwBufLen / sizeof(IP_ADAPTER_ADDRESSES) + 1;
|
||||
AdapterInfo = std::make_unique<IP_ADAPTER_ADDRESSES[]>(neededSize);
|
||||
dwBufLen = sizeof(IP_ADAPTER_ADDRESSES) * neededSize;
|
||||
DevCon.WriteLn("DEV9: New size %i", neededSize);
|
||||
|
||||
dwStatus = GetAdaptersAddresses(
|
||||
AF_UNSPEC,
|
||||
GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_INCLUDE_GATEWAYS,
|
||||
NULL,
|
||||
AdapterInfo.get(),
|
||||
&dwBufLen);
|
||||
}
|
||||
if (dwStatus != ERROR_SUCCESS)
|
||||
return false;
|
||||
|
||||
pAdapterInfo = AdapterInfo.get();
|
||||
|
||||
do
|
||||
{
|
||||
if (strcmp(pAdapterInfo->AdapterName, name.c_str()) == 0)
|
||||
{
|
||||
*adapter = *pAdapterInfo;
|
||||
buffer->swap(AdapterInfo);
|
||||
return true;
|
||||
}
|
||||
|
||||
pAdapterInfo = pAdapterInfo->Next;
|
||||
} while (pAdapterInfo);
|
||||
return false;
|
||||
}
|
||||
bool SocketAdapter::GetWin32AutoAdapter(PIP_ADAPTER_ADDRESSES adapter, std::unique_ptr<IP_ADAPTER_ADDRESSES[]>* buffer)
|
||||
{
|
||||
int neededSize = 128;
|
||||
std::unique_ptr<IP_ADAPTER_ADDRESSES[]> AdapterInfo = std::make_unique<IP_ADAPTER_ADDRESSES[]>(neededSize);
|
||||
ULONG dwBufLen = sizeof(IP_ADAPTER_ADDRESSES) * neededSize;
|
||||
|
||||
PIP_ADAPTER_ADDRESSES pAdapterInfo;
|
||||
|
||||
DWORD dwStatus = GetAdaptersAddresses(
|
||||
AF_UNSPEC,
|
||||
GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_INCLUDE_GATEWAYS,
|
||||
NULL,
|
||||
AdapterInfo.get(),
|
||||
&dwBufLen);
|
||||
|
||||
if (dwStatus == ERROR_BUFFER_OVERFLOW)
|
||||
{
|
||||
DevCon.WriteLn("DEV9: PCAPGetWin32Adapter() buffer too small, resizing");
|
||||
//
|
||||
neededSize = dwBufLen / sizeof(IP_ADAPTER_ADDRESSES) + 1;
|
||||
AdapterInfo = std::make_unique<IP_ADAPTER_ADDRESSES[]>(neededSize);
|
||||
dwBufLen = sizeof(IP_ADAPTER_ADDRESSES) * neededSize;
|
||||
DevCon.WriteLn("DEV9: New size %i", neededSize);
|
||||
|
||||
dwStatus = GetAdaptersAddresses(
|
||||
AF_UNSPEC,
|
||||
GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_INCLUDE_GATEWAYS,
|
||||
NULL,
|
||||
AdapterInfo.get(),
|
||||
&dwBufLen);
|
||||
}
|
||||
|
||||
if (dwStatus != ERROR_SUCCESS)
|
||||
return 0;
|
||||
|
||||
pAdapterInfo = AdapterInfo.get();
|
||||
|
||||
do
|
||||
{
|
||||
if (pAdapterInfo->IfType != IF_TYPE_SOFTWARE_LOOPBACK &&
|
||||
pAdapterInfo->OperStatus == IfOperStatusUp)
|
||||
{
|
||||
//Search for an adapter with;
|
||||
//IPv4 Address
|
||||
//DNS
|
||||
//Gateway
|
||||
|
||||
bool hasIPv4 = false;
|
||||
bool hasDNS = false;
|
||||
bool hasGateway = false;
|
||||
|
||||
//IPv4
|
||||
PIP_ADAPTER_UNICAST_ADDRESS ipAddress = nullptr;
|
||||
ipAddress = pAdapterInfo->FirstUnicastAddress;
|
||||
while (ipAddress != nullptr && ipAddress->Address.lpSockaddr->sa_family != AF_INET)
|
||||
ipAddress = ipAddress->Next;
|
||||
if (ipAddress != nullptr)
|
||||
hasIPv4 = true;
|
||||
|
||||
//DNS
|
||||
PIP_ADAPTER_DNS_SERVER_ADDRESS dnsAddress = pAdapterInfo->FirstDnsServerAddress;
|
||||
while (dnsAddress != nullptr && dnsAddress->Address.lpSockaddr->sa_family != AF_INET)
|
||||
dnsAddress = dnsAddress->Next;
|
||||
if (dnsAddress != nullptr)
|
||||
hasDNS = true;
|
||||
|
||||
//Gateway
|
||||
PIP_ADAPTER_GATEWAY_ADDRESS gatewayAddress = pAdapterInfo->FirstGatewayAddress;
|
||||
while (gatewayAddress != nullptr && gatewayAddress->Address.lpSockaddr->sa_family != AF_INET)
|
||||
gatewayAddress = gatewayAddress->Next;
|
||||
if (gatewayAddress != nullptr)
|
||||
hasGateway = true;
|
||||
|
||||
if (hasIPv4 && hasDNS && hasGateway)
|
||||
{
|
||||
*adapter = *pAdapterInfo;
|
||||
buffer->swap(AdapterInfo);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
pAdapterInfo = pAdapterInfo->Next;
|
||||
} while (pAdapterInfo);
|
||||
|
||||
return false;
|
||||
}
|
||||
#elif defined(__POSIX__)
|
||||
bool SocketAdapter::GetIfSelectedAdapter(const std::string& name, ifaddrs* adapter, ifaddrs** buffer)
|
||||
{
|
||||
ifaddrs* adapterInfo;
|
||||
ifaddrs* pAdapter;
|
||||
|
||||
int error = getifaddrs(&adapterInfo);
|
||||
if (error)
|
||||
return false;
|
||||
|
||||
pAdapter = adapterInfo;
|
||||
|
||||
do
|
||||
{
|
||||
if (pAdapter->ifa_addr->sa_family == AF_INET && strcmp(pAdapter->ifa_name, name.c_str()) == 0)
|
||||
break;
|
||||
|
||||
pAdapter = pAdapter->ifa_next;
|
||||
} while (pAdapter);
|
||||
|
||||
if (pAdapter != nullptr)
|
||||
{
|
||||
*adapter = *pAdapter;
|
||||
*buffer = adapterInfo;
|
||||
return true;
|
||||
}
|
||||
|
||||
freeifaddrs(adapterInfo);
|
||||
return false;
|
||||
}
|
||||
bool SocketAdapter::GetIfAutoAdapter(ifaddrs* adapter, ifaddrs** buffer)
|
||||
{
|
||||
ifaddrs* adapterInfo;
|
||||
ifaddrs* pAdapter;
|
||||
|
||||
int error = getifaddrs(&adapterInfo);
|
||||
if (error)
|
||||
return false;
|
||||
|
||||
pAdapter = adapterInfo;
|
||||
|
||||
do
|
||||
{
|
||||
if ((pAdapter->ifa_flags & IFF_LOOPBACK) == 0 &&
|
||||
(pAdapter->ifa_flags & IFF_UP) != 0)
|
||||
{
|
||||
//Search for an adapter with;
|
||||
//IPv4 Address
|
||||
//Gateway
|
||||
|
||||
bool hasIPv4 = false;
|
||||
bool hasGateway = false;
|
||||
|
||||
if (pAdapter->ifa_addr->sa_family == AF_INET)
|
||||
hasIPv4 = true;
|
||||
|
||||
#ifdef __linux__
|
||||
std::vector<IP_Address> gateways = InternalServers::DHCP_Server::GetGatewaysLinux(pAdapter->ifa_name);
|
||||
|
||||
if (gateways.size() > 0)
|
||||
hasGateway = true;
|
||||
|
||||
#elif defined(__FreeBSD__) || (__APPLE__)
|
||||
std::vector<IP_Address> gateways = InternalServers::DHCP_Server::GetGatewaysBSD(pAdapter->ifa_name);
|
||||
|
||||
if (gateways.size() > 0)
|
||||
hasGateway = true;
|
||||
|
||||
#else
|
||||
Console.Error("DHCP: Unsupported OS, can't find Gateway");
|
||||
#endif
|
||||
if (hasIPv4 && hasGateway)
|
||||
{
|
||||
*adapter = *pAdapter;
|
||||
*buffer = adapterInfo;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
pAdapter = pAdapter->ifa_next;
|
||||
} while (pAdapter);
|
||||
|
||||
freeifaddrs(adapterInfo);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool SocketAdapter::blocks()
|
||||
{
|
||||
return false;
|
||||
@@ -664,18 +434,18 @@ void SocketAdapter::reloadSettings()
|
||||
std::unique_ptr<IP_ADAPTER_ADDRESSES[]> buffer;
|
||||
|
||||
if (strcmp(EmuConfig.DEV9.EthDevice.c_str(), "Auto") != 0)
|
||||
foundAdapter = GetWin32SelectedAdapter(EmuConfig.DEV9.EthDevice, &adapter, &buffer);
|
||||
foundAdapter = AdapterUtils::GetWin32Adapter(EmuConfig.DEV9.EthDevice, &adapter, &buffer);
|
||||
else
|
||||
foundAdapter = GetWin32AutoAdapter(&adapter, &buffer);
|
||||
foundAdapter = AdapterUtils::GetWin32AdapterAuto(&adapter, &buffer);
|
||||
|
||||
#elif defined(__POSIX__)
|
||||
ifaddrs adapter;
|
||||
ifaddrs* buffer;
|
||||
|
||||
if (strcmp(EmuConfig.DEV9.EthDevice.c_str(), "Auto") != 0)
|
||||
foundAdapter = GetIfSelectedAdapter(EmuConfig.DEV9.EthDevice, &adapter, &buffer);
|
||||
foundAdapter = AdapterUtils::GetIfAdapter(EmuConfig.DEV9.EthDevice, &adapter, &buffer);
|
||||
else
|
||||
foundAdapter = GetIfAutoAdapter(&adapter, &buffer);
|
||||
foundAdapter = AdapterUtils::GetIfAdapterAuto(&adapter, &buffer);
|
||||
#endif
|
||||
|
||||
const IP_Address ps2IP = {internalIP.bytes[0], internalIP.bytes[1], internalIP.bytes[2], 100};
|
||||
|
||||
@@ -16,14 +16,6 @@
|
||||
#pragma once
|
||||
#include <vector>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <iphlpapi.h>
|
||||
#elif defined(__POSIX__)
|
||||
#include <sys/types.h>
|
||||
#include <ifaddrs.h>
|
||||
#endif
|
||||
|
||||
#include "net.h"
|
||||
|
||||
#include "PacketReader/IP/IP_Packet.h"
|
||||
@@ -64,14 +56,6 @@ public:
|
||||
static AdapterOptions GetAdapterOptions();
|
||||
|
||||
private:
|
||||
#ifdef _WIN32
|
||||
bool GetWin32SelectedAdapter(const std::string& name, PIP_ADAPTER_ADDRESSES adapter, std::unique_ptr<IP_ADAPTER_ADDRESSES[]>* buffer);
|
||||
bool GetWin32AutoAdapter(PIP_ADAPTER_ADDRESSES adapter, std::unique_ptr<IP_ADAPTER_ADDRESSES[]>* buffer);
|
||||
#elif defined(__POSIX__)
|
||||
bool GetIfSelectedAdapter(const std::string& name, ifaddrs* adapter, ifaddrs** buffer);
|
||||
bool GetIfAutoAdapter(ifaddrs* adapter, ifaddrs** buffer);
|
||||
#endif // _WIN32
|
||||
|
||||
bool SendIP(PacketReader::IP::IP_Packet* ipPkt);
|
||||
bool SendICMP(Sessions::ConnectionKey Key, PacketReader::IP::IP_Packet* ipPkt);
|
||||
bool SendIGMP(Sessions::ConnectionKey Key, PacketReader::IP::IP_Packet* ipPkt);
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
# Documentation Artifacts
|
||||
|
||||
- Source Directory: `/pcsx2/pcsx2/Docs`
|
||||
- Release Directory: `/pcsx2/bin/Docs`
|
||||
|
||||
Docs should be written in the source directory first in an easily editable format. Currently, Markdown is the preferred format due to its simple markup and easy portability. GitHub's built-in preview functions are a huge benefit as well.
|
||||
|
||||
Visual Studio Code is a cross platform text editor/development platform that can handle Markdown syntax, plus extensions are available to enable in-editor previewing and PDF generation. However, this is not a requirement since other editors will support Markdown, and worst case GitHub supports editing Markdown files in-browser.
|
||||
|
||||
## How to Generate
|
||||
|
||||
### Setup
|
||||
|
||||
To generate the documentation artifacts into the release directory, you will require the following:
|
||||
|
||||
- `pandoc`
|
||||
- Converts from Markdown to PDF
|
||||
|
||||
- `miktex` or something similar that provides `pdflatex`
|
||||
- this is what generates the PDF file
|
||||
|
||||
#### Linux / MacOS
|
||||
|
||||
Consult pandoc's official documentation - https://pandoc.org/installing.html
|
||||
|
||||
#### Windows
|
||||
|
||||
In a PowerShell shell, run the following:
|
||||
|
||||
```ps1
|
||||
> iwr -useb get.scoop.sh | iex
|
||||
> scoop install pandoc latex
|
||||
```
|
||||
|
||||
If you prefer Chocolatey or using the installer, consult pandoc's official documentation - https://pandoc.org/installing.html
|
||||
|
||||
### Usage
|
||||
|
||||
Run the following, this assumes you have access to bash, either by virtue of running on linux or through something like `git-bash` on Windows.
|
||||
|
||||
```bash
|
||||
> ./gen-docs.sh
|
||||
```
|
||||
|
||||
> You can override the default output directory like so - `OUT_DIR=<PATH> ./gen-docs.sh`
|
||||
|
||||
### Customizing Output
|
||||
|
||||
For generating the PDF's this popular template is used and has many features that could be useful https://github.com/Wandmalfarbe/pandoc-latex-template#usage reference it's documentation to take advantage of those if desired.
|
||||
+16
-40
@@ -1,49 +1,25 @@
|
||||
# Documentation Artifacts
|
||||
# PCSX2
|
||||
|
||||
- Source Directory: `/pcsx2/pcsx2/Docs`
|
||||
- Release Directory: `/pcsx2/bin/Docs`
|
||||
PCSX2 is a Playstation 2 emulator for Windows, Linux and Mac. The project has been going since 2001 and still going strong, with contributions from many very clever developers over the years! PCSX2 has compatibility upwards of 95% of the Playstation 2 library being playable.
|
||||
|
||||
Docs should be written in the source directory first in an easily editable format. Currently, Markdown is the preferred format due to its simple markup and easy portability. GitHub's built-in preview functions are a huge benefit as well.
|
||||
## Basic usage
|
||||
|
||||
Visual Studio Code is a cross platform text editor/development platform that can handle Markdown syntax, plus extensions are available to enable in-editor previewing and PDF generation. However, this is not a requirement since other editors will support Markdown, and worst case GitHub supports editing Markdown files in-browser.
|
||||
For information on how to set up the emulator, please see our [basic setup](https://pcsx2.net/guides/basic-setup/) guide.
|
||||
|
||||
## How to Generate
|
||||
## Contributing
|
||||
Pull requests are welcome and can be submitted at our [GitHub page](https://github.com/PCSX2/pcsx2/)
|
||||
|
||||
### Setup
|
||||
Please make sure to follow our coding style guide and fill out the pull request forms with the appropriate information.
|
||||
|
||||
To generate the documentation artifacts into the release directory, you will require the following:
|
||||
## License
|
||||
[GPL 3.0](https://www.gnu.org/licenses/gpl-3.0.en.html)
|
||||
|
||||
- `pandoc`
|
||||
- Converts from Markdown to PDF
|
||||
## Donating to the project
|
||||
If you wish to donate monetarily to the project you can do so via the [GitHub Sponsors](https://github.com/sponsors/PCSX2). All donations are gratefully received!
|
||||
|
||||
- `miktex` or something similar that provides `pdflatex`
|
||||
- this is what generates the PDF file
|
||||
## Thanks to the following monthly donators
|
||||
We thank everybody for their contributions to the project, but we would like to give a special shout out to:
|
||||
|
||||
#### Linux / MacOS
|
||||
|
||||
Consult pandoc's official documentation - https://pandoc.org/installing.html
|
||||
|
||||
#### Windows
|
||||
|
||||
In a PowerShell shell, run the following:
|
||||
|
||||
```ps1
|
||||
> iwr -useb get.scoop.sh | iex
|
||||
> scoop install pandoc latex
|
||||
```
|
||||
|
||||
If you prefer Chocolatey or using the installer, consult pandoc's official documentation - https://pandoc.org/installing.html
|
||||
|
||||
### Usage
|
||||
|
||||
Run the following, this assumes you have access to bash, either by virtue of running on linux or through something like `git-bash` on Windows.
|
||||
|
||||
```bash
|
||||
> ./gen-docs.sh
|
||||
```
|
||||
|
||||
> You can override the default output directory like so - `OUT_DIR=<PATH> ./gen-docs.sh`
|
||||
|
||||
### Customizing Output
|
||||
|
||||
For generating the PDF's this popular template is used and has many features that could be useful https://github.com/Wandmalfarbe/pandoc-latex-template#usage reference it's documentation to take advantage of those if desired.
|
||||
- noigeaR
|
||||
- xTVaser
|
||||
- And 1 anonymous donator!
|
||||
@@ -95,8 +95,9 @@ D3D11HostDisplay::D3D11HostDisplay() = default;
|
||||
|
||||
D3D11HostDisplay::~D3D11HostDisplay()
|
||||
{
|
||||
pxAssertMsg(!m_context, "Context should have been destroyed by now");
|
||||
pxAssertMsg(!m_swap_chain, "Swap chain should have been destroyed by now");
|
||||
D3D11HostDisplay::DestroyRenderSurface();
|
||||
m_context.Reset();
|
||||
m_device.Reset();
|
||||
}
|
||||
|
||||
HostDisplay::RenderAPI D3D11HostDisplay::GetRenderAPI() const
|
||||
@@ -332,13 +333,6 @@ bool D3D11HostDisplay::InitializeRenderDevice(std::string_view shader_cache_dire
|
||||
return true;
|
||||
}
|
||||
|
||||
void D3D11HostDisplay::DestroyRenderDevice()
|
||||
{
|
||||
DestroyRenderSurface();
|
||||
m_context.Reset();
|
||||
m_device.Reset();
|
||||
}
|
||||
|
||||
bool D3D11HostDisplay::MakeRenderContextCurrent()
|
||||
{
|
||||
return true;
|
||||
@@ -757,7 +751,7 @@ void D3D11HostDisplay::EndPresent()
|
||||
KickTimestampQuery();
|
||||
}
|
||||
|
||||
void D3D11HostDisplay::CreateTimestampQueries()
|
||||
bool D3D11HostDisplay::CreateTimestampQueries()
|
||||
{
|
||||
for (u32 i = 0; i < NUM_TIMESTAMP_QUERIES; i++)
|
||||
{
|
||||
@@ -768,12 +762,13 @@ void D3D11HostDisplay::CreateTimestampQueries()
|
||||
if (FAILED(hr))
|
||||
{
|
||||
m_timestamp_queries = {};
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
KickTimestampQuery();
|
||||
return true;
|
||||
}
|
||||
|
||||
void D3D11HostDisplay::DestroyTimestampQueries()
|
||||
@@ -835,7 +830,7 @@ void D3D11HostDisplay::PopTimestampQuery()
|
||||
|
||||
void D3D11HostDisplay::KickTimestampQuery()
|
||||
{
|
||||
if (m_timestamp_query_started)
|
||||
if (m_timestamp_query_started || !m_timestamp_queries[0][0])
|
||||
return;
|
||||
|
||||
m_context->Begin(m_timestamp_queries[m_write_timestamp_query][0].Get());
|
||||
@@ -843,16 +838,21 @@ void D3D11HostDisplay::KickTimestampQuery()
|
||||
m_timestamp_query_started = true;
|
||||
}
|
||||
|
||||
void D3D11HostDisplay::SetGPUTimingEnabled(bool enabled)
|
||||
bool D3D11HostDisplay::SetGPUTimingEnabled(bool enabled)
|
||||
{
|
||||
if (m_gpu_timing_enabled == enabled)
|
||||
return;
|
||||
return true;
|
||||
|
||||
m_gpu_timing_enabled = enabled;
|
||||
if (m_gpu_timing_enabled)
|
||||
CreateTimestampQueries();
|
||||
{
|
||||
return CreateTimestampQueries();
|
||||
}
|
||||
else
|
||||
{
|
||||
DestroyTimestampQueries();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
float D3D11HostDisplay::GetAndResetAccumulatedGPUTime()
|
||||
|
||||
@@ -45,7 +45,6 @@ public:
|
||||
|
||||
bool CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, VsyncMode vsync, bool threaded_presentation, bool debug_device) override;
|
||||
bool InitializeRenderDevice(std::string_view shader_cache_directory, bool debug_device) override;
|
||||
void DestroyRenderDevice() override;
|
||||
|
||||
bool MakeRenderContextCurrent() override;
|
||||
bool DoneRenderContextCurrent() override;
|
||||
@@ -69,7 +68,7 @@ public:
|
||||
bool BeginPresent(bool frame_skip) override;
|
||||
void EndPresent() override;
|
||||
|
||||
void SetGPUTimingEnabled(bool enabled) override;
|
||||
bool SetGPUTimingEnabled(bool enabled) override;
|
||||
float GetAndResetAccumulatedGPUTime() override;
|
||||
|
||||
static AdapterAndModeList StaticGetAdapterAndModeList();
|
||||
@@ -87,7 +86,7 @@ protected:
|
||||
bool CreateSwapChain(const DXGI_MODE_DESC* fullscreen_mode);
|
||||
bool CreateSwapChainRTV();
|
||||
|
||||
void CreateTimestampQueries();
|
||||
bool CreateTimestampQueries();
|
||||
void DestroyTimestampQueries();
|
||||
void PopTimestampQuery();
|
||||
void KickTimestampQuery();
|
||||
|
||||
@@ -51,8 +51,12 @@ D3D12HostDisplay::D3D12HostDisplay() = default;
|
||||
|
||||
D3D12HostDisplay::~D3D12HostDisplay()
|
||||
{
|
||||
pxAssertMsg(!g_d3d12_context, "Context should have been destroyed by now");
|
||||
pxAssertMsg(!m_swap_chain, "Swap chain should have been destroyed by now");
|
||||
if (g_d3d12_context)
|
||||
{
|
||||
g_d3d12_context->WaitForGPUIdle();
|
||||
D3D12HostDisplay::DestroyRenderSurface();
|
||||
g_d3d12_context->Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
HostDisplay::RenderAPI D3D12HostDisplay::GetRenderAPI() const
|
||||
@@ -85,7 +89,8 @@ bool D3D12HostDisplay::HasRenderSurface() const
|
||||
return static_cast<bool>(m_swap_chain);
|
||||
}
|
||||
|
||||
std::unique_ptr<HostDisplayTexture> D3D12HostDisplay::CreateTexture(u32 width, u32 height, const void* data, u32 data_stride, bool dynamic /* = false */)
|
||||
std::unique_ptr<HostDisplayTexture> D3D12HostDisplay::CreateTexture(
|
||||
u32 width, u32 height, const void* data, u32 data_stride, bool dynamic /* = false */)
|
||||
{
|
||||
D3D12::Texture tex;
|
||||
if (!tex.Create(width, height, 1, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_UNKNOWN, DXGI_FORMAT_UNKNOWN,
|
||||
@@ -94,17 +99,17 @@ std::unique_ptr<HostDisplayTexture> D3D12HostDisplay::CreateTexture(u32 width, u
|
||||
return {};
|
||||
}
|
||||
|
||||
if (data && !tex.LoadData(0, 0, 0, width, height, data, data_stride))
|
||||
if (data && !tex.LoadData(g_d3d12_context->GetInitCommandList(), 0, 0, 0, width, height, data, data_stride))
|
||||
return {};
|
||||
|
||||
return std::make_unique<D3D12HostDisplayTexture>(std::move(tex));
|
||||
}
|
||||
|
||||
void D3D12HostDisplay::UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height,
|
||||
const void* texture_data, u32 texture_data_stride)
|
||||
void D3D12HostDisplay::UpdateTexture(
|
||||
HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* texture_data, u32 texture_data_stride)
|
||||
{
|
||||
static_cast<D3D12HostDisplayTexture*>(texture)->GetTexture().LoadData(0, x, y, width, height, texture_data,
|
||||
texture_data_stride);
|
||||
static_cast<D3D12HostDisplayTexture*>(texture)->GetTexture().LoadData(
|
||||
g_d3d12_context->GetCommandList(), 0, x, y, width, height, texture_data, texture_data_stride);
|
||||
}
|
||||
|
||||
bool D3D12HostDisplay::GetHostRefreshRate(float* refresh_rate)
|
||||
@@ -203,15 +208,6 @@ bool D3D12HostDisplay::InitializeRenderDevice(std::string_view shader_cache_dire
|
||||
return true;
|
||||
}
|
||||
|
||||
void D3D12HostDisplay::DestroyRenderDevice()
|
||||
{
|
||||
g_d3d12_context->ExecuteCommandList(true);
|
||||
|
||||
DestroyRenderSurface();
|
||||
if (g_d3d12_context)
|
||||
g_d3d12_context->Destroy();
|
||||
}
|
||||
|
||||
bool D3D12HostDisplay::MakeRenderContextCurrent()
|
||||
{
|
||||
return true;
|
||||
@@ -644,9 +640,10 @@ void D3D12HostDisplay::EndPresent()
|
||||
m_swap_chain->Present(static_cast<UINT>(vsync), 0);
|
||||
}
|
||||
|
||||
void D3D12HostDisplay::SetGPUTimingEnabled(bool enabled)
|
||||
bool D3D12HostDisplay::SetGPUTimingEnabled(bool enabled)
|
||||
{
|
||||
g_d3d12_context->SetEnableGPUTiming(enabled);
|
||||
return true;
|
||||
}
|
||||
|
||||
float D3D12HostDisplay::GetAndResetAccumulatedGPUTime()
|
||||
|
||||
@@ -51,7 +51,6 @@ public:
|
||||
|
||||
bool CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, VsyncMode vsync, bool threaded_presentation, bool debug_device) override;
|
||||
bool InitializeRenderDevice(std::string_view shader_cache_directory, bool debug_device) override;
|
||||
void DestroyRenderDevice() override;
|
||||
|
||||
bool MakeRenderContextCurrent() override;
|
||||
bool DoneRenderContextCurrent() override;
|
||||
@@ -75,7 +74,7 @@ public:
|
||||
bool BeginPresent(bool frame_skip) override;
|
||||
void EndPresent() override;
|
||||
|
||||
void SetGPUTimingEnabled(bool enabled) override;
|
||||
bool SetGPUTimingEnabled(bool enabled) override;
|
||||
float GetAndResetAccumulatedGPUTime() override;
|
||||
|
||||
static AdapterAndModeList StaticGetAdapterAndModeList();
|
||||
|
||||
@@ -185,6 +185,11 @@ void INISettingsInterface::SetStringValue(const char* section, const char* key,
|
||||
m_ini.SetValue(section, key, value, nullptr, true);
|
||||
}
|
||||
|
||||
bool INISettingsInterface::ContainsValue(const char* section, const char* key) const
|
||||
{
|
||||
return (m_ini.GetValue(section, key, nullptr) != nullptr);
|
||||
}
|
||||
|
||||
void INISettingsInterface::DeleteValue(const char* section, const char* key)
|
||||
{
|
||||
m_dirty = true;
|
||||
@@ -198,7 +203,7 @@ void INISettingsInterface::ClearSection(const char* section)
|
||||
m_ini.SetValue(section, nullptr, nullptr);
|
||||
}
|
||||
|
||||
std::vector<std::string> INISettingsInterface::GetStringList(const char* section, const char* key)
|
||||
std::vector<std::string> INISettingsInterface::GetStringList(const char* section, const char* key) const
|
||||
{
|
||||
std::list<CSimpleIniA::Entry> entries;
|
||||
if (!m_ini.GetAllValues(section, key, entries))
|
||||
|
||||
@@ -48,10 +48,11 @@ public:
|
||||
void SetDoubleValue(const char* section, const char* key, double value) override;
|
||||
void SetBoolValue(const char* section, const char* key, bool value) override;
|
||||
void SetStringValue(const char* section, const char* key, const char* value) override;
|
||||
bool ContainsValue(const char* section, const char* key) const override;
|
||||
void DeleteValue(const char* section, const char* key) override;
|
||||
void ClearSection(const char* section) override;
|
||||
|
||||
std::vector<std::string> GetStringList(const char* section, const char* key) override;
|
||||
std::vector<std::string> GetStringList(const char* section, const char* key) const override;
|
||||
void SetStringList(const char* section, const char* key, const std::vector<std::string>& items) override;
|
||||
bool RemoveFromStringList(const char* section, const char* key, const char* item) override;
|
||||
bool AddToStringList(const char* section, const char* key, const char* item) override;
|
||||
|
||||
+247
-55
@@ -19,15 +19,18 @@
|
||||
#include <cmath>
|
||||
#include <deque>
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "fmt/core.h"
|
||||
|
||||
#include "common/StringUtil.h"
|
||||
#include "common/Timer.h"
|
||||
#include "imgui.h"
|
||||
|
||||
#include "Config.h"
|
||||
#include "Counters.h"
|
||||
#include "Frontend/ImGuiManager.h"
|
||||
#include "Frontend/InputManager.h"
|
||||
#include "GS.h"
|
||||
#include "GS/GS.h"
|
||||
#include "Host.h"
|
||||
@@ -39,10 +42,21 @@
|
||||
#include "VMManager.h"
|
||||
#endif
|
||||
|
||||
static void SetImGuiStyle();
|
||||
static bool LoadFontData();
|
||||
static void UnloadFontData();
|
||||
static bool AddImGuiFonts();
|
||||
namespace ImGuiManager
|
||||
{
|
||||
static void SetStyle();
|
||||
static void SetKeyMap();
|
||||
static bool LoadFontData();
|
||||
static void UnloadFontData();
|
||||
static bool AddImGuiFonts();
|
||||
static ImFont* AddTextFont(float size);
|
||||
static ImFont* AddFixedFont(float size);
|
||||
static bool AddIconFonts(float size);
|
||||
static void AcquirePendingOSDMessages();
|
||||
static void DrawOSDMessages();
|
||||
static void FormatProcessorStat(std::string& text, double usage, double time);
|
||||
static void DrawPerformanceOverlay();
|
||||
} // namespace ImGuiManager
|
||||
|
||||
static float s_global_scale = 1.0f;
|
||||
|
||||
@@ -53,6 +67,17 @@ static std::vector<u8> s_standard_font_data;
|
||||
static std::vector<u8> s_fixed_font_data;
|
||||
static std::vector<u8> s_icon_font_data;
|
||||
|
||||
static Common::Timer s_last_render_time;
|
||||
|
||||
#ifdef PCSX2_CORE
|
||||
// cached copies of WantCaptureKeyboard/Mouse, used to know when to dispatch events
|
||||
static std::atomic_bool s_imgui_wants_keyboard{false};
|
||||
static std::atomic_bool s_imgui_wants_mouse{false};
|
||||
|
||||
// mapping of host key -> imgui key
|
||||
static std::unordered_map<u32, ImGuiKey> s_imgui_key_map;
|
||||
#endif
|
||||
|
||||
bool ImGuiManager::Initialize()
|
||||
{
|
||||
if (!LoadFontData())
|
||||
@@ -62,23 +87,30 @@ bool ImGuiManager::Initialize()
|
||||
}
|
||||
|
||||
HostDisplay* display = Host::GetHostDisplay();
|
||||
|
||||
ImGui::CreateContext();
|
||||
ImGui::GetIO().IniFilename = nullptr;
|
||||
|
||||
s_global_scale = std::max(1.0f, display->GetWindowScale() * static_cast<float>(EmuConfig.GS.OsdScale / 100.0));
|
||||
|
||||
ImGui::GetIO().DisplayFramebufferScale = ImVec2(1, 1); // We already scale things ourselves, this would double-apply scaling
|
||||
ImGui::GetIO().DisplaySize.x = static_cast<float>(display->GetWindowWidth());
|
||||
ImGui::GetIO().DisplaySize.y = static_cast<float>(display->GetWindowHeight());
|
||||
ImGui::GetStyle() = ImGuiStyle();
|
||||
ImGui::GetStyle().WindowMinSize = ImVec2(1.0f, 1.0f);
|
||||
SetImGuiStyle();
|
||||
ImGui::GetStyle().ScaleAllSizes(s_global_scale);
|
||||
ImGui::CreateContext();
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.IniFilename = nullptr;
|
||||
#ifdef PCSX2_CORE
|
||||
io.BackendFlags |= ImGuiBackendFlags_HasGamepad;
|
||||
io.BackendUsingLegacyKeyArrays = 0;
|
||||
io.BackendUsingLegacyNavInputArray = 0;
|
||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard | ImGuiConfigFlags_NavEnableGamepad;
|
||||
#endif
|
||||
|
||||
io.DisplayFramebufferScale = ImVec2(1, 1); // We already scale things ourselves, this would double-apply scaling
|
||||
io.DisplaySize.x = static_cast<float>(display->GetWindowWidth());
|
||||
io.DisplaySize.y = static_cast<float>(display->GetWindowHeight());
|
||||
|
||||
SetKeyMap();
|
||||
SetStyle();
|
||||
|
||||
if (!display->CreateImGuiContext())
|
||||
{
|
||||
pxFailRel("Failed to create ImGui device context");
|
||||
display->DestroyImGuiContext();
|
||||
ImGui::DestroyContext();
|
||||
UnloadFontData();
|
||||
return false;
|
||||
@@ -93,6 +125,9 @@ bool ImGuiManager::Initialize()
|
||||
return false;
|
||||
}
|
||||
|
||||
// don't need the font data anymore, save some memory
|
||||
ImGui::GetIO().Fonts->ClearTexData();
|
||||
|
||||
NewFrame();
|
||||
return true;
|
||||
}
|
||||
@@ -104,6 +139,10 @@ void ImGuiManager::Shutdown()
|
||||
display->DestroyImGuiContext();
|
||||
if (ImGui::GetCurrentContext())
|
||||
ImGui::DestroyContext();
|
||||
|
||||
s_standard_font = nullptr;
|
||||
s_fixed_font = nullptr;
|
||||
|
||||
UnloadFontData();
|
||||
}
|
||||
|
||||
@@ -139,7 +178,7 @@ void ImGuiManager::UpdateScale()
|
||||
|
||||
ImGui::GetStyle() = ImGuiStyle();
|
||||
ImGui::GetStyle().WindowMinSize = ImVec2(1.0f, 1.0f);
|
||||
SetImGuiStyle();
|
||||
SetStyle();
|
||||
ImGui::GetStyle().ScaleAllSizes(scale);
|
||||
|
||||
if (!AddImGuiFonts())
|
||||
@@ -153,14 +192,24 @@ void ImGuiManager::UpdateScale()
|
||||
|
||||
void ImGuiManager::NewFrame()
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
io.DeltaTime = s_last_render_time.GetTimeSecondsAndReset();
|
||||
|
||||
ImGui::NewFrame();
|
||||
|
||||
#ifdef PCSX2_CORE
|
||||
s_imgui_wants_keyboard.store(io.WantCaptureKeyboard, std::memory_order_relaxed);
|
||||
s_imgui_wants_mouse.store(io.WantCaptureMouse, std::memory_order_release);
|
||||
#endif
|
||||
}
|
||||
|
||||
void SetImGuiStyle()
|
||||
void ImGuiManager::SetStyle()
|
||||
{
|
||||
ImGuiStyle* style = &ImGui::GetStyle();
|
||||
ImVec4* colors = style->Colors;
|
||||
ImGuiStyle& style = ImGui::GetStyle();
|
||||
style = ImGuiStyle();
|
||||
style.WindowMinSize = ImVec2(1.0f, 1.0f);
|
||||
|
||||
ImVec4* colors = style.Colors;
|
||||
colors[ImGuiCol_Text] = ImVec4(0.95f, 0.96f, 0.98f, 1.00f);
|
||||
colors[ImGuiCol_TextDisabled] = ImVec4(0.36f, 0.42f, 0.47f, 1.00f);
|
||||
colors[ImGuiCol_WindowBg] = ImVec4(0.11f, 0.15f, 0.17f, 1.00f);
|
||||
@@ -209,9 +258,58 @@ void SetImGuiStyle()
|
||||
colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f);
|
||||
colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f);
|
||||
colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f);
|
||||
|
||||
style.ScaleAllSizes(s_global_scale);
|
||||
}
|
||||
|
||||
bool LoadFontData()
|
||||
void ImGuiManager::SetKeyMap()
|
||||
{
|
||||
#ifdef PCSX2_CORE
|
||||
struct KeyMapping
|
||||
{
|
||||
int index;
|
||||
const char* name;
|
||||
const char* alt_name;
|
||||
};
|
||||
|
||||
static constexpr KeyMapping mapping[] = {{ImGuiKey_LeftArrow, "Left"}, {ImGuiKey_RightArrow, "Right"}, {ImGuiKey_UpArrow, "Up"},
|
||||
{ImGuiKey_DownArrow, "Down"}, {ImGuiKey_PageUp, "PageUp"}, {ImGuiKey_PageDown, "PageDown"}, {ImGuiKey_Home, "Home"},
|
||||
{ImGuiKey_End, "End"}, {ImGuiKey_Insert, "Insert"}, {ImGuiKey_Delete, "Delete"}, {ImGuiKey_Backspace, "Backspace"},
|
||||
{ImGuiKey_Space, "Space"}, {ImGuiKey_Enter, "Return"}, {ImGuiKey_Escape, "Escape"}, {ImGuiKey_LeftCtrl, "LeftCtrl", "Ctrl"},
|
||||
{ImGuiKey_LeftShift, "LeftShift", "Shift"}, {ImGuiKey_LeftAlt, "LeftAlt", "Alt"}, {ImGuiKey_LeftSuper, "LeftSuper", "Super"},
|
||||
{ImGuiKey_RightCtrl, "RightCtrl"}, {ImGuiKey_RightShift, "RightShift"}, {ImGuiKey_RightAlt, "RightAlt"},
|
||||
{ImGuiKey_RightSuper, "RightSuper"}, {ImGuiKey_Menu, "Menu"}, {ImGuiKey_0, "0"}, {ImGuiKey_1, "1"}, {ImGuiKey_2, "2"},
|
||||
{ImGuiKey_3, "3"}, {ImGuiKey_4, "4"}, {ImGuiKey_5, "5"}, {ImGuiKey_6, "6"}, {ImGuiKey_7, "7"}, {ImGuiKey_8, "8"}, {ImGuiKey_9, "9"},
|
||||
{ImGuiKey_A, "A"}, {ImGuiKey_B, "B"}, {ImGuiKey_C, "C"}, {ImGuiKey_D, "D"}, {ImGuiKey_E, "E"}, {ImGuiKey_F, "F"}, {ImGuiKey_G, "G"},
|
||||
{ImGuiKey_H, "H"}, {ImGuiKey_I, "I"}, {ImGuiKey_J, "J"}, {ImGuiKey_K, "K"}, {ImGuiKey_L, "L"}, {ImGuiKey_M, "M"}, {ImGuiKey_N, "N"},
|
||||
{ImGuiKey_O, "O"}, {ImGuiKey_P, "P"}, {ImGuiKey_Q, "Q"}, {ImGuiKey_R, "R"}, {ImGuiKey_S, "S"}, {ImGuiKey_T, "T"}, {ImGuiKey_U, "U"},
|
||||
{ImGuiKey_V, "V"}, {ImGuiKey_W, "W"}, {ImGuiKey_X, "X"}, {ImGuiKey_Y, "Y"}, {ImGuiKey_Z, "Z"}, {ImGuiKey_F1, "F1"},
|
||||
{ImGuiKey_F2, "F2"}, {ImGuiKey_F3, "F3"}, {ImGuiKey_F4, "F4"}, {ImGuiKey_F5, "F5"}, {ImGuiKey_F6, "F6"}, {ImGuiKey_F7, "F7"},
|
||||
{ImGuiKey_F8, "F8"}, {ImGuiKey_F9, "F9"}, {ImGuiKey_F10, "F10"}, {ImGuiKey_F11, "F11"}, {ImGuiKey_F12, "F12"},
|
||||
{ImGuiKey_Apostrophe, "Apostrophe"}, {ImGuiKey_Comma, "Comma"}, {ImGuiKey_Minus, "Minus"}, {ImGuiKey_Period, "Period"},
|
||||
{ImGuiKey_Slash, "Slash"}, {ImGuiKey_Semicolon, "Semicolon"}, {ImGuiKey_Equal, "Equal"}, {ImGuiKey_LeftBracket, "BracketLeft"},
|
||||
{ImGuiKey_Backslash, "Backslash"}, {ImGuiKey_RightBracket, "BracketRight"}, {ImGuiKey_GraveAccent, "QuoteLeft"},
|
||||
{ImGuiKey_CapsLock, "CapsLock"}, {ImGuiKey_ScrollLock, "ScrollLock"}, {ImGuiKey_NumLock, "NumLock"},
|
||||
{ImGuiKey_PrintScreen, "PrintScreen"}, {ImGuiKey_Pause, "Pause"}, {ImGuiKey_Keypad0, "Keypad0"}, {ImGuiKey_Keypad1, "Keypad1"},
|
||||
{ImGuiKey_Keypad2, "Keypad2"}, {ImGuiKey_Keypad3, "Keypad3"}, {ImGuiKey_Keypad4, "Keypad4"}, {ImGuiKey_Keypad5, "Keypad5"},
|
||||
{ImGuiKey_Keypad6, "Keypad6"}, {ImGuiKey_Keypad7, "Keypad7"}, {ImGuiKey_Keypad8, "Keypad8"}, {ImGuiKey_Keypad9, "Keypad9"},
|
||||
{ImGuiKey_KeypadDecimal, "KeypadPeriod"}, {ImGuiKey_KeypadDivide, "KeypadDivide"}, {ImGuiKey_KeypadMultiply, "KeypadMultiply"},
|
||||
{ImGuiKey_KeypadSubtract, "KeypadMinus"}, {ImGuiKey_KeypadAdd, "KeypadPlus"}, {ImGuiKey_KeypadEnter, "KeypadReturn"},
|
||||
{ImGuiKey_KeypadEqual, "KeypadEqual"}};
|
||||
|
||||
s_imgui_key_map.clear();
|
||||
for (const KeyMapping& km : mapping)
|
||||
{
|
||||
std::optional<u32> map(InputManager::ConvertHostKeyboardStringToCode(km.name));
|
||||
if (!map.has_value() && km.alt_name)
|
||||
map = InputManager::ConvertHostKeyboardStringToCode(km.alt_name);
|
||||
if (map.has_value())
|
||||
s_imgui_key_map[map.value()] = km.index;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool ImGuiManager::LoadFontData()
|
||||
{
|
||||
if (s_standard_font_data.empty())
|
||||
{
|
||||
@@ -243,14 +341,14 @@ bool LoadFontData()
|
||||
return true;
|
||||
}
|
||||
|
||||
void UnloadFontData()
|
||||
void ImGuiManager::UnloadFontData()
|
||||
{
|
||||
std::vector<u8>().swap(s_standard_font_data);
|
||||
std::vector<u8>().swap(s_fixed_font_data);
|
||||
std::vector<u8>().swap(s_icon_font_data);
|
||||
}
|
||||
|
||||
static ImFont* AddTextFont(float size /*= 15.0f*/)
|
||||
ImFont* ImGuiManager::AddTextFont(float size)
|
||||
{
|
||||
static const ImWchar default_ranges[] = {
|
||||
// Basic Latin + Latin Supplement + Central European diacritics
|
||||
@@ -278,15 +376,15 @@ static ImFont* AddTextFont(float size /*= 15.0f*/)
|
||||
s_standard_font_data.data(), static_cast<int>(s_standard_font_data.size()), size, &cfg, default_ranges);
|
||||
}
|
||||
|
||||
static ImFont* AddFixedFont(float size)
|
||||
ImFont* ImGuiManager::AddFixedFont(float size)
|
||||
{
|
||||
ImFontConfig cfg;
|
||||
cfg.FontDataOwnedByAtlas = false;
|
||||
return ImGui::GetIO().Fonts->AddFontFromMemoryTTF(s_fixed_font_data.data(),
|
||||
static_cast<int>(s_fixed_font_data.size()), size, &cfg, nullptr);
|
||||
return ImGui::GetIO().Fonts->AddFontFromMemoryTTF(
|
||||
s_fixed_font_data.data(), static_cast<int>(s_fixed_font_data.size()), size, &cfg, nullptr);
|
||||
}
|
||||
|
||||
static bool AddIconFonts(float size)
|
||||
bool ImGuiManager::AddIconFonts(float size)
|
||||
{
|
||||
static const ImWchar range_fa[] = {ICON_MIN_FA, ICON_MAX_FA, 0};
|
||||
|
||||
@@ -297,11 +395,11 @@ static bool AddIconFonts(float size)
|
||||
cfg.GlyphMaxAdvanceX = size * 0.75f;
|
||||
cfg.FontDataOwnedByAtlas = false;
|
||||
|
||||
return (ImGui::GetIO().Fonts->AddFontFromMemoryTTF(s_icon_font_data.data(), static_cast<int>(s_icon_font_data.size()),
|
||||
size * 0.75f, &cfg, range_fa) != nullptr);
|
||||
return (ImGui::GetIO().Fonts->AddFontFromMemoryTTF(
|
||||
s_icon_font_data.data(), static_cast<int>(s_icon_font_data.size()), size * 0.75f, &cfg, range_fa) != nullptr);
|
||||
}
|
||||
|
||||
bool AddImGuiFonts()
|
||||
bool ImGuiManager::AddImGuiFonts()
|
||||
{
|
||||
const float standard_font_size = std::ceil(15.0f * s_global_scale);
|
||||
|
||||
@@ -387,7 +485,7 @@ void Host::ClearOSDMessages()
|
||||
s_osd_active_messages.clear();
|
||||
}
|
||||
|
||||
static void AcquirePendingOSDMessages()
|
||||
void ImGuiManager::AcquirePendingOSDMessages()
|
||||
{
|
||||
std::atomic_thread_fence(std::memory_order_consume);
|
||||
if (s_osd_posted_messages.empty())
|
||||
@@ -403,10 +501,9 @@ static void AcquirePendingOSDMessages()
|
||||
{
|
||||
OSDMessage& new_msg = s_osd_posted_messages.front();
|
||||
std::deque<OSDMessage>::iterator iter;
|
||||
if (!new_msg.key.empty() && (iter = std::find_if(s_osd_active_messages.begin(), s_osd_active_messages.end(),
|
||||
[&new_msg](const OSDMessage& other) {
|
||||
return new_msg.key == other.key;
|
||||
})) != s_osd_active_messages.end())
|
||||
if (!new_msg.key.empty() &&
|
||||
(iter = std::find_if(s_osd_active_messages.begin(), s_osd_active_messages.end(),
|
||||
[&new_msg](const OSDMessage& other) { return new_msg.key == other.key; })) != s_osd_active_messages.end())
|
||||
{
|
||||
iter->text = std::move(new_msg.text);
|
||||
iter->duration = new_msg.duration;
|
||||
@@ -426,7 +523,7 @@ static void AcquirePendingOSDMessages()
|
||||
}
|
||||
}
|
||||
|
||||
static void DrawOSDMessages()
|
||||
void ImGuiManager::DrawOSDMessages()
|
||||
{
|
||||
ImFont* const font = ImGui::GetFont();
|
||||
const float scale = s_global_scale;
|
||||
@@ -469,13 +566,13 @@ static void DrawOSDMessages()
|
||||
ImDrawList* dl = ImGui::GetBackgroundDrawList();
|
||||
dl->AddRectFilled(pos, ImVec2(pos.x + size.x, pos.y + size.y), IM_COL32(0x21, 0x21, 0x21, alpha), rounding);
|
||||
dl->AddRect(pos, ImVec2(pos.x + size.x, pos.y + size.y), IM_COL32(0x48, 0x48, 0x48, alpha), rounding);
|
||||
dl->AddText(font, font->FontSize, ImVec2(text_rect.x, text_rect.y), IM_COL32(0xff, 0xff, 0xff, alpha),
|
||||
msg.text.c_str(), msg.text.c_str() + msg.text.length(), max_width, &text_rect);
|
||||
dl->AddText(font, font->FontSize, ImVec2(text_rect.x, text_rect.y), IM_COL32(0xff, 0xff, 0xff, alpha), msg.text.c_str(),
|
||||
msg.text.c_str() + msg.text.length(), max_width, &text_rect);
|
||||
position_y += size.y + spacing;
|
||||
}
|
||||
}
|
||||
|
||||
static void FormatProcessorStat(std::string& text, double usage, double time)
|
||||
void ImGuiManager::FormatProcessorStat(std::string& text, double usage, double time)
|
||||
{
|
||||
// Some values, such as GPU (and even CPU to some extent) can be out of phase with the wall clock,
|
||||
// which the processor time is divided by to get a utilization percentage. Let's clamp it at 100%,
|
||||
@@ -486,7 +583,7 @@ static void FormatProcessorStat(std::string& text, double usage, double time)
|
||||
fmt::format_to(std::back_inserter(text), "{:.1f}% ({:.2f}ms)", usage, time);
|
||||
}
|
||||
|
||||
static void DrawPerformanceOverlay()
|
||||
void ImGuiManager::DrawPerformanceOverlay()
|
||||
{
|
||||
const float scale = s_global_scale;
|
||||
const float shadow_offset = std::ceil(1.0f * scale);
|
||||
@@ -504,14 +601,11 @@ static void DrawPerformanceOverlay()
|
||||
#define DRAW_LINE(font, text, color) \
|
||||
do \
|
||||
{ \
|
||||
text_size = \
|
||||
font->CalcTextSizeA(font->FontSize, std::numeric_limits<float>::max(), -1.0f, (text), nullptr, nullptr); \
|
||||
dl->AddText( \
|
||||
font, font->FontSize, \
|
||||
text_size = font->CalcTextSizeA(font->FontSize, std::numeric_limits<float>::max(), -1.0f, (text), nullptr, nullptr); \
|
||||
dl->AddText(font, font->FontSize, \
|
||||
ImVec2(ImGui::GetIO().DisplaySize.x - margin - text_size.x + shadow_offset, position_y + shadow_offset), \
|
||||
IM_COL32(0, 0, 0, 100), (text)); \
|
||||
dl->AddText(font, font->FontSize, ImVec2(ImGui::GetIO().DisplaySize.x - margin - text_size.x, position_y), color, \
|
||||
(text)); \
|
||||
dl->AddText(font, font->FontSize, ImVec2(ImGui::GetIO().DisplaySize.x - margin - text_size.x, position_y), color, (text)); \
|
||||
position_y += text_size.y + spacing; \
|
||||
} while (0)
|
||||
|
||||
@@ -528,18 +622,20 @@ static void DrawPerformanceOverlay()
|
||||
{
|
||||
switch (PerformanceMetrics::GetInternalFPSMethod())
|
||||
{
|
||||
case PerformanceMetrics::InternalFPSMethod::GSPrivilegedRegister:
|
||||
fmt::format_to(std::back_inserter(text), "G: {:.2f} [P] | V: {:.2f}", PerformanceMetrics::GetInternalFPS(), PerformanceMetrics::GetFPS());
|
||||
break;
|
||||
case PerformanceMetrics::InternalFPSMethod::GSPrivilegedRegister:
|
||||
fmt::format_to(std::back_inserter(text), "G: {:.2f} [P] | V: {:.2f}", PerformanceMetrics::GetInternalFPS(),
|
||||
PerformanceMetrics::GetFPS());
|
||||
break;
|
||||
|
||||
case PerformanceMetrics::InternalFPSMethod::DISPFBBlit:
|
||||
fmt::format_to(std::back_inserter(text), "G: {:.2f} [B] | V: {:.2f}", PerformanceMetrics::GetInternalFPS(), PerformanceMetrics::GetFPS());
|
||||
break;
|
||||
case PerformanceMetrics::InternalFPSMethod::DISPFBBlit:
|
||||
fmt::format_to(std::back_inserter(text), "G: {:.2f} [B] | V: {:.2f}", PerformanceMetrics::GetInternalFPS(),
|
||||
PerformanceMetrics::GetFPS());
|
||||
break;
|
||||
|
||||
case PerformanceMetrics::InternalFPSMethod::None:
|
||||
default:
|
||||
fmt::format_to(std::back_inserter(text), "V: {:.2f}", PerformanceMetrics::GetFPS());
|
||||
break;
|
||||
case PerformanceMetrics::InternalFPSMethod::None:
|
||||
default:
|
||||
fmt::format_to(std::back_inserter(text), "V: {:.2f}", PerformanceMetrics::GetFPS());
|
||||
break;
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
@@ -651,6 +747,9 @@ static void DrawPerformanceOverlay()
|
||||
|
||||
void ImGuiManager::RenderOSD()
|
||||
{
|
||||
// acquire for IO.MousePos.
|
||||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
|
||||
DrawPerformanceOverlay();
|
||||
|
||||
AcquirePendingOSDMessages();
|
||||
@@ -671,3 +770,96 @@ ImFont* ImGuiManager::GetFixedFont()
|
||||
{
|
||||
return s_fixed_font;
|
||||
}
|
||||
|
||||
#ifdef PCSX2_CORE
|
||||
|
||||
void ImGuiManager::UpdateMousePosition(float x, float y)
|
||||
{
|
||||
if (!ImGui::GetCurrentContext())
|
||||
return;
|
||||
|
||||
ImGui::GetIO().MousePos = ImVec2(x, y);
|
||||
std::atomic_thread_fence(std::memory_order_release);
|
||||
}
|
||||
|
||||
bool ImGuiManager::ProcessPointerButtonEvent(InputBindingKey key, float value)
|
||||
{
|
||||
if (!ImGui::GetCurrentContext() || key.data >= std::size(ImGui::GetIO().MouseDown))
|
||||
return false;
|
||||
|
||||
// still update state anyway
|
||||
GetMTGS().RunOnGSThread([button = key.data, down = (value != 0.0f)]() { ImGui::GetIO().AddMouseButtonEvent(button, down); });
|
||||
|
||||
return s_imgui_wants_mouse.load(std::memory_order_acquire);
|
||||
}
|
||||
|
||||
bool ImGuiManager::ProcessPointerAxisEvent(InputBindingKey key, float value)
|
||||
{
|
||||
if (!ImGui::GetCurrentContext() || value == 0.0f || key.data < static_cast<u32>(InputPointerAxis::WheelX))
|
||||
return false;
|
||||
|
||||
// still update state anyway
|
||||
const bool horizontal = (key.data == static_cast<u32>(InputPointerAxis::WheelX));
|
||||
GetMTGS().RunOnGSThread([wheel_x = horizontal ? value : 0.0f, wheel_y = horizontal ? 0.0f : value]() {
|
||||
ImGui::GetIO().AddMouseWheelEvent(wheel_x, wheel_y);
|
||||
});
|
||||
|
||||
return s_imgui_wants_mouse.load(std::memory_order_acquire);
|
||||
}
|
||||
|
||||
bool ImGuiManager::ProcessHostKeyEvent(InputBindingKey key, float value)
|
||||
{
|
||||
decltype(s_imgui_key_map)::iterator iter;
|
||||
if (!ImGui::GetCurrentContext() || (iter = s_imgui_key_map.find(key.data)) == s_imgui_key_map.end())
|
||||
return false;
|
||||
|
||||
// still update state anyway
|
||||
GetMTGS().RunOnGSThread([imkey = iter->second, down = (value != 0.0f)]() { ImGui::GetIO().AddKeyEvent(imkey, down); });
|
||||
|
||||
return s_imgui_wants_keyboard.load(std::memory_order_acquire);
|
||||
}
|
||||
|
||||
bool ImGuiManager::ProcessGenericInputEvent(GenericInputBinding key, float value)
|
||||
{
|
||||
static constexpr ImGuiKey key_map[] = {
|
||||
ImGuiKey_None, // Unknown,
|
||||
ImGuiKey_GamepadDpadUp, // DPadUp
|
||||
ImGuiKey_GamepadDpadRight, // DPadRight
|
||||
ImGuiKey_GamepadDpadLeft, // DPadLeft
|
||||
ImGuiKey_GamepadDpadDown, // DPadDown
|
||||
ImGuiKey_None, // LeftStickUp
|
||||
ImGuiKey_None, // LeftStickRight
|
||||
ImGuiKey_None, // LeftStickDown
|
||||
ImGuiKey_None, // LeftStickLeft
|
||||
ImGuiKey_GamepadL3, // L3
|
||||
ImGuiKey_None, // RightStickUp
|
||||
ImGuiKey_None, // RightStickRight
|
||||
ImGuiKey_None, // RightStickDown
|
||||
ImGuiKey_None, // RightStickLeft
|
||||
ImGuiKey_GamepadR3, // R3
|
||||
ImGuiKey_GamepadFaceUp, // Triangle
|
||||
ImGuiKey_GamepadFaceRight, // Circle
|
||||
ImGuiKey_GamepadFaceDown, // Cross
|
||||
ImGuiKey_GamepadFaceLeft, // Square
|
||||
ImGuiKey_GamepadBack, // Select
|
||||
ImGuiKey_GamepadStart, // Start
|
||||
ImGuiKey_None, // System
|
||||
ImGuiKey_GamepadL1, // L1
|
||||
ImGuiKey_GamepadL2, // L2
|
||||
ImGuiKey_GamepadR1, // R1
|
||||
ImGuiKey_GamepadL2, // R2
|
||||
};
|
||||
|
||||
if (!ImGui::GetCurrentContext() || !s_imgui_wants_keyboard.load(std::memory_order_acquire))
|
||||
return false;
|
||||
|
||||
if (static_cast<u32>(key) >= std::size(key_map) || key_map[static_cast<u32>(key)] == ImGuiKey_None)
|
||||
return false;
|
||||
|
||||
GetMTGS().RunOnGSThread(
|
||||
[key = key_map[static_cast<u32>(key)], value]() { ImGui::GetIO().AddKeyAnalogEvent(key, (value > 0.0f), value); });
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // PCSX2_CORE
|
||||
@@ -17,6 +17,9 @@
|
||||
|
||||
struct ImFont;
|
||||
|
||||
union InputBindingKey;
|
||||
enum class GenericInputBinding : u8;
|
||||
|
||||
namespace ImGuiManager
|
||||
{
|
||||
/// Initializes ImGui, creates fonts, etc.
|
||||
@@ -45,5 +48,25 @@ namespace ImGuiManager
|
||||
|
||||
/// Returns the fixed-width font for external drawing.
|
||||
ImFont* GetFixedFont();
|
||||
|
||||
#ifdef PCSX2_CORE
|
||||
/// Called on the UI or CPU thread in response to mouse movement.
|
||||
void UpdateMousePosition(float x, float y);
|
||||
|
||||
/// Called on the CPU thread in response to a mouse button press.
|
||||
/// Returns true if ImGui intercepted the event, and regular handlers should not execute.
|
||||
bool ProcessPointerButtonEvent(InputBindingKey key, float value);
|
||||
|
||||
/// Called on the CPU thread in response to a mouse wheel movement.
|
||||
/// Returns true if ImGui intercepted the event, and regular handlers should not execute.
|
||||
bool ProcessPointerAxisEvent(InputBindingKey key, float value);
|
||||
|
||||
/// Called on the CPU thread in response to a key press.
|
||||
/// Returns true if ImGui intercepted the event, and regular handlers should not execute.
|
||||
bool ProcessHostKeyEvent(InputBindingKey key, float value);
|
||||
|
||||
/// Called on the CPU thread when any input event fires. Allows imgui to take over controller navigation.
|
||||
bool ProcessGenericInputEvent(GenericInputBinding key, float value);
|
||||
#endif
|
||||
} // namespace ImGuiManager
|
||||
|
||||
|
||||
+280
-114
@@ -16,10 +16,14 @@
|
||||
#include "PrecompiledHeader.h"
|
||||
#include "Frontend/InputManager.h"
|
||||
#include "Frontend/InputSource.h"
|
||||
#include "Frontend/ImGuiManager.h"
|
||||
#include "PAD/Host/PAD.h"
|
||||
#include "common/StringUtil.h"
|
||||
#include "common/Timer.h"
|
||||
#include "VMManager.h"
|
||||
|
||||
#include "fmt/core.h"
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
@@ -36,7 +40,7 @@ enum : u32
|
||||
{
|
||||
MAX_KEYS_PER_BINDING = 4,
|
||||
MAX_MOTORS_PER_PAD = 2,
|
||||
FIRST_EXTERNAL_INPUT_SOURCE = static_cast<u32>(InputSourceType::Mouse) + 1u,
|
||||
FIRST_EXTERNAL_INPUT_SOURCE = static_cast<u32>(InputSourceType::Pointer) + 1u,
|
||||
LAST_EXTERNAL_INPUT_SOURCE = static_cast<u32>(InputSourceType::Count),
|
||||
};
|
||||
|
||||
@@ -90,10 +94,8 @@ struct PadVibrationBinding
|
||||
// ------------------------------------------------------------------------
|
||||
namespace InputManager
|
||||
{
|
||||
static std::optional<InputBindingKey> ParseHostKeyboardKey(
|
||||
const std::string_view& source, const std::string_view& sub_binding);
|
||||
static std::optional<InputBindingKey> ParseHostMouseKey(
|
||||
const std::string_view& source, const std::string_view& sub_binding);
|
||||
static std::optional<InputBindingKey> ParseHostKeyboardKey(const std::string_view& source, const std::string_view& sub_binding);
|
||||
static std::optional<InputBindingKey> ParsePointerKey(const std::string_view& source, const std::string_view& sub_binding);
|
||||
|
||||
static std::vector<std::string_view> SplitChord(const std::string_view& binding);
|
||||
static bool SplitBinding(const std::string_view& binding, std::string_view* source, std::string_view* sub_binding);
|
||||
@@ -105,8 +107,10 @@ namespace InputManager
|
||||
static void AddHotkeyBindings(SettingsInterface& si);
|
||||
static void AddPadBindings(SettingsInterface& si, u32 pad, const char* default_type);
|
||||
static void UpdateContinuedVibration();
|
||||
static void GenerateRelativeMouseEvents();
|
||||
|
||||
static bool DoEventHook(InputBindingKey key, float value);
|
||||
static bool PreprocessEvent(InputBindingKey key, float value, GenericInputBinding generic_key);
|
||||
} // namespace InputManager
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
@@ -132,6 +136,24 @@ static std::array<std::unique_ptr<InputSource>, static_cast<u32>(InputSourceType
|
||||
// ------------------------------------------------------------------------
|
||||
static const HotkeyInfo* const s_hotkey_list[] = {g_vm_manager_hotkeys, g_gs_hotkeys, g_host_hotkeys};
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Tracking host mouse movement and turning into relative events
|
||||
// 4 axes: pointer left/right, wheel vertical/horizontal. Last/Next/Normalized.
|
||||
// ------------------------------------------------------------------------
|
||||
static constexpr const std::array<const char*, static_cast<u8>(InputPointerAxis::Count)> s_pointer_axis_names = {
|
||||
{"X", "Y", "WheelX", "WheelY"}};
|
||||
static constexpr const std::array<const char*, 3> s_pointer_button_names = {{"LeftButton", "RightButton", "MiddleButton"}};
|
||||
|
||||
struct PointerAxisState
|
||||
{
|
||||
std::atomic<s32> delta;
|
||||
float last_value;
|
||||
};
|
||||
static std::array<std::array<float, static_cast<u8>(InputPointerAxis::Count)>, InputManager::MAX_POINTER_DEVICES> s_host_pointer_positions;
|
||||
static std::array<std::array<PointerAxisState, static_cast<u8>(InputPointerAxis::Count)>, InputManager::MAX_POINTER_DEVICES>
|
||||
s_pointer_state;
|
||||
static std::array<float, static_cast<u8>(InputPointerAxis::Count)> s_pointer_axis_scale;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Binding Parsing
|
||||
// ------------------------------------------------------------------------
|
||||
@@ -166,8 +188,7 @@ std::vector<std::string_view> InputManager::SplitChord(const std::string_view& b
|
||||
return parts;
|
||||
}
|
||||
|
||||
bool InputManager::SplitBinding(
|
||||
const std::string_view& binding, std::string_view* source, std::string_view* sub_binding)
|
||||
bool InputManager::SplitBinding(const std::string_view& binding, std::string_view* source, std::string_view* sub_binding)
|
||||
{
|
||||
const std::string_view::size_type slash_pos = binding.find('/');
|
||||
if (slash_pos == std::string_view::npos)
|
||||
@@ -192,9 +213,9 @@ std::optional<InputBindingKey> InputManager::ParseInputBindingKey(const std::str
|
||||
{
|
||||
return ParseHostKeyboardKey(source, sub_binding);
|
||||
}
|
||||
else if (StringUtil::StartsWith(source, "Mouse"))
|
||||
else if (StringUtil::StartsWith(source, "Pointer"))
|
||||
{
|
||||
return ParseHostMouseKey(source, sub_binding);
|
||||
return ParsePointerKey(source, sub_binding);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -241,17 +262,21 @@ std::string InputManager::ConvertInputBindingKeyToString(InputBindingKey key)
|
||||
{
|
||||
const std::optional<std::string> str(ConvertHostKeyboardCodeToString(key.data));
|
||||
if (str.has_value() && !str->empty())
|
||||
return StringUtil::StdStringFromFormat("Keyboard/%s", str->c_str());
|
||||
return fmt::format("Keyboard/{}", str->c_str());
|
||||
}
|
||||
else if (key.source_type == InputSourceType::Mouse)
|
||||
else if (key.source_type == InputSourceType::Pointer)
|
||||
{
|
||||
if (key.source_subtype == InputSubclass::MouseButton)
|
||||
return StringUtil::StdStringFromFormat("Mouse%u/Button%u", key.source_index, key.data);
|
||||
else if (key.source_subtype == InputSubclass::MousePointer)
|
||||
return StringUtil::StdStringFromFormat("Mouse%u/Pointer%u", key.source_index, key.data);
|
||||
else if (key.source_subtype == InputSubclass::MouseWheel)
|
||||
return StringUtil::StdStringFromFormat(
|
||||
"Mouse%u/Wheel%u%c", key.source_index, key.data, key.negative ? '-' : '+');
|
||||
if (key.source_subtype == InputSubclass::PointerButton)
|
||||
{
|
||||
if (key.data < s_pointer_button_names.size())
|
||||
return fmt::format("Pointer-{}/{}", u32{key.source_index}, s_pointer_button_names[key.data]);
|
||||
else
|
||||
return fmt::format("Pointer-{}/Button{}", u32{key.source_index}, key.data);
|
||||
}
|
||||
else if (key.source_subtype == InputSubclass::PointerAxis)
|
||||
{
|
||||
return fmt::format("Pointer-{}/{}{:c}", u32{key.source_index}, s_pointer_axis_names[key.data], key.negative ? '-' : '+');
|
||||
}
|
||||
}
|
||||
else if (key.source_type < InputSourceType::Count && s_input_sources[static_cast<u32>(key.source_type)])
|
||||
{
|
||||
@@ -327,29 +352,31 @@ void InputManager::AddBindings(const std::vector<std::string>& bindings, const I
|
||||
// Key Decoders
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
InputBindingKey InputManager::MakeHostKeyboardKey(s32 key_code)
|
||||
InputBindingKey InputManager::MakeHostKeyboardKey(u32 key_code)
|
||||
{
|
||||
InputBindingKey key = {};
|
||||
key.source_type = InputSourceType::Keyboard;
|
||||
key.data = static_cast<u32>(key_code);
|
||||
key.data = key_code;
|
||||
return key;
|
||||
}
|
||||
|
||||
InputBindingKey InputManager::MakeHostMouseButtonKey(s32 button_index)
|
||||
InputBindingKey InputManager::MakePointerButtonKey(u32 index, u32 button_index)
|
||||
{
|
||||
InputBindingKey key = {};
|
||||
key.source_type = InputSourceType::Mouse;
|
||||
key.source_subtype = InputSubclass::MouseButton;
|
||||
key.data = static_cast<u32>(button_index);
|
||||
key.source_index = index;
|
||||
key.source_type = InputSourceType::Pointer;
|
||||
key.source_subtype = InputSubclass::PointerButton;
|
||||
key.data = button_index;
|
||||
return key;
|
||||
}
|
||||
|
||||
InputBindingKey InputManager::MakeHostMouseWheelKey(s32 axis_index)
|
||||
InputBindingKey InputManager::MakePointerAxisKey(u32 index, InputPointerAxis axis)
|
||||
{
|
||||
InputBindingKey key = {};
|
||||
key.source_type = InputSourceType::Mouse;
|
||||
key.source_subtype = InputSubclass::MouseWheel;
|
||||
key.data = static_cast<u32>(axis_index);
|
||||
key.data = static_cast<u32>(axis);
|
||||
key.source_index = index;
|
||||
key.source_type = InputSourceType::Pointer;
|
||||
key.source_subtype = InputSubclass::PointerAxis;
|
||||
return key;
|
||||
}
|
||||
|
||||
@@ -389,8 +416,7 @@ std::optional<InputSourceType> InputManager::ParseInputSourceString(const std::s
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<InputBindingKey> InputManager::ParseHostKeyboardKey(
|
||||
const std::string_view& source, const std::string_view& sub_binding)
|
||||
std::optional<InputBindingKey> InputManager::ParseHostKeyboardKey(const std::string_view& source, const std::string_view& sub_binding)
|
||||
{
|
||||
if (source != "Keyboard")
|
||||
return std::nullopt;
|
||||
@@ -405,14 +431,15 @@ std::optional<InputBindingKey> InputManager::ParseHostKeyboardKey(
|
||||
return key;
|
||||
}
|
||||
|
||||
std::optional<InputBindingKey> InputManager::ParseHostMouseKey(
|
||||
const std::string_view& source, const std::string_view& sub_binding)
|
||||
std::optional<InputBindingKey> InputManager::ParsePointerKey(const std::string_view& source, const std::string_view& sub_binding)
|
||||
{
|
||||
if (source != "Mouse")
|
||||
const std::optional<s32> pointer_index = StringUtil::FromChars<s32>(source.substr(8));
|
||||
if (!pointer_index.has_value() || pointer_index.value() < 0)
|
||||
return std::nullopt;
|
||||
|
||||
InputBindingKey key = {};
|
||||
key.source_type = InputSourceType::Mouse;
|
||||
key.source_type = InputSourceType::Pointer;
|
||||
key.source_index = static_cast<u32>(pointer_index.value());
|
||||
|
||||
if (StringUtil::StartsWith(sub_binding, "Button"))
|
||||
{
|
||||
@@ -420,15 +447,41 @@ std::optional<InputBindingKey> InputManager::ParseHostMouseKey(
|
||||
if (!button_number.has_value() || button_number.value() < 0)
|
||||
return std::nullopt;
|
||||
|
||||
key.source_subtype = InputSubclass::MouseButton;
|
||||
key.source_subtype = InputSubclass::PointerButton;
|
||||
key.data = static_cast<u32>(button_number.value());
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::nullopt;
|
||||
return key;
|
||||
}
|
||||
|
||||
return key;
|
||||
for (u32 i = 0; i < s_pointer_axis_names.size(); i++)
|
||||
{
|
||||
if (StringUtil::StartsWith(sub_binding, s_pointer_axis_names[i]))
|
||||
{
|
||||
key.source_subtype = InputSubclass::PointerAxis;
|
||||
key.data = i;
|
||||
|
||||
const std::string_view dir_part(sub_binding.substr(std::strlen(s_pointer_axis_names[i])));
|
||||
if (dir_part == "+")
|
||||
key.negative = false;
|
||||
else if (dir_part == "-")
|
||||
key.negative = true;
|
||||
else
|
||||
return std::nullopt;
|
||||
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < s_pointer_button_names.size(); i++)
|
||||
{
|
||||
if (sub_binding == s_pointer_button_names[i])
|
||||
{
|
||||
key.source_subtype = InputSubclass::PointerButton;
|
||||
key.data = i;
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
@@ -484,17 +537,16 @@ void InputManager::AddPadBindings(SettingsInterface& si, u32 pad_index, const ch
|
||||
if (!bindings.empty())
|
||||
{
|
||||
// we use axes for all pad bindings to simplify things, and because they are pressure sensitive
|
||||
AddBindings(bindings, InputAxisEventHandler{[pad_index, bind_index, bind_names](float value) {
|
||||
PAD::SetControllerState(pad_index, bind_index, value);
|
||||
}});
|
||||
AddBindings(bindings, InputAxisEventHandler{[pad_index, bind_index, bind_names](
|
||||
float value) { PAD::SetControllerState(pad_index, bind_index, value); }});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (u32 macro_button_index = 0; macro_button_index < PAD::NUM_MACRO_BUTTONS_PER_CONTROLLER; macro_button_index++)
|
||||
{
|
||||
const std::vector<std::string> bindings(si.GetStringList(section.c_str(),
|
||||
StringUtil::StdStringFromFormat("Macro%u", macro_button_index + 1).c_str()));
|
||||
const std::vector<std::string> bindings(
|
||||
si.GetStringList(section.c_str(), StringUtil::StdStringFromFormat("Macro%u", macro_button_index + 1).c_str()));
|
||||
if (!bindings.empty())
|
||||
{
|
||||
AddBindings(bindings, InputButtonEventHandler{[pad_index, macro_button_index](bool state) {
|
||||
@@ -547,58 +599,43 @@ bool InputManager::HasAnyBindingsForKey(InputBindingKey key)
|
||||
return (s_binding_map.find(key.MaskDirection()) != s_binding_map.end());
|
||||
}
|
||||
|
||||
bool InputManager::HasAnyBindingsForSource(InputBindingKey key)
|
||||
{
|
||||
std::unique_lock lock(s_binding_map_write_lock);
|
||||
for (const auto& it : s_binding_map)
|
||||
{
|
||||
const InputBindingKey& okey = it.first;
|
||||
if (okey.source_type == key.source_type && okey.source_index == key.source_index &&
|
||||
okey.source_subtype == key.source_subtype)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool InputManager::IsAxisHandler(const InputEventHandler& handler)
|
||||
{
|
||||
return std::holds_alternative<InputAxisEventHandler>(handler);
|
||||
}
|
||||
|
||||
bool InputManager::InvokeEvents(InputBindingKey key, float value)
|
||||
bool InputManager::InvokeEvents(InputBindingKey key, float value, GenericInputBinding generic_key)
|
||||
{
|
||||
if (DoEventHook(key, value))
|
||||
return true;
|
||||
|
||||
// If imgui ate the event, don't fire our handlers.
|
||||
const bool skip_button_handlers = PreprocessEvent(key, value, generic_key);
|
||||
|
||||
// find all the bindings associated with this key
|
||||
const InputBindingKey masked_key = key.MaskDirection();
|
||||
const auto range = s_binding_map.equal_range(masked_key);
|
||||
if (range.first == s_binding_map.end())
|
||||
return false;
|
||||
|
||||
// Workaround for modifier keys. Basically, if we bind say, F1 and Shift+F1, and press shift
|
||||
// and then F1, we'll fire bindings for both F1 and Shift+F1, when we really only want to fire
|
||||
// the binding for Shift+F1. So, let's search through the binding list, and see if there's a
|
||||
// "longer" binding (more keys), and if so, only activate that and not the shorter binding(s).
|
||||
const InputBinding* longest_hotkey_binding = nullptr;
|
||||
for (auto it = range.first; it != range.second; ++it)
|
||||
{
|
||||
InputBinding* binding = it->second.get();
|
||||
if (IsAxisHandler(binding->handler))
|
||||
continue;
|
||||
|
||||
// find the key which matches us
|
||||
for (u32 i = 0; i < binding->num_keys; i++)
|
||||
{
|
||||
if (binding->keys[i].MaskDirection() != masked_key)
|
||||
continue;
|
||||
|
||||
const u8 bit = static_cast<u8>(1) << i;
|
||||
const bool negative = binding->keys[i].negative;
|
||||
const bool new_state = (negative ? (value < 0.0f) : (value > 0.0f));
|
||||
const u8 new_mask = (new_state ? (binding->current_mask | bit) : (binding->current_mask & ~bit));
|
||||
const bool prev_full_state = (binding->current_mask == binding->full_mask);
|
||||
const bool new_full_state = (new_mask == binding->full_mask);
|
||||
|
||||
// If we're activating this chord, block activation of other bindings with fewer keys.
|
||||
if (prev_full_state || new_full_state)
|
||||
{
|
||||
if (!longest_hotkey_binding || longest_hotkey_binding->num_keys < binding->num_keys)
|
||||
longest_hotkey_binding = binding;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Now we can actually fire/activate bindings.
|
||||
u32 min_num_keys = 0;
|
||||
for (auto it = range.first; it != range.second; ++it)
|
||||
{
|
||||
InputBinding* binding = it->second.get();
|
||||
@@ -613,23 +650,8 @@ bool InputManager::InvokeEvents(InputBindingKey key, float value)
|
||||
const bool negative = binding->keys[i].negative;
|
||||
const bool new_state = (negative ? (value < 0.0f) : (value > 0.0f));
|
||||
|
||||
// Don't register the key press when we're part of a longer chord. That way,
|
||||
// the state won't change, and it won't get the released event either.
|
||||
if (longest_hotkey_binding && new_state && !IsAxisHandler(binding->handler) &&
|
||||
binding->num_keys != longest_hotkey_binding->num_keys)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// update state based on whether the whole chord was activated
|
||||
const u8 new_mask = (new_state ? (binding->current_mask | bit) : (binding->current_mask & ~bit));
|
||||
const bool prev_full_state = (binding->current_mask == binding->full_mask);
|
||||
const bool new_full_state = (new_mask == binding->full_mask);
|
||||
binding->current_mask = new_mask;
|
||||
|
||||
// invert if we're negative, since the handler expects 0..1
|
||||
const float value_to_pass = (negative ? ((value < 0.0f) ? -value : 0.0f) : (value > 0.0f) ? value :
|
||||
0.0f);
|
||||
const float value_to_pass = (negative ? ((value < 0.0f) ? -value : 0.0f) : (value > 0.0f) ? value : 0.0f);
|
||||
|
||||
// axes are fired regardless of a state change, unless they're zero
|
||||
// (but going from not-zero to zero will still fire, because of the full state)
|
||||
@@ -637,13 +659,60 @@ bool InputManager::InvokeEvents(InputBindingKey key, float value)
|
||||
// and 0 on release (when the full state changes).
|
||||
if (IsAxisHandler(binding->handler))
|
||||
{
|
||||
if (prev_full_state != new_full_state || value_to_pass >= 0.0f)
|
||||
if (value_to_pass >= 0.0f)
|
||||
std::get<InputAxisEventHandler>(binding->handler)(value_to_pass);
|
||||
}
|
||||
else
|
||||
else if (binding->num_keys >= min_num_keys)
|
||||
{
|
||||
if (prev_full_state != new_full_state)
|
||||
std::get<InputButtonEventHandler>(binding->handler)(value_to_pass > 0.0f);
|
||||
// update state based on whether the whole chord was activated
|
||||
const u8 new_mask = (new_state ? (binding->current_mask | bit) : (binding->current_mask & ~bit));
|
||||
const bool prev_full_state = (binding->current_mask == binding->full_mask);
|
||||
const bool new_full_state = (new_mask == binding->full_mask);
|
||||
binding->current_mask = new_mask;
|
||||
|
||||
// Workaround for multi-key bindings that share the same keys.
|
||||
if (binding->num_keys > 1 && new_full_state && prev_full_state != new_full_state &&
|
||||
range.first != range.second)
|
||||
{
|
||||
// Because the binding map isn't ordered, we could iterate in the order of Shift+F1 and then
|
||||
// F1, which would mean that F1 wouldn't get cancelled and still activate. So, to handle this
|
||||
// case, we skip activating any future bindings with a fewer number of keys.
|
||||
min_num_keys = std::max<u32>(min_num_keys, binding->num_keys);
|
||||
|
||||
// Basically, if we bind say, F1 and Shift+F1, and press shift and then F1, we'll fire bindings
|
||||
// for both F1 and Shift+F1, when we really only want to fire the binding for Shift+F1. So,
|
||||
// when we activate a multi-key chord (key press), we go through the binding map for all the
|
||||
// other keys in the chord, and cancel them if they have a shorter chord. If they're longer,
|
||||
// they could still activate and take precedence over us, so we leave them alone.
|
||||
for (u32 i = 0; i < binding->num_keys; i++)
|
||||
{
|
||||
const auto range = s_binding_map.equal_range(binding->keys[i].MaskDirection());
|
||||
for (auto it = range.first; it != range.second; ++it)
|
||||
{
|
||||
InputBinding* other_binding = it->second.get();
|
||||
if (other_binding == binding || IsAxisHandler(other_binding->handler) ||
|
||||
other_binding->num_keys >= binding->num_keys)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// We only need to cancel the binding if it was fully active before. Which in the above
|
||||
// case of Shift+F1 / F1, it will be.
|
||||
if (other_binding->current_mask == other_binding->full_mask)
|
||||
std::get<InputButtonEventHandler>(other_binding->handler)(-1);
|
||||
|
||||
// Zero out the current bits so that we don't release this binding, if the other part
|
||||
// of the chord releases first.
|
||||
other_binding->current_mask = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (prev_full_state != new_full_state && binding->num_keys >= min_num_keys)
|
||||
{
|
||||
const s32 pressed = skip_button_handlers ? -1 : static_cast<s32>(value_to_pass > 0.0f);
|
||||
std::get<InputButtonEventHandler>(binding->handler)(pressed);
|
||||
}
|
||||
}
|
||||
|
||||
// bail out, since we shouldn't have the same key twice in the chord
|
||||
@@ -654,6 +723,86 @@ bool InputManager::InvokeEvents(InputBindingKey key, float value)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InputManager::PreprocessEvent(InputBindingKey key, float value, GenericInputBinding generic_key)
|
||||
{
|
||||
// does imgui want the event?
|
||||
if (key.source_type == InputSourceType::Keyboard)
|
||||
{
|
||||
if (ImGuiManager::ProcessHostKeyEvent(key, value))
|
||||
return true;
|
||||
}
|
||||
else if (key.source_type == InputSourceType::Pointer && key.source_subtype == InputSubclass::PointerButton)
|
||||
{
|
||||
if (ImGuiManager::ProcessPointerButtonEvent(key, value))
|
||||
return true;
|
||||
}
|
||||
else if (generic_key != GenericInputBinding::Unknown)
|
||||
{
|
||||
if (ImGuiManager::ProcessGenericInputEvent(generic_key, value) && value != 0.0f)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void InputManager::GenerateRelativeMouseEvents()
|
||||
{
|
||||
for (u32 device = 0; device < MAX_POINTER_DEVICES; device++)
|
||||
{
|
||||
for (u32 axis = 0; axis < static_cast<u32>(static_cast<u8>(InputPointerAxis::Count)); axis++)
|
||||
{
|
||||
PointerAxisState& state = s_pointer_state[device][axis];
|
||||
const float delta = static_cast<float>(state.delta.exchange(0, std::memory_order_acquire)) / 65536.0f;
|
||||
const float unclamped_value = delta * s_pointer_axis_scale[axis];
|
||||
|
||||
const InputBindingKey key(MakePointerAxisKey(device, static_cast<InputPointerAxis>(axis)));
|
||||
if (axis >= static_cast<u32>(InputPointerAxis::WheelX) && ImGuiManager::ProcessPointerAxisEvent(key, unclamped_value))
|
||||
continue;
|
||||
|
||||
const float value = std::clamp(unclamped_value, -1.0f, 1.0f);
|
||||
if (value != state.last_value)
|
||||
{
|
||||
state.last_value = value;
|
||||
InvokeEvents(key, value, GenericInputBinding::Unknown);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InputManager::UpdatePointerAbsolutePosition(u32 index, float x, float y)
|
||||
{
|
||||
const float dx = x - std::exchange(s_host_pointer_positions[index][static_cast<u8>(InputPointerAxis::X)], x);
|
||||
const float dy = y - std::exchange(s_host_pointer_positions[index][static_cast<u8>(InputPointerAxis::Y)], y);
|
||||
|
||||
if (dx != 0.0f)
|
||||
UpdatePointerRelativeDelta(index, InputPointerAxis::X, dx);
|
||||
if (dy != 0.0f)
|
||||
UpdatePointerRelativeDelta(index, InputPointerAxis::Y, dy);
|
||||
|
||||
ImGuiManager::UpdateMousePosition(x, y);
|
||||
}
|
||||
|
||||
void InputManager::UpdatePointerRelativeDelta(u32 index, InputPointerAxis axis, float d, bool raw_input)
|
||||
{
|
||||
s_pointer_state[index][static_cast<u8>(axis)].delta.fetch_add(static_cast<s32>(d * 65536.0f), std::memory_order_release);
|
||||
}
|
||||
|
||||
bool InputManager::HasPointerAxisBinds()
|
||||
{
|
||||
std::unique_lock lock(s_binding_map_write_lock);
|
||||
for (const auto& it : s_binding_map)
|
||||
{
|
||||
const InputBindingKey& key = it.first;
|
||||
if (key.source_type == InputSourceType::Pointer && key.source_subtype == InputSubclass::PointerAxis &&
|
||||
key.data >= static_cast<u32>(InputPointerAxis::X) && key.data <= static_cast<u32>(InputPointerAxis::Y))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Vibration
|
||||
// ------------------------------------------------------------------------
|
||||
@@ -684,7 +833,8 @@ void InputManager::SetPadVibrationIntensity(u32 pad_index, float large_or_single
|
||||
{
|
||||
// both motors are bound to the same source, do an optimal update
|
||||
large_motor.last_update_time = Common::Timer::GetCurrentValue();
|
||||
large_motor.source->UpdateMotorState(large_motor.binding, small_motor.binding, large_or_single_motor_intensity, small_motor_intensity);
|
||||
large_motor.source->UpdateMotorState(
|
||||
large_motor.binding, small_motor.binding, large_or_single_motor_intensity, small_motor_intensity);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -801,20 +951,18 @@ bool InputManager::DoEventHook(InputBindingKey key, float value)
|
||||
return false;
|
||||
|
||||
const InputInterceptHook::CallbackResult action = m_event_intercept_callback(key, value);
|
||||
return (action == InputInterceptHook::CallbackResult::StopProcessingEvent);
|
||||
if (action >= InputInterceptHook::CallbackResult::RemoveHookAndStopProcessingEvent)
|
||||
m_event_intercept_callback = {};
|
||||
|
||||
return (action == InputInterceptHook::CallbackResult::RemoveHookAndStopProcessingEvent ||
|
||||
action == InputInterceptHook::CallbackResult::StopProcessingEvent);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Binding Updater
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
// TODO(Stenzek): Find a better place for this. Maybe in PAD?
|
||||
static constexpr std::array<const char*, InputManager::MAX_PAD_NUMBER> s_default_pad_types = {{
|
||||
"DualShock2", // Pad 1
|
||||
"None" // Pad 2
|
||||
}};
|
||||
|
||||
void InputManager::ReloadBindings(SettingsInterface& si)
|
||||
void InputManager::ReloadBindings(SettingsInterface& si, SettingsInterface& binding_si)
|
||||
{
|
||||
PauseVibration();
|
||||
|
||||
@@ -823,10 +971,25 @@ void InputManager::ReloadBindings(SettingsInterface& si)
|
||||
s_binding_map.clear();
|
||||
s_pad_vibration_array.clear();
|
||||
|
||||
AddHotkeyBindings(si);
|
||||
// Hotkeys use the base configuration, except if the custom hotkeys option is enabled.
|
||||
const bool use_profile_hotkeys = si.GetBoolValue("Pad", "UseProfileHotkeyBindings", false);
|
||||
AddHotkeyBindings(use_profile_hotkeys ? binding_si : si);
|
||||
|
||||
for (u32 pad = 0; pad < MAX_PAD_NUMBER; pad++)
|
||||
AddPadBindings(si, pad, s_default_pad_types[pad]);
|
||||
// If there's an input profile, we load pad bindings from it alone, rather than
|
||||
// falling back to the base configuration.
|
||||
for (u32 pad = 0; pad < PAD::NUM_CONTROLLER_PORTS; pad++)
|
||||
AddPadBindings(binding_si, pad, PAD::GetDefaultPadType(pad));
|
||||
|
||||
for (u32 axis = 0; axis < static_cast<u32>(InputPointerAxis::Count); axis++)
|
||||
{
|
||||
// From lilypad: 1 mouse pixel = 1/8th way down.
|
||||
const float default_scale = (axis <= static_cast<u32>(InputPointerAxis::Y)) ? 8.0f : 1.0f;
|
||||
const float invert =
|
||||
si.GetBoolValue("Pad", fmt::format("Pointer{}Invert", s_pointer_axis_names[axis]).c_str(), false) ? -1.0f : 1.0f;
|
||||
s_pointer_axis_scale[axis] =
|
||||
invert /
|
||||
std::max(si.GetFloatValue("Pad", fmt::format("Pointer{}Scale", s_pointer_axis_names[axis]).c_str(), default_scale), 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
@@ -853,6 +1016,8 @@ void InputManager::PollSources()
|
||||
s_input_sources[i]->PollEvents();
|
||||
}
|
||||
|
||||
GenerateRelativeMouseEvents();
|
||||
|
||||
if (VMManager::GetState() == VMState::Running && !s_pad_vibration_array.empty())
|
||||
UpdateContinuedVibration();
|
||||
}
|
||||
@@ -955,7 +1120,8 @@ GenericInputBindingMapping InputManager::GetGenericBindingMapping(const std::str
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void UpdateInputSourceState(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock, InputSourceType type, bool default_state)
|
||||
static void UpdateInputSourceState(
|
||||
SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock, InputSourceType type, bool default_state)
|
||||
{
|
||||
const bool enabled = si.GetBoolValue("InputSources", InputManager::InputSourceToString(type), default_state);
|
||||
if (enabled)
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
enum class InputSourceType : u32
|
||||
{
|
||||
Keyboard,
|
||||
Mouse,
|
||||
Pointer,
|
||||
#ifdef _WIN32
|
||||
//DInput,
|
||||
XInput,
|
||||
@@ -44,9 +44,8 @@ enum class InputSubclass : u32
|
||||
{
|
||||
None = 0,
|
||||
|
||||
MouseButton = 0,
|
||||
MousePointer = 1,
|
||||
MouseWheel = 2,
|
||||
PointerButton = 0,
|
||||
PointerAxis = 1,
|
||||
|
||||
ControllerButton = 0,
|
||||
ControllerAxis = 1,
|
||||
@@ -91,7 +90,7 @@ struct InputBindingKeyHash
|
||||
};
|
||||
|
||||
/// Callback type for a binary event. Usually used for hotkeys.
|
||||
using InputButtonEventHandler = std::function<void(bool value)>;
|
||||
using InputButtonEventHandler = std::function<void(s32 value)>;
|
||||
|
||||
/// Callback types for a normalized event. Usually used for pads.
|
||||
using InputAxisEventHandler = std::function<void(float value)>;
|
||||
@@ -102,31 +101,41 @@ struct InputInterceptHook
|
||||
enum class CallbackResult
|
||||
{
|
||||
StopProcessingEvent,
|
||||
ContinueProcessingEvent
|
||||
ContinueProcessingEvent,
|
||||
RemoveHookAndStopProcessingEvent,
|
||||
RemoveHookAndContinueProcessingEvent,
|
||||
};
|
||||
|
||||
using Callback = std::function<CallbackResult(InputBindingKey key, float value)>;
|
||||
};
|
||||
|
||||
/// Hotkeys are actions (e.g. toggle frame limit) which can be bound to keys or chords.
|
||||
/// The handler is called with an integer representing the key state, where 0 means that
|
||||
/// one or more keys were released, 1 means all the keys were pressed, and -1 means that
|
||||
/// the hotkey was cancelled due to a chord with more keys being activated.
|
||||
struct HotkeyInfo
|
||||
{
|
||||
const char* name;
|
||||
const char* category;
|
||||
const char* display_name;
|
||||
void(*handler)(bool pressed);
|
||||
void (*handler)(s32 pressed);
|
||||
};
|
||||
#define DECLARE_HOTKEY_LIST(name) extern const HotkeyInfo name[]
|
||||
#define BEGIN_HOTKEY_LIST(name) const HotkeyInfo name[] = {
|
||||
#define DEFINE_HOTKEY(name, category, display_name, handler) {(name), (category), (display_name), (handler)},
|
||||
#define END_HOTKEY_LIST() {nullptr, nullptr, nullptr, nullptr} };
|
||||
#define END_HOTKEY_LIST() \
|
||||
{ \
|
||||
nullptr, nullptr, nullptr, nullptr \
|
||||
} \
|
||||
} \
|
||||
;
|
||||
|
||||
DECLARE_HOTKEY_LIST(g_vm_manager_hotkeys);
|
||||
DECLARE_HOTKEY_LIST(g_gs_hotkeys);
|
||||
DECLARE_HOTKEY_LIST(g_host_hotkeys);
|
||||
|
||||
/// Generic input bindings. These roughly match a DualShock 4 or XBox One controller.
|
||||
/// They are used for automatic binding to PS2 controller types.
|
||||
/// They are used for automatic binding to PS2 controller types, and for big picture mode navigation.
|
||||
enum class GenericInputBinding : u8
|
||||
{
|
||||
Unknown,
|
||||
@@ -169,16 +178,26 @@ enum class GenericInputBinding : u8
|
||||
};
|
||||
using GenericInputBindingMapping = std::vector<std::pair<GenericInputBinding, std::string>>;
|
||||
|
||||
/// Host mouse relative axes are X, Y, wheel horizontal, wheel vertical.
|
||||
enum class InputPointerAxis : u8
|
||||
{
|
||||
X,
|
||||
Y,
|
||||
WheelX,
|
||||
WheelY,
|
||||
Count
|
||||
};
|
||||
|
||||
/// External input source class.
|
||||
class InputSource;
|
||||
|
||||
namespace InputManager
|
||||
{
|
||||
/// Number of emulated pads. TODO: Multitap support.
|
||||
static constexpr u32 MAX_PAD_NUMBER = 2;
|
||||
|
||||
/// Minimum interval between vibration updates when the effect is continuous.
|
||||
static constexpr double VIBRATION_UPDATE_INTERVAL_SECONDS = 0.5; // 500ms
|
||||
static constexpr double VIBRATION_UPDATE_INTERVAL_SECONDS = 0.5; // 500ms
|
||||
|
||||
/// Maximum number of host mouse devices.
|
||||
static constexpr u32 MAX_POINTER_DEVICES = 1;
|
||||
|
||||
/// Returns a pointer to the external input source class, if present.
|
||||
InputSource* GetInputSourceInterface(InputSourceType type);
|
||||
@@ -196,13 +215,14 @@ namespace InputManager
|
||||
std::optional<std::string> ConvertHostKeyboardCodeToString(u32 code);
|
||||
|
||||
/// Creates a key for a host-specific key code.
|
||||
InputBindingKey MakeHostKeyboardKey(s32 key_code);
|
||||
InputBindingKey MakeHostKeyboardKey(u32 key_code);
|
||||
|
||||
/// Creates a key for a host-specific button.
|
||||
InputBindingKey MakeHostMouseButtonKey(s32 button_index);
|
||||
InputBindingKey MakePointerButtonKey(u32 index, u32 button_index);
|
||||
|
||||
/// Creates a key for a host-specific mouse wheel axis (0 = vertical, 1 = horizontal).
|
||||
InputBindingKey MakeHostMouseWheelKey(s32 axis_index);
|
||||
/// Creates a key for a host-specific mouse relative event
|
||||
/// (axis 0 = horizontal, 1 = vertical, 2 = wheel horizontal, 3 = wheel vertical).
|
||||
InputBindingKey MakePointerAxisKey(u32 index, InputPointerAxis axis);
|
||||
|
||||
/// Parses an input binding key string.
|
||||
std::optional<InputBindingKey> ParseInputBindingKey(const std::string_view& binding);
|
||||
@@ -226,7 +246,7 @@ namespace InputManager
|
||||
GenericInputBindingMapping GetGenericBindingMapping(const std::string_view& device);
|
||||
|
||||
/// Re-parses the config and registers all hotkey and pad bindings.
|
||||
void ReloadBindings(SettingsInterface& si);
|
||||
void ReloadBindings(SettingsInterface& si, SettingsInterface& binding_si);
|
||||
|
||||
/// Re-parses the sources part of the config and initializes any backends.
|
||||
void ReloadSources(SettingsInterface& si, std::unique_lock<std::mutex>& settings_lock);
|
||||
@@ -238,12 +258,16 @@ namespace InputManager
|
||||
void PollSources();
|
||||
|
||||
/// Returns true if any bindings exist for the specified key.
|
||||
/// This is the only function which can be safely called on another thread.
|
||||
/// Can be safely called on another thread.
|
||||
bool HasAnyBindingsForKey(InputBindingKey key);
|
||||
|
||||
/// Returns true if any bindings exist for the specified source + index.
|
||||
/// Can be safely called on another thread.
|
||||
bool HasAnyBindingsForSource(InputBindingKey key);
|
||||
|
||||
/// Updates internal state for any binds for this key, and fires callbacks as needed.
|
||||
/// Returns true if anything was bound to this key, otherwise false.
|
||||
bool InvokeEvents(InputBindingKey key, float value);
|
||||
bool InvokeEvents(InputBindingKey key, float value, GenericInputBinding generic_key = GenericInputBinding::Unknown);
|
||||
|
||||
/// Sets a hook which can be used to intercept events before they're processed by the normal bindings.
|
||||
/// This is typically used when binding new controls to detect what gets pressed.
|
||||
@@ -262,6 +286,15 @@ namespace InputManager
|
||||
/// Zeros all vibration intensities. Call when pausing.
|
||||
/// The pad vibration state will internally remain, so that when emulation is unpaused, the effect resumes.
|
||||
void PauseVibration();
|
||||
|
||||
/// Updates absolute pointer position. Can call from UI thread, use when the host only reports absolute coordinates.
|
||||
void UpdatePointerAbsolutePosition(u32 index, float x, float y);
|
||||
|
||||
/// Updates relative pointer position. Can call from the UI thread, use when host supports relative coordinate reporting.
|
||||
void UpdatePointerRelativeDelta(u32 index, InputPointerAxis axis, float d, bool raw_input = false);
|
||||
|
||||
/// Returns true if any bindings are present which require relative mouse movement.
|
||||
bool HasPointerAxisBinds();
|
||||
} // namespace InputManager
|
||||
|
||||
namespace Host
|
||||
@@ -271,4 +304,4 @@ namespace Host
|
||||
|
||||
/// Called when an input device is disconnected.
|
||||
void OnInputDeviceDisconnected(const std::string_view& identifier);
|
||||
}
|
||||
} // namespace Host
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user