Compare commits
1275 Commits
CI-238dda1
...
master
Author | SHA1 | Date |
---|---|---|
![]() |
ec9934af2d | |
![]() |
ce15f50848 | |
![]() |
b1df891433 | |
![]() |
5355e08b30 | |
![]() |
7762e883a8 | |
![]() |
cada16125d | |
![]() |
eecc1ac1f1 | |
![]() |
2d6696451b | |
![]() |
dd36dd598c | |
![]() |
87634a2e27 | |
![]() |
6f32d89545 | |
![]() |
ec0c288bc4 | |
![]() |
8bfbcb56fd | |
![]() |
8965d2443b | |
![]() |
b33ed95c5b | |
![]() |
8ee17b512c | |
![]() |
50334cbc31 | |
![]() |
41454b8c26 | |
![]() |
204dcf8801 | |
![]() |
77c63ceec3 | |
![]() |
2cfaba893e | |
![]() |
17b0cb81d4 | |
![]() |
daa6a816ff | |
![]() |
6caf3ea679 | |
![]() |
9a58823b70 | |
![]() |
3edd8d168b | |
![]() |
f894d31332 | |
![]() |
9241bec768 | |
![]() |
c50a0c5c7d | |
![]() |
87bab04932 | |
![]() |
ad6769bbf3 | |
![]() |
0e63131fc3 | |
![]() |
889040c56a | |
![]() |
86542c9f2e | |
![]() |
c9edbd1003 | |
![]() |
ebb122f2a0 | |
![]() |
c158a472ff | |
![]() |
6961d1c7a1 | |
![]() |
2f7cfe7e95 | |
![]() |
46d0173673 | |
![]() |
c7b028b3e7 | |
![]() |
3d12edc77d | |
![]() |
08ab4b9164 | |
![]() |
4fca5c7007 | |
![]() |
e26f20108a | |
![]() |
8475124e5b | |
![]() |
9b2ae106e5 | |
![]() |
b3bfeca3a8 | |
![]() |
b77a13b708 | |
![]() |
1b5e111ae3 | |
![]() |
1504a75a46 | |
![]() |
87496ab873 | |
![]() |
5b37a7ec21 | |
![]() |
639f42c318 | |
![]() |
8d92992a6b | |
![]() |
7323eed73e | |
![]() |
b47c1f195c | |
![]() |
7c73bfc525 | |
![]() |
1b4a3bb54f | |
![]() |
750d202fa8 | |
![]() |
e7bca5e1bf | |
![]() |
937ab9e1c2 | |
![]() |
8006f55cf3 | |
![]() |
1828ddfd6f | |
![]() |
bc42cfaa6b | |
![]() |
b1235b7733 | |
![]() |
1615ecc976 | |
![]() |
0007d20b03 | |
![]() |
bfb10092c0 | |
![]() |
f5b4878245 | |
![]() |
4174fbc23f | |
![]() |
0560ed6955 | |
![]() |
875015164c | |
![]() |
aedb5ba87b | |
![]() |
e5dcdebe7f | |
![]() |
ad0b8340da | |
![]() |
7298b6c4dc | |
![]() |
b20db36e15 | |
![]() |
a03d50df56 | |
![]() |
0e25897f77 | |
![]() |
c6049b768c | |
![]() |
399baccadb | |
![]() |
3edc388abf | |
![]() |
796e8d2beb | |
![]() |
282c5f5622 | |
![]() |
8e5b27d054 | |
![]() |
b64a3b6faa | |
![]() |
d64e172c9f | |
![]() |
d6b96b8ea1 | |
![]() |
131b330a85 | |
![]() |
bf6193202a | |
![]() |
06c28a847e | |
![]() |
8cc9c73f58 | |
![]() |
2452965580 | |
![]() |
eddc14e151 | |
![]() |
31ff15ba1d | |
![]() |
4d9151ca26 | |
![]() |
1f1d1ac631 | |
![]() |
e5043dbc05 | |
![]() |
a2fb41856d | |
![]() |
b09d3ca69a | |
![]() |
684d3338f2 | |
![]() |
ae140bb6bf | |
![]() |
a5b8f15a14 | |
![]() |
2c8a764fc7 | |
![]() |
605271245c | |
![]() |
93e36f7be3 | |
![]() |
a7bc6a307d | |
![]() |
7ad047bcea | |
![]() |
0f21e25d7d | |
![]() |
79884bdf3d | |
![]() |
260e2fb7c8 | |
![]() |
4d221c3c81 | |
![]() |
712d3bee2f | |
![]() |
3cd551d827 | |
![]() |
397f33143d | |
![]() |
c7e75d7c5c | |
![]() |
4808be65c4 | |
![]() |
def10ff466 | |
![]() |
e1ea10c4cb | |
![]() |
67f21d5c30 | |
![]() |
971318a89a | |
![]() |
b62d39da7d | |
![]() |
6c530fbf86 | |
![]() |
a8f6d0496e | |
![]() |
6389cb6524 | |
![]() |
ef3439e46f | |
![]() |
ed8a6124e4 | |
![]() |
b1bd9dd5d0 | |
![]() |
062752e1a7 | |
![]() |
99ab34ac82 | |
![]() |
8e0df988a8 | |
![]() |
58041c95b4 | |
![]() |
827a3212f8 | |
![]() |
d0890d588d | |
![]() |
9e9d3f390f | |
![]() |
4821a72b6f | |
![]() |
bf1483ae56 | |
![]() |
b2f05b8b0b | |
![]() |
111728f170 | |
![]() |
ce05ea1397 | |
![]() |
f4488c0270 | |
![]() |
65a5ad6591 | |
![]() |
0b695637ce | |
![]() |
fe9a706a8e | |
![]() |
8ac5d14cd2 | |
![]() |
628323218a | |
![]() |
f7c09ddc4f | |
![]() |
09e744ecc4 | |
![]() |
a37124e2dc | |
![]() |
5f58ae918c | |
![]() |
f17b7f7fa6 | |
![]() |
4dccf6d5b9 | |
![]() |
6bbe6cefe8 | |
![]() |
547c3ae663 | |
![]() |
c594e34ac5 | |
![]() |
caae99952c | |
![]() |
aeeb67dc6a | |
![]() |
4204640052 | |
![]() |
3c78dd29a7 | |
![]() |
42ff76ce0f | |
![]() |
bf931d2d81 | |
![]() |
a2a4fb35a4 | |
![]() |
f570c05e95 | |
![]() |
0b76da7c00 | |
![]() |
9ee5b45b88 | |
![]() |
ee7be21bbb | |
![]() |
8fcc2f5e0c | |
![]() |
56610cd899 | |
![]() |
9fab1d5bed | |
![]() |
0043e45531 | |
![]() |
bc9cbec518 | |
![]() |
4edd3feb3e | |
![]() |
0717c0166b | |
![]() |
16ffe3a80f | |
![]() |
5f3cfdeb77 | |
![]() |
a650fd2078 | |
![]() |
cfa7be71cf | |
![]() |
4076a5b758 | |
![]() |
6e3635d90a | |
![]() |
ce55fe8627 | |
![]() |
b2f63918de | |
![]() |
f6274cc59f | |
![]() |
8546d7c10d | |
![]() |
4c5995af0c | |
![]() |
c981ff23b1 | |
![]() |
186b5fa8ee | |
![]() |
ce4f4a07f0 | |
![]() |
4d110bad6e | |
![]() |
6f79b035bd | |
![]() |
7bc95d7a67 | |
![]() |
5a454aad5c | |
![]() |
6cbb385b89 | |
![]() |
31a47cde37 | |
![]() |
aba8fc8341 | |
![]() |
46b1f24153 | |
![]() |
b43f6bbcdf | |
![]() |
33aad02f93 | |
![]() |
1710f01c35 | |
![]() |
f8e4f59eae | |
![]() |
4b5edbdc94 | |
![]() |
3bf2effa4d | |
![]() |
6ab30793ed | |
![]() |
3d244b78b3 | |
![]() |
2512840968 | |
![]() |
ecef7aec39 | |
![]() |
95b789eb27 | |
![]() |
5e928e508a | |
![]() |
39ced81d58 | |
![]() |
b7006e2b01 | |
![]() |
fa85d3dad4 | |
![]() |
05a7acf13e | |
![]() |
8b35389c71 | |
![]() |
e8f943ebbc | |
![]() |
87042c6bcc | |
![]() |
88a37ac496 | |
![]() |
2168b033c6 | |
![]() |
a1cffc79f8 | |
![]() |
1077115038 | |
![]() |
774ef7c9e3 | |
![]() |
9973ec7b6f | |
![]() |
5e42d181f2 | |
![]() |
23488ad22b | |
![]() |
8b0b016aec | |
![]() |
cd09cf8dfd | |
![]() |
374ba5ec70 | |
![]() |
3a50d7e136 | |
![]() |
696d49820c | |
![]() |
2a3656bf24 | |
![]() |
469352e72a | |
![]() |
72908248eb | |
![]() |
e9212c35f7 | |
![]() |
4b5bef273d | |
![]() |
a338a12d77 | |
![]() |
88b686c27d | |
![]() |
b84e80663f | |
![]() |
351c9a7c86 | |
![]() |
6d395bf2ee | |
![]() |
57640cad49 | |
![]() |
1d030aa41f | |
![]() |
c723c56e4a | |
![]() |
5f7b9417b0 | |
![]() |
877c87537e | |
![]() |
9f87854040 | |
![]() |
38eeef7c0d | |
![]() |
5d87ad46c6 | |
![]() |
7b9634a3ec | |
![]() |
8dd54df4a8 | |
![]() |
c5fe198bb2 | |
![]() |
a81ec74d06 | |
![]() |
82427abcb8 | |
![]() |
f0a1301b64 | |
![]() |
d9785e7225 | |
![]() |
067aa82cc7 | |
![]() |
5d5fc992da | |
![]() |
dc1f93b120 | |
![]() |
d0b4c6abac | |
![]() |
09c5eb405d | |
![]() |
3908a8c7b2 | |
![]() |
51ddb6c1d1 | |
![]() |
bfa9abbc1b | |
![]() |
aac207c78e | |
![]() |
49b4988953 | |
![]() |
da27e1456b | |
![]() |
baa1cf5470 | |
![]() |
feb1f0383d | |
![]() |
6788bf16f3 | |
![]() |
b1446a5f6b | |
![]() |
0a72fbf7f7 | |
![]() |
4186d4ba8b | |
![]() |
4c30264136 | |
![]() |
7528d9a4e3 | |
![]() |
60dbf241e8 | |
![]() |
852adf0d21 | |
![]() |
1e300d63ec | |
![]() |
5b0cf41507 | |
![]() |
0c8dd778d0 | |
![]() |
25b9a2efcc | |
![]() |
3a59c62753 | |
![]() |
884a9080b5 | |
![]() |
f857593f77 | |
![]() |
d3b2554b20 | |
![]() |
f174872702 | |
![]() |
c6ea72dcf4 | |
![]() |
bc98e164b2 | |
![]() |
6867907a3c | |
![]() |
7589f0a94c | |
![]() |
a769e896c6 | |
![]() |
44ed2ee3aa | |
![]() |
06f34134ff | |
![]() |
6320dd5539 | |
![]() |
8c7247abf5 | |
![]() |
0b90a48434 | |
![]() |
e85af190d5 | |
![]() |
733670c7f8 | |
![]() |
79ac0c3019 | |
![]() |
ec6b16c68a | |
![]() |
e9cc351bba | |
![]() |
e208c73586 | |
![]() |
7e5f9a7cb7 | |
![]() |
b39801df11 | |
![]() |
a791b7609c | |
![]() |
b664488274 | |
![]() |
114be1b7c9 | |
![]() |
607a48e3ea | |
![]() |
9082891903 | |
![]() |
484a2c3f47 | |
![]() |
c883034372 | |
![]() |
41d45dd88d | |
![]() |
86022747f0 | |
![]() |
1125c1c45d | |
![]() |
7d116628c2 | |
![]() |
f41cc02c6c | |
![]() |
da72da4d03 | |
![]() |
db1bae2d4e | |
![]() |
59fe8eb6db | |
![]() |
be4fb1deb6 | |
![]() |
1e05973b81 | |
![]() |
79b3b4e803 | |
![]() |
02b9d75b38 | |
![]() |
349f28c6cb | |
![]() |
4625a34eec | |
![]() |
5ac2d3e152 | |
![]() |
1b10e1b9d4 | |
![]() |
822f4f9b9a | |
![]() |
c65d26a284 | |
![]() |
54d3ee11bb | |
![]() |
50b969549f | |
![]() |
f8b449d6b1 | |
![]() |
a844dffa95 | |
![]() |
a25e455289 | |
![]() |
f41f73f6c3 | |
![]() |
283331412a | |
![]() |
6078193fec | |
![]() |
922bd4e9d2 | |
![]() |
a7cf67cd71 | |
![]() |
c1fb2d665b | |
![]() |
3e5272d91a | |
![]() |
e77404472e | |
![]() |
ef5c9ad4fb | |
![]() |
0c28aca19c | |
![]() |
7c630d6104 | |
![]() |
29e1dc865d | |
![]() |
c9fe07ab98 | |
![]() |
0b2c0a2e33 | |
![]() |
66b83d98e4 | |
![]() |
caf7927445 | |
![]() |
c658777645 | |
![]() |
2c1f5bd430 | |
![]() |
4645d42130 | |
![]() |
41c9d7a352 | |
![]() |
84ea340da1 | |
![]() |
6d08f2a99b | |
![]() |
886bef5c8a | |
![]() |
4457d110bf | |
![]() |
8e424759df | |
![]() |
f7042be933 | |
![]() |
7791c9dd78 | |
![]() |
c76de904dc | |
![]() |
5a01ce5297 | |
![]() |
1886819a35 | |
![]() |
6a9e242fad | |
![]() |
9092f7bbe6 | |
![]() |
006af26a6e | |
![]() |
b748c5f61a | |
![]() |
94f02583ba | |
![]() |
ac5289d83a | |
![]() |
51c3f37596 | |
![]() |
ca5a1aaa71 | |
![]() |
23c72d825e | |
![]() |
4f26ab927f | |
![]() |
309975da61 | |
![]() |
be56eac811 | |
![]() |
326a5bb714 | |
![]() |
3bdd689e03 | |
![]() |
9b65924898 | |
![]() |
b863432904 | |
![]() |
32fa33ddab | |
![]() |
629d6d2054 | |
![]() |
b52f5655e4 | |
![]() |
35072da2ea | |
![]() |
b804ed1f03 | |
![]() |
ac68fd481c | |
![]() |
9b02cac7ad | |
![]() |
b405153c7e | |
![]() |
bc6c017b7a | |
![]() |
9bf21223f2 | |
![]() |
2c46ea3d98 | |
![]() |
cc6041d2de | |
![]() |
5e26b938fb | |
![]() |
f3dc44ebae | |
![]() |
5692f79d78 | |
![]() |
093c23d5bc | |
![]() |
249d6b2169 | |
![]() |
0e5e791a55 | |
![]() |
16ea4519c8 | |
![]() |
93b5e88754 | |
![]() |
08ee4a15d3 | |
![]() |
cefea8ad83 | |
![]() |
094256ef43 | |
![]() |
8de8f411c1 | |
![]() |
0c2b7b4220 | |
![]() |
a5fa40956a | |
![]() |
edffb3a128 | |
![]() |
0fb2e6208d | |
![]() |
e1a8391170 | |
![]() |
b11cb57b0b | |
![]() |
50d50288a5 | |
![]() |
9439b9f54c | |
![]() |
de16fe345a | |
![]() |
5e7c6a082f | |
![]() |
a6e17bc4de | |
![]() |
660e6bca1e | |
![]() |
b4dadb1dff | |
![]() |
e37bb218ba | |
![]() |
30956c1044 | |
![]() |
cb3330a9e4 | |
![]() |
d42e3ee271 | |
![]() |
cf8ff008a8 | |
![]() |
74c8b0cde1 | |
![]() |
390466e615 | |
![]() |
6e68433dbd | |
![]() |
85daa21ae2 | |
![]() |
533e80f171 | |
![]() |
755bb73b1c | |
![]() |
8c5c80c284 | |
![]() |
fc430320ac | |
![]() |
516457c89c | |
![]() |
2e27e0d4b5 | |
![]() |
74138d14cc | |
![]() |
56f98f9561 | |
![]() |
c4016448ef | |
![]() |
edad809de0 | |
![]() |
1c67c0d16d | |
![]() |
cd768c6800 | |
![]() |
e6650da541 | |
![]() |
9536ba3312 | |
![]() |
efd9108279 | |
![]() |
3e60c31d26 | |
![]() |
88a786b700 | |
![]() |
4cf90a6170 | |
![]() |
2e9546a20a | |
![]() |
9307f816ba | |
![]() |
1d9dc0df2d | |
![]() |
1f404c57da | |
![]() |
38aaf7189f | |
![]() |
309db8cdae | |
![]() |
06fadd6b74 | |
![]() |
a69a985651 | |
![]() |
05b7478d18 | |
![]() |
91a77b01f5 | |
![]() |
b8b08e716e | |
![]() |
8e384b4b8c | |
![]() |
494ef0b267 | |
![]() |
1ed65ec29a | |
![]() |
f2aaa2adea | |
![]() |
bc14c34efc | |
![]() |
a1f0290039 | |
![]() |
07992147bd | |
![]() |
1475761d5c | |
![]() |
4d2a59d737 | |
![]() |
af43500c1a | |
![]() |
56eede299b | |
![]() |
ee9ba1cacb | |
![]() |
1f0c3f677e | |
![]() |
0643645ddd | |
![]() |
23c1dcf1c9 | |
![]() |
addf4b42fd | |
![]() |
c4d75368a5 | |
![]() |
f1e54be515 | |
![]() |
d847580881 | |
![]() |
c7bf62ce62 | |
![]() |
98a44aa47d | |
![]() |
f003c11260 | |
![]() |
55e45e728e | |
![]() |
ba9ee5fd2f | |
![]() |
fa1f4d4c50 | |
![]() |
ea55dfa45d | |
![]() |
6bb0234dc8 | |
![]() |
8b9b26b56e | |
![]() |
fa0a114e0c | |
![]() |
a8fae55299 | |
![]() |
c03b2ed151 | |
![]() |
061e38af6f | |
![]() |
d46abef9a1 | |
![]() |
3da5b9f5d9 | |
![]() |
a29c2f7d62 | |
![]() |
d8c18cf268 | |
![]() |
6bf2a1f44f | |
![]() |
ce7a5f6e40 | |
![]() |
5aaadd026c | |
![]() |
990a24292d | |
![]() |
85f792d2b2 | |
![]() |
2f9558d307 | |
![]() |
814b040ff1 | |
![]() |
657a8ef7c3 | |
![]() |
5ea12636ee | |
![]() |
3ea3cdc1a8 | |
![]() |
6f2460c70a | |
![]() |
03200fdcd3 | |
![]() |
90bdeac904 | |
![]() |
726d6ff4f3 | |
![]() |
512502ce36 | |
![]() |
ad1652f050 | |
![]() |
fe6de7c621 | |
![]() |
6373ba58bb | |
![]() |
3c96e3236b | |
![]() |
b565d39ffe | |
![]() |
7745515588 | |
![]() |
55f3c60ef2 | |
![]() |
b5cc970d7e | |
![]() |
7f89e72b2b | |
![]() |
e3c0b7287c | |
![]() |
cb4bbc17ee | |
![]() |
3216931da6 | |
![]() |
9480bea9c0 | |
![]() |
65734fac9d | |
![]() |
845bc7ef06 | |
![]() |
af0058ad61 | |
![]() |
c6fdfc7101 | |
![]() |
4af986f058 | |
![]() |
29017db910 | |
![]() |
2990552230 | |
![]() |
b72b52a4a2 | |
![]() |
4517f36456 | |
![]() |
609a4d3276 | |
![]() |
1e6845c940 | |
![]() |
f6e54acf17 | |
![]() |
da7a917ec5 | |
![]() |
7d672600bb | |
![]() |
0cb849a3f8 | |
![]() |
3b1daf52ab | |
![]() |
76eb475ed6 | |
![]() |
b66f04d811 | |
![]() |
8087b157e5 | |
![]() |
917bf50482 | |
![]() |
f3251128e8 | |
![]() |
1ed640a0d7 | |
![]() |
55ada8d50d | |
![]() |
5d222c10a0 | |
![]() |
8cc4b10ce0 | |
![]() |
df22c8baed | |
![]() |
2e1ed31aaa | |
![]() |
a665cf1f8e | |
![]() |
d49762d27e | |
![]() |
8d725a689c | |
![]() |
08dd615d37 | |
![]() |
cf3655bed1 | |
![]() |
d8eb26fbda | |
![]() |
9eadb8d393 | |
![]() |
cec1b0b885 | |
![]() |
9d601299ad | |
![]() |
b0b47ab744 | |
![]() |
867a0b1045 | |
![]() |
0453e451f1 | |
![]() |
a04a079f19 | |
![]() |
a5f4b3b494 | |
![]() |
c769dce20e | |
![]() |
2397ece059 | |
![]() |
12f2237c79 | |
![]() |
8a4c7469e6 | |
![]() |
7a6983478f | |
![]() |
d74a9a1dfb | |
![]() |
2d10c1ffe2 | |
![]() |
a95636afcd | |
![]() |
dff5fb04cc | |
![]() |
1e92046b0b | |
![]() |
3554d8ef03 | |
![]() |
b6d4c76b42 | |
![]() |
ea434d9cf2 | |
![]() |
1034185a62 | |
![]() |
cf8f2628c0 | |
![]() |
dd7fbe302f | |
![]() |
e6e0d5da9e | |
![]() |
cb2dc36e9e | |
![]() |
4778aeab1e | |
![]() |
11ac2f8058 | |
![]() |
0da1273404 | |
![]() |
8445a02998 | |
![]() |
8f7efbe1e8 | |
![]() |
db545a3900 | |
![]() |
36b83a8e52 | |
![]() |
3c74d95e17 | |
![]() |
f0e99ba436 | |
![]() |
3b43c081e4 | |
![]() |
c809b0d01b | |
![]() |
c808cf2834 | |
![]() |
c127a13291 | |
![]() |
68b3f0f22b | |
![]() |
59ee8326d9 | |
![]() |
9e9f78ec94 | |
![]() |
401337a09e | |
![]() |
91fdc1317c | |
![]() |
6f81d212b3 | |
![]() |
01f33a87d4 | |
![]() |
4258407b5b | |
![]() |
8d9deb8138 | |
![]() |
48814d3173 | |
![]() |
affae4cc0e | |
![]() |
cb9bb62146 | |
![]() |
fe84236330 | |
![]() |
49e2dc34eb | |
![]() |
7030e1551d | |
![]() |
a8405c967e | |
![]() |
1e0c75c3bd | |
![]() |
52c88d7462 | |
![]() |
781b7b8618 | |
![]() |
3ba0ff084d | |
![]() |
000dd6c0a5 | |
![]() |
74df117284 | |
![]() |
c6d1ec4924 | |
![]() |
0875de0727 | |
![]() |
e052a681be | |
![]() |
c403d6d129 | |
![]() |
9885859916 | |
![]() |
23681729a5 | |
![]() |
5c4e6945dc | |
![]() |
327490a8ed | |
![]() |
4985d9ca7e | |
![]() |
f68c706b1e | |
![]() |
55f1228c66 | |
![]() |
611966f34e | |
![]() |
a57aeed9f0 | |
![]() |
5995641a8f | |
![]() |
a53f3604fd | |
![]() |
d0e525cd99 | |
![]() |
db6dd7110e | |
![]() |
45e4e18415 | |
![]() |
58f1c0959c | |
![]() |
f3aaea3bc2 | |
![]() |
d66c50ad26 | |
![]() |
3d95e0223b | |
![]() |
8a750fb4f2 | |
![]() |
3ff7869331 | |
![]() |
98805bd0c5 | |
![]() |
6cfad6f212 | |
![]() |
6d187f1015 | |
![]() |
2b6f452f18 | |
![]() |
c30a2e058a | |
![]() |
39c938f990 | |
![]() |
187f4a8162 | |
![]() |
d929e81f1f | |
![]() |
2d63e89208 | |
![]() |
721d83eaf1 | |
![]() |
7518f8375a | |
![]() |
efda454399 | |
![]() |
4938b13bc5 | |
![]() |
d9b994c357 | |
![]() |
8c754be62a | |
![]() |
9d18a16370 | |
![]() |
dd5196f3ca | |
![]() |
977fdd360c | |
![]() |
609614f735 | |
![]() |
6db6256e45 | |
![]() |
4f91ca6838 | |
![]() |
9c6e2656af | |
![]() |
d382722d38 | |
![]() |
61e7e30e29 | |
![]() |
a414ee20b9 | |
![]() |
b3768ba5ec | |
![]() |
6332b9beaf | |
![]() |
3ac793eb6e | |
![]() |
72acea23b2 | |
![]() |
55d81a3bfb | |
![]() |
0c8ae3f3e2 | |
![]() |
3c393227be | |
![]() |
e4ef9c1985 | |
![]() |
6abf4f0c66 | |
![]() |
0217200a4c | |
![]() |
f04c518d15 | |
![]() |
35cd99a844 | |
![]() |
487ad3fa19 | |
![]() |
fb4ca717e4 | |
![]() |
9ea0051d92 | |
![]() |
6d1e095a41 | |
![]() |
84cd4e3ba4 | |
![]() |
15d5397037 | |
![]() |
23c8d37731 | |
![]() |
f32a2e7d19 | |
![]() |
5bfc595414 | |
![]() |
018a8061ad | |
![]() |
65959ec439 | |
![]() |
e6d9c6de15 | |
![]() |
72492527e5 | |
![]() |
4361c7c6c9 | |
![]() |
7f86dc80ae | |
![]() |
97b90fcfd7 | |
![]() |
807f95cae2 | |
![]() |
a60c6aa701 | |
![]() |
63e1e0d339 | |
![]() |
00fa639a11 | |
![]() |
e30217f2ac | |
![]() |
6c70627ad2 | |
![]() |
8f848f8dda | |
![]() |
de20deaa8a | |
![]() |
16c449ddc7 | |
![]() |
f818e43fc7 | |
![]() |
7c51e2e34b | |
![]() |
3dd4ca7349 | |
![]() |
e68d277929 | |
![]() |
c36da13798 | |
![]() |
1b2308f3e1 | |
![]() |
86788a558e | |
![]() |
559230a02a | |
![]() |
240dc03dd5 | |
![]() |
bf6d8b804f | |
![]() |
07b4738e97 | |
![]() |
cd362b6383 | |
![]() |
f750b2e4f2 | |
![]() |
9c1c61f191 | |
![]() |
769444f91c | |
![]() |
6a54aa5573 | |
![]() |
689e3ca93c | |
![]() |
4f2404867e | |
![]() |
d9a2e7a715 | |
![]() |
d7c9e78195 | |
![]() |
59d635821a | |
![]() |
2bb2e5c3d4 | |
![]() |
d26e028125 | |
![]() |
4056974209 | |
![]() |
87196b8231 | |
![]() |
463277c5d8 | |
![]() |
6166a6ee85 | |
![]() |
049a070a10 | |
![]() |
f390c79bdf | |
![]() |
ad7328d963 | |
![]() |
3abddb5983 | |
![]() |
2331816a99 | |
![]() |
b6db19e353 | |
![]() |
24b38ae3b3 | |
![]() |
5441dbff1c | |
![]() |
8a5c9a6445 | |
![]() |
c722d80503 | |
![]() |
54e0c08ef1 | |
![]() |
c77582524d | |
![]() |
134dd70117 | |
![]() |
bd76d67c78 | |
![]() |
39e91ffec6 | |
![]() |
0245cc6ee8 | |
![]() |
8200cd8e43 | |
![]() |
8b8d1e0d39 | |
![]() |
43be445c37 | |
![]() |
b4685c1dc2 | |
![]() |
f98d040a65 | |
![]() |
5720444c6b | |
![]() |
3bfad0327f | |
![]() |
99a96e675d | |
![]() |
ddc62ad00e | |
![]() |
f44f35f6fa | |
![]() |
fe398a4562 | |
![]() |
20549fec19 | |
![]() |
ae43ded58b | |
![]() |
515df2b533 | |
![]() |
8c1ee7d755 | |
![]() |
b3f1e610ba | |
![]() |
7e838ff677 | |
![]() |
8d741e66d3 | |
![]() |
e39a9a0420 | |
![]() |
ab01047450 | |
![]() |
6f62ec001b | |
![]() |
d7f0957cba | |
![]() |
dab91c1913 | |
![]() |
ce369a6259 | |
![]() |
29719e8fc1 | |
![]() |
27dbf03743 | |
![]() |
301205051b | |
![]() |
363d91faff | |
![]() |
8eeb061a42 | |
![]() |
59534bdbcc | |
![]() |
70088b3697 | |
![]() |
0bfc4c4479 | |
![]() |
e7f2e88784 | |
![]() |
ffee8ace55 | |
![]() |
4d84e71363 | |
![]() |
e0f41fe6f7 | |
![]() |
aa3c09c430 | |
![]() |
55932e5493 | |
![]() |
38a0f82980 | |
![]() |
875f97b5dd | |
![]() |
9e05b3342d | |
![]() |
dfe9a19b0d | |
![]() |
4ff30fff20 | |
![]() |
d82e0ad07a | |
![]() |
9f5b4e0e11 | |
![]() |
f6d210461d | |
![]() |
a1dfa3d6fe | |
![]() |
8fe6092f0f | |
![]() |
626e84763e | |
![]() |
f0531c5d09 | |
![]() |
77579a6113 | |
![]() |
c9a7911d15 | |
![]() |
f553265c03 | |
![]() |
c67e925011 | |
![]() |
ef30044a93 | |
![]() |
9635ba9d39 | |
![]() |
c89e1ba079 | |
![]() |
afbf1fd723 | |
![]() |
c2dc6a44f1 | |
![]() |
456fd3e30a | |
![]() |
deb597dd59 | |
![]() |
8ab6b91fe5 | |
![]() |
89f72d8ff0 | |
![]() |
357948a457 | |
![]() |
2d3977b220 | |
![]() |
6c3c033158 | |
![]() |
b5788e85ca | |
![]() |
afc4c0b561 | |
![]() |
2f74af168d | |
![]() |
1ceb0b424f | |
![]() |
e42c39e9ba | |
![]() |
fe0c2db158 | |
![]() |
a02efe0466 | |
![]() |
0356b40735 | |
![]() |
efee57a10c | |
![]() |
4d4f6dd681 | |
![]() |
10ba282305 | |
![]() |
f5ed14d276 | |
![]() |
b86e64f36a | |
![]() |
2691f44970 | |
![]() |
5a8cfaf7f9 | |
![]() |
7902c12738 | |
![]() |
e2fcedd1b7 | |
![]() |
07c3f3b0fa | |
![]() |
f872bb5f8a | |
![]() |
50d21d8127 | |
![]() |
3a506df754 | |
![]() |
5031f1aa65 | |
![]() |
3209bf7be5 | |
![]() |
ee9612e263 | |
![]() |
471f3894cc | |
![]() |
93a3a3b35c | |
![]() |
3a7b233199 | |
![]() |
764304c0ca | |
![]() |
0411f27c65 | |
![]() |
8415397067 | |
![]() |
a99d3f923a | |
![]() |
6c0bb86336 | |
![]() |
6915ccb027 | |
![]() |
8c986c2480 | |
![]() |
47795babfd | |
![]() |
64672ddb4b | |
![]() |
362c93801f | |
![]() |
246d1fa3fe | |
![]() |
2480582b0c | |
![]() |
2324b798ab | |
![]() |
1aac347af9 | |
![]() |
d748d3d4f2 | |
![]() |
698719d5ad | |
![]() |
d1596da695 | |
![]() |
7268219f5e | |
![]() |
95b97b0502 | |
![]() |
b2ca28198e | |
![]() |
eca9c330c5 | |
![]() |
beac314243 | |
![]() |
7af503b90c | |
![]() |
ec6987d17f | |
![]() |
4d8c4fbb68 | |
![]() |
e0b62dde9d | |
![]() |
36e6349de5 | |
![]() |
8c3d1bcdfa | |
![]() |
55da0a278b | |
![]() |
e424d05252 | |
![]() |
a08145b0c2 | |
![]() |
21c27b416f | |
![]() |
9d714c4488 | |
![]() |
9ebdef8502 | |
![]() |
46ec7516fa | |
![]() |
c566836f42 | |
![]() |
6350abaaf7 | |
![]() |
43eefa8041 | |
![]() |
74333af9c0 | |
![]() |
dc5f56222e | |
![]() |
6892591084 | |
![]() |
1c2c02f47b | |
![]() |
7e0f8f4b30 | |
![]() |
770d062014 | |
![]() |
67c31c650b | |
![]() |
dab1da6caf | |
![]() |
c3568f6ea3 | |
![]() |
213dd2f86f | |
![]() |
3f4f141cf1 | |
![]() |
a6353f7554 | |
![]() |
498cf39664 | |
![]() |
2759d9bb8c | |
![]() |
c3993c6abb | |
![]() |
50164a5a67 | |
![]() |
561f76c067 | |
![]() |
97bf1d9169 | |
![]() |
2875342b5c | |
![]() |
65d5abc813 | |
![]() |
feef6ffb3d | |
![]() |
cbe534cb54 | |
![]() |
62af56b67a | |
![]() |
8b7f4a5027 | |
![]() |
38242d48f9 | |
![]() |
16efb84eb9 | |
![]() |
5fe769b906 | |
![]() |
44f0aee5d4 | |
![]() |
b8bb054402 | |
![]() |
c09a90e459 | |
![]() |
eae97f3f07 | |
![]() |
337946db25 | |
![]() |
f8593e692d | |
![]() |
dd0e331528 | |
![]() |
4323e401d8 | |
![]() |
1c465409c2 | |
![]() |
4dd9aaeed7 | |
![]() |
acff986fe1 | |
![]() |
3b82af621d | |
![]() |
e81c9fecb8 | |
![]() |
5592f81c02 | |
![]() |
9a773ef7ac | |
![]() |
d5adbb2ab3 | |
![]() |
23a3bc4b78 | |
![]() |
709a3508ee | |
![]() |
9b2c1ba2ce | |
![]() |
0f88b77bfe | |
![]() |
724a1ca684 | |
![]() |
a412c80b24 | |
![]() |
1ee123900b | |
![]() |
4e6068f6b4 | |
![]() |
7938142faf | |
![]() |
a4d1807b4c | |
![]() |
47ea099a92 | |
![]() |
ea98d4bdea | |
![]() |
b7b2c24fdb | |
![]() |
b04980a150 | |
![]() |
6f27d335f7 | |
![]() |
8588230ee1 | |
![]() |
b07ca858d5 | |
![]() |
2d33a1bb6b | |
![]() |
cc98adb38c | |
![]() |
03d864c465 | |
![]() |
4665bd0c3f | |
![]() |
6a70a08c59 | |
![]() |
21092a5d38 | |
![]() |
4b85f0949a | |
![]() |
fa10dcfd29 | |
![]() |
d9ec4342d7 | |
![]() |
6d2e598c8c | |
![]() |
3dcf1e67e0 | |
![]() |
8d8ebd76f7 | |
![]() |
0f7ce3b527 | |
![]() |
8ae094d730 | |
![]() |
7a59d775f9 | |
![]() |
a7a69f5108 | |
![]() |
28d031d9f9 | |
![]() |
b34165d63b | |
![]() |
8a87fd8376 | |
![]() |
9b5fe396ca | |
![]() |
621960258d | |
![]() |
efe42f4eba | |
![]() |
df1ead013a | |
![]() |
f42009a27e | |
![]() |
190ef8c3d5 | |
![]() |
0d1a8e3afd | |
![]() |
7767250624 | |
![]() |
756ad91cbe | |
![]() |
dd5a029ee6 | |
![]() |
4c8c00fecd | |
![]() |
dce84c4b7e | |
![]() |
cd918389a4 | |
![]() |
0a3dd68191 | |
![]() |
d7c6648162 | |
![]() |
0b31f3ad95 | |
![]() |
3241ba8fef | |
![]() |
216b5c274e | |
![]() |
2d649c969f | |
![]() |
24c4e3d0a7 | |
![]() |
cf594cda97 | |
![]() |
dced533dd8 | |
![]() |
e01b863fd2 | |
![]() |
96155736e5 | |
![]() |
3a740d7933 | |
![]() |
1887f3ac29 | |
![]() |
a4c4719a19 | |
![]() |
ad6438f936 | |
![]() |
a380927fba | |
![]() |
fd490e9929 | |
![]() |
ec8c930ebc | |
![]() |
2c72faad81 | |
![]() |
4271a857cc | |
![]() |
a0ae63d030 | |
![]() |
665dc37877 | |
![]() |
13d79192c8 | |
![]() |
ad3c042df2 | |
![]() |
05bae29ec3 | |
![]() |
556a65f1dc | |
![]() |
3fdfa89812 | |
![]() |
24fa7dc935 | |
![]() |
13bd79f930 | |
![]() |
8a1e4b1beb | |
![]() |
f8e0b73e23 | |
![]() |
0a46366c22 | |
![]() |
746a7e6450 | |
![]() |
200c614d21 | |
![]() |
31fd0600b6 | |
![]() |
a852c3ef9d | |
![]() |
bd759e5858 | |
![]() |
550df54b77 | |
![]() |
da4e1a3aec | |
![]() |
42dc0c0fc9 | |
![]() |
ecc6669158 | |
![]() |
ea7007090c | |
![]() |
6c56bcfcf3 | |
![]() |
2c16a3f1b6 | |
![]() |
44f1e0937c | |
![]() |
5af26d23f5 | |
![]() |
c48484c135 | |
![]() |
e34c990ff4 | |
![]() |
5aad40ce9d | |
![]() |
abe0c827d3 | |
![]() |
eaeb521bd9 | |
![]() |
abb50d6f99 | |
![]() |
cc032120bf | |
![]() |
cb2bd277cd | |
![]() |
fc888cac2d | |
![]() |
dd24225477 | |
![]() |
4c47d5a6d9 | |
![]() |
01382d7e1d | |
![]() |
cd11b34415 | |
![]() |
6ecd89cd27 | |
![]() |
6afcd6a3f3 | |
![]() |
92b6a9800d | |
![]() |
d091a0ee8f | |
![]() |
6e265244cf | |
![]() |
1ea6c5485e | |
![]() |
fa6387a545 | |
![]() |
e3b1cffd3a | |
![]() |
0b32d66e37 | |
![]() |
4cd89d77b8 | |
![]() |
e6f875b7a7 | |
![]() |
e7be2435c2 | |
![]() |
6111fc9fdb | |
![]() |
5272b1de12 | |
![]() |
fc655cdca5 | |
![]() |
ee6a61c364 | |
![]() |
79391fc55a | |
![]() |
2720c5b430 | |
![]() |
a501e9a4a4 | |
![]() |
eb90237285 | |
![]() |
96e2b593a6 | |
![]() |
e1f587a629 | |
![]() |
b304e538c6 | |
![]() |
8919d9981c | |
![]() |
f9084d9b2e | |
![]() |
615b702cde | |
![]() |
b10d242b80 | |
![]() |
ffe3b95323 | |
![]() |
967f53ad6f | |
![]() |
3550fa4ed1 | |
![]() |
d961d4e7e7 | |
![]() |
cdb3b13756 | |
![]() |
dd36bce933 | |
![]() |
7bfd8bed46 | |
![]() |
4c384ef322 | |
![]() |
8861b845d7 | |
![]() |
e0f6d75cd0 | |
![]() |
35227da440 | |
![]() |
4b735c58cc | |
![]() |
f46bcd6875 | |
![]() |
2695d91496 | |
![]() |
d51743a132 | |
![]() |
b0ebc8b332 | |
![]() |
fb4b988eb7 | |
![]() |
de92e5048b | |
![]() |
71dc7e988e | |
![]() |
f911980a37 | |
![]() |
d184035103 | |
![]() |
4d06712489 | |
![]() |
d95249cab2 | |
![]() |
250b2f5157 | |
![]() |
e1c53ac304 | |
![]() |
c06817d8fa | |
![]() |
a6a95072a9 | |
![]() |
54005aad18 | |
![]() |
8eb5384ad9 | |
![]() |
d5af8461be | |
![]() |
9a5aa06e7f | |
![]() |
9e90a2df50 | |
![]() |
ed57ca9788 | |
![]() |
0d38f6cfad | |
![]() |
6de2d464c4 | |
![]() |
222f266cd1 | |
![]() |
e2d1b4de30 | |
![]() |
997f4bd928 | |
![]() |
4da39275b4 | |
![]() |
2c73d8b736 | |
![]() |
4043ac1b01 | |
![]() |
cf87eaef06 | |
![]() |
91241dbd08 | |
![]() |
bbe3cc1f47 | |
![]() |
66bccac3cf | |
![]() |
f503902267 | |
![]() |
7f4da40f21 | |
![]() |
93962a9de4 | |
![]() |
d881695cf4 | |
![]() |
9f593237fe | |
![]() |
5bc4eee10b | |
![]() |
ce3626eb9d | |
![]() |
458b332e8e | |
![]() |
77d469ddb5 | |
![]() |
c0f2d60a3f | |
![]() |
dbae5dbb79 | |
![]() |
9bee8ea17b | |
![]() |
f1d09aff15 | |
![]() |
b8d87ecdc3 | |
![]() |
3e7ac34987 | |
![]() |
a216c3d90e | |
![]() |
b5358508d6 | |
![]() |
64f69f78ae | |
![]() |
d3544f7b5f | |
![]() |
a981607e51 | |
![]() |
0afcf04c06 | |
![]() |
ca0b978cf9 | |
![]() |
e166b97cd7 | |
![]() |
326f645b8f | |
![]() |
6d8d692b7c | |
![]() |
857b8f933e | |
![]() |
503ce9b825 | |
![]() |
db1429a4b9 | |
![]() |
ab6b4786bd | |
![]() |
201ab08043 | |
![]() |
e5af2b1754 | |
![]() |
52f18bca28 | |
![]() |
49e68a1ecc | |
![]() |
b72be80b88 | |
![]() |
a679073ec6 | |
![]() |
6f5a1f2c46 | |
![]() |
f375bbf6ba | |
![]() |
a2e623180a | |
![]() |
d1580cd19d | |
![]() |
ba8adc04f4 | |
![]() |
772e6ed18e | |
![]() |
9871b25fa8 | |
![]() |
95e8642970 | |
![]() |
97abbd0a7c | |
![]() |
ada86a42b5 | |
![]() |
fad467196a | |
![]() |
0c5117dc06 | |
![]() |
06af046c13 | |
![]() |
ce0e35b052 | |
![]() |
8b780f2d5c | |
![]() |
ee4856a06d | |
![]() |
72401c44d4 | |
![]() |
e91d1bf23c | |
![]() |
04dce78f53 | |
![]() |
18a22cd934 | |
![]() |
ab142abd69 | |
![]() |
d7d1d781d8 | |
![]() |
dab7a608c2 | |
![]() |
935fab7b9c | |
![]() |
9f8e617890 | |
![]() |
b281861e49 | |
![]() |
bd93e2288d | |
![]() |
34f8d30219 | |
![]() |
fcdab48d00 | |
![]() |
ba980d249d | |
![]() |
d756012ea3 | |
![]() |
0f853f3665 | |
![]() |
6d9dfb2dde | |
![]() |
ba2d18d17f | |
![]() |
fec845f6f8 | |
![]() |
85c0f608e2 | |
![]() |
23104c8280 | |
![]() |
e499d3ad07 | |
![]() |
b0bcc2fd9b | |
![]() |
543756d712 | |
![]() |
97012d649f | |
![]() |
86bb8cad97 | |
![]() |
82c61be866 | |
![]() |
8667d22196 | |
![]() |
555f240319 | |
![]() |
2ab2965f3a | |
![]() |
f3d7ae61c2 | |
![]() |
e17d872356 | |
![]() |
db640d5b6f | |
![]() |
a32b10aa79 | |
![]() |
f98023bbb8 | |
![]() |
5a1b8b55e5 | |
![]() |
0aa92e826a | |
![]() |
ada56843ad | |
![]() |
7370a29367 | |
![]() |
176dc9a38c | |
![]() |
79102c6ef8 | |
![]() |
9ab91550ae | |
![]() |
1087b3e645 | |
![]() |
e60d11959c | |
![]() |
7d53eaae73 | |
![]() |
6a8534a22e | |
![]() |
00e85b8af8 | |
![]() |
932398547e | |
![]() |
ab6bb98758 | |
![]() |
311e1037a6 | |
![]() |
ddc5d14c52 | |
![]() |
e94be42c40 | |
![]() |
7bab062ff5 | |
![]() |
5a222185a3 | |
![]() |
ea5f494a8e | |
![]() |
cc7e1a4069 | |
![]() |
3db98e4e90 | |
![]() |
848f4eeee3 | |
![]() |
c1b58dafb9 | |
![]() |
f296636643 | |
![]() |
47b53211f9 | |
![]() |
a2b5d2c466 | |
![]() |
eaa095e8a2 | |
![]() |
57a8dc6f3b | |
![]() |
1a2df9cd13 | |
![]() |
e6b2ed88af | |
![]() |
c27da955ab | |
![]() |
10b7d06be8 | |
![]() |
a554f1cbba | |
![]() |
653252d1f3 | |
![]() |
0623d4f485 | |
![]() |
d2f104f251 | |
![]() |
1a1019b85c | |
![]() |
897bc182f8 | |
![]() |
55f84cd67e | |
![]() |
35319dc724 | |
![]() |
57905bab69 | |
![]() |
32001136ae | |
![]() |
2ead1e0fe0 | |
![]() |
7bfd1c795b | |
![]() |
04840af6d3 | |
![]() |
9e1077fe9f | |
![]() |
af3858c0d8 | |
![]() |
fbe4987569 | |
![]() |
fb7398d7c9 | |
![]() |
37b230fbfe | |
![]() |
8a33562dc8 | |
![]() |
b20a970b1d | |
![]() |
7fca148bc6 | |
![]() |
380d93c03e | |
![]() |
0f38209e4b | |
![]() |
11c046e0aa | |
![]() |
446b7efc29 | |
![]() |
f1255cb89b | |
![]() |
79a3a8d9a6 | |
![]() |
1485d9c82b | |
![]() |
95d2406937 | |
![]() |
52f0d6f03b | |
![]() |
a8e8f0c071 | |
![]() |
c4f9821c6a | |
![]() |
affc999d70 | |
![]() |
f283dff3b6 | |
![]() |
254e666bfe | |
![]() |
170b971a8e | |
![]() |
890a5ffd2f | |
![]() |
37f5a751a1 | |
![]() |
daffa99825 | |
![]() |
cd62ac9cc1 | |
![]() |
3be54d4569 | |
![]() |
c537539c6e | |
![]() |
bf115fe7ab | |
![]() |
c42aff2307 | |
![]() |
39a9bd451f | |
![]() |
747ec875aa | |
![]() |
41c2de8e5d | |
![]() |
93c8514700 | |
![]() |
b2b0813db4 | |
![]() |
9f19b26161 | |
![]() |
4e1062905d | |
![]() |
e333152bd1 | |
![]() |
032eee144f | |
![]() |
420d689d82 | |
![]() |
2295a10e77 | |
![]() |
0532fa7c58 | |
![]() |
da10d3602f | |
![]() |
34072e9fd9 | |
![]() |
208ce0e35c | |
![]() |
ca6423b484 | |
![]() |
2a23634c77 | |
![]() |
52cdb4e984 | |
![]() |
525a2fb330 |
|
@ -8,7 +8,6 @@ skip_commits:
|
|||
- .github/*
|
||||
- .github/*/*
|
||||
- .azure-pipelines.yml
|
||||
- .travis.yml
|
||||
- CONTRIBUTORS
|
||||
- COPYING
|
||||
- README.md
|
||||
|
@ -16,7 +15,10 @@ skip_commits:
|
|||
- setup.bat
|
||||
|
||||
init:
|
||||
- ps: Update-AppveyorBuild -Version "$env:appveyor_repo_commit"
|
||||
- ps: |-
|
||||
echo "This CI isn't tested against master, and therefore, isn't guaranteed to work. Pull requests are welcome."
|
||||
echo "If it doesn't work and you'd rather not fix it, it's recommended to use GitHub Actions CI instead."
|
||||
Update-AppveyorBuild -Version "$env:appveyor_repo_commit"
|
||||
|
||||
image: # If this is modified, please also update the build script
|
||||
- Visual Studio 2019
|
||||
|
@ -38,9 +40,7 @@ build_script:
|
|||
on_success:
|
||||
- ps: |-
|
||||
If ($env:configuration -eq 'Release') {
|
||||
cd bin\$env:configuration
|
||||
7z u "$env:configuration.zip" ..\..\..\COPYING ..\..\..\README.md
|
||||
7z u "$env:configuration.zip" Cxbx.exe glew32.dll subhook.dll SDL2.dll
|
||||
7z u "$env:configuration.zip" cxbxr-debugger.exe capstone.dll cs_x86.dll
|
||||
cmake --install . --config $env:configuration --prefix artifacts
|
||||
7z a "$env:configuration.zip" ./artifacts/bin/*
|
||||
Get-ChildItem .\*.zip | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name }
|
||||
}
|
||||
|
|
|
@ -3,18 +3,13 @@ trigger:
|
|||
include:
|
||||
- '*'
|
||||
paths:
|
||||
exclude:
|
||||
- doc/*
|
||||
- doc/*/*
|
||||
- .github/*
|
||||
- .github/*/*
|
||||
- .appveyor.yml
|
||||
- .travis.yml
|
||||
- CONTRIBUTORS
|
||||
- COPYING
|
||||
- README.md
|
||||
- gen-msvc-project.bat
|
||||
- setup.bat
|
||||
exclude: # Azure Pipelines doesn't support recursive wildcards, see
|
||||
- '.github/*' # https://developercommunity.visualstudio.com/t/support-wildcards-in-trigger-path-filters-1/366363
|
||||
- '.github/*/*'
|
||||
- '*.bat'
|
||||
- '.appveyor.yml'
|
||||
- 'doc/*/*'
|
||||
- 'doc/*'
|
||||
|
||||
pr:
|
||||
branches:
|
||||
|
@ -22,61 +17,44 @@ pr:
|
|||
- '*'
|
||||
paths:
|
||||
exclude:
|
||||
- doc/*
|
||||
- doc/*/*
|
||||
- .github/*
|
||||
- .github/*/*
|
||||
- .appveyor.yml
|
||||
- .travis.yml
|
||||
- CONTRIBUTORS
|
||||
- COPYING
|
||||
- README.md
|
||||
- gen-msvc-project.bat
|
||||
- setup.bat
|
||||
- '.github/*'
|
||||
- '.github/*/*'
|
||||
- '*.bat'
|
||||
- '.appveyor.yml'
|
||||
- 'doc/*/*'
|
||||
- 'doc/*'
|
||||
|
||||
jobs:
|
||||
- job:
|
||||
pool:
|
||||
vmImage: windows-latest
|
||||
strategy:
|
||||
matrix:
|
||||
Release:
|
||||
configuration: Release
|
||||
Debug:
|
||||
configuration: Debug
|
||||
pool:
|
||||
vmImage: windows-latest
|
||||
strategy:
|
||||
matrix:
|
||||
Release:
|
||||
configuration: Release
|
||||
Debug:
|
||||
configuration: Debug
|
||||
|
||||
steps:
|
||||
- checkout: self
|
||||
submodules: recursive
|
||||
steps:
|
||||
- pwsh: |
|
||||
echo "This CI isn't tested against master, and therefore, isn't guaranteed to work. Pull requests are welcome."
|
||||
echo "If it doesn't work and you'd rather not fix it, it's recommended to use GitHub Actions CI instead."
|
||||
displayName: Third-Party CI Warning
|
||||
|
||||
- script: |
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. -G "Visual Studio 16 2019" -A Win32
|
||||
displayName: 'Before build'
|
||||
- checkout: self
|
||||
submodules: recursive
|
||||
|
||||
- script: cmake --build . --config %configuration%
|
||||
workingDirectory: build
|
||||
displayName: 'Build'
|
||||
- pwsh: cmake -B build -A Win32
|
||||
displayName: Before build
|
||||
|
||||
- task: CopyFiles@2
|
||||
displayName: 'Copy files to $(Build.ArtifactStagingDirectory)'
|
||||
condition: and(succeeded(), eq(variables['Agent.JobName'], 'Release'))
|
||||
inputs:
|
||||
Contents: |
|
||||
COPYING
|
||||
README.md
|
||||
build\bin\$(configuration)\Cxbx.exe
|
||||
build\bin\$(configuration)\glew32.dll
|
||||
build\bin\$(configuration)\subhook.dll
|
||||
build\bin\$(configuration)\SDL2.dll
|
||||
build\bin\$(configuration)\cxbxr-debugger.exe
|
||||
build\bin\$(configuration)\capstone.dll
|
||||
build\bin\$(configuration)\cx_x86.dll
|
||||
TargetFolder: '$(Build.ArtifactStagingDirectory)'
|
||||
flattenFolders: true
|
||||
- pwsh: cmake --build . --config $env:configuration
|
||||
workingDirectory: build
|
||||
displayName: Build
|
||||
|
||||
- publish: $(Build.ArtifactStagingDirectory)
|
||||
artifact: $(configuration)
|
||||
condition: and(succeeded(), eq(variables['Agent.JobName'], 'Release'))
|
||||
displayName: Publish artifact(s)
|
||||
- pwsh: cmake --install . --config $env:configuration --prefix $(Build.ArtifactStagingDirectory)
|
||||
workingDirectory: build
|
||||
condition: and(succeeded(), eq(variables['configuration'], 'Release'))
|
||||
displayName: Prepare artifacts
|
||||
|
||||
- publish: $(Build.ArtifactStagingDirectory)
|
||||
artifact: $(configuration)
|
||||
condition: and(succeeded(), eq(variables['configuration'], 'Release'))
|
||||
displayName: Publish artifacts
|
||||
|
|
|
@ -1,11 +1,3 @@
|
|||
# Custom for Visual Studio
|
||||
*.cs diff=csharp
|
||||
*.sln merge=union
|
||||
*.csproj merge=union
|
||||
*.vbproj merge=union
|
||||
*.fsproj merge=union
|
||||
*.dbproj merge=union
|
||||
|
||||
# Standard to msysgit
|
||||
*.doc diff=astextplain
|
||||
*.DOC diff=astextplain
|
||||
|
@ -18,5 +10,16 @@
|
|||
*.rtf diff=astextplain
|
||||
*.RTF diff=astextplain
|
||||
|
||||
[Cc][Mm]ake[Ll]ists.txt text=lf
|
||||
*.bat text=lf
|
||||
* text=auto
|
||||
|
||||
[Cc][Mm]ake[Ll]ists.txt text eol=lf
|
||||
*.bat text eol=lf
|
||||
*.c text eol=lf
|
||||
*.h text eol=lf
|
||||
*.cpp text eol=lf
|
||||
*.hpp text eol=lf
|
||||
*.unused-patches text eol=lf
|
||||
*.rc text eol=lf
|
||||
|
||||
# All module imports are vendor, remove them from linguist stats chart for accurate stats.
|
||||
import/* linguist-vendored
|
||||
|
|
|
@ -8,7 +8,38 @@ assignees: ''
|
|||
---
|
||||
|
||||
<!--
|
||||
Questions can be asked on Discord: https://discord.gg/26Xjx23
|
||||
If this is an issue specifically related to one game, please report it at https://github.com/Cxbx-Reloaded/game-compatibility
|
||||
Any emulation/general issues like crashes when a controller is connected, or regressions across several titles can be reported here.
|
||||
ISSUES NOT UTILIZING THE TEMPLATE BELOW WILL BE CLOSED!
|
||||
-->
|
||||
<!--
|
||||
Please read https://github.com/Cxbx-Reloaded/Cxbx-Reloaded/blob/master/README.md and https://github.com/Cxbx-Reloaded/Cxbx-Reloaded/wiki/Frequently-Asked-Questions-(FAQ) before opening an issue.
|
||||
Remember, the GitHub Issue Tracker is not the place to ask for support. You must use our forum on Discord https://discord.gg/26Xjx23 for that.
|
||||
Compatibility Reports should be submitted at the website: https://cxbx-reloaded.co.uk
|
||||
Otherwise, for any other emulation/general issues like crashes when a controller is connected, or regressions across several titles, feel free to report your issue here.
|
||||
-->
|
||||
|
||||
|
||||
## Quick summary
|
||||
<!--
|
||||
Please briefly describe what is not working correctly.
|
||||
-->
|
||||
|
||||
|
||||
## Details
|
||||
<!--
|
||||
Please describe the problem as accurately as possible.
|
||||
-->
|
||||
|
||||
|
||||
### System Configuration:
|
||||
<!--
|
||||
Please provide your system configuration
|
||||
-->
|
||||
* OS
|
||||
* CPU
|
||||
* GPU
|
||||
* etc.
|
||||
|
||||
### Additional Information (if any):
|
||||
<!--
|
||||
Anything else you deem to be important
|
||||
-->
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
# Labels are in alphabetical order.
|
||||
|
||||
cmake:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'CMake*'
|
||||
- '**/CMakeLists.txt'
|
||||
- '**/*.cmake'
|
||||
|
||||
cpu-emulation:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'src/devices/x86/**'
|
||||
|
||||
deployment:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- '*.yml'
|
||||
- '.github/workflows/CI.yml'
|
||||
|
||||
file-system:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'src/core/kernel/support/EmuFile*'
|
||||
|
||||
graphics:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'src/core/hle/D3D8/**'
|
||||
- 'src/core/hle/XGRAPHIC/**'
|
||||
- 'src/devices/video/**'
|
||||
- 'src/gui/*Video*'
|
||||
|
||||
HLE:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'src/core/hle/**'
|
||||
- 'src/core/kernel/**'
|
||||
|
||||
informational:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- '**/*Logging*'
|
||||
- '**/*Logging*/**'
|
||||
- '**/README.md'
|
||||
|
||||
input:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'src/common/input/**'
|
||||
- 'src/core/hle/XAPI/input/**'
|
||||
- 'src/devices/usb/**'
|
||||
- 'src/gui/controllers/**'
|
||||
- 'src/gui/*Input*'
|
||||
|
||||
kernel:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'src/core/kernel/**'
|
||||
|
||||
LLE:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'src/devices/**'
|
||||
|
||||
memory:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'src/core/kernel/memory-manager/**'
|
||||
|
||||
networking:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'src/core/hle/XONLINE/**'
|
||||
- 'src/devices/network/**'
|
||||
- 'src/gui/*Network*'
|
||||
|
||||
sound:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'src/common/audio/**'
|
||||
- 'src/core/hle/DSOUND/**'
|
||||
- 'src/core/hle/XACTENG/**'
|
||||
- 'src/devices/audio/**'
|
||||
- 'src/gui/*Audio*'
|
||||
|
||||
modules:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'import/**'
|
||||
|
||||
threading:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'src/core/kernel/support/EmuFS*'
|
||||
|
||||
timing:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'src/common/Timer*'
|
||||
|
||||
user interface:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'src/core/common/imgui/*'
|
||||
- 'src/gui/**'
|
||||
|
||||
xbdm:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- 'src/common/xbdm/**'
|
|
@ -3,117 +3,79 @@ name: GitHub CI
|
|||
on:
|
||||
push:
|
||||
paths-ignore:
|
||||
- '.github/CONTRIBUTING.md'
|
||||
- '.github/FUNDING.md'
|
||||
- '.github/ISSUE_TEMPLATE/*'
|
||||
- 'doc/*'
|
||||
- 'doc/*/*'
|
||||
- '.appveyor.yml'
|
||||
- '.azure-pipelines.yml'
|
||||
- '.travis.yml'
|
||||
- 'gen-msvc-project.bat'
|
||||
- 'setup.bat'
|
||||
- '.gitattributes'
|
||||
- '.github/*'
|
||||
- '.github/*_TEMPLATE/**'
|
||||
- '.gitignore'
|
||||
- '*.bat'
|
||||
- '*.yml'
|
||||
- 'doc/**'
|
||||
pull_request:
|
||||
paths-ignore:
|
||||
- '.github/CONTRIBUTING.md'
|
||||
- '.github/FUNDING.md'
|
||||
- '.github/ISSUE_TEMPLATE/*'
|
||||
- 'doc/*'
|
||||
- 'doc/*/*'
|
||||
- '.appveyor.yml'
|
||||
- '.azure-pipelines.yml'
|
||||
- '.travis.yml'
|
||||
- 'gen-msvc-project.bat'
|
||||
- 'setup.bat'
|
||||
- '.gitattributes'
|
||||
- '.github/*'
|
||||
- '.github/*_TEMPLATE/**'
|
||||
- '.gitignore'
|
||||
- '*.bat'
|
||||
- '*.yml'
|
||||
- 'doc/**'
|
||||
|
||||
jobs:
|
||||
build-windows:
|
||||
runs-on: ${{ matrix.os }}
|
||||
name: Build (Windows, ${{ matrix.configuration }}, VS${{ matrix.vsver }}) # runner.os doesn't work here
|
||||
runs-on: windows-${{ matrix.vsver }}
|
||||
env:
|
||||
POWERSHELL_TELEMETRY_OPTOUT: 1
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
configuration: [Release, Debug]
|
||||
vsver: [VS2019, VS2017]
|
||||
include:
|
||||
- vsver: VS2019
|
||||
os: windows-latest
|
||||
- vsver: VS2017 # TODO: Remove VS2017 once WINE supports VS2019 runtimes;
|
||||
os: windows-2016 # https://github.com/actions/virtual-environments/issues/68#issuecomment-602652021
|
||||
vsver: [2019]
|
||||
winver: [7]
|
||||
sdkver: [10.0.22621.0]
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Generate cmake files
|
||||
run: |
|
||||
mkdir build && cd build
|
||||
cmake .. -A Win32
|
||||
- name: Generate CMake files
|
||||
run: cmake -B build -A Win32,version=${{ matrix.sdkver }} -DCMAKE_SYSTEM_VERSION=${{ matrix.winver }} -DBUILD_CXBXR_DEBUGGER=ON
|
||||
- name: Build
|
||||
working-directory: build
|
||||
run: cmake --build . --config ${{ matrix.configuration }} -j $env:NUMBER_OF_PROCESSORS
|
||||
run: cmake --build build --config ${{ matrix.configuration }} -j $env:NUMBER_OF_PROCESSORS
|
||||
- name: Prepare artifacts
|
||||
if: matrix.configuration == 'Release'
|
||||
run: |
|
||||
robocopy . artifacts COPYING README.md /r:0 /w:0
|
||||
robocopy build\bin\${{ matrix.configuration }} artifacts `
|
||||
Cxbx.exe glew32.dll subhook.dll SDL2.dll `
|
||||
cxbxr-debugger.exe capstone.dll cs_x86.dll /r:0 /w:0
|
||||
If ($LastExitCode -le 7) { $LastExitCode = 0 }
|
||||
- uses: actions/upload-artifact@v1
|
||||
run: cmake --install build --config ${{ matrix.configuration }} --prefix artifacts
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: matrix.configuration == 'Release'
|
||||
with:
|
||||
name: CxbxReloaded-${{ matrix.configuration }}-${{ matrix.vsver }}
|
||||
path: artifacts
|
||||
name: CxbxReloaded-${{ matrix.configuration }}-VS${{ matrix.vsver }}
|
||||
path: artifacts/bin
|
||||
if-no-files-found: error
|
||||
|
||||
release:
|
||||
if: | # TODO: Remove develop once rebased
|
||||
if: |
|
||||
github.event.action != 'pull_request' &&
|
||||
(github.ref == 'refs/heads/develop' ||
|
||||
github.ref == 'refs/heads/master') &&
|
||||
github.ref == 'refs/heads/master' &&
|
||||
github.repository == 'Cxbx-Reloaded/Cxbx-Reloaded'
|
||||
needs: build-windows
|
||||
env:
|
||||
artifact_1: CxbxReloaded-Release-VS2019
|
||||
artifact_2: CxbxReloaded-Release-VS2017
|
||||
runs-on: windows-latest
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Download artifacts (1)
|
||||
uses: actions/download-artifact@v1
|
||||
- uses: actions/checkout@v4
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: ${{ env.artifact_1 }}
|
||||
- name: Download artifacts (2)
|
||||
uses: actions/download-artifact@v1
|
||||
with:
|
||||
name: ${{ env.artifact_2 }}
|
||||
- name: Prepare artifacts for release
|
||||
run: | # download-artifact doesn't download a zip, so rezip it
|
||||
echo "::set-env name=short_commit_sha::$(git rev-parse --short HEAD)"
|
||||
7z a -mx1 "$env:artifact_1.zip" ".\$env:artifact_1\*"
|
||||
7z a -mx1 "$env:artifact_2.zip" ".\$env:artifact_2\*"
|
||||
path: artifacts
|
||||
- name: Re-zip artifacts
|
||||
id: zip
|
||||
run: |
|
||||
for artifact in artifacts/*; do
|
||||
7z a ${artifact}.zip "./${artifact}/*"
|
||||
if [ $(stat -c %s ${artifact}.zip) -le 100000 ]; then
|
||||
echo "Error: Archive ${artifact}.zip too small!"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
echo "tag_name=CI-${GITHUB_SHA::7}" >> "$GITHUB_OUTPUT"
|
||||
- name: Create Release
|
||||
id: create_release
|
||||
uses: actions/create-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: CI-${{ env.short_commit_sha }}
|
||||
release_name: CI-${{ env.short_commit_sha }}
|
||||
prerelease: true
|
||||
- name: Upload Release Asset (1)
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: ${{ env.artifact_1 }}.zip
|
||||
asset_name: ${{ env.artifact_1 }}.zip
|
||||
asset_content_type: application/zip
|
||||
- name: Upload Release Asset (2)
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: ${{ env.artifact_2 }}.zip
|
||||
asset_name: ${{ env.artifact_2 }}.zip
|
||||
asset_content_type: application/zip
|
||||
run: gh release create ${{ steps.zip.outputs.tag_name }} artifacts/*.zip -p --target $GITHUB_SHA --title '${{ steps.zip.outputs.tag_name }}'
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
on:
|
||||
issues:
|
||||
types: opened
|
||||
|
||||
jobs:
|
||||
auto_close_issues:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Automatically close issues that don't follow the issue template
|
||||
uses: ergo720/auto-close-issues@v1
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
issue-close-message: "@${issue.user.login}: your issue has been automatically closed because it does not follow the issue template." # optional property
|
||||
closed-issues-label: "invalid" # optional property
|
|
@ -0,0 +1,13 @@
|
|||
name: Pull Request Manager
|
||||
|
||||
on: pull_request_target
|
||||
|
||||
jobs:
|
||||
pr_manager:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Labeler
|
||||
uses: actions/labeler@v5
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
sync-labels: true
|
|
@ -2,6 +2,10 @@
|
|||
[Bb]uild/
|
||||
[Bb]uild-*/
|
||||
|
||||
# CLion
|
||||
.idea/
|
||||
cmake-build-*/
|
||||
|
||||
# Visual Studio Cache
|
||||
.vs/
|
||||
|
||||
|
|
|
@ -1,23 +1,49 @@
|
|||
[submodule "import/subhook"]
|
||||
path = import/subhook
|
||||
url = https://github.com/Zeex/subhook.git
|
||||
url = https://github.com/Cxbx-Reloaded/subhook.git
|
||||
shallow = true
|
||||
[submodule "import/cs_x86"]
|
||||
path = import/cs_x86
|
||||
url = https://github.com/x1nixmzeng/cs_x86
|
||||
url = https://github.com/x1nixmzeng/cs_x86.git
|
||||
[submodule "import/XbSymbolDatabase"]
|
||||
path = import/XbSymbolDatabase
|
||||
url = https://github.com/Cxbx-Reloaded/XbSymbolDatabase
|
||||
url = https://github.com/Cxbx-Reloaded/XbSymbolDatabase.git
|
||||
[submodule "import/simpleini"]
|
||||
path = import/simpleini
|
||||
url = https://github.com/brofield/simpleini
|
||||
url = https://github.com/brofield/simpleini.git
|
||||
shallow = true
|
||||
[submodule "import/libtommath"]
|
||||
path = import/libtommath
|
||||
url = https://github.com/libtom/libtommath
|
||||
url = https://github.com/libtom/libtommath.git
|
||||
branch = master
|
||||
shallow = true
|
||||
[submodule "import/libtomcrypt"]
|
||||
path = import/libtomcrypt
|
||||
url = https://github.com/libtom/libtomcrypt
|
||||
url = https://github.com/libtom/libtomcrypt.git
|
||||
branch = master
|
||||
shallow = true
|
||||
[submodule "import/xxHash"]
|
||||
path = import/xxHash
|
||||
url = https://github.com/Cyan4973/xxHash.git
|
||||
branch = release
|
||||
shallow = true
|
||||
[submodule "import/imgui"]
|
||||
path = import/imgui
|
||||
url = https://github.com/ocornut/imgui.git
|
||||
shadow = true
|
||||
[submodule "import/SDL2"]
|
||||
path = import/SDL2
|
||||
url = https://github.com/SDL-mirror/SDL
|
||||
url = https://github.com/libsdl-org/SDL
|
||||
shallow = true
|
||||
[submodule "import/libusb"]
|
||||
path = import/libusb
|
||||
url = https://github.com/Cxbx-Reloaded/libusb
|
||||
branch = deadlock_fix
|
||||
shallow = true
|
||||
[submodule "import/nv2a_vsh_cpu"]
|
||||
path = import/nv2a_vsh_cpu
|
||||
url = https://github.com/abaire/nv2a_vsh_cpu.git
|
||||
[submodule "import/mio"]
|
||||
path = import/mio
|
||||
url = https://github.com/mandreyel/mio.git
|
||||
shadow = true
|
||||
|
|
20
.travis.yml
20
.travis.yml
|
@ -1,20 +0,0 @@
|
|||
language: cpp
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- os: windows
|
||||
env: configuration=Debug
|
||||
- os: windows
|
||||
env: configuration=Release
|
||||
|
||||
before_script:
|
||||
- if [ $TRAVIS_OS_NAME == 'windows' ]; then
|
||||
mkdir build;
|
||||
cd build;
|
||||
cmake .. -G "Visual Studio 15 2017" -A Win32;
|
||||
fi
|
||||
|
||||
script:
|
||||
- if [ $TRAVIS_OS_NAME == 'windows' ]; then
|
||||
cmake --build . --config $configuration;
|
||||
fi
|
273
CMakeLists.txt
273
CMakeLists.txt
|
@ -13,48 +13,36 @@ endif()
|
|||
|
||||
set(SUBHOOK_TESTS OFF)
|
||||
set(SUBHOOK_INSTALL OFF)
|
||||
add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/import/subhook")
|
||||
add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/import/subhook" EXCLUDE_FROM_ALL)
|
||||
|
||||
add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/import/XbSymbolDatabase")
|
||||
|
||||
# Not require since only include a header file
|
||||
#add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/import/simpleini")
|
||||
|
||||
add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/import/SDL2")
|
||||
add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/import/SDL2" EXCLUDE_FROM_ALL)
|
||||
|
||||
if(${CMAKE_GENERATOR} MATCHES "Visual Studio ([^9]|[9][0-9])")
|
||||
add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/import/cs_x86")
|
||||
endif()
|
||||
add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/import/mio" EXCLUDE_FROM_ALL)
|
||||
|
||||
# Cxbx-Reloaded projects
|
||||
set(CXBXR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/projects/libtom")
|
||||
|
||||
find_package(Git)
|
||||
|
||||
if(Git_FOUND)
|
||||
message("Git found: ${GIT_EXECUTABLE}")
|
||||
|
||||
execute_process(
|
||||
COMMAND git describe --always --tags --first-parent
|
||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE _GIT_VERSION
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
message("Git version: " ${_GIT_VERSION})
|
||||
else()
|
||||
set(_GIT_VERSION "unknown")
|
||||
endif()
|
||||
|
||||
# Appears to update whenever define has changed.
|
||||
configure_file(
|
||||
"${CXBXR_ROOT_DIR}/src/version.h.in" "${CXBXR_ROOT_DIR}/src/version.h" @ONLY
|
||||
NEWLINE_STYLE LF
|
||||
add_custom_target(misc-batch
|
||||
${CMAKE_COMMAND} -DTargetRunTimeDir=${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$<CONFIG>
|
||||
-P ${CXBXR_ROOT_DIR}/projects/misc/batch.cmake
|
||||
WORKING_DIRECTORY ${CXBXR_ROOT_DIR}
|
||||
)
|
||||
|
||||
#add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/projects/vsbc")
|
||||
# Custom CMake projects since some import libraries doesn't have it.
|
||||
|
||||
add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/projects/libtom")
|
||||
|
||||
add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/projects/imgui")
|
||||
|
||||
add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/projects/libusb")
|
||||
|
||||
set(nv2a_vsh_cpu_UNIT_TEST OFF)
|
||||
add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/import/nv2a_vsh_cpu" EXCLUDE_FROM_ALL)
|
||||
|
||||
# Split the files into group for which project is likely
|
||||
# going to be used for both header and source files.
|
||||
|
@ -66,39 +54,52 @@ configure_file(
|
|||
|
||||
# Common (GUI and Emulator)
|
||||
file (GLOB CXBXR_HEADER_COMMON
|
||||
"${CXBXR_ROOT_DIR}/src/common/AddressRanges.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/crypto/EmuDes.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/crypto/EmuRsa.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/crypto/EmuSha.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/crypto/LibRc4.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/CxbxDebugger.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/cxbxr.hpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/EmuEEPROM.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/Error.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/FilePaths.hpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/input/DInputKeyboardCodes.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/input/DInputKeyboardMouse.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/input/layout_xbox_controller.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/input/layout_xbox_device.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/input/LibusbDevice.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/input/InputDevice.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/input/InputManager.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/input/SdlJoystick.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/input/XInputPad.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/input/RawDevice.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/IPCHybrid.hpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/Logging.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/ReservedMemory.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/Settings.hpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/Timer.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/util/cliConfig.hpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/util/cliConverter.hpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/util/CPUID.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/util/crc32c.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/util/CxbxUtil.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/util/std_extend.hpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/util/strConverter.hpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/win32/AlignPosfix1.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/win32/AlignPrefix1.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/win32/EmuShared.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/win32/Mutex.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/win32/Threads.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/win32/Util.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/win32/WineEnv.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/xbdm/CxbxXbdm.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/xbe/Xbe.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/xbe/XbePrinter.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/xbox/Logging.hpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/xbox/Types.hpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/xbox_types.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/xdvdfs-tools/buffered_io.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/xdvdfs-tools/xdvdfs.h"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/XbConvert.h"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/XbD3D8Types.h"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/XAPI/Xapi.h"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/exports/EmuKrnlLogging.h"
|
||||
"${CXBXR_ROOT_DIR}/src/Cxbx.h"
|
||||
"${CXBXR_ROOT_DIR}/src/CxbxVersion.h"
|
||||
"${CXBXR_ROOT_DIR}/src/version.h"
|
||||
|
@ -109,33 +110,55 @@ file (GLOB CXBXR_HEADER_GUIv1
|
|||
"${CXBXR_ROOT_DIR}/src/common/input/Button.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/input/EmuDevice.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/input/InputWindow.h"
|
||||
"${CXBXR_ROOT_DIR}/src/gui/DbgConsole.h"
|
||||
"${CXBXR_ROOT_DIR}/src/gui/input/DlgDukeControllerConfig.h"
|
||||
"${CXBXR_ROOT_DIR}/src/gui/input/DlgLibusbControllerConfig.h"
|
||||
"${CXBXR_ROOT_DIR}/src/gui/input/DlgLightgunConfig.h"
|
||||
"${CXBXR_ROOT_DIR}/src/gui/input/DlgSBControllerConfig.h"
|
||||
"${CXBXR_ROOT_DIR}/src/gui/DlgAbout.h"
|
||||
"${CXBXR_ROOT_DIR}/src/gui/DlgAudioConfig.h"
|
||||
"${CXBXR_ROOT_DIR}/src/gui/DlgInputConfig.h"
|
||||
"${CXBXR_ROOT_DIR}/src/gui/DlgDukeControllerConfig.h"
|
||||
"${CXBXR_ROOT_DIR}/src/gui/DlgEepromConfig.h"
|
||||
"${CXBXR_ROOT_DIR}/src/gui/DlgLoggingConfig.h"
|
||||
"${CXBXR_ROOT_DIR}/src/gui/DlgNetworkConfig.h"
|
||||
"${CXBXR_ROOT_DIR}/src/gui/DlgVideoConfig.h"
|
||||
"${CXBXR_ROOT_DIR}/src/gui/ResCxbx.h"
|
||||
"${CXBXR_ROOT_DIR}/src/gui/Wnd.h"
|
||||
"${CXBXR_ROOT_DIR}/src/gui/WndMain.h"
|
||||
)
|
||||
|
||||
# Emulator (module)
|
||||
file (GLOB CXBXR_HEADER_EMU_IMPORT
|
||||
"${CXBXR_ROOT_DIR}/import/imgui/backends/imgui_impl_dx9.h"
|
||||
"${CXBXR_ROOT_DIR}/import/imgui/backends/imgui_impl_opengl3.h"
|
||||
"${CXBXR_ROOT_DIR}/import/imgui/backends/imgui_impl_win32.h"
|
||||
)
|
||||
file (GLOB CXBXR_HEADER_EMU
|
||||
"${CXBXR_ROOT_DIR}/src/common/audio/converter.hpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/audio/XADPCM.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/Timer.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/util/gloffscreen/glextensions.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/util/gloffscreen/gloffscreen.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/XADPCM.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/win32/Threads.h"
|
||||
"${CXBXR_ROOT_DIR}/src/core/common/imgui/audio.hpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/common/imgui/ui.hpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/common/imgui/settings.h"
|
||||
"${CXBXR_ROOT_DIR}/src/core/common/imgui/video.hpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/common/video/RenderBase.hpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/Direct3D9/CxbxPixelShaderTemplate.hlsl"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/Direct3D9/CxbxVertexShaderTemplate.hlsl"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/Direct3D9/CxbxVertexShaderPassthrough.hlsl"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/Direct3D9/Direct3D9.h"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/Direct3D9/FixedFunctionPixelShader.hlsl"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/Direct3D9/FixedFunctionPixelShader.hlsli"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/Direct3D9/FixedFunctionVertexShader.hlsl"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/Direct3D9/FixedFunctionVertexShaderState.hlsli"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/Direct3D9/PixelShader.h"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/Direct3D9/Shader.h"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/Direct3D9/VertexShader.h"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/Direct3D9/VertexShaderSource.h"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/Direct3D9/VertexShaderCache.h"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/Direct3D9/WalkIndexBuffer.h"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/FixedFunctionState.h"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/ResourceTracker.h"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/XbConvert.h"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/XbD3D8Logging.h"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/XbD3D8Types.h"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/XbPixelShader.h"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/XbPushBuffer.h"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/XbState.h"
|
||||
|
@ -147,21 +170,22 @@ file (GLOB CXBXR_HEADER_EMU
|
|||
"${CXBXR_ROOT_DIR}/src/core/hle/DSOUND/DirectSound/DirectSoundInline.hpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/DSOUND/DirectSound/DirectSoundLogging.hpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/DSOUND/DirectSound/DSStream_PacketManager.hpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/DSOUND/XbDSoundFuncs.hpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/DSOUND/XbDSoundLogging.hpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/DSOUND/XbDSoundTypes.h"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/DSOUND/common/XbInternalStruct.hpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/Intercept.hpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/Patches.hpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/XACTENG/XactEng.h"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/XAPI/Xapi.h"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/XAPI/XapiCxbxr.h"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/XGRAPHIC/XGraphic.h"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/XONLINE/XOnline.h"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/common/strings.hpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/exports/EmuKrnlAvModes.h"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/exports/EmuKrnlKe.h"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/exports/EmuKrnlKi.h"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/exports/EmuKrnlLogging.h"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/exports/EmuKrnlPs.hpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/init/CxbxKrnl.h"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/init/KrnlPatches.hpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/memory-manager/PhysicalMemory.h"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/memory-manager/PoolManager.h"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/memory-manager/VMManager.h"
|
||||
|
@ -169,9 +193,11 @@ file (GLOB CXBXR_HEADER_EMU
|
|||
"${CXBXR_ROOT_DIR}/src/core/kernel/support/EmuFile.h"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/support/EmuFS.h"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/support/EmuNtDll.h"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/support/NativeHandle.h"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/support/PatchRdtsc.hpp"
|
||||
"${CXBXR_ROOT_DIR}/src/devices/ADM1032Device.h"
|
||||
"${CXBXR_ROOT_DIR}/src/devices/EEPROMDevice.h"
|
||||
"${CXBXR_ROOT_DIR}/src/devices/EmuNVNet.h"
|
||||
"${CXBXR_ROOT_DIR}/src/devices/network/NVNetDevice.h"
|
||||
"${CXBXR_ROOT_DIR}/src/devices/LED.h"
|
||||
"${CXBXR_ROOT_DIR}/src/devices/MCPXDevice.h"
|
||||
"${CXBXR_ROOT_DIR}/src/devices/PCIBus.h"
|
||||
|
@ -200,38 +226,55 @@ file (GLOB CXBXR_HEADER_EMU
|
|||
"${CXBXR_ROOT_DIR}/src/devices/Xbox.h"
|
||||
)
|
||||
|
||||
# filter hlsl files into its own list
|
||||
# excluding hlsli file(s)
|
||||
set(CXBXR_HEADER_HLSL ${CXBXR_HEADER_EMU})
|
||||
list(FILTER CXBXR_HEADER_HLSL INCLUDE REGEX ".*\\.hlsl$")
|
||||
|
||||
# Common (GUI and Emulator)
|
||||
file (GLOB CXBXR_SOURCE_COMMON
|
||||
"${CXBXR_ROOT_DIR}/src/common/AddressRanges.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/crypto/EmuDes.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/crypto/EmuRsa.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/crypto/EmuSha.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/crypto/LibRc4.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/CxbxDebugger.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/cxbxr.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/EmuEEPROM.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/Error.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/FilePaths.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/input/DInputKeyboardMouse.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/input/InputDevice.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/input/InputManager.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/input/LibusbDevice.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/input/SdlJoystick.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/input/XInputPad.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/input/RawDevice.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/Logging.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/Settings.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/Timer.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/util/crc32c.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/util/cliConfig.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/util/cliConverter.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/util/CxbxUtil.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/util/hasher.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/win32/EmuShared.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/win32/InlineFunc.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/win32/IPCWindows.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/win32/Mutex.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/win32/Threads.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/win32/Util.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/win32/WineEnv.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/xbdm/CxbxXbdm.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/xbe/Xbe.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/xbe/XbePrinter.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/xbox/Logging.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/xbox/Types.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/xdvdfs-tools/buffered_io.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/xdvdfs-tools/xdvdfs.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/XbConvert.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/XAPI/Xapi.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/exports/EmuKrnlLogging.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/exports/EmuKrnlXbox.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/exports/EmuKrnlXc.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/exports/EmuKrnlXe.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/CxbxVersion.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/gui/DbgConsole.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/HighPerformanceGraphicsEnabler.c"
|
||||
)
|
||||
|
||||
|
@ -240,10 +283,13 @@ file (GLOB CXBXR_SOURCE_GUIv1
|
|||
"${CXBXR_ROOT_DIR}/src/common/input/Button.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/input/EmuDevice.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/input/InputWindow.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/gui/input/DlgDukeControllerConfig.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/gui/input/DlgLibusbControllerConfig.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/gui/input/DlgLightgunConfig.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/gui/input/DlgSBControllerConfig.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/gui/DlgAbout.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/gui/DlgAudioConfig.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/gui/DlgInputConfig.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/gui/DlgDukeControllerConfig.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/gui/DlgEepromConfig.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/gui/DlgLoggingConfig.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/gui/DlgNetworkConfig.cpp"
|
||||
|
@ -258,20 +304,33 @@ file (GLOB CXBXR_SOURCE_GUIv1
|
|||
file (GLOB CXBXR_KRNL_CPP
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/init/CxbxKrnl.cpp"
|
||||
)
|
||||
file (GLOB CXBXR_SOURCE_EMU_IMPORT
|
||||
"${CXBXR_ROOT_DIR}/import/imgui/backends/imgui_impl_dx9.cpp"
|
||||
"${CXBXR_ROOT_DIR}/import/imgui/backends/imgui_impl_opengl3.cpp"
|
||||
"${CXBXR_ROOT_DIR}/import/imgui/backends/imgui_impl_win32.cpp"
|
||||
)
|
||||
file (GLOB CXBXR_SOURCE_EMU
|
||||
"${CXBXR_KRNL_CPP}"
|
||||
"${CXBXR_ROOT_DIR}/HighPerformanceGraphicsEnabler.c"
|
||||
"${CXBXR_ROOT_DIR}/src/common/Timer.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/util/gloffscreen/glextensions.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/util/gloffscreen/gloffscreen_common.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/util/gloffscreen/gloffscreen_wgl.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/VerifyAddressRanges.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/win32/Threads.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/common/imgui/audio.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/common/imgui/ui.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/common/imgui/video.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/common/video/RenderBase.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/Direct3D9/Direct3D9.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/Direct3D9/PixelShader.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/Direct3D9/RenderStates.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/Direct3D9/Shader.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/Direct3D9/TextureStates.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/Direct3D9/VertexShader.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/Direct3D9/VertexShaderSource.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/Direct3D9/VertexShaderCache.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/Direct3D9/WalkIndexBuffer.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/FixedFunctionState.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/ResourceTracker.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/XbConvert.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/XbD3D8Logging.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/XbPixelShader.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/D3D8/XbPushBuffer.cpp"
|
||||
|
@ -286,10 +345,12 @@ file (GLOB CXBXR_SOURCE_EMU
|
|||
"${CXBXR_ROOT_DIR}/src/core/hle/DSOUND/DirectSound/DSStream_PacketManager.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/DSOUND/DirectSound/XFileMediaObject.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/DSOUND/XbDSoundLogging.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/DSOUND/common/XbInternalDSVoice.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/DSOUND/common/XbInternalStruct.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/Intercept.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/JVS/JVS.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/Patches.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/XACTENG/XactEng.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/XAPI/Xapi.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/hle/XGRAPHIC/XGraphic.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/exports/EmuKrnl.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/exports/EmuKrnlAv.cpp"
|
||||
|
@ -301,16 +362,12 @@ file (GLOB CXBXR_SOURCE_EMU
|
|||
"${CXBXR_ROOT_DIR}/src/core/kernel/exports/EmuKrnlKd.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/exports/EmuKrnlKe.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/exports/EmuKrnlKi.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/exports/EmuKrnlLogging.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/exports/EmuKrnlMm.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/exports/EmuKrnlNt.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/exports/EmuKrnlOb.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/exports/EmuKrnlPhy.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/exports/EmuKrnlPs.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/exports/EmuKrnlRtl.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/exports/EmuKrnlXbox.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/exports/EmuKrnlXc.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/exports/EmuKrnlXe.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/exports/KernelThunk.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/memory-manager/PhysicalMemory.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/memory-manager/PoolManager.cpp"
|
||||
|
@ -319,9 +376,13 @@ file (GLOB CXBXR_SOURCE_EMU
|
|||
"${CXBXR_ROOT_DIR}/src/core/kernel/support/EmuFile.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/support/EmuFS.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/support/EmuNtDll.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/support/NativeHandle.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/core/kernel/support/PatchRdtsc.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/devices/ADM1032Device.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/devices/Chihiro/JvsIO.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/devices/Chihiro/MediaBoard.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/devices/EEPROMDevice.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/devices/EmuNVNet.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/devices/network/NVNetDevice.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/devices/MCPXDevice.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/devices/PCIBus.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/devices/PCIDevice.cpp"
|
||||
|
@ -332,6 +393,8 @@ file (GLOB CXBXR_SOURCE_EMU
|
|||
"${CXBXR_ROOT_DIR}/src/devices/usb/OHCI.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/devices/usb/USBDevice.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/devices/usb/XidGamepad.cpp"
|
||||
|
||||
#NOTE: These files are direct includes inside nv2a.cpp file. If we comment them out, we will have compile errors.
|
||||
#"${CXBXR_ROOT_DIR}/src/devices/video/EmuNV2A_DEBUG.cpp"
|
||||
#"${CXBXR_ROOT_DIR}/src/devices/video/EmuNV2A_PBUS.cpp"
|
||||
#"${CXBXR_ROOT_DIR}/src/devices/video/EmuNV2A_PCOUNTER.cpp"
|
||||
|
@ -353,6 +416,7 @@ file (GLOB CXBXR_SOURCE_EMU
|
|||
#"${CXBXR_ROOT_DIR}/src/devices/video/EmuNV2A_PVIDEO.cpp"
|
||||
#"${CXBXR_ROOT_DIR}/src/devices/video/EmuNV2A_PVPE.cpp"
|
||||
#"${CXBXR_ROOT_DIR}/src/devices/video/EmuNV2A_USER.cpp"
|
||||
|
||||
"${CXBXR_ROOT_DIR}/src/devices/video/nv2a.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/devices/video/nv2a_debug.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/devices/video/nv2a_psh.cpp"
|
||||
|
@ -362,39 +426,84 @@ file (GLOB CXBXR_SOURCE_EMU
|
|||
"${CXBXR_ROOT_DIR}/src/devices/video/swizzle.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/devices/x86/EmuX86.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/devices/Xbox.cpp"
|
||||
# Temporary usage for need ReserveAddressRanges func with cxbx.exe's emulation.
|
||||
"${CXBXR_ROOT_DIR}/src/common/ReserveAddressRanges.cpp"
|
||||
)
|
||||
|
||||
|
||||
option(BUILD_CXBXR_DEBUGGER "Build cxbxr-debugger tool (with cheat table support)")
|
||||
if(BUILD_CXBXR_DEBUGGER)
|
||||
message(DEPRECATION "The Cxbxr-Debugger tool will eventually be removed from the upstream branch.")
|
||||
endif()
|
||||
|
||||
add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/projects/cxbx")
|
||||
|
||||
# Issues with compile (the same with develop branch) and
|
||||
# for some reason did not put the files into virtual folder?
|
||||
# Might need to put the list in the source folder for workaround fix.
|
||||
if(${CMAKE_GENERATOR} MATCHES "Visual Studio ([^9]|[9][0-9])")
|
||||
#add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/projects/debugger")
|
||||
add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/src/CxbxDebugger")
|
||||
endif()
|
||||
add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/projects/cxbxr-ldr")
|
||||
|
||||
add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/projects/cxbxr-emu")
|
||||
|
||||
set(cxbxr_INSTALL_files "COPYING" "README.md")
|
||||
|
||||
# Cxbx-Reloaded project with third-party libraries
|
||||
set_target_properties(cxbx cxbxr-ldr cxbxr-emu misc-batch SDL2 subhook libXbSymbolDatabase libtommath libtomcrypt imgui libusb
|
||||
PROPERTIES FOLDER Cxbx-Reloaded
|
||||
)
|
||||
|
||||
set_target_properties(nv2a_vsh_emulator nv2a_vsh_disassembler nv2a_vsh_cpu
|
||||
PROPERTIES FOLDER Cxbx-Reloaded/nv2a_vsh
|
||||
)
|
||||
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
# Configure startup project
|
||||
set_property(DIRECTORY "${CMAKE_CURRENT_LIST_DIR}" PROPERTY VS_STARTUP_PROJECT cxbx)
|
||||
endif()
|
||||
|
||||
if(${CMAKE_GENERATOR} MATCHES "Visual Studio ([^9]|[9][0-9])")
|
||||
# Refuse to exclude due to install is not set to optional
|
||||
#set_target_properties(cstool
|
||||
# PROPERTIES EXCLUDE_FROM_ALL TRUE
|
||||
#)
|
||||
set_target_properties(Tests_cs_x86
|
||||
PROPERTIES EXCLUDE_FROM_ALL TRUE
|
||||
)
|
||||
# Check if generator is Visual Studio then enable Cxbxr-Debugger project.
|
||||
# Since C# is currently supported with Visual Studio for now.
|
||||
if(${CMAKE_GENERATOR} MATCHES "Visual Studio ([^9]|[9][0-9])" AND BUILD_CXBXR_DEBUGGER)
|
||||
# Issues with compile (the same with develop branch) and
|
||||
# for some reason did not put the files into virtual folder?
|
||||
# Might need to put the list in the source folder for workaround fix.
|
||||
add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/src/CxbxDebugger")
|
||||
|
||||
# Cxbx-Debugger project with third-party libraries
|
||||
set_target_properties(cxbxr-debugger cs_x86 Tests_cs_x86 capstone-shared cstool
|
||||
PROPERTIES FOLDER Cxbx-Reloaded/debugger
|
||||
)
|
||||
set_target_properties(Tests_cs_x86
|
||||
PROPERTIES EXCLUDE_FROM_ALL TRUE
|
||||
)
|
||||
|
||||
# Cxbx-Debugger project with third-party libraries
|
||||
set_target_properties(cxbxr-debugger cs_x86 Tests_cs_x86 capstone-shared
|
||||
PROPERTIES FOLDER Cxbx-Reloaded/debugger
|
||||
)
|
||||
endif()
|
||||
|
||||
# Cxbx-Reloaded project with third-party libraries
|
||||
set_target_properties(cxbx subhook XbSymbolDatabase libtommath libtomcrypt
|
||||
PROPERTIES FOLDER Cxbx-Reloaded
|
||||
install(FILES ${cxbxr_INSTALL_files}
|
||||
DESTINATION bin
|
||||
)
|
||||
|
||||
# Copy HLSL files to the output directory, which are loaded at runtime
|
||||
set(CXBXR_HLSL_FILES ${CXBXR_HEADER_EMU})
|
||||
list(FILTER CXBXR_HLSL_FILES INCLUDE REGEX ".*/src/core/hle/D3D8/Direct3D9/[^/]+\.hlsli?")
|
||||
add_custom_command(
|
||||
TARGET misc-batch POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$<CONFIG>/hlsl
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CXBXR_HLSL_FILES} "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$<CONFIG>/hlsl"
|
||||
# These files can be edited.
|
||||
# Create backup copies for convenience of restoring original shader behaviour.
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$<CONFIG>/hlsl/backup
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CXBXR_HLSL_FILES} "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$<CONFIG>/hlsl/backup"
|
||||
)
|
||||
install(DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$<CONFIG>/hlsl DESTINATION bin)
|
||||
|
||||
set(cxbxr_GLEW_DLL "${CMAKE_SOURCE_DIR}/import/glew-2.0.0/bin/Release/Win32/glew32.dll")
|
||||
|
||||
install(PROGRAMS ${cxbxr_GLEW_DLL}
|
||||
DESTINATION bin
|
||||
)
|
||||
|
||||
install(PROGRAMS $<TARGET_FILE_DIR:cxbx>/${CMAKE_SHARED_LIBRARY_PREFIX}subhook${CMAKE_SHARED_LIBRARY_SUFFIX}
|
||||
DESTINATION bin
|
||||
)
|
||||
|
||||
install(PROGRAMS $<TARGET_FILE_DIR:cxbx>/${CMAKE_SHARED_LIBRARY_PREFIX}SDL2${CMAKE_SHARED_LIBRARY_SUFFIX}
|
||||
DESTINATION bin
|
||||
)
|
||||
|
|
13
CONTRIBUTORS
13
CONTRIBUTORS
|
@ -7,7 +7,7 @@ Cxbx was initiated by Caustik. Dxbx was initiated by shadowtj.
|
|||
|
||||
The following contributors are grouped per project and listed in alphabetical order,
|
||||
based on sources like https://github.com/Cxbx-Reloaded/Cxbx-Reloaded/graphs/contributors ,
|
||||
http://www.caustik.com/cxbx/about.htm , http://emulation.gametechwiki.com/index.php/Cxbx ,
|
||||
http://www.caustik.com/cxbx/about.htm , https://emulation.gametechwiki.com/index.php/Cxbx ,
|
||||
and https://github.com/PatrickvL/Dxbx/graphs/contributors .
|
||||
|
||||
|
||||
|
@ -34,7 +34,7 @@ Ernegien (Mike Davis)
|
|||
ergo720
|
||||
faha223 (Fred Hallock)
|
||||
Fisherman166
|
||||
gandalfthewhite19890404
|
||||
gandalfthewhite19890404
|
||||
gellis713
|
||||
ggKismet
|
||||
GXTX (wutno)
|
||||
|
@ -46,14 +46,15 @@ JayFoxRox (Jannik Vogel)
|
|||
literalmente-game
|
||||
Luca1991 (Luca D'Amico) [Luca91]
|
||||
LukeUsher (Luke Usher) [SoullessSentinel]
|
||||
Margen67
|
||||
Margen67
|
||||
NZJenkins
|
||||
PatrickvL (Patrick van Logchem)
|
||||
phire (Scott Mansell)
|
||||
RadWolfie
|
||||
revel8n
|
||||
Silent (CookiePLMonster)
|
||||
StrikerX3 (Ivan Roberto de Oliveira)
|
||||
TotalCaesar659
|
||||
TotalCaesar659
|
||||
Voxel9 (Voxel)
|
||||
x1nixmzeng
|
||||
|
||||
|
@ -61,7 +62,7 @@ x1nixmzeng
|
|||
Cxbx-Reloaded Supporters:
|
||||
|
||||
Cedric Wilson
|
||||
Cisco Martinez
|
||||
Cisco Martinez
|
||||
Cody Dale Barton
|
||||
Elijah Chondropoulos
|
||||
Jacob Kelly
|
||||
|
@ -72,7 +73,7 @@ Kenneth Edmonds
|
|||
Kyle Lenhardt
|
||||
Manny Calavera
|
||||
Mark Knasiak
|
||||
Marko V.
|
||||
Marko V.
|
||||
Matt Coady
|
||||
Roman Guivan
|
||||
Taylor Stock
|
||||
|
|
78
README.md
78
README.md
|
@ -1,45 +1,57 @@
|
|||
# Cxbx-Reloaded - Original Xbox Emulator
|
||||
[](https://img.shields.io/badge/License-GPL%20v2-blue.svg)
|
||||
[](https://github.com/Cxbx-Reloaded/Cxbx-Reloaded/actions?query=workflow%3A%22GitHub+CI%22)
|
||||
[](https://Cxbx-Reloaded.visualstudio.com/Cxbx-Reloaded/_build/latest?definitionId=7&branchName=develop)
|
||||
[](https://github.com/Cxbx-Reloaded/Cxbx-Reloaded/blob/master/COPYING)
|
||||
[](https://github.com/Cxbx-Reloaded/Cxbx-Reloaded/actions?query=event%3Apush+workflow%3A%22GitHub+CI%22)
|
||||
[](https://discord.gg/26Xjx23)
|
||||
|
||||
Cxbx-Reloaded is an emulator for running Microsoft Xbox (and eventually, Chihiro) games on Microsoft Windows.
|
||||
Cxbx-Reloaded is an emulator for running Microsoft Xbox (and eventually, Chihiro) games on Microsoft Windows and Wine.
|
||||
|
||||
## System Requirements
|
||||
### Minimum
|
||||
* OS: Windows 7+ x64. 32-bit is not supported.
|
||||
* OS: Windows 7+ x64, or x86-64 Linux with Wine. 32-bit is not supported.
|
||||
* MacOS with Wine is known not to work, and BSD-based systems are untested.
|
||||
* Also note that Wine is relatively unstable, and it might break compatibility with Cxbx-Reloaded at any time without warning.
|
||||
* GPU: Direct3D 9.0c with Pixel Shader Model 2.x, and Vertex Shader Model 3.0.
|
||||
|
||||
### Prerequisites
|
||||
* [32-bit (x86) Visual C++ 2019 Redistributable](https://aka.ms/vs/16/release/vc_redist.x86.exe)
|
||||
## Prerequisites
|
||||
### Windows
|
||||
* [32-bit (x86) Visual C++ 2022 Redistributable](https://aka.ms/vs/17/release/vc_redist.x86.exe)
|
||||
* [Npcap *(used for network emulation)*](https://nmap.org/npcap/#download)
|
||||
* Make sure to enable winpcap compatibility mode!
|
||||
* Make sure to enable winpcap compatibility mode.
|
||||
* [WinUSB compliant driver](https://github.com/libusb/libusb/wiki/Windows#Driver_Installation)
|
||||
* *Optional, only needed for USB pass-through of original Xbox and Steel Battalion controllers.*
|
||||
|
||||
### Wine
|
||||
**Please use the latest stable release version of Wine. If it does not work for you, then roll back to Wine 7.0 which is the last known working version.**<br/>
|
||||
**There also exists this known [issue](https://github.com/Cxbx-Reloaded/Cxbx-Reloaded/issues/2314) which currently prevents savings in some games with the most recent Wine 6.8 and later versions.**
|
||||
* Winetricks
|
||||
* `vcrun2019`
|
||||
* Requires the latest winetricks script.
|
||||
* `d3dcompiler_47`
|
||||
* This may be subject to change.
|
||||
* Winpcap is built-in, no installation is required.
|
||||
|
||||
## Automated Builds
|
||||
Cxbx-Reloaded doesn't currently have stable builds, but you can obtain pre-release builds from the Releases tab, or the links below:
|
||||
Cxbx-Reloaded doesn't currently have stable builds, but you can obtain pre-release builds from our official website's download page, or the links below:
|
||||
|
||||
* **[Release Builds](https://github.com/Cxbx-Reloaded/Cxbx-Reloaded/releases)**
|
||||
* **WINE users will need to use `CxbxReloaded-Release-VS2017.zip` for it to run correctly.**
|
||||
* **[Release Builds](https://cxbx-reloaded.co.uk/download)**
|
||||
* *[Full build history](https://github.com/Cxbx-Reloaded/Cxbx-Reloaded/actions?query=workflow%3A%22GitHub+CI%22)*
|
||||
|
||||
## Compatibility
|
||||
Cxbx-Reloaded has a [compatibility list](https://github.com/Cxbx-Reloaded/game-compatibility#cxbx-reloaded-game-compatibility-project).
|
||||
Cxbx-Reloaded has a [compatibility list](https://cxbx-reloaded.co.uk/compatibility).
|
||||
|
||||
If you have something to report on a title, please create or update the issue for it there.
|
||||
|
||||
Please read the [Readme file](https://github.com/Cxbx-Reloaded/game-compatibility/blob/master/README.md) first!
|
||||
If you would like to submit compatibility reports, please request permission in our Discord server.
|
||||
|
||||
## Bug Reports
|
||||
Game or software specific issues can be reported in the [compatibility list](https://github.com/Cxbx-Reloaded/game-compatibility#cxbx-reloaded-game-compatibility-project).
|
||||
Game or software specific issues can be reported in the [compatibility website](https://cxbx-reloaded.co.uk/compatibility).
|
||||
|
||||
For emulation issues that are not specific to any single piece of software, a bug report can be submitted at [the Cxbx-Reloaded issue tracker](https://github.com/Cxbx-Reloaded/Cxbx-Reloaded/issues).
|
||||
|
||||
Make sure bug reports contain:
|
||||
<!--Make sure to follow the issue template and that it contains:
|
||||
* The build tested with, error message displayed (if any)
|
||||
* Screenshots
|
||||
* Xbe dump (created via `Edit > Dump Xbe Info To > File`)
|
||||
* Kernel Debug log (created when running a game with `View > Debug Output (Kernel) > File` selected).
|
||||
* **You can copy and paste any popup messages. However, please keep it clean by pasting and trimming down to only the message itself.**
|
||||
* Screenshots
|
||||
* Optional unless there are graphic bugs for reference.
|
||||
|
||||
**Failure to follow the template will auto close your ticket.**-->
|
||||
|
||||
## Additional information
|
||||
Cxbx-Reloaded has a [wiki](https://github.com/Cxbx-Reloaded/Cxbx-Reloaded/wiki) containing various subjects and background information.
|
||||
|
@ -51,19 +63,18 @@ We welcome contributions, large and small.
|
|||
|
||||
If you want to do some coding, be sure to read the [Developer notes](https://github.com/Cxbx-Reloaded/Cxbx-Reloaded/wiki/Developer-notes).
|
||||
|
||||
**IMPORTANT: Pull-Requests containing code derived from XQEMU will _not_ be approved until an agreement is reached to make work mutually beneficial. this includes updates to existing XQEMU derived code. We should not/will not become a hostile fork.**
|
||||
**IMPORTANT: Pull-Requests containing code derived from XQEMU will _not_ be approved until an agreement is reached to make work mutually beneficial. This includes updates to existing XQEMU derived code. We should not/will not become a hostile fork.**
|
||||
|
||||
Please contact us before you start working on something, so we can make sure your work is going to be accepted once finished.
|
||||
|
||||
### Main Prerequisites
|
||||
1. [Git for Windows](https://git-scm.com)
|
||||
2. [CMake](https://cmake.org)
|
||||
* Some IDEs already have CMake support, so this is optional.
|
||||
* Some IDEs already have CMake support, this is optional.
|
||||
|
||||
### Fetching the code
|
||||
1. Run the following command in the command line:
|
||||
|
||||
`git clone --recurse-submodules https://github.com/Cxbx-Reloaded/Cxbx-Reloaded.git`
|
||||
<br>`git clone --recurse-submodules https://github.com/Cxbx-Reloaded/Cxbx-Reloaded.git`
|
||||
* Please note the `--recurse-submodules` parameter. This is required to fetch submodules.
|
||||
* If Cxbx-Reloaded was checked out without submodules, they can be updated/fetched with the following command:
|
||||
|
||||
|
@ -72,12 +83,13 @@ Please contact us before you start working on something, so we can make sure you
|
|||
### Compiling
|
||||
|
||||
#### Windows
|
||||
**NOTE:** Don't open `CMakeLists.txt` from Visual Studio, as it won't generate files in the `build` directory.
|
||||
Don't open `CMakeLists.txt` from Visual Studio, as it won't generate files in the `build` directory.
|
||||
|
||||
##### Prerequisites
|
||||
1. [Visual Studio](https://visualstudio.microsoft.com/downloads/) 2017 or later
|
||||
1. [Visual Studio](https://visualstudio.microsoft.com/downloads/) 2022
|
||||
* C++ and C# desktop development
|
||||
* Windows Universal CRT SDK
|
||||
* Windows 11 SDK (10.0.22621.0) or later
|
||||
* C++ CMake tools for Windows
|
||||
* *Optional if CMake is installed*
|
||||
* [Microsoft Child Process Debugging Power Tool](https://marketplace.visualstudio.com/items?itemName=vsdbgplat.MicrosoftChildProcessDebuggingPowerTool)
|
||||
|
@ -85,11 +97,11 @@ Please contact us before you start working on something, so we can make sure you
|
|||
##### Generate Visual Studio files
|
||||
1. If you don't have CMake installed, open `___ Native Tools Command Prompt for VS 20##`.
|
||||
2. `cd` to the Cxbx-Reloaded directory.
|
||||
3. Run these commands.
|
||||
1. `mkdir build & cd build`
|
||||
2. `cmake .. -G "Visual Studio 16 2019" -A Win32`
|
||||
* Visual Studio 2019 16.1 or later has CMake 3.14 bundled, and is required for the Visual Studio 2019 generator.
|
||||
* Use `cmake .. -G "Visual Studio 15 2017" -A Win32` for Visual Studio 2017.
|
||||
3. Run the following command: `cmake -B build -G "Visual Studio 17 2022" -A Win32` \
|
||||
**NOTES**:
|
||||
* VS2022 17.0 or later is required.
|
||||
* To build the Cxbx-Reloaded Debugger tool, add the variable `-DBUILD_CXBXR_DEBUGGER=ON` to the above command.
|
||||
* _This debugger tool is deprecated and will be eventually removed, please use the Visual Studio debugger instead._
|
||||
4. Open `Cxbx-Reloaded.sln` from the `build` directory.
|
||||
5. Select the Release configuration, then click Build.
|
||||
* Debug builds are **significantly slower, and only for developers**.
|
||||
|
@ -104,3 +116,5 @@ You can support [Luke Usher](https://github.com/LukeUsher), initiator of Cxbx-Re
|
|||
* All contributors to the original Cxbx and [Dxbx](https://github.com/PatrickvL/Dxbx) projects. Without them Cxbx-Reloaded would not exist at all.
|
||||
* [XQEMU](https://github.com/xqemu/xqemu) - While the majority of Cxbx-R is our own work (Kernel, HLE, etc), the NV2A LLE and NVNet implementation are primarily the work of the XQEMU developers.
|
||||
* [XboxDev](https://github.com/xboxdev) - Providing Xbox hardware research & useful tooling.
|
||||
* [XbSymbolDatabase](https://github.com/Cxbx-Reloaded/XbSymbolDatabase) - Providing support to detect symbols across XDK builds from reverse engineered retail titles.
|
||||
* [Xbox Kernel Test Suite](https://github.com/Cxbx-Reloaded/xbox_kernel_test_suite) - Making accurate tests on hardware to compare against cxbxr's kernel implementation.
|
||||
|
|
|
@ -47,6 +47,9 @@ GOTO :helpInfo
|
|||
)
|
||||
|
||||
:: Check second arg (Visual Studio version)
|
||||
IF "%2"=="2022" (
|
||||
SET msvc_compiler=Visual Studio 17 2022
|
||||
)
|
||||
IF "%2"=="2019" (
|
||||
SET msvc_compiler=Visual Studio 16 2019
|
||||
)
|
||||
|
@ -54,7 +57,7 @@ IF "%2"=="2017" (
|
|||
SET msvc_compiler=Visual Studio 15 2017
|
||||
)
|
||||
IF "%2"=="" (
|
||||
SET msvc_compiler=Visual Studio 15 2017
|
||||
SET msvc_compiler=Visual Studio 16 2019
|
||||
)
|
||||
IF NOT DEFINED msvc_compiler (
|
||||
GOTO :helpInfo
|
||||
|
@ -100,8 +103,9 @@ ECHO - ARM
|
|||
ECHO - ARM64
|
||||
ECHO ---
|
||||
ECHO arg2
|
||||
ECHO - 2017
|
||||
ECHO - 2022
|
||||
ECHO - 2019
|
||||
ECHO - 2017
|
||||
PAUSE
|
||||
GOTO :end
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit c7b8b49ef8691ac85ad18298468f7e4a616290ed
|
||||
Subproject commit fa24d868ac2f8fd558e4e914c9863411245db8fd
|
|
@ -1 +1 @@
|
|||
Subproject commit 0f2794cac610fad4f1955241ef43e6254fd11205
|
||||
Subproject commit 774111351210e6f340246d6fb32741b09708f381
|
|
@ -1 +1 @@
|
|||
Subproject commit 7c491b6ef7e49c7f35dcdd39f99f1f5943e48e9e
|
||||
Subproject commit f8a95b7afa963c90b01a9e7cd758346f95c90f50
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 8ced41570e4692b0d556503683ae45f92416f5f1
|
|
@ -0,0 +1 @@
|
|||
Subproject commit cf178f1fac38426990425cc034f7d4b8c9e1e388
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 3f86a95c0784d73ce6815237ec33ed25f233b643
|
|
@ -0,0 +1 @@
|
|||
Subproject commit ead0af5dee49e408c005151393f8a7dbcd27026c
|
|
@ -1 +1 @@
|
|||
Subproject commit 29cb47ea7674b36cf2b742c11cf2568add1f47fc
|
||||
Subproject commit 83d4e1ebef3588fae48b69a7352cc21801cb70bc
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 94e5f23e736f2bb67ebdf90727353e65344f9fc0
|
|
@ -2,7 +2,7 @@ cmake_minimum_required (VERSION 3.12)
|
|||
project(cxbx)
|
||||
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
# Suppress extra stuff from generated solution
|
||||
set(CMAKE_SUPPRESS_REGENERATION true)
|
||||
|
@ -12,16 +12,13 @@ include_directories(
|
|||
"${CXBXR_ROOT_DIR}/src/common"
|
||||
"${CXBXR_ROOT_DIR}/src/common/Win32"
|
||||
"${CXBXR_ROOT_DIR}/import/OpenXDK/include"
|
||||
"${CXBXR_ROOT_DIR}/import/DirectX9/include"
|
||||
"${CXBXR_ROOT_DIR}/import/distorm/include"
|
||||
"${CXBXR_ROOT_DIR}/import/glew-2.0.0/include"
|
||||
"${CXBXR_ROOT_DIR}/import/subhook"
|
||||
"${CXBXR_ROOT_DIR}/import/DirectX9/include"
|
||||
"${CXBXR_ROOT_DIR}/import/XbSymbolDatabase"
|
||||
"${CXBXR_ROOT_DIR}/import/libusb/libusb"
|
||||
"${CXBXR_ROOT_DIR}/import/simpleini"
|
||||
"${CXBXR_ROOT_DIR}/import/libtommath"
|
||||
"${CXBXR_ROOT_DIR}/import/libtomcrypt/src/headers"
|
||||
"${CXBXR_ROOT_DIR}/import/winpcap/Include"
|
||||
"${CXBXR_ROOT_DIR}/import/SDL2/include"
|
||||
"${CXBXR_ROOT_DIR}/import/xxHash"
|
||||
)
|
||||
|
||||
link_directories(
|
||||
|
@ -45,8 +42,11 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
|||
LTC_NO_PRNGS
|
||||
LTC_NO_MISC
|
||||
LTC_NO_PROTOTYPES
|
||||
|
||||
# Enable Chihiro work
|
||||
CHIHIRO_WORK
|
||||
)
|
||||
|
||||
|
||||
# Reference: https://docs.microsoft.com/en-us/cpp/build/reference/compiler-options-listed-alphabetically
|
||||
add_compile_options(
|
||||
# Catch synchronous (C++) exceptions only
|
||||
|
@ -68,28 +68,31 @@ XXH_INLINE_ALL
|
|||
)
|
||||
|
||||
file (GLOB RESOURCES
|
||||
|
||||
|
||||
"${CXBXR_ROOT_DIR}/CONTRIBUTORS"
|
||||
"${CXBXR_ROOT_DIR}/COPYING"
|
||||
"${CXBXR_ROOT_DIR}/README.md"
|
||||
"${CXBXR_ROOT_DIR}/resource/.editorconfig"
|
||||
"${CXBXR_ROOT_DIR}/resource/Cxbx.rc"
|
||||
"${CXBXR_ROOT_DIR}/resource/Cxbx-R.ico"
|
||||
"${CXBXR_ROOT_DIR}/resource/Logo.bmp"
|
||||
"${CXBXR_ROOT_DIR}/resource/Logo-License-CC4.bmp"
|
||||
"${CXBXR_ROOT_DIR}/src/gui/resource/.editorconfig"
|
||||
"${CXBXR_ROOT_DIR}/src/gui/resource/Cxbx.rc"
|
||||
"${CXBXR_ROOT_DIR}/src/gui/resource/Cxbx-R.ico"
|
||||
"${CXBXR_ROOT_DIR}/src/gui/resource/Logo.bmp"
|
||||
"${CXBXR_ROOT_DIR}/src/gui/resource/Logo-License-CC4.bmp"
|
||||
"${CXBXR_ROOT_DIR}/src/gui/resource/ResCxbx.h"
|
||||
"${CXBXR_ROOT_DIR}/src/.editorconfig"
|
||||
)
|
||||
|
||||
source_group(TREE ${CXBXR_ROOT_DIR}/src PREFIX header FILES
|
||||
${CXBXR_HEADER_GUIv1}
|
||||
${CXBXR_HEADER_COMMON}
|
||||
${CXBXR_HEADER_EMU}
|
||||
)
|
||||
|
||||
source_group(TREE ${CXBXR_ROOT_DIR}/src PREFIX source FILES
|
||||
source_group(TREE ${CXBXR_ROOT_DIR}/import PREFIX import FILES
|
||||
${CXBXR_SOURCE_EMU_IMPORT}
|
||||
)
|
||||
|
||||
source_group(TREE ${CXBXR_ROOT_DIR}/src PREFIX source FILES
|
||||
${CXBXR_SOURCE_GUIv1}
|
||||
${CXBXR_SOURCE_COMMON}
|
||||
${CXBXR_SOURCE_EMU}
|
||||
)
|
||||
|
||||
source_group(TREE ${CXBXR_ROOT_DIR} FILES ${RESOURCES})
|
||||
|
@ -97,10 +100,8 @@ source_group(TREE ${CXBXR_ROOT_DIR} FILES ${RESOURCES})
|
|||
add_executable(cxbx WIN32 ${RESOURCES}
|
||||
${CXBXR_HEADER_GUIv1}
|
||||
${CXBXR_HEADER_COMMON}
|
||||
${CXBXR_HEADER_EMU}
|
||||
${CXBXR_SOURCE_GUIv1}
|
||||
${CXBXR_SOURCE_COMMON}
|
||||
${CXBXR_SOURCE_EMU}
|
||||
${CXBXR_GIT_VERSION_H}
|
||||
)
|
||||
|
||||
|
@ -110,25 +111,17 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
|||
# Reference: https://docs.microsoft.com/en-us/cpp/build/reference/linker-options
|
||||
set_target_properties(cxbx PROPERTIES
|
||||
LINK_FLAGS "
|
||||
/INCREMENTAL:NO
|
||||
/LARGEADDRESSAWARE
|
||||
/FIXED
|
||||
/SAFESEH:NO
|
||||
/DYNAMICBASE:NO
|
||||
/BASE:0x10000
|
||||
/STACK:65536,65536
|
||||
/NODEFAULTLIB:libcmt
|
||||
/DELAYLOAD:wpcap.dll
|
||||
/NODEFAULTLIB:libcmt \
|
||||
"
|
||||
LINK_FLAGS_RELEASE "
|
||||
/LTCG
|
||||
/DEBUG
|
||||
/LTCG \
|
||||
/DEBUG \
|
||||
"
|
||||
)
|
||||
|
||||
# Reference: https://docs.microsoft.com/en-us/cpp/build/reference/compiler-options-listed-alphabetically
|
||||
# /Zi = create a PDB file without affecting optimization
|
||||
# /Ob2 = Controls inline expansion of functions.
|
||||
# /Ob3 = Controls inline expansion of functions.
|
||||
# /Oi = Generate intrinsic functions
|
||||
# /Ot = In favor of using fast code than small code
|
||||
# /GL = Whole program optimization
|
||||
|
@ -137,19 +130,19 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
|||
# /Qpar = Enable automatic parallelize loops in the code
|
||||
|
||||
# Set optimization options for release build
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}
|
||||
/Zi
|
||||
/Ob2
|
||||
/Oi
|
||||
/Ot
|
||||
/GL
|
||||
|
||||
/GS-
|
||||
/Gy
|
||||
/Qpar
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} \
|
||||
/Zi \
|
||||
/Ob3 \
|
||||
/Oi \
|
||||
/Ot \
|
||||
/GL \
|
||||
\
|
||||
/GS- \
|
||||
/Gy \
|
||||
/Qpar \
|
||||
"
|
||||
)
|
||||
|
||||
|
||||
# disable optimization for CxbxKrnl.cpp file
|
||||
set_source_files_properties(
|
||||
${CXBXR_KRNL_CPP} PROPERTIES COMPILE_FLAGS "/Od /GL-"
|
||||
|
@ -157,10 +150,11 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
|||
endif()
|
||||
|
||||
# Windows libraries
|
||||
set(WINS_LIB
|
||||
set(WINS_LIB
|
||||
legacy_stdio_definitions
|
||||
d3d9
|
||||
d3dcompiler
|
||||
delayimp
|
||||
dinput8
|
||||
dxguid
|
||||
odbc32
|
||||
|
@ -176,25 +170,36 @@ set(WINS_LIB
|
|||
comctl32
|
||||
XINPUT9_1_0
|
||||
Iphlpapi
|
||||
wpcap
|
||||
Dwmapi
|
||||
)
|
||||
|
||||
target_link_libraries(cxbx
|
||||
PUBLIC XbSymbolDatabase
|
||||
PUBLIC libXbSymbolDatabase
|
||||
subhook
|
||||
libtomcrypt
|
||||
SDL2
|
||||
imgui
|
||||
libusb
|
||||
mio::mio_min_winapi
|
||||
|
||||
${WINS_LIB}
|
||||
)
|
||||
|
||||
if(${CMAKE_GENERATOR} MATCHES "Visual Studio ([^9]|[9][0-9])")
|
||||
install(TARGETS ${PROJECT_NAME}
|
||||
RUNTIME DESTINATION bin
|
||||
)
|
||||
|
||||
if(${CMAKE_GENERATOR} MATCHES "Visual Studio ([^9]|[9][0-9])" AND BUILD_CXBXR_DEBUGGER)
|
||||
add_dependencies(cxbx cxbxr-debugger)
|
||||
endif()
|
||||
|
||||
set(CXBXR_GLEW_DLL "${CXBXR_ROOT_DIR}/import/glew-2.0.0/bin/Release/Win32/glew32.dll")
|
||||
add_dependencies(cxbx cxbxr-ldr cxbxr-emu misc-batch)
|
||||
|
||||
# Copy glew32.dll to build type's folder after build.
|
||||
add_custom_command(TARGET cxbx POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${CXBXR_GLEW_DLL} $<TARGET_FILE_DIR:cxbx>
|
||||
# Try to stop cmake from building hlsl files
|
||||
# Which are all currently loaded at runtime only
|
||||
set_source_files_properties(
|
||||
${CXBXR_HEADER_HLSL}
|
||||
PROPERTIES
|
||||
HEADER_FILE_ONLY TRUE
|
||||
VS_TOOL_OVERRIDE "None"
|
||||
)
|
||||
|
|
|
@ -0,0 +1,196 @@
|
|||
cmake_minimum_required (VERSION 3.12)
|
||||
project(cxbxr-emu)
|
||||
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
# Suppress extra stuff from generated solution
|
||||
set(CMAKE_SUPPRESS_REGENERATION true)
|
||||
|
||||
# Force exclude default libraries being included
|
||||
#set(CMAKE_CXX_STANDARD_LIBRARIES "")
|
||||
|
||||
include_directories(
|
||||
"${CXBXR_ROOT_DIR}/src"
|
||||
"${CXBXR_ROOT_DIR}/src/common"
|
||||
"${CXBXR_ROOT_DIR}/src/common/Win32"
|
||||
"${CXBXR_ROOT_DIR}/import/OpenXDK/include"
|
||||
"${CXBXR_ROOT_DIR}/import/DirectX9/include"
|
||||
"${CXBXR_ROOT_DIR}/import/distorm/include"
|
||||
"${CXBXR_ROOT_DIR}/import/glew-2.0.0/include"
|
||||
"${CXBXR_ROOT_DIR}/import/libusb/libusb"
|
||||
"${CXBXR_ROOT_DIR}/import/simpleini"
|
||||
"${CXBXR_ROOT_DIR}/import/winpcap/Include"
|
||||
"${CXBXR_ROOT_DIR}/import/xxHash"
|
||||
)
|
||||
|
||||
link_directories(
|
||||
"${CXBXR_ROOT_DIR}/import/distorm/lib/Win32"
|
||||
"${CXBXR_ROOT_DIR}/import/glew-2.0.0/lib/Release/Win32"
|
||||
"${CXBXR_ROOT_DIR}/import/DirectX9/lib"
|
||||
"${CXBXR_ROOT_DIR}/import/winpcap/Lib"
|
||||
)
|
||||
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
add_compile_definitions(
|
||||
_CRT_SECURE_NO_WARNINGS
|
||||
# Windows 7 minimum requirement
|
||||
_WIN32_WINNT=0x0601
|
||||
LTM_DESC
|
||||
USE_LTM
|
||||
LTC_NO_TEST
|
||||
LTC_NO_CIPHERS
|
||||
LTC_NO_HASHES
|
||||
LTC_NO_MACS
|
||||
LTC_NO_PRNGS
|
||||
LTC_NO_MISC
|
||||
LTC_NO_PROTOTYPES
|
||||
|
||||
# Use inline XXHash version
|
||||
XXH_INLINE_ALL
|
||||
|
||||
# Enable Chihiro work
|
||||
CHIHIRO_WORK
|
||||
)
|
||||
add_compile_options(
|
||||
/EHs
|
||||
/MP
|
||||
/GF
|
||||
/arch:SSE2
|
||||
)
|
||||
endif()
|
||||
|
||||
add_compile_definitions(
|
||||
NOMINMAX
|
||||
CXBXR_EMU
|
||||
CXBXR_EMU_EXPORTS
|
||||
)
|
||||
|
||||
file (GLOB RESOURCES
|
||||
"${CXBXR_ROOT_DIR}/CONTRIBUTORS"
|
||||
"${CXBXR_ROOT_DIR}/COPYING"
|
||||
"${CXBXR_ROOT_DIR}/README.md"
|
||||
)
|
||||
|
||||
source_group(TREE ${CXBXR_ROOT_DIR}/import PREFIX import FILES
|
||||
${CXBXR_HEADER_EMU_IMPORT}
|
||||
)
|
||||
|
||||
source_group(TREE ${CXBXR_ROOT_DIR}/src PREFIX header FILES
|
||||
${CXBXR_HEADER_GUIv1}
|
||||
${CXBXR_HEADER_COMMON}
|
||||
${CXBXR_HEADER_EMU}
|
||||
"${CXBXR_ROOT_DIR}/src/emulator/targetver.h"
|
||||
)
|
||||
|
||||
source_group(TREE ${CXBXR_ROOT_DIR}/import PREFIX import FILES
|
||||
${CXBXR_SOURCE_EMU_IMPORT}
|
||||
)
|
||||
|
||||
source_group(TREE ${CXBXR_ROOT_DIR}/src PREFIX source FILES
|
||||
${CXBXR_SOURCE_GUIv1}
|
||||
${CXBXR_SOURCE_COMMON}
|
||||
${CXBXR_SOURCE_EMU}
|
||||
"${CXBXR_ROOT_DIR}/src/emulator/cxbxr-emu.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/emulator/dllmain.cpp"
|
||||
)
|
||||
|
||||
source_group(TREE ${CXBXR_ROOT_DIR} FILES ${RESOURCES})
|
||||
|
||||
add_library(cxbxr-emu SHARED ${RESOURCES}
|
||||
${CXBXR_HEADER_COMMON}
|
||||
${CXBXR_HEADER_EMU_IMPORT}
|
||||
${CXBXR_HEADER_EMU}
|
||||
"${CXBXR_ROOT_DIR}/src/emulator/targetver.h"
|
||||
${CXBXR_SOURCE_COMMON}
|
||||
${CXBXR_SOURCE_EMU_IMPORT}
|
||||
${CXBXR_SOURCE_EMU}
|
||||
${CXBXR_GIT_VERSION_H}
|
||||
"${CXBXR_ROOT_DIR}/src/emulator/cxbxr-emu.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/emulator/dllmain.cpp"
|
||||
)
|
||||
|
||||
# Link and compile flags
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
|
||||
set_target_properties(cxbxr-emu PROPERTIES
|
||||
LINK_FLAGS "
|
||||
/INCREMENTAL:NO \
|
||||
/LARGEADDRESSAWARE \
|
||||
/SAFESEH:NO \
|
||||
/STACK:65536,65536 \
|
||||
/NODEFAULTLIB:libcmt \
|
||||
/DELAYLOAD:wpcap.dll \
|
||||
"
|
||||
LINK_FLAGS_RELEASE "
|
||||
/LTCG \
|
||||
/DEBUG \
|
||||
"
|
||||
)
|
||||
|
||||
# Set optimization options for release build
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} \
|
||||
/Zi \
|
||||
/Ob3 \
|
||||
/Oi \
|
||||
/Ot \
|
||||
/GL \
|
||||
\
|
||||
/GS- \
|
||||
/Gy \
|
||||
/Qpar \
|
||||
"
|
||||
)
|
||||
endif()
|
||||
|
||||
# Windows libraries
|
||||
set(WINS_LIB
|
||||
legacy_stdio_definitions
|
||||
d3d9
|
||||
d3dcompiler
|
||||
delayimp
|
||||
dinput8
|
||||
dxguid
|
||||
odbc32
|
||||
odbccp32
|
||||
Shlwapi
|
||||
dxerr9
|
||||
ws2_32
|
||||
dsound
|
||||
winmm
|
||||
ddraw
|
||||
d3dx9
|
||||
dbghelp
|
||||
comctl32
|
||||
XINPUT9_1_0
|
||||
Iphlpapi
|
||||
wpcap
|
||||
)
|
||||
|
||||
target_link_libraries(cxbxr-emu
|
||||
PUBLIC libXbSymbolDatabase
|
||||
subhook
|
||||
libtomcrypt
|
||||
SDL2
|
||||
imgui
|
||||
libusb
|
||||
nv2a_vsh_emulator
|
||||
mio::mio_min_winapi
|
||||
|
||||
${WINS_LIB}
|
||||
)
|
||||
|
||||
install(TARGETS ${PROJECT_NAME}
|
||||
RUNTIME DESTINATION bin
|
||||
)
|
||||
|
||||
add_dependencies(cxbxr-emu cxbxr-ldr misc-batch)
|
||||
|
||||
# Try to stop cmake from building hlsl files
|
||||
# Which are all currently loaded at runtime only
|
||||
set_source_files_properties(
|
||||
${CXBXR_HEADER_HLSL}
|
||||
PROPERTIES
|
||||
HEADER_FILE_ONLY TRUE
|
||||
VS_TOOL_OVERRIDE "None"
|
||||
)
|
|
@ -0,0 +1,75 @@
|
|||
cmake_minimum_required (VERSION 3.12)
|
||||
project(cxbxr-ldr)
|
||||
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
# Suppress extra stuff from generated solution
|
||||
set(CMAKE_SUPPRESS_REGENERATION true)
|
||||
|
||||
# Force exclude default libraries being included
|
||||
set(CMAKE_CXX_STANDARD_LIBRARIES "")
|
||||
|
||||
# Force set BasicRunTimeChecks to default
|
||||
STRING (REGEX REPLACE "/RTC(su|[1su])" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
|
||||
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
add_compile_definitions(
|
||||
_CRT_SECURE_NO_WARNINGS
|
||||
)
|
||||
add_compile_options(
|
||||
/sdl-
|
||||
)
|
||||
endif()
|
||||
|
||||
file (GLOB HEADERS
|
||||
"${CXBXR_ROOT_DIR}/src/common/AddressRanges.h"
|
||||
"${CXBXR_ROOT_DIR}/src/common/ReserveAddressRanges.h"
|
||||
"${CXBXR_ROOT_DIR}/src/CxbxVersion.h"
|
||||
"${CXBXR_ROOT_DIR}/src/version.h"
|
||||
)
|
||||
|
||||
file (GLOB SOURCES
|
||||
"${CXBXR_ROOT_DIR}/src/common/AddressRanges.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/common/ReserveAddressRanges.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/CxbxVersion.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/loader/cxbxr-ldr.cpp"
|
||||
)
|
||||
|
||||
source_group(TREE ${CXBXR_ROOT_DIR}/src PREFIX header FILES ${HEADERS})
|
||||
|
||||
source_group(TREE ${CXBXR_ROOT_DIR}/src PREFIX source FILES ${SOURCES})
|
||||
|
||||
add_executable(cxbxr-ldr ${HEADERS} ${SOURCES})
|
||||
|
||||
# Link and compile flags
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
|
||||
set_target_properties(cxbxr-ldr PROPERTIES
|
||||
LINK_FLAGS "
|
||||
/LARGEADDRESSAWARE \
|
||||
/FIXED \
|
||||
/DYNAMICBASE:NO \
|
||||
/BASE:0x10000 \
|
||||
/STACK:65536,65536 \
|
||||
/NODEFAULTLIB \
|
||||
/ENTRY:rawMain \
|
||||
"
|
||||
)
|
||||
|
||||
# Set optimization options for release build
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} \
|
||||
/Oi \
|
||||
"
|
||||
)
|
||||
endif()
|
||||
|
||||
target_link_libraries(cxbxr-ldr
|
||||
PUBLIC kernel32.lib
|
||||
)
|
||||
|
||||
install(TARGETS ${PROJECT_NAME}
|
||||
RUNTIME DESTINATION bin
|
||||
)
|
||||
|
||||
add_dependencies(cxbxr-ldr misc-batch)
|
|
@ -0,0 +1,42 @@
|
|||
cmake_minimum_required (VERSION 3.8)
|
||||
project(imgui LANGUAGES CXX)
|
||||
# Since imgui doesn't have CMake, we'll make an interface project here.
|
||||
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
add_compile_definitions(
|
||||
_CRT_SECURE_NO_WARNINGS
|
||||
_CRT_NONSTDC_NO_DEPRECATE
|
||||
)
|
||||
endif()
|
||||
|
||||
# Add any defines from imconfig.h file in here without need to edit import file directly.
|
||||
add_compile_definitions(
|
||||
IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS
|
||||
IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS
|
||||
)
|
||||
|
||||
file (GLOB HEADERS
|
||||
"${CXBXR_ROOT_DIR}/import/imgui/imconfig.h"
|
||||
"${CXBXR_ROOT_DIR}/import/imgui/imgui.h"
|
||||
"${CXBXR_ROOT_DIR}/import/imgui/imgui_internal.h"
|
||||
"${CXBXR_ROOT_DIR}/import/imgui/imstb_rectpack.h"
|
||||
"${CXBXR_ROOT_DIR}/import/imgui/imstb_textedit.h"
|
||||
"${CXBXR_ROOT_DIR}/import/imgui/imstb_truetype.h"
|
||||
)
|
||||
|
||||
file (GLOB SOURCES
|
||||
"${CXBXR_ROOT_DIR}/import/imgui/imgui.cpp"
|
||||
"${CXBXR_ROOT_DIR}/import/imgui/imgui_draw.cpp"
|
||||
"${CXBXR_ROOT_DIR}/import/imgui/imgui_tables.cpp"
|
||||
"${CXBXR_ROOT_DIR}/import/imgui/imgui_widgets.cpp"
|
||||
)
|
||||
|
||||
source_group(TREE ${CXBXR_ROOT_DIR}/import/imgui PREFIX header FILES ${HEADERS})
|
||||
|
||||
source_group(TREE ${CXBXR_ROOT_DIR}/import/imgui PREFIX source FILES ${SOURCES})
|
||||
|
||||
add_library(${PROJECT_NAME} ${HEADERS} ${SOURCES})
|
||||
|
||||
target_include_directories(${PROJECT_NAME}
|
||||
PUBLIC "${CXBXR_ROOT_DIR}/import/imgui"
|
||||
)
|
|
@ -17,11 +17,6 @@ add_compile_definitions(
|
|||
LTC_NO_PROTOTYPES
|
||||
)
|
||||
|
||||
include_directories(
|
||||
"${CXBXR_ROOT_DIR}/import/libtommath"
|
||||
"${CXBXR_ROOT_DIR}/import/libtomcrypt/src/headers"
|
||||
)
|
||||
|
||||
file (GLOB HEADERS
|
||||
"${CXBXR_ROOT_DIR}/import/libtomcrypt/src/headers/tomcrypt.h"
|
||||
"${CXBXR_ROOT_DIR}/import/libtomcrypt/src/headers/tomcrypt_argchk.h"
|
||||
|
@ -462,6 +457,10 @@ add_library(libtomcrypt ${HEADERS} ${SOURCES})
|
|||
|
||||
target_compile_definitions(libtomcrypt PUBLIC LTM_DESC=1)
|
||||
|
||||
target_include_directories(libtomcrypt
|
||||
PUBLIC "${CXBXR_ROOT_DIR}/import/libtomcrypt/src/headers"
|
||||
)
|
||||
|
||||
target_link_libraries(libtomcrypt
|
||||
PUBLIC libtommath
|
||||
|
||||
|
|
|
@ -11,11 +11,6 @@ if ("${CMAKE_C_COMPILER_ID}" STREQUAL "MSVC")
|
|||
)
|
||||
endif()
|
||||
|
||||
|
||||
include_directories(
|
||||
"${CXBXR_ROOT_DIR}/import/libtommath"
|
||||
)
|
||||
|
||||
file (GLOB HEADERS
|
||||
"${CXBXR_ROOT_DIR}/import/libtommath/tommath.h"
|
||||
"${CXBXR_ROOT_DIR}/import/libtommath/tommath_class.h"
|
||||
|
@ -170,3 +165,7 @@ source_group(TREE ${CXBXR_ROOT_DIR}/import/libtommath PREFIX header FILES ${HEAD
|
|||
source_group(TREE ${CXBXR_ROOT_DIR}/import/libtommath PREFIX source FILES ${SOURCES})
|
||||
|
||||
add_library(libtommath ${HEADERS} ${SOURCES})
|
||||
|
||||
target_include_directories(libtommath
|
||||
PUBLIC "${CXBXR_ROOT_DIR}/import/libtommath"
|
||||
)
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
cmake_minimum_required (VERSION 3.8)
|
||||
project(libusb LANGUAGES CXX)
|
||||
# Since libusb doesn't have CMake, we'll make an interface project here.
|
||||
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
add_compile_definitions(
|
||||
_CRT_SECURE_NO_WARNINGS
|
||||
_CRT_NONSTDC_NO_DEPRECATE
|
||||
)
|
||||
endif()
|
||||
|
||||
include_directories(
|
||||
"${CXBXR_ROOT_DIR}/import/libusb/msvc"
|
||||
"${CXBXR_ROOT_DIR}/import/libusb/libusb")
|
||||
|
||||
file (GLOB HEADERS
|
||||
"${CXBXR_ROOT_DIR}/import/libusb/libusb/libusb.h"
|
||||
"${CXBXR_ROOT_DIR}/import/libusb/libusb/libusbi.h"
|
||||
"${CXBXR_ROOT_DIR}/import/libusb/libusb/version.h"
|
||||
"${CXBXR_ROOT_DIR}/import/libusb/libusb/version_nano.h"
|
||||
"${CXBXR_ROOT_DIR}/import/libusb/libusb/msvc/config.h"
|
||||
"${CXBXR_ROOT_DIR}/import/libusb/libusb/os/events_windows.h"
|
||||
"${CXBXR_ROOT_DIR}/import/libusb/libusb/os/threads_windows.h"
|
||||
"${CXBXR_ROOT_DIR}/import/libusb/libusb/os/windows_common.h"
|
||||
"${CXBXR_ROOT_DIR}/import/libusb/libusb/os/windows_usbdk.h"
|
||||
"${CXBXR_ROOT_DIR}/import/libusb/libusb/os/windows_winusb.h"
|
||||
)
|
||||
|
||||
file (GLOB SOURCES
|
||||
"${CXBXR_ROOT_DIR}/import/libusb/libusb/core.c"
|
||||
"${CXBXR_ROOT_DIR}/import/libusb/libusb/descriptor.c"
|
||||
"${CXBXR_ROOT_DIR}/import/libusb/libusb/hotplug.c"
|
||||
"${CXBXR_ROOT_DIR}/import/libusb/libusb/io.c"
|
||||
"${CXBXR_ROOT_DIR}/import/libusb/libusb/strerror.c"
|
||||
"${CXBXR_ROOT_DIR}/import/libusb/libusb/sync.c"
|
||||
"${CXBXR_ROOT_DIR}/import/libusb/libusb/os/events_windows.c"
|
||||
"${CXBXR_ROOT_DIR}/import/libusb/libusb/os/threads_windows.c"
|
||||
"${CXBXR_ROOT_DIR}/import/libusb/libusb/os/windows_common.c"
|
||||
"${CXBXR_ROOT_DIR}/import/libusb/libusb/os/windows_usbdk.c"
|
||||
"${CXBXR_ROOT_DIR}/import/libusb/libusb/os/windows_winusb.c"
|
||||
)
|
||||
|
||||
source_group(TREE ${CXBXR_ROOT_DIR}/import/libusb/libusb PREFIX header FILES ${HEADERS})
|
||||
|
||||
source_group(TREE ${CXBXR_ROOT_DIR}/import/libusb/libusb PREFIX source FILES ${SOURCES})
|
||||
|
||||
add_library(${PROJECT_NAME} ${HEADERS} ${SOURCES})
|
||||
|
||||
target_include_directories(${PROJECT_NAME}
|
||||
PUBLIC "${CXBXR_ROOT_DIR}/import/libusb"
|
||||
)
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
find_package(Git)
|
||||
|
||||
if(Git_FOUND)
|
||||
message("Git found: ${GIT_EXECUTABLE}")
|
||||
|
||||
execute_process(
|
||||
COMMAND git describe --always --tags --first-parent --dirty
|
||||
OUTPUT_VARIABLE _GIT_VERSION
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
message("Git version: " ${_GIT_VERSION})
|
||||
else()
|
||||
set(_GIT_VERSION "unknown")
|
||||
endif()
|
||||
|
||||
# Appears to update whenever define has changed.
|
||||
configure_file(
|
||||
"${CMAKE_SOURCE_DIR}/src/version.h.in" "${CMAKE_SOURCE_DIR}/src/version.h" @ONLY
|
||||
NEWLINE_STYLE LF
|
||||
)
|
||||
|
||||
|
||||
message("Runtime Build Directory: ${TargetRunTimeDir}")
|
||||
|
||||
# Copy glew32.dll to build type's folder.
|
||||
set(CXBXR_GLEW_DLL "${CMAKE_SOURCE_DIR}/import/glew-2.0.0/bin/Release/Win32/glew32.dll")
|
||||
file(COPY ${CXBXR_GLEW_DLL} DESTINATION ${TargetRunTimeDir})
|
|
@ -1,40 +0,0 @@
|
|||
cmake_minimum_required (VERSION 3.8)
|
||||
project(vsbc)
|
||||
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
# Suppress extra stuff from generated solution
|
||||
set(CMAKE_SUPPRESS_REGENERATION true)
|
||||
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
|
||||
add_compile_definitions(_CRT_SECURE_NO_WARNINGS
|
||||
)
|
||||
endif()
|
||||
|
||||
add_compile_definitions(CXBXVSBC_EXPORTS
|
||||
)
|
||||
|
||||
file (GLOB HEADERS
|
||||
"${CXBXR_ROOT_DIR}/src/vsbc/CxbxVSBC.h"
|
||||
"${CXBXR_ROOT_DIR}/src/vsbc/DlgVirtualSBCFeedback.h"
|
||||
"${CXBXR_ROOT_DIR}/src/vsbc/stdafx.h"
|
||||
"${CXBXR_ROOT_DIR}/src/vsbc/targetver.h"
|
||||
)
|
||||
|
||||
file (GLOB SOURCES
|
||||
"${CXBXR_ROOT_DIR}/src/vsbc/CxbxVSBC.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/vsbc/DlgVirtualSBCFeedback.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/vsbc/dllmain.cpp"
|
||||
"${CXBXR_ROOT_DIR}/src/vsbc/stdafx.cpp"
|
||||
)
|
||||
|
||||
source_group(TREE ${CXBXR_ROOT_DIR}/src/vsbc PREFIX header FILES ${HEADERS})
|
||||
|
||||
source_group(TREE ${CXBXR_ROOT_DIR}/src/vsbc PREFIX source FILES ${SOURCES})
|
||||
|
||||
add_library(vsbc SHARED ${HEADERS} ${SOURCES})
|
||||
|
||||
set_target_properties(vsbc PROPERTIES
|
||||
OUTPUT_NAME CxbxVSBC
|
||||
)
|
52
setup.bat
52
setup.bat
|
@ -1,26 +1,26 @@
|
|||
@echo off
|
||||
|
||||
REM CXbx-Reloaded setup script
|
||||
REM
|
||||
REM Depends on git, cmake and Visual Studio being installed.
|
||||
|
||||
echo Pulling lastest version from git...
|
||||
REM git clone --recurse-submodules https://github.com/Cxbx-Reloaded/Cxbx-Reloaded/
|
||||
git pull --recurse-submodules
|
||||
|
||||
REM echo Synchronizing submodules...
|
||||
REM git submodule update --init --recursive
|
||||
|
||||
echo Initializing most recent Visual Studio build environment...
|
||||
@call "%VS140COMNTOOLS%vsvars32.bat"
|
||||
|
||||
echo Generating solution...
|
||||
mkdir build
|
||||
cd build
|
||||
REM cmake .. -G "Visual Studio 16 2019" -A Win32
|
||||
cmake .. -A Win32
|
||||
|
||||
echo Building solution...
|
||||
cmake --build .
|
||||
|
||||
echo Done! Enjoy using Cxbx-Reloaded!
|
||||
@echo off
|
||||
|
||||
REM Cxbx-Reloaded setup script
|
||||
REM
|
||||
REM Depends on git, cmake and Visual Studio being installed.
|
||||
|
||||
echo Pulling latest version from git...
|
||||
REM git clone --recurse-submodules https://github.com/Cxbx-Reloaded/Cxbx-Reloaded/
|
||||
git pull --recurse-submodules
|
||||
|
||||
REM echo Synchronizing submodules...
|
||||
REM git submodule update --init --recursive
|
||||
|
||||
echo Initializing most recent Visual Studio build environment...
|
||||
@call "%VS140COMNTOOLS%vsvars32.bat"
|
||||
|
||||
echo Generating solution...
|
||||
mkdir build
|
||||
cd build
|
||||
REM cmake .. -G "Visual Studio 16 2019" -A Win32
|
||||
cmake .. -A Win32
|
||||
|
||||
echo Building solution...
|
||||
cmake --build . -j %NUMBER_OF_PROCESSORS%
|
||||
|
||||
echo Done! Enjoy using Cxbx-Reloaded!
|
||||
|
|
|
@ -3,5 +3,5 @@ root = true
|
|||
[*]
|
||||
indent_size = 4
|
||||
trim_trailing_whitespace = true
|
||||
end_of_line = crlf
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
|
|
25
src/Cxbx.h
25
src/Cxbx.h
|
@ -27,14 +27,7 @@
|
|||
|
||||
#include <cstdint>
|
||||
|
||||
/*! xbaddr is the type of a physical address */
|
||||
typedef uint32_t xbaddr;
|
||||
|
||||
/*! xbnullptr is the type of null pointer address*/
|
||||
#define xbnullptr nullptr
|
||||
|
||||
/*! xbnull is the type of null address or value*/
|
||||
#define xbnull 0
|
||||
#define FUNC_EXPORTS __pragma(comment(linker, "/EXPORT:" __FUNCTION__ "=" __FUNCDNAME__))
|
||||
|
||||
#ifdef _DEBUG
|
||||
/*! define this to track memory allocations */
|
||||
|
@ -68,18 +61,14 @@ enum DebugMode { DM_NONE, DM_CONSOLE, DM_FILE };
|
|||
/*! debugger enable state */
|
||||
enum DebuggerState { debuggerOff, debuggerOn };
|
||||
|
||||
/*! type of Xbe */
|
||||
enum XbeType { xtRetail, xtDebug, xtChihiro };
|
||||
|
||||
extern XbeType g_XbeType;
|
||||
|
||||
/*! indicates emulation of an Chihiro (arcade, instead of Xbox console) executable */
|
||||
/*! indicates emulation of a Chihiro system */
|
||||
extern bool g_bIsChihiro;
|
||||
|
||||
/*! indicates emulation of a Debug xbe executable */
|
||||
extern bool g_bIsDebug;
|
||||
/*! indicates emulation of a DevKit system */
|
||||
/* Note: Our DevKit emulation lacks the kernel debugging interface and virtual dvd-rom emulator card, so this is actually a Debug Kit */
|
||||
extern bool g_bIsDevKit;
|
||||
|
||||
/*! indicates emulation of a Retail xbe executable*/
|
||||
/*! indicates emulation of a Retail system */
|
||||
extern bool g_bIsRetail;
|
||||
|
||||
/*! indicates ability to save on exit (needed for settings reset) */
|
||||
|
@ -95,6 +84,4 @@ extern volatile bool g_bPrintfOn;
|
|||
#define CxbxSetThreadName(Name)
|
||||
#endif
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/>
|
||||
<supportedRuntime version="v4.8" sku=".NETFramework,Version=v4.8"/>
|
||||
</startup>
|
||||
</configuration>
|
||||
|
|
|
@ -13,6 +13,12 @@ add_compile_options(
|
|||
/langversion:6
|
||||
)
|
||||
|
||||
# First, we must define .NET Framework version before include cs_x86's projects.
|
||||
# Which then will pass down version we want unified.
|
||||
set(DOTNET_TARGET_FRAMEWORK_VERSION "v4.8")
|
||||
|
||||
add_subdirectory("${CXBXR_ROOT_DIR}/import/cs_x86" "${CMAKE_BINARY_DIR}/import/cs_x86")
|
||||
|
||||
set(CXBXR_DEBUGGER_SRC_DIR "${CXBXR_ROOT_DIR}/src/CxbxDebugger")
|
||||
|
||||
file (GLOB SOURCES
|
||||
|
@ -37,16 +43,15 @@ file (GLOB SOURCES
|
|||
"${CXBXR_DEBUGGER_SRC_DIR}/DebugOutputManager.cs"
|
||||
"${CXBXR_DEBUGGER_SRC_DIR}/FileEventManager.cs"
|
||||
"${CXBXR_DEBUGGER_SRC_DIR}/FileWatchManager.cs"
|
||||
"${CXBXR_DEBUGGER_SRC_DIR}/Form1.cs"
|
||||
"${CXBXR_DEBUGGER_SRC_DIR}/Form1.Designer.cs"
|
||||
"${CXBXR_DEBUGGER_SRC_DIR}/Form1.resx"
|
||||
"${CXBXR_DEBUGGER_SRC_DIR}/IDebugWindow.cs"
|
||||
"${CXBXR_DEBUGGER_SRC_DIR}/CxbxDebuggerInstance.cs"
|
||||
"${CXBXR_DEBUGGER_SRC_DIR}/CxbxDebuggerInstance.Designer.cs"
|
||||
"${CXBXR_DEBUGGER_SRC_DIR}/CxbxDebuggerInstance.resx"
|
||||
"${CXBXR_DEBUGGER_SRC_DIR}/CxbxDebuggerMain.cs"
|
||||
"${CXBXR_DEBUGGER_SRC_DIR}/CxbxDebuggerMain.Designer.cs"
|
||||
"${CXBXR_DEBUGGER_SRC_DIR}/CxbxDebuggerMain.resx"
|
||||
"${CXBXR_DEBUGGER_SRC_DIR}/PatchManager.cs"
|
||||
"${CXBXR_DEBUGGER_SRC_DIR}/Program.cs"
|
||||
"${CXBXR_DEBUGGER_SRC_DIR}/Properties/AssemblyInfo.cs"
|
||||
"${CXBXR_DEBUGGER_SRC_DIR}/Properties/Resources.Designer.cs"
|
||||
"${CXBXR_DEBUGGER_SRC_DIR}/Properties/Resources.resx"
|
||||
"${CXBXR_DEBUGGER_SRC_DIR}/Properties/Settings.Designer.cs"
|
||||
"${CXBXR_DEBUGGER_SRC_DIR}/Properties/Settings.settings"
|
||||
"${CXBXR_DEBUGGER_SRC_DIR}/Resources/BreakpointDisable_16x_24.bmp"
|
||||
"${CXBXR_DEBUGGER_SRC_DIR}/Resources/BreakpointEnable_16x_24.bmp"
|
||||
"${CXBXR_DEBUGGER_SRC_DIR}/Resources/Pause_16x_24.bmp"
|
||||
|
@ -92,10 +97,8 @@ file (GLOB SOURCES
|
|||
"${CXBXR_DEBUGGER_SRC_DIR}/Win32/Windows/NativeMethods.cs"
|
||||
)
|
||||
|
||||
csharp_set_windows_forms_properties(
|
||||
"${CXBXR_DEBUGGER_SRC_DIR}/Form1.Designer.cs"
|
||||
"${CXBXR_DEBUGGER_SRC_DIR}/Form1.cs"
|
||||
"${CXBXR_DEBUGGER_SRC_DIR}/Form1.resx"
|
||||
file (GLOB PROPERTIES
|
||||
"${CXBXR_DEBUGGER_SRC_DIR}/Properties/Settings.settings"
|
||||
"${CXBXR_DEBUGGER_SRC_DIR}/Properties/AssemblyInfo.cs"
|
||||
"${CXBXR_DEBUGGER_SRC_DIR}/Properties/Resources.Designer.cs"
|
||||
"${CXBXR_DEBUGGER_SRC_DIR}/Properties/Resources.resx"
|
||||
|
@ -103,7 +106,22 @@ csharp_set_windows_forms_properties(
|
|||
"${CXBXR_DEBUGGER_SRC_DIR}/Properties/Settings.settings"
|
||||
)
|
||||
|
||||
set_source_files_properties("${CXBXR_DEBUGGER_SRC_DIR}/Form1.cs"
|
||||
csharp_set_windows_forms_properties(
|
||||
"${CXBXR_DEBUGGER_SRC_DIR}/CxbxDebuggerInstance.cs"
|
||||
"${CXBXR_DEBUGGER_SRC_DIR}/CxbxDebuggerInstance.Designer.cs"
|
||||
"${CXBXR_DEBUGGER_SRC_DIR}/CxbxDebuggerInstance.resx"
|
||||
"${CXBXR_DEBUGGER_SRC_DIR}/CxbxDebuggerMain.Designer.cs"
|
||||
"${CXBXR_DEBUGGER_SRC_DIR}/CxbxDebuggerMain.cs"
|
||||
"${CXBXR_DEBUGGER_SRC_DIR}/CxbxDebuggerMain.resx"
|
||||
)
|
||||
|
||||
csharp_set_designer_cs_properties(
|
||||
${PROPERTIES}
|
||||
)
|
||||
|
||||
set_source_files_properties(
|
||||
"${CXBXR_DEBUGGER_SRC_DIR}/CxbxDebuggerInstance.cs"
|
||||
"${CXBXR_DEBUGGER_SRC_DIR}/CxbxDebuggerMain.cs"
|
||||
VS_CSHARP_SubType "Form"
|
||||
)
|
||||
|
||||
|
@ -113,18 +131,21 @@ set_source_files_properties("${CXBXR_DEBUGGER_SRC_DIR}/RicherTextBox.cs"
|
|||
|
||||
source_group(TREE ${CXBXR_ROOT_DIR} FILES ${SOURCES})
|
||||
|
||||
add_executable(cxbxr-debugger WIN32 ${SOURCES} #Test WIN32 like cxbx does if doesn't need compile option set
|
||||
add_executable(cxbxr-debugger WIN32 ${SOURCES} ${PROPERTIES} #Test WIN32 like cxbx does if doesn't need compile option set
|
||||
)
|
||||
|
||||
set_target_properties(cxbxr-debugger PROPERTIES
|
||||
set_target_properties(cxbxr-debugger PROPERTIES
|
||||
VS_DOTNET_REFERENCES
|
||||
"Microsoft.CSharp;System;System.Core;System.Data;System.Data.DataSetExtensions;System.Deployment;System.Drawing;System.Windows;System.Windows.Forms;System.Xml;System.Xml.Linq;System.Net.Http"
|
||||
VS_GLOBAL_ApplicationIcon "${CXBXR_ROOT_DIR}/resource/Cxbx-R.ico"
|
||||
|
||||
VS_GLOBAL_ApplicationIcon "${CXBXR_ROOT_DIR}/src/gui/resource/Cxbx-R.ico"
|
||||
|
||||
VS_GLOBAL_ROOTNAMESPACE "CxbxDebugger"
|
||||
|
||||
|
||||
DOTNET_TARGET_FRAMEWORK_VERSION ${DOTNET_TARGET_FRAMEWORK_VERSION}
|
||||
)
|
||||
|
||||
set_property(TARGET cxbxr-debugger PROPERTY DOTNET_TARGET_FRAMEWORK_VERSION "v4.5")
|
||||
|
||||
target_link_libraries(cxbxr-debugger cs_x86)
|
||||
|
||||
install(TARGETS ${PROJECT_NAME}
|
||||
RUNTIME DESTINATION bin
|
||||
)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
namespace CxbxDebugger
|
||||
{
|
||||
partial class Form1
|
||||
partial class CxbxDebuggerInstance
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
|
@ -28,22 +28,21 @@
|
|||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1));
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(CxbxDebuggerInstance));
|
||||
this.lbConsole = new System.Windows.Forms.ListBox();
|
||||
this.toolStrip1 = new System.Windows.Forms.ToolStrip();
|
||||
this.btnStart = new System.Windows.Forms.ToolStripButton();
|
||||
this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.btnSuspend = new System.Windows.Forms.ToolStripButton();
|
||||
this.btnResume = new System.Windows.Forms.ToolStripButton();
|
||||
this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.toolStripLabel1 = new System.Windows.Forms.ToolStripLabel();
|
||||
this.cbThreads = new System.Windows.Forms.ToolStripComboBox();
|
||||
this.toolStripLabel2 = new System.Windows.Forms.ToolStripLabel();
|
||||
this.cbFrames = new System.Windows.Forms.ToolStripComboBox();
|
||||
this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel();
|
||||
this.statusBar = new System.Windows.Forms.StatusStrip();
|
||||
this.lblStatus = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.tabContainer = new System.Windows.Forms.TabControl();
|
||||
this.tabSummary = new System.Windows.Forms.TabPage();
|
||||
this.linkLabel3 = new System.Windows.Forms.LinkLabel();
|
||||
this.linkLabel2 = new System.Windows.Forms.LinkLabel();
|
||||
this.linkLabel1 = new System.Windows.Forms.LinkLabel();
|
||||
this.label9 = new System.Windows.Forms.Label();
|
||||
this.label7 = new System.Windows.Forms.Label();
|
||||
this.tabDisassembly = new System.Windows.Forms.TabPage();
|
||||
this.splitContainer2 = new System.Windows.Forms.SplitContainer();
|
||||
this.btnToMemory = new System.Windows.Forms.Button();
|
||||
|
@ -52,7 +51,6 @@
|
|||
this.btnGo = new System.Windows.Forms.Button();
|
||||
this.label6 = new System.Windows.Forms.Label();
|
||||
this.cbDisAddr = new System.Windows.Forms.ComboBox();
|
||||
this.txDisassembly = new CxbxDebugger.RicherTextBox();
|
||||
this.tabBreakpoints = new System.Windows.Forms.TabPage();
|
||||
this.splitContainer3 = new System.Windows.Forms.SplitContainer();
|
||||
this.groupBox4 = new System.Windows.Forms.GroupBox();
|
||||
|
@ -112,10 +110,11 @@
|
|||
this.lbDebug = new System.Windows.Forms.ListBox();
|
||||
this.diagSaveMemory = new System.Windows.Forms.SaveFileDialog();
|
||||
this.diagBrowseCT = new System.Windows.Forms.OpenFileDialog();
|
||||
this.txDisassembly = new CxbxDebugger.RicherTextBox();
|
||||
this.toolStrip1.SuspendLayout();
|
||||
this.tableLayoutPanel3.SuspendLayout();
|
||||
this.statusBar.SuspendLayout();
|
||||
this.tabContainer.SuspendLayout();
|
||||
this.tabSummary.SuspendLayout();
|
||||
this.tabDisassembly.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.splitContainer2)).BeginInit();
|
||||
this.splitContainer2.Panel1.SuspendLayout();
|
||||
|
@ -158,73 +157,33 @@
|
|||
//
|
||||
this.lbConsole.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.lbConsole.FormattingEnabled = true;
|
||||
this.lbConsole.Location = new System.Drawing.Point(3, 231);
|
||||
this.lbConsole.Location = new System.Drawing.Point(3, 271);
|
||||
this.lbConsole.Name = "lbConsole";
|
||||
this.lbConsole.ScrollAlwaysVisible = true;
|
||||
this.lbConsole.Size = new System.Drawing.Size(728, 51);
|
||||
this.lbConsole.Size = new System.Drawing.Size(728, 62);
|
||||
this.lbConsole.TabIndex = 2;
|
||||
//
|
||||
// toolStrip1
|
||||
//
|
||||
this.toolStrip1.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden;
|
||||
this.toolStrip1.ImageScalingSize = new System.Drawing.Size(24, 24);
|
||||
this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.btnStart,
|
||||
this.toolStripSeparator1,
|
||||
this.btnSuspend,
|
||||
this.btnResume,
|
||||
this.toolStripSeparator2,
|
||||
this.toolStripLabel1,
|
||||
this.cbThreads,
|
||||
this.toolStripLabel2,
|
||||
this.cbFrames});
|
||||
this.toolStrip1.Location = new System.Drawing.Point(0, 0);
|
||||
this.toolStrip1.Name = "toolStrip1";
|
||||
this.toolStrip1.Padding = new System.Windows.Forms.Padding(0, 0, 2, 0);
|
||||
this.toolStrip1.RenderMode = System.Windows.Forms.ToolStripRenderMode.Professional;
|
||||
this.toolStrip1.Size = new System.Drawing.Size(734, 25);
|
||||
this.toolStrip1.TabIndex = 7;
|
||||
this.toolStrip1.Text = "toolStrip1";
|
||||
//
|
||||
// btnStart
|
||||
//
|
||||
this.btnStart.Image = global::CxbxDebugger.Properties.Resources.run;
|
||||
this.btnStart.ImageTransparentColor = System.Drawing.Color.Magenta;
|
||||
this.btnStart.Name = "btnStart";
|
||||
this.btnStart.Size = new System.Drawing.Size(51, 22);
|
||||
this.btnStart.Text = "Start";
|
||||
this.btnStart.Click += new System.EventHandler(this.toolStripButton1_Click);
|
||||
//
|
||||
// toolStripSeparator1
|
||||
//
|
||||
this.toolStripSeparator1.Name = "toolStripSeparator1";
|
||||
this.toolStripSeparator1.Size = new System.Drawing.Size(6, 25);
|
||||
//
|
||||
// btnSuspend
|
||||
//
|
||||
this.btnSuspend.Image = global::CxbxDebugger.Properties.Resources.pause;
|
||||
this.btnSuspend.ImageTransparentColor = System.Drawing.Color.Magenta;
|
||||
this.btnSuspend.Name = "btnSuspend";
|
||||
this.btnSuspend.Size = new System.Drawing.Size(72, 22);
|
||||
this.btnSuspend.Text = "Suspend";
|
||||
this.btnSuspend.Click += new System.EventHandler(this.toolStripButton2_Click);
|
||||
//
|
||||
// btnResume
|
||||
//
|
||||
this.btnResume.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Text;
|
||||
this.btnResume.ImageTransparentColor = System.Drawing.Color.Magenta;
|
||||
this.btnResume.Name = "btnResume";
|
||||
this.btnResume.Size = new System.Drawing.Size(53, 22);
|
||||
this.btnResume.Text = "Resume";
|
||||
this.btnResume.Click += new System.EventHandler(this.toolStripButton3_Click);
|
||||
//
|
||||
// toolStripSeparator2
|
||||
//
|
||||
this.toolStripSeparator2.Name = "toolStripSeparator2";
|
||||
this.toolStripSeparator2.Size = new System.Drawing.Size(6, 25);
|
||||
//
|
||||
// toolStripLabel1
|
||||
//
|
||||
this.toolStripLabel1.Name = "toolStripLabel1";
|
||||
this.toolStripLabel1.Size = new System.Drawing.Size(47, 22);
|
||||
this.toolStripLabel1.Size = new System.Drawing.Size(46, 22);
|
||||
this.toolStripLabel1.Text = "Thread:";
|
||||
//
|
||||
// cbThreads
|
||||
|
@ -244,45 +203,28 @@
|
|||
//
|
||||
this.cbFrames.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.cbFrames.Name = "cbFrames";
|
||||
this.cbFrames.Size = new System.Drawing.Size(200, 25);
|
||||
this.cbFrames.Size = new System.Drawing.Size(135, 25);
|
||||
this.cbFrames.SelectedIndexChanged += new System.EventHandler(this.cbFrames_SelectedIndexChanged);
|
||||
//
|
||||
// tableLayoutPanel3
|
||||
//
|
||||
this.tableLayoutPanel3.ColumnCount = 1;
|
||||
this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
|
||||
this.tableLayoutPanel3.Controls.Add(this.statusBar, 0, 2);
|
||||
this.tableLayoutPanel3.Controls.Add(this.tabContainer, 0, 0);
|
||||
this.tableLayoutPanel3.Controls.Add(this.lbConsole, 0, 1);
|
||||
this.tableLayoutPanel3.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.tableLayoutPanel3.Location = new System.Drawing.Point(0, 25);
|
||||
this.tableLayoutPanel3.Name = "tableLayoutPanel3";
|
||||
this.tableLayoutPanel3.RowCount = 3;
|
||||
this.tableLayoutPanel3.RowCount = 2;
|
||||
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 80F));
|
||||
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 20F));
|
||||
this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
|
||||
this.tableLayoutPanel3.Size = new System.Drawing.Size(734, 306);
|
||||
this.tableLayoutPanel3.Size = new System.Drawing.Size(734, 336);
|
||||
this.tableLayoutPanel3.TabIndex = 9;
|
||||
//
|
||||
// statusBar
|
||||
//
|
||||
this.statusBar.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.statusBar.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.lblStatus});
|
||||
this.statusBar.Location = new System.Drawing.Point(0, 285);
|
||||
this.statusBar.Name = "statusBar";
|
||||
this.statusBar.Size = new System.Drawing.Size(734, 21);
|
||||
this.statusBar.TabIndex = 10;
|
||||
this.statusBar.Text = "statusStrip1";
|
||||
//
|
||||
// lblStatus
|
||||
//
|
||||
this.lblStatus.Name = "lblStatus";
|
||||
this.lblStatus.Size = new System.Drawing.Size(39, 16);
|
||||
this.lblStatus.Text = "Ready";
|
||||
//
|
||||
// tabContainer
|
||||
//
|
||||
this.tabContainer.Controls.Add(this.tabSummary);
|
||||
this.tabContainer.Controls.Add(this.tabDisassembly);
|
||||
this.tabContainer.Controls.Add(this.tabBreakpoints);
|
||||
this.tabContainer.Controls.Add(this.tabWatch);
|
||||
|
@ -294,16 +236,82 @@
|
|||
this.tabContainer.Multiline = true;
|
||||
this.tabContainer.Name = "tabContainer";
|
||||
this.tabContainer.SelectedIndex = 0;
|
||||
this.tabContainer.Size = new System.Drawing.Size(728, 222);
|
||||
this.tabContainer.Size = new System.Drawing.Size(728, 262);
|
||||
this.tabContainer.TabIndex = 3;
|
||||
//
|
||||
// tabSummary
|
||||
//
|
||||
this.tabSummary.Controls.Add(this.linkLabel3);
|
||||
this.tabSummary.Controls.Add(this.linkLabel2);
|
||||
this.tabSummary.Controls.Add(this.linkLabel1);
|
||||
this.tabSummary.Controls.Add(this.label9);
|
||||
this.tabSummary.Controls.Add(this.label7);
|
||||
this.tabSummary.Location = new System.Drawing.Point(4, 22);
|
||||
this.tabSummary.Name = "tabSummary";
|
||||
this.tabSummary.Padding = new System.Windows.Forms.Padding(3, 3, 3, 3);
|
||||
this.tabSummary.Size = new System.Drawing.Size(654, 318);
|
||||
this.tabSummary.TabIndex = 6;
|
||||
this.tabSummary.Text = "Summary";
|
||||
this.tabSummary.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// linkLabel3
|
||||
//
|
||||
this.linkLabel3.AutoSize = true;
|
||||
this.linkLabel3.Location = new System.Drawing.Point(11, 112);
|
||||
this.linkLabel3.Name = "linkLabel3";
|
||||
this.linkLabel3.Size = new System.Drawing.Size(89, 13);
|
||||
this.linkLabel3.TabIndex = 5;
|
||||
this.linkLabel3.TabStop = true;
|
||||
this.linkLabel3.Text = "View disassembly";
|
||||
this.linkLabel3.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabel3_LinkClicked);
|
||||
//
|
||||
// linkLabel2
|
||||
//
|
||||
this.linkLabel2.AutoSize = true;
|
||||
this.linkLabel2.Location = new System.Drawing.Point(11, 85);
|
||||
this.linkLabel2.Name = "linkLabel2";
|
||||
this.linkLabel2.Size = new System.Drawing.Size(69, 13);
|
||||
this.linkLabel2.TabIndex = 4;
|
||||
this.linkLabel2.TabStop = true;
|
||||
this.linkLabel2.Text = "View memory";
|
||||
this.linkLabel2.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabel2_LinkClicked);
|
||||
//
|
||||
// linkLabel1
|
||||
//
|
||||
this.linkLabel1.AutoSize = true;
|
||||
this.linkLabel1.Location = new System.Drawing.Point(11, 60);
|
||||
this.linkLabel1.Name = "linkLabel1";
|
||||
this.linkLabel1.Size = new System.Drawing.Size(95, 13);
|
||||
this.linkLabel1.TabIndex = 3;
|
||||
this.linkLabel1.TabStop = true;
|
||||
this.linkLabel1.Text = "View file resources";
|
||||
this.linkLabel1.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabel1_LinkClicked);
|
||||
//
|
||||
// label9
|
||||
//
|
||||
this.label9.AutoSize = true;
|
||||
this.label9.Location = new System.Drawing.Point(9, 35);
|
||||
this.label9.Name = "label9";
|
||||
this.label9.Size = new System.Drawing.Size(268, 13);
|
||||
this.label9.TabIndex = 1;
|
||||
this.label9.Text = "To get started, select Debug->Start from the main menu";
|
||||
//
|
||||
// label7
|
||||
//
|
||||
this.label7.AutoSize = true;
|
||||
this.label7.Location = new System.Drawing.Point(11, 6);
|
||||
this.label7.Name = "label7";
|
||||
this.label7.Size = new System.Drawing.Size(155, 13);
|
||||
this.label7.TabIndex = 0;
|
||||
this.label7.Text = "Welcome to the cxbx-debugger";
|
||||
//
|
||||
// tabDisassembly
|
||||
//
|
||||
this.tabDisassembly.Controls.Add(this.splitContainer2);
|
||||
this.tabDisassembly.Location = new System.Drawing.Point(4, 22);
|
||||
this.tabDisassembly.Name = "tabDisassembly";
|
||||
this.tabDisassembly.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.tabDisassembly.Size = new System.Drawing.Size(720, 196);
|
||||
this.tabDisassembly.Padding = new System.Windows.Forms.Padding(3, 3, 3, 3);
|
||||
this.tabDisassembly.Size = new System.Drawing.Size(654, 318);
|
||||
this.tabDisassembly.TabIndex = 0;
|
||||
this.tabDisassembly.Text = "Disassembly";
|
||||
this.tabDisassembly.UseVisualStyleBackColor = true;
|
||||
|
@ -329,14 +337,14 @@
|
|||
// splitContainer2.Panel2
|
||||
//
|
||||
this.splitContainer2.Panel2.Controls.Add(this.txDisassembly);
|
||||
this.splitContainer2.Size = new System.Drawing.Size(714, 190);
|
||||
this.splitContainer2.Size = new System.Drawing.Size(648, 312);
|
||||
this.splitContainer2.SplitterDistance = 34;
|
||||
this.splitContainer2.TabIndex = 2;
|
||||
//
|
||||
// btnToMemory
|
||||
//
|
||||
this.btnToMemory.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnToMemory.Location = new System.Drawing.Point(452, 3);
|
||||
this.btnToMemory.Location = new System.Drawing.Point(386, 3);
|
||||
this.btnToMemory.Name = "btnToMemory";
|
||||
this.btnToMemory.Size = new System.Drawing.Size(119, 23);
|
||||
this.btnToMemory.TabIndex = 4;
|
||||
|
@ -347,7 +355,7 @@
|
|||
// btnNext
|
||||
//
|
||||
this.btnNext.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnNext.Location = new System.Drawing.Point(647, 3);
|
||||
this.btnNext.Location = new System.Drawing.Point(581, 3);
|
||||
this.btnNext.Name = "btnNext";
|
||||
this.btnNext.Size = new System.Drawing.Size(64, 23);
|
||||
this.btnNext.TabIndex = 3;
|
||||
|
@ -358,7 +366,7 @@
|
|||
// btnPrev
|
||||
//
|
||||
this.btnPrev.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnPrev.Location = new System.Drawing.Point(577, 3);
|
||||
this.btnPrev.Location = new System.Drawing.Point(512, 3);
|
||||
this.btnPrev.Name = "btnPrev";
|
||||
this.btnPrev.Size = new System.Drawing.Size(64, 23);
|
||||
this.btnPrev.TabIndex = 2;
|
||||
|
@ -369,7 +377,7 @@
|
|||
// btnGo
|
||||
//
|
||||
this.btnGo.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnGo.Location = new System.Drawing.Point(327, 3);
|
||||
this.btnGo.Location = new System.Drawing.Point(261, 3);
|
||||
this.btnGo.Name = "btnGo";
|
||||
this.btnGo.Size = new System.Drawing.Size(119, 23);
|
||||
this.btnGo.TabIndex = 1;
|
||||
|
@ -393,33 +401,18 @@
|
|||
this.cbDisAddr.FormattingEnabled = true;
|
||||
this.cbDisAddr.Location = new System.Drawing.Point(132, 5);
|
||||
this.cbDisAddr.Name = "cbDisAddr";
|
||||
this.cbDisAddr.Size = new System.Drawing.Size(189, 21);
|
||||
this.cbDisAddr.Size = new System.Drawing.Size(124, 21);
|
||||
this.cbDisAddr.TabIndex = 0;
|
||||
this.cbDisAddr.SelectedIndexChanged += new System.EventHandler(this.cbDisAddr_SelectedIndexChanged);
|
||||
this.cbDisAddr.KeyDown += new System.Windows.Forms.KeyEventHandler(this.comboBox1_KeyDown);
|
||||
//
|
||||
// txDisassembly
|
||||
//
|
||||
this.txDisassembly.BackColor = System.Drawing.SystemColors.Window;
|
||||
this.txDisassembly.BorderStyle = System.Windows.Forms.BorderStyle.None;
|
||||
this.txDisassembly.Cursor = System.Windows.Forms.Cursors.Default;
|
||||
this.txDisassembly.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.txDisassembly.Font = new System.Drawing.Font("Lucida Console", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.txDisassembly.Location = new System.Drawing.Point(0, 0);
|
||||
this.txDisassembly.Name = "txDisassembly";
|
||||
this.txDisassembly.ReadOnly = true;
|
||||
this.txDisassembly.ScrollBars = System.Windows.Forms.RichTextBoxScrollBars.ForcedVertical;
|
||||
this.txDisassembly.Size = new System.Drawing.Size(714, 152);
|
||||
this.txDisassembly.TabIndex = 1;
|
||||
this.txDisassembly.Text = "";
|
||||
//
|
||||
// tabBreakpoints
|
||||
//
|
||||
this.tabBreakpoints.Controls.Add(this.splitContainer3);
|
||||
this.tabBreakpoints.Location = new System.Drawing.Point(4, 22);
|
||||
this.tabBreakpoints.Name = "tabBreakpoints";
|
||||
this.tabBreakpoints.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.tabBreakpoints.Size = new System.Drawing.Size(720, 196);
|
||||
this.tabBreakpoints.Padding = new System.Windows.Forms.Padding(3, 3, 3, 3);
|
||||
this.tabBreakpoints.Size = new System.Drawing.Size(654, 318);
|
||||
this.tabBreakpoints.TabIndex = 1;
|
||||
this.tabBreakpoints.Text = "Breakpoints";
|
||||
this.tabBreakpoints.UseVisualStyleBackColor = true;
|
||||
|
@ -438,8 +431,8 @@
|
|||
// splitContainer3.Panel2
|
||||
//
|
||||
this.splitContainer3.Panel2.Controls.Add(this.clbBreakpoints);
|
||||
this.splitContainer3.Size = new System.Drawing.Size(714, 190);
|
||||
this.splitContainer3.SplitterDistance = 237;
|
||||
this.splitContainer3.Size = new System.Drawing.Size(648, 312);
|
||||
this.splitContainer3.SplitterDistance = 214;
|
||||
this.splitContainer3.TabIndex = 5;
|
||||
//
|
||||
// groupBox4
|
||||
|
@ -451,7 +444,7 @@
|
|||
this.groupBox4.Controls.Add(this.cbBreakpointCxbx);
|
||||
this.groupBox4.Location = new System.Drawing.Point(2, 112);
|
||||
this.groupBox4.Name = "groupBox4";
|
||||
this.groupBox4.Size = new System.Drawing.Size(233, 75);
|
||||
this.groupBox4.Size = new System.Drawing.Size(210, 196);
|
||||
this.groupBox4.TabIndex = 5;
|
||||
this.groupBox4.TabStop = false;
|
||||
this.groupBox4.Text = "Interrupts";
|
||||
|
@ -489,7 +482,7 @@
|
|||
this.groupBox1.Controls.Add(this.tbFilter);
|
||||
this.groupBox1.Location = new System.Drawing.Point(0, 0);
|
||||
this.groupBox1.Name = "groupBox1";
|
||||
this.groupBox1.Size = new System.Drawing.Size(234, 106);
|
||||
this.groupBox1.Size = new System.Drawing.Size(211, 106);
|
||||
this.groupBox1.TabIndex = 4;
|
||||
this.groupBox1.TabStop = false;
|
||||
this.groupBox1.Text = "File Watch";
|
||||
|
@ -502,7 +495,7 @@
|
|||
this.cbAction.FormattingEnabled = true;
|
||||
this.cbAction.Location = new System.Drawing.Point(89, 45);
|
||||
this.cbAction.Name = "cbAction";
|
||||
this.cbAction.Size = new System.Drawing.Size(139, 21);
|
||||
this.cbAction.Size = new System.Drawing.Size(115, 21);
|
||||
this.cbAction.TabIndex = 6;
|
||||
//
|
||||
// label5
|
||||
|
@ -529,7 +522,7 @@
|
|||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnAddFileBp.Location = new System.Drawing.Point(89, 72);
|
||||
this.btnAddFileBp.Name = "btnAddFileBp";
|
||||
this.btnAddFileBp.Size = new System.Drawing.Size(139, 23);
|
||||
this.btnAddFileBp.Size = new System.Drawing.Size(115, 23);
|
||||
this.btnAddFileBp.TabIndex = 4;
|
||||
this.btnAddFileBp.Text = "Add";
|
||||
this.btnAddFileBp.UseVisualStyleBackColor = true;
|
||||
|
@ -541,7 +534,7 @@
|
|||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.tbFilter.Location = new System.Drawing.Point(89, 19);
|
||||
this.tbFilter.Name = "tbFilter";
|
||||
this.tbFilter.Size = new System.Drawing.Size(139, 20);
|
||||
this.tbFilter.Size = new System.Drawing.Size(115, 20);
|
||||
this.tbFilter.TabIndex = 2;
|
||||
//
|
||||
// clbBreakpoints
|
||||
|
@ -550,7 +543,7 @@
|
|||
this.clbBreakpoints.FormattingEnabled = true;
|
||||
this.clbBreakpoints.Location = new System.Drawing.Point(0, 0);
|
||||
this.clbBreakpoints.Name = "clbBreakpoints";
|
||||
this.clbBreakpoints.Size = new System.Drawing.Size(473, 190);
|
||||
this.clbBreakpoints.Size = new System.Drawing.Size(430, 312);
|
||||
this.clbBreakpoints.TabIndex = 0;
|
||||
this.clbBreakpoints.ItemCheck += new System.Windows.Forms.ItemCheckEventHandler(this.clbBreakpoints_ItemCheck);
|
||||
this.clbBreakpoints.KeyDown += new System.Windows.Forms.KeyEventHandler(this.clbBreakpoints_KeyDown);
|
||||
|
@ -560,8 +553,8 @@
|
|||
this.tabWatch.Controls.Add(this.splitContainer1);
|
||||
this.tabWatch.Location = new System.Drawing.Point(4, 22);
|
||||
this.tabWatch.Name = "tabWatch";
|
||||
this.tabWatch.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.tabWatch.Size = new System.Drawing.Size(720, 196);
|
||||
this.tabWatch.Padding = new System.Windows.Forms.Padding(3, 3, 3, 3);
|
||||
this.tabWatch.Size = new System.Drawing.Size(654, 318);
|
||||
this.tabWatch.TabIndex = 2;
|
||||
this.tabWatch.Text = "File Watcher";
|
||||
this.tabWatch.UseVisualStyleBackColor = true;
|
||||
|
@ -579,8 +572,8 @@
|
|||
// splitContainer1.Panel2
|
||||
//
|
||||
this.splitContainer1.Panel2.Controls.Add(this.lbOpenedFiles);
|
||||
this.splitContainer1.Size = new System.Drawing.Size(714, 190);
|
||||
this.splitContainer1.SplitterDistance = 501;
|
||||
this.splitContainer1.Size = new System.Drawing.Size(648, 312);
|
||||
this.splitContainer1.SplitterDistance = 453;
|
||||
this.splitContainer1.TabIndex = 3;
|
||||
//
|
||||
// lvFileDetails
|
||||
|
@ -595,7 +588,7 @@
|
|||
this.lvFileDetails.Location = new System.Drawing.Point(0, 0);
|
||||
this.lvFileDetails.MultiSelect = false;
|
||||
this.lvFileDetails.Name = "lvFileDetails";
|
||||
this.lvFileDetails.Size = new System.Drawing.Size(501, 190);
|
||||
this.lvFileDetails.Size = new System.Drawing.Size(453, 312);
|
||||
this.lvFileDetails.TabIndex = 2;
|
||||
this.lvFileDetails.UseCompatibleStateImageBehavior = false;
|
||||
this.lvFileDetails.View = System.Windows.Forms.View.Details;
|
||||
|
@ -621,7 +614,7 @@
|
|||
this.lbOpenedFiles.FormattingEnabled = true;
|
||||
this.lbOpenedFiles.Location = new System.Drawing.Point(0, 0);
|
||||
this.lbOpenedFiles.Name = "lbOpenedFiles";
|
||||
this.lbOpenedFiles.Size = new System.Drawing.Size(209, 190);
|
||||
this.lbOpenedFiles.Size = new System.Drawing.Size(191, 312);
|
||||
this.lbOpenedFiles.TabIndex = 0;
|
||||
//
|
||||
// tabMemory
|
||||
|
@ -629,8 +622,8 @@
|
|||
this.tabMemory.Controls.Add(this.splitContainer4);
|
||||
this.tabMemory.Location = new System.Drawing.Point(4, 22);
|
||||
this.tabMemory.Name = "tabMemory";
|
||||
this.tabMemory.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.tabMemory.Size = new System.Drawing.Size(720, 196);
|
||||
this.tabMemory.Padding = new System.Windows.Forms.Padding(3, 3, 3, 3);
|
||||
this.tabMemory.Size = new System.Drawing.Size(720, 236);
|
||||
this.tabMemory.TabIndex = 4;
|
||||
this.tabMemory.Text = "Memory Viewer";
|
||||
this.tabMemory.UseVisualStyleBackColor = true;
|
||||
|
@ -648,8 +641,8 @@
|
|||
// splitContainer4.Panel2
|
||||
//
|
||||
this.splitContainer4.Panel2.Controls.Add(this.groupBox2);
|
||||
this.splitContainer4.Size = new System.Drawing.Size(714, 190);
|
||||
this.splitContainer4.SplitterDistance = 376;
|
||||
this.splitContainer4.Size = new System.Drawing.Size(714, 230);
|
||||
this.splitContainer4.SplitterDistance = 375;
|
||||
this.splitContainer4.TabIndex = 7;
|
||||
//
|
||||
// txMemoryDump
|
||||
|
@ -663,7 +656,7 @@
|
|||
this.txMemoryDump.Name = "txMemoryDump";
|
||||
this.txMemoryDump.ReadOnly = true;
|
||||
this.txMemoryDump.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
|
||||
this.txMemoryDump.Size = new System.Drawing.Size(376, 190);
|
||||
this.txMemoryDump.Size = new System.Drawing.Size(375, 230);
|
||||
this.txMemoryDump.TabIndex = 0;
|
||||
//
|
||||
// groupBox2
|
||||
|
@ -681,7 +674,7 @@
|
|||
this.groupBox2.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.groupBox2.Location = new System.Drawing.Point(0, 0);
|
||||
this.groupBox2.Name = "groupBox2";
|
||||
this.groupBox2.Size = new System.Drawing.Size(334, 190);
|
||||
this.groupBox2.Size = new System.Drawing.Size(335, 230);
|
||||
this.groupBox2.TabIndex = 8;
|
||||
this.groupBox2.TabStop = false;
|
||||
this.groupBox2.Text = "View or Dump Memory";
|
||||
|
@ -690,9 +683,9 @@
|
|||
//
|
||||
this.textBox2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.textBox2.Location = new System.Drawing.Point(213, 129);
|
||||
this.textBox2.Location = new System.Drawing.Point(183, 129);
|
||||
this.textBox2.Name = "textBox2";
|
||||
this.textBox2.Size = new System.Drawing.Size(115, 20);
|
||||
this.textBox2.Size = new System.Drawing.Size(146, 20);
|
||||
this.textBox2.TabIndex = 10;
|
||||
//
|
||||
// label8
|
||||
|
@ -706,13 +699,11 @@
|
|||
//
|
||||
// cbDataFormat
|
||||
//
|
||||
this.cbDataFormat.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.cbDataFormat.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.cbDataFormat.FormattingEnabled = true;
|
||||
this.cbDataFormat.Location = new System.Drawing.Point(88, 130);
|
||||
this.cbDataFormat.Name = "cbDataFormat";
|
||||
this.cbDataFormat.Size = new System.Drawing.Size(119, 21);
|
||||
this.cbDataFormat.Size = new System.Drawing.Size(89, 21);
|
||||
this.cbDataFormat.TabIndex = 8;
|
||||
this.cbDataFormat.SelectionChangeCommitted += new System.EventHandler(this.cbDataFormat_SelectionChangeCommitted);
|
||||
//
|
||||
|
@ -722,7 +713,7 @@
|
|||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnAddWatch.Location = new System.Drawing.Point(88, 157);
|
||||
this.btnAddWatch.Name = "btnAddWatch";
|
||||
this.btnAddWatch.Size = new System.Drawing.Size(240, 23);
|
||||
this.btnAddWatch.Size = new System.Drawing.Size(241, 23);
|
||||
this.btnAddWatch.TabIndex = 7;
|
||||
this.btnAddWatch.Text = "Add to Editor...";
|
||||
this.btnAddWatch.UseVisualStyleBackColor = true;
|
||||
|
@ -743,7 +734,7 @@
|
|||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnDumpMemory.Location = new System.Drawing.Point(88, 100);
|
||||
this.btnDumpMemory.Name = "btnDumpMemory";
|
||||
this.btnDumpMemory.Size = new System.Drawing.Size(240, 23);
|
||||
this.btnDumpMemory.Size = new System.Drawing.Size(241, 23);
|
||||
this.btnDumpMemory.TabIndex = 6;
|
||||
this.btnDumpMemory.Text = "Dump Memory to File...";
|
||||
this.btnDumpMemory.UseVisualStyleBackColor = true;
|
||||
|
@ -755,7 +746,7 @@
|
|||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.txAddress.Location = new System.Drawing.Point(88, 18);
|
||||
this.txAddress.Name = "txAddress";
|
||||
this.txAddress.Size = new System.Drawing.Size(240, 20);
|
||||
this.txAddress.Size = new System.Drawing.Size(241, 20);
|
||||
this.txAddress.TabIndex = 1;
|
||||
//
|
||||
// label2
|
||||
|
@ -773,7 +764,7 @@
|
|||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnReadMemory.Location = new System.Drawing.Point(88, 71);
|
||||
this.btnReadMemory.Name = "btnReadMemory";
|
||||
this.btnReadMemory.Size = new System.Drawing.Size(240, 23);
|
||||
this.btnReadMemory.Size = new System.Drawing.Size(241, 23);
|
||||
this.btnReadMemory.TabIndex = 2;
|
||||
this.btnReadMemory.Text = "Read Memory";
|
||||
this.btnReadMemory.UseVisualStyleBackColor = true;
|
||||
|
@ -785,7 +776,7 @@
|
|||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.txSize.Location = new System.Drawing.Point(88, 45);
|
||||
this.txSize.Name = "txSize";
|
||||
this.txSize.Size = new System.Drawing.Size(240, 20);
|
||||
this.txSize.Size = new System.Drawing.Size(241, 20);
|
||||
this.txSize.TabIndex = 3;
|
||||
this.txSize.Text = "32";
|
||||
//
|
||||
|
@ -794,8 +785,8 @@
|
|||
this.tabTweaks.Controls.Add(this.tabCEContainer);
|
||||
this.tabTweaks.Location = new System.Drawing.Point(4, 22);
|
||||
this.tabTweaks.Name = "tabTweaks";
|
||||
this.tabTweaks.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.tabTweaks.Size = new System.Drawing.Size(720, 196);
|
||||
this.tabTweaks.Padding = new System.Windows.Forms.Padding(3, 3, 3, 3);
|
||||
this.tabTweaks.Size = new System.Drawing.Size(654, 318);
|
||||
this.tabTweaks.TabIndex = 5;
|
||||
this.tabTweaks.Text = "Memory Editor";
|
||||
this.tabTweaks.UseVisualStyleBackColor = true;
|
||||
|
@ -808,7 +799,7 @@
|
|||
this.tabCEContainer.Location = new System.Drawing.Point(3, 3);
|
||||
this.tabCEContainer.Name = "tabCEContainer";
|
||||
this.tabCEContainer.SelectedIndex = 0;
|
||||
this.tabCEContainer.Size = new System.Drawing.Size(714, 190);
|
||||
this.tabCEContainer.Size = new System.Drawing.Size(648, 312);
|
||||
this.tabCEContainer.TabIndex = 5;
|
||||
//
|
||||
// tabSubData
|
||||
|
@ -816,8 +807,8 @@
|
|||
this.tabSubData.Controls.Add(this.splitContainer6);
|
||||
this.tabSubData.Location = new System.Drawing.Point(4, 22);
|
||||
this.tabSubData.Name = "tabSubData";
|
||||
this.tabSubData.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.tabSubData.Size = new System.Drawing.Size(706, 164);
|
||||
this.tabSubData.Padding = new System.Windows.Forms.Padding(3, 3, 3, 3);
|
||||
this.tabSubData.Size = new System.Drawing.Size(640, 286);
|
||||
this.tabSubData.TabIndex = 0;
|
||||
this.tabSubData.Text = "Edit Data";
|
||||
this.tabSubData.UseVisualStyleBackColor = true;
|
||||
|
@ -839,8 +830,8 @@
|
|||
// splitContainer6.Panel2
|
||||
//
|
||||
this.splitContainer6.Panel2.Controls.Add(this.lvCEMemory);
|
||||
this.splitContainer6.Size = new System.Drawing.Size(700, 158);
|
||||
this.splitContainer6.SplitterDistance = 34;
|
||||
this.splitContainer6.Size = new System.Drawing.Size(634, 280);
|
||||
this.splitContainer6.SplitterDistance = 57;
|
||||
this.splitContainer6.TabIndex = 2;
|
||||
//
|
||||
// btnRefresh
|
||||
|
@ -866,7 +857,7 @@
|
|||
// btnApply
|
||||
//
|
||||
this.btnApply.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.btnApply.Location = new System.Drawing.Point(574, 3);
|
||||
this.btnApply.Location = new System.Drawing.Point(508, 3);
|
||||
this.btnApply.Name = "btnApply";
|
||||
this.btnApply.Size = new System.Drawing.Size(123, 23);
|
||||
this.btnApply.TabIndex = 4;
|
||||
|
@ -880,7 +871,7 @@
|
|||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.txNewValue.Location = new System.Drawing.Point(261, 5);
|
||||
this.txNewValue.Name = "txNewValue";
|
||||
this.txNewValue.Size = new System.Drawing.Size(307, 20);
|
||||
this.txNewValue.Size = new System.Drawing.Size(240, 20);
|
||||
this.txNewValue.TabIndex = 2;
|
||||
//
|
||||
// lvCEMemory
|
||||
|
@ -896,7 +887,7 @@
|
|||
this.lvCEMemory.Location = new System.Drawing.Point(0, 0);
|
||||
this.lvCEMemory.MultiSelect = false;
|
||||
this.lvCEMemory.Name = "lvCEMemory";
|
||||
this.lvCEMemory.Size = new System.Drawing.Size(700, 120);
|
||||
this.lvCEMemory.Size = new System.Drawing.Size(634, 219);
|
||||
this.lvCEMemory.TabIndex = 1;
|
||||
this.lvCEMemory.UseCompatibleStateImageBehavior = false;
|
||||
this.lvCEMemory.View = System.Windows.Forms.View.Details;
|
||||
|
@ -926,8 +917,8 @@
|
|||
this.tabSubAssembly.Controls.Add(this.lvCEAssembly);
|
||||
this.tabSubAssembly.Location = new System.Drawing.Point(4, 22);
|
||||
this.tabSubAssembly.Name = "tabSubAssembly";
|
||||
this.tabSubAssembly.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.tabSubAssembly.Size = new System.Drawing.Size(706, 164);
|
||||
this.tabSubAssembly.Padding = new System.Windows.Forms.Padding(3, 3, 3, 3);
|
||||
this.tabSubAssembly.Size = new System.Drawing.Size(640, 286);
|
||||
this.tabSubAssembly.TabIndex = 1;
|
||||
this.tabSubAssembly.Text = "Edit Assembly";
|
||||
this.tabSubAssembly.UseVisualStyleBackColor = true;
|
||||
|
@ -945,7 +936,7 @@
|
|||
this.lvCEAssembly.Location = new System.Drawing.Point(3, 3);
|
||||
this.lvCEAssembly.MultiSelect = false;
|
||||
this.lvCEAssembly.Name = "lvCEAssembly";
|
||||
this.lvCEAssembly.Size = new System.Drawing.Size(700, 158);
|
||||
this.lvCEAssembly.Size = new System.Drawing.Size(635, 280);
|
||||
this.lvCEAssembly.TabIndex = 4;
|
||||
this.lvCEAssembly.UseCompatibleStateImageBehavior = false;
|
||||
this.lvCEAssembly.View = System.Windows.Forms.View.Details;
|
||||
|
@ -975,8 +966,8 @@
|
|||
this.tabOutput.Controls.Add(this.splitContainer5);
|
||||
this.tabOutput.Location = new System.Drawing.Point(4, 22);
|
||||
this.tabOutput.Name = "tabOutput";
|
||||
this.tabOutput.Padding = new System.Windows.Forms.Padding(3);
|
||||
this.tabOutput.Size = new System.Drawing.Size(720, 196);
|
||||
this.tabOutput.Padding = new System.Windows.Forms.Padding(3, 3, 3, 3);
|
||||
this.tabOutput.Size = new System.Drawing.Size(654, 318);
|
||||
this.tabOutput.TabIndex = 3;
|
||||
this.tabOutput.Text = "Debug Output";
|
||||
this.tabOutput.UseVisualStyleBackColor = true;
|
||||
|
@ -998,7 +989,7 @@
|
|||
// splitContainer5.Panel2
|
||||
//
|
||||
this.splitContainer5.Panel2.Controls.Add(this.lbDebug);
|
||||
this.splitContainer5.Size = new System.Drawing.Size(714, 190);
|
||||
this.splitContainer5.Size = new System.Drawing.Size(648, 312);
|
||||
this.splitContainer5.SplitterDistance = 26;
|
||||
this.splitContainer5.TabIndex = 6;
|
||||
//
|
||||
|
@ -1009,7 +1000,7 @@
|
|||
this.txFilter.Enabled = false;
|
||||
this.txFilter.Location = new System.Drawing.Point(41, 3);
|
||||
this.txFilter.Name = "txFilter";
|
||||
this.txFilter.Size = new System.Drawing.Size(670, 20);
|
||||
this.txFilter.Size = new System.Drawing.Size(604, 20);
|
||||
this.txFilter.TabIndex = 4;
|
||||
//
|
||||
// label3
|
||||
|
@ -1029,7 +1020,7 @@
|
|||
this.lbDebug.Location = new System.Drawing.Point(0, 0);
|
||||
this.lbDebug.Name = "lbDebug";
|
||||
this.lbDebug.ScrollAlwaysVisible = true;
|
||||
this.lbDebug.Size = new System.Drawing.Size(714, 160);
|
||||
this.lbDebug.Size = new System.Drawing.Size(648, 282);
|
||||
this.lbDebug.TabIndex = 3;
|
||||
//
|
||||
// diagSaveMemory
|
||||
|
@ -1042,24 +1033,40 @@
|
|||
this.diagBrowseCT.Filter = "Cheat Engine Tables (*.CT)|*.ct";
|
||||
this.diagBrowseCT.Title = "Load cheat table";
|
||||
//
|
||||
// Form1
|
||||
// txDisassembly
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(734, 331);
|
||||
this.txDisassembly.BackColor = System.Drawing.SystemColors.Window;
|
||||
this.txDisassembly.BorderStyle = System.Windows.Forms.BorderStyle.None;
|
||||
this.txDisassembly.Cursor = System.Windows.Forms.Cursors.Default;
|
||||
this.txDisassembly.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
this.txDisassembly.Font = new System.Drawing.Font("Lucida Console", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.txDisassembly.Location = new System.Drawing.Point(0, 0);
|
||||
this.txDisassembly.Name = "txDisassembly";
|
||||
this.txDisassembly.ReadOnly = true;
|
||||
this.txDisassembly.ScrollBars = System.Windows.Forms.RichTextBoxScrollBars.ForcedVertical;
|
||||
this.txDisassembly.Size = new System.Drawing.Size(648, 274);
|
||||
this.txDisassembly.TabIndex = 1;
|
||||
this.txDisassembly.Text = "";
|
||||
//
|
||||
// CxbxDebuggerInstance
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
this.ClientSize = new System.Drawing.Size(734, 361);
|
||||
this.ControlBox = false;
|
||||
this.Controls.Add(this.tableLayoutPanel3);
|
||||
this.Controls.Add(this.toolStrip1);
|
||||
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
|
||||
this.Name = "Form1";
|
||||
this.Text = "Cxbx-Reloaded Debugger";
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "CxbxDebuggerInstance";
|
||||
this.Text = "unnamed instance";
|
||||
this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.Form1_FormClosed);
|
||||
this.toolStrip1.ResumeLayout(false);
|
||||
this.toolStrip1.PerformLayout();
|
||||
this.tableLayoutPanel3.ResumeLayout(false);
|
||||
this.tableLayoutPanel3.PerformLayout();
|
||||
this.statusBar.ResumeLayout(false);
|
||||
this.statusBar.PerformLayout();
|
||||
this.tabContainer.ResumeLayout(false);
|
||||
this.tabSummary.ResumeLayout(false);
|
||||
this.tabSummary.PerformLayout();
|
||||
this.tabDisassembly.ResumeLayout(false);
|
||||
this.splitContainer2.Panel1.ResumeLayout(false);
|
||||
this.splitContainer2.Panel1.PerformLayout();
|
||||
|
@ -1111,11 +1118,6 @@
|
|||
#endregion
|
||||
private System.Windows.Forms.ListBox lbConsole;
|
||||
private System.Windows.Forms.ToolStrip toolStrip1;
|
||||
private System.Windows.Forms.ToolStripButton btnStart;
|
||||
private System.Windows.Forms.ToolStripSeparator toolStripSeparator1;
|
||||
private System.Windows.Forms.ToolStripButton btnSuspend;
|
||||
private System.Windows.Forms.ToolStripButton btnResume;
|
||||
private System.Windows.Forms.ToolStripSeparator toolStripSeparator2;
|
||||
private System.Windows.Forms.ToolStripComboBox cbThreads;
|
||||
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel3;
|
||||
private System.Windows.Forms.TabControl tabContainer;
|
||||
|
@ -1135,8 +1137,6 @@
|
|||
private System.Windows.Forms.TextBox txAddress;
|
||||
private System.Windows.Forms.GroupBox groupBox1;
|
||||
private System.Windows.Forms.TextBox tbFilter;
|
||||
private System.Windows.Forms.StatusStrip statusBar;
|
||||
private System.Windows.Forms.ToolStripStatusLabel lblStatus;
|
||||
private RicherTextBox txDisassembly;
|
||||
private System.Windows.Forms.Label label2;
|
||||
private System.Windows.Forms.Label label1;
|
||||
|
@ -1192,6 +1192,11 @@
|
|||
private System.Windows.Forms.Button btnLoadCT;
|
||||
private System.Windows.Forms.Button btnRefresh;
|
||||
private System.Windows.Forms.TextBox textBox2;
|
||||
private System.Windows.Forms.TabPage tabSummary;
|
||||
private System.Windows.Forms.Label label7;
|
||||
private System.Windows.Forms.Label label9;
|
||||
private System.Windows.Forms.LinkLabel linkLabel3;
|
||||
private System.Windows.Forms.LinkLabel linkLabel2;
|
||||
private System.Windows.Forms.LinkLabel linkLabel1;
|
||||
}
|
||||
}
|
||||
|
|
@ -8,15 +8,15 @@ using System.Collections.Generic;
|
|||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using cs_x86;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace CxbxDebugger
|
||||
{
|
||||
public partial class Form1 : Form
|
||||
public partial class CxbxDebuggerInstance : Form, IDebugWindow
|
||||
{
|
||||
Thread DebuggerWorkerThread;
|
||||
Debugger DebuggerInst;
|
||||
string[] CachedArgs;
|
||||
string CachedTitle = "";
|
||||
string[] StartupArgs;
|
||||
bool SuspendedOnBp = false;
|
||||
|
||||
DebuggerFormEvents DebugEvents;
|
||||
|
@ -29,33 +29,45 @@ namespace CxbxDebugger
|
|||
DebugOutputManager debugStrMan;
|
||||
PatchManager patchMan;
|
||||
|
||||
IDebugContainerWindow DebugContainer
|
||||
{
|
||||
get
|
||||
{
|
||||
return MdiParent as IDebugContainerWindow;
|
||||
}
|
||||
}
|
||||
|
||||
DebugStateInfo StateInfo = new DebugStateInfo();
|
||||
|
||||
private void SetDebugState(DebugState State, string Detail = "")
|
||||
{
|
||||
DebugContainer.ReportStatus(this, State, Detail);
|
||||
|
||||
StateInfo.State = State;
|
||||
StateInfo.Detail = Detail;
|
||||
}
|
||||
|
||||
List<DebuggerMessages.FileOpened> FileHandles = new List<DebuggerMessages.FileOpened>();
|
||||
|
||||
public Form1()
|
||||
public CxbxDebuggerInstance(Form Owner, string[] args)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
// TODO: Cleanup arg handling
|
||||
|
||||
string[] args = Environment.GetCommandLineArgs();
|
||||
MdiParent = Owner;
|
||||
|
||||
#if !DEBUG
|
||||
// Arguments are expected before the Form is created
|
||||
if (args.Length < 2)
|
||||
{
|
||||
throw new Exception("Incorrect usage");
|
||||
}
|
||||
#endif
|
||||
|
||||
var items = new List<string>(args.Length - 1);
|
||||
for (int i = 1; i < args.Length; ++i)
|
||||
{
|
||||
items.Add(args[i]);
|
||||
}
|
||||
|
||||
CachedArgs = items.ToArray();
|
||||
StartupArgs = args;
|
||||
|
||||
DebugEvents = new DebuggerFormEvents(this);
|
||||
|
||||
SetDebugProcessActive(false);
|
||||
SetDebugState(DebugState.Unknown);
|
||||
|
||||
txDisassembly.InlineLinkClicked += OnDisassemblyNavigation;
|
||||
|
||||
|
@ -77,6 +89,8 @@ namespace CxbxDebugger
|
|||
fileWatchMan = new FileWatchManager(clbBreakpoints);
|
||||
debugStrMan = new DebugOutputManager(lbDebug);
|
||||
patchMan = new PatchManager();
|
||||
|
||||
CreateDebuggerOnce();
|
||||
}
|
||||
|
||||
private void OnDisassemblyNavigation(object sender, InlineLinkClickedEventArgs e)
|
||||
|
@ -86,38 +100,85 @@ namespace CxbxDebugger
|
|||
ShowDisassemblyAt(e.Link);
|
||||
}
|
||||
|
||||
private void StartDebugging()
|
||||
private void CreateDebuggerOnce()
|
||||
{
|
||||
bool Create = false;
|
||||
|
||||
if (DebuggerWorkerThread == null)
|
||||
{
|
||||
// First launch
|
||||
Create = true;
|
||||
}
|
||||
else if (DebuggerWorkerThread.ThreadState == ThreadState.Stopped)
|
||||
{
|
||||
// Further launches
|
||||
Create = true;
|
||||
}
|
||||
|
||||
if (Create)
|
||||
if (DebuggerInst == null)
|
||||
{
|
||||
// Create debugger instance
|
||||
DebuggerInst = new Debugger(CachedArgs);
|
||||
DebuggerInst = new Debugger(StartupArgs);
|
||||
DebuggerInst.RegisterEventInterfaces(DebugEvents);
|
||||
DebuggerInst.RegisterEventInterfaces(patchMan);
|
||||
|
||||
var TargetXbeName = ValidateXbeTargetName(DebuggerInst.TargetPath);
|
||||
var TargetXbeValid = true;
|
||||
|
||||
if (string.IsNullOrEmpty(TargetXbeName))
|
||||
{
|
||||
TargetXbeName = "<unknown>";
|
||||
TargetXbeValid = false;
|
||||
}
|
||||
|
||||
if (InvokeRequired)
|
||||
{
|
||||
// Set form title based on this new process
|
||||
Invoke(new MethodInvoker(delegate ()
|
||||
{
|
||||
Text = TargetXbeName;
|
||||
}));
|
||||
}
|
||||
else
|
||||
{
|
||||
Text = TargetXbeName;
|
||||
}
|
||||
|
||||
if (TargetXbeValid)
|
||||
{
|
||||
SetDebugState(DebugState.Idle, $"{TargetXbeName} is waiting to start");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string ValidateXbeTargetName(string XbePath)
|
||||
{
|
||||
var XbeName = Path.GetFileName(XbePath);
|
||||
|
||||
if (File.Exists(XbePath))
|
||||
{
|
||||
return XbeName;
|
||||
}
|
||||
|
||||
// Cxbx CLI will pass through the path as a list of parameters, "dir;name"
|
||||
if (XbeName.StartsWith(";"))
|
||||
{
|
||||
var CleanedXbePath = XbePath.Remove(XbePath.Length - XbeName.Length, 1);
|
||||
|
||||
if (File.Exists(CleanedXbePath))
|
||||
{
|
||||
return XbeName.Substring(1);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void StartDebugging()
|
||||
{
|
||||
if (GetSessionState() == SessionState.Inactive)
|
||||
{
|
||||
// Setup new debugger thread
|
||||
DebuggerWorkerThread = new Thread(x =>
|
||||
{
|
||||
CreateDebuggerOnce();
|
||||
|
||||
if (DebuggerInst.Launch())
|
||||
{
|
||||
DebuggerInst.RunThreaded();
|
||||
}
|
||||
});
|
||||
|
||||
DebuggerWorkerThread.Name = "CxbxDebugger";
|
||||
var ProcessName = Path.GetFileName(DebuggerInst.TargetPath);
|
||||
|
||||
DebuggerWorkerThread.Name = $"DebuggerFor_{ProcessName}";
|
||||
DebuggerWorkerThread.Start();
|
||||
}
|
||||
}
|
||||
|
@ -146,7 +207,7 @@ namespace CxbxDebugger
|
|||
if (IsMainThread)
|
||||
PrefixStr = "> ";
|
||||
|
||||
string DisplayStr = string.Format("{0}[{1}] ", PrefixStr, (uint)Thread.Handle);
|
||||
var DisplayStr = $"{PrefixStr}[{(uint)Thread.Handle}]";
|
||||
|
||||
// Resolve thread name
|
||||
|
||||
|
@ -206,7 +267,7 @@ namespace CxbxDebugger
|
|||
|
||||
private void DebugLog(string Message)
|
||||
{
|
||||
string MessageStamped = string.Format("[{0}] {1}", DateTime.Now.ToLongTimeString(), Message);
|
||||
var MessageStamped = $"[{DateTime.Now.ToLongTimeString()}] {Message}";
|
||||
|
||||
if (InvokeRequired)
|
||||
{
|
||||
|
@ -235,11 +296,11 @@ namespace CxbxDebugger
|
|||
{
|
||||
case FileEventType.Read:
|
||||
case FileEventType.Write:
|
||||
string text = string.Format("{0} bytes", Event.Length.ToString());
|
||||
string text = $"{Event.Length} bytes";
|
||||
|
||||
if (Event.Offset != uint.MaxValue)
|
||||
{
|
||||
text += string.Format(" from offset {0}", Event.Offset);
|
||||
text += $" from offset {Event.Offset}";
|
||||
}
|
||||
|
||||
lvi.SubItems.Add(text);
|
||||
|
@ -280,7 +341,7 @@ namespace CxbxDebugger
|
|||
{
|
||||
Invoke(new MethodInvoker(delegate ()
|
||||
{
|
||||
Suspend("file open");
|
||||
Suspend(DebugState.Breakpoint, "Hit file event");
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
@ -290,12 +351,10 @@ namespace CxbxDebugger
|
|||
{
|
||||
Invoke(new MethodInvoker(delegate ()
|
||||
{
|
||||
CachedTitle = Title;
|
||||
|
||||
Text = string.Format("{0} - Cxbx-Reloaded Debugger", CachedTitle);
|
||||
DebugContainer.ReportGameTitle(Title);
|
||||
|
||||
// This is done too late - modules are already loaded
|
||||
//LoadCheatTable(string.Format("{0}.ct", CachedTitle));
|
||||
//LoadCheatTable($"{Title}.ct");
|
||||
}));
|
||||
}
|
||||
|
||||
|
@ -329,7 +388,7 @@ namespace CxbxDebugger
|
|||
else
|
||||
{
|
||||
string module_name = Path.GetFileName(Module.Path);
|
||||
Suspend(string.Format("Breakpoint hit in {0} at 0x{1:x}", module_name, Address));
|
||||
Suspend(DebugState.Breakpoint, string.Format("Breakpoint hit in {0} at 0x{1:x}", module_name, Address));
|
||||
|
||||
// Forces a refresh at the breakpoint address (not the callstack trace)
|
||||
DumpDisassembly(Address);
|
||||
|
@ -344,35 +403,21 @@ namespace CxbxDebugger
|
|||
{
|
||||
Invoke(new MethodInvoker(delegate ()
|
||||
{
|
||||
// Disable when active
|
||||
btnStart.Enabled = !Active;
|
||||
|
||||
// Enable when active
|
||||
btnSuspend.Enabled = Active;
|
||||
btnResume.Enabled = Active;
|
||||
|
||||
lblStatus.Text = (Active ? "Running" : "Inactive");
|
||||
SetDebugState(Active ? DebugState.Running : DebugState.Terminated);
|
||||
}));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Disable when active
|
||||
btnStart.Enabled = !Active;
|
||||
|
||||
// Enable when active
|
||||
btnSuspend.Enabled = Active;
|
||||
btnResume.Enabled = Active;
|
||||
|
||||
lblStatus.Text = (Active ? "Running" : "Inactive");
|
||||
SetDebugState(Active ? DebugState.Running : DebugState.Terminated);
|
||||
}
|
||||
}
|
||||
|
||||
private void btnClearLog_Click(object sender, EventArgs e)
|
||||
{
|
||||
lbConsole.Items.Clear();
|
||||
//lbConsole.Items.Clear();
|
||||
}
|
||||
|
||||
class DebuggerFormEvents : IDebuggerGeneralEvents,
|
||||
class DebuggerFormEvents : IDebuggerSessionEvents,
|
||||
IDebuggerProcessEvents,
|
||||
IDebuggerModuleEvents,
|
||||
IDebuggerThreadEvents,
|
||||
|
@ -380,9 +425,12 @@ namespace CxbxDebugger
|
|||
IDebuggerExceptionEvents,
|
||||
IDebuggerFileEvents
|
||||
{
|
||||
Form1 frm;
|
||||
CxbxDebuggerInstance frm;
|
||||
|
||||
public DebuggerFormEvents(Form1 main)
|
||||
|
||||
|
||||
|
||||
public DebuggerFormEvents(CxbxDebuggerInstance main)
|
||||
{
|
||||
frm = main;
|
||||
}
|
||||
|
@ -397,8 +445,8 @@ namespace CxbxDebugger
|
|||
{
|
||||
int remainingThreads = Process.Threads.Count;
|
||||
|
||||
frm.DebugLog(string.Format("Process exited {0} ({1})", Process.ProcessID, NtStatus.PrettyPrint(ExitCode)));
|
||||
frm.DebugLog(string.Format("{0} child thread(s) remain open", remainingThreads));
|
||||
frm.DebugLog($"Process exited {Process.ProcessID} ({NtStatus.PrettyPrint(ExitCode)})");
|
||||
frm.DebugLog($"{remainingThreads} child thread(s) remain open");
|
||||
|
||||
frm.DebugModules.Clear();
|
||||
|
||||
|
@ -426,36 +474,70 @@ namespace CxbxDebugger
|
|||
|
||||
public void OnDebugTitleLoaded(string Title)
|
||||
{
|
||||
frm.DebugLog(string.Format("Loaded title \"{0}\"", Title));
|
||||
frm.DebugLog($"Loaded title \"{Title}\"");
|
||||
frm.DebugTitle(Title);
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/749653
|
||||
public static string[] CommandLineToArgs(string commandLine)
|
||||
{
|
||||
int argc;
|
||||
var argv = VsChromium.Core.Win32.Processes.NativeMethods.CommandLineToArgvW(commandLine, out argc);
|
||||
if (argv == IntPtr.Zero)
|
||||
throw new System.ComponentModel.Win32Exception();
|
||||
try
|
||||
{
|
||||
var args = new string[argc];
|
||||
for (var i = 0; i < args.Length; i++)
|
||||
{
|
||||
var p = Marshal.ReadIntPtr(argv, i * IntPtr.Size);
|
||||
args[i] = Marshal.PtrToStringUni(p);
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
finally
|
||||
{
|
||||
Marshal.FreeHGlobal(argv);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnDebugTargetChanged(string CommandLine)
|
||||
{
|
||||
frm.DebugLog($"New debug session started - {CommandLine}");
|
||||
|
||||
frm.Invoke(new MethodInvoker(delegate ()
|
||||
{
|
||||
frm.DebugContainer.AddDebugSession(CommandLineToArgs(CommandLine), true);
|
||||
}));
|
||||
}
|
||||
|
||||
public void OnThreadCreate(DebuggerThread Thread)
|
||||
{
|
||||
frm.DebugLog(string.Format("Thread created {0}", Thread.ThreadID));
|
||||
frm.DebugLog($"Thread created {Thread.ThreadID}");
|
||||
frm.DebugThreads.Add(Thread);
|
||||
}
|
||||
|
||||
public void OnThreadExit(DebuggerThread Thread, uint ExitCode)
|
||||
{
|
||||
frm.DebugLog(string.Format("Thread exited {0} ({1})", Thread.ThreadID, NtStatus.PrettyPrint(ExitCode)));
|
||||
frm.DebugLog($"Thread exited {Thread.ThreadID} ({NtStatus.PrettyPrint(ExitCode)})");
|
||||
frm.DebugThreads.Remove(Thread);
|
||||
}
|
||||
|
||||
public void OnThreadNamed(DebuggerThread Thread)
|
||||
{
|
||||
frm.DebugLog(string.Format("Thread {0} named {1}", Thread.ThreadID, Thread.DebugName));
|
||||
frm.DebugLog($"Thread {Thread.ThreadID} named {Thread.DebugName}");
|
||||
}
|
||||
|
||||
public void OnModuleLoaded(DebuggerModule Module)
|
||||
{
|
||||
frm.DebugLog(string.Format("Loaded module \"{0}\"", Module.Path));
|
||||
frm.DebugLog($"Loaded module \"{Module.Path}\"");
|
||||
frm.DebugModules.Add(Module);
|
||||
}
|
||||
|
||||
public void OnModuleUnloaded(DebuggerModule Module)
|
||||
{
|
||||
frm.DebugLog(string.Format("Unloaded module \"{0}\"", Module.Path));
|
||||
frm.DebugLog($"Unloaded module \"{Module.Path}\"");
|
||||
frm.DebugModules.Remove(Module);
|
||||
}
|
||||
|
||||
|
@ -475,7 +557,7 @@ namespace CxbxDebugger
|
|||
}
|
||||
|
||||
// TODO Include GetLastError string
|
||||
string ExceptionMessage = string.Format("Access violation thrown at 0x{0:X8} ({1})", Address, ProcessName);
|
||||
var ExceptionMessage = string.Format("Access violation thrown at 0x{0:X8} ({1})", Address, ProcessName);
|
||||
|
||||
ExceptionMessage += string.Format("\n\nException code {0:X8}", Code);
|
||||
|
||||
|
@ -505,13 +587,13 @@ namespace CxbxDebugger
|
|||
if (Info.Succeeded)
|
||||
{
|
||||
frm.FileHandles.Add(Info);
|
||||
frm.DebugLog(string.Format("Opened file: \"{0}\"", Info.FileName));
|
||||
frm.DebugLog($"Opened file: \"{Info.FileName}\"");
|
||||
|
||||
frm.DebugFileEvent(FileEvents.Opened(Info.FileName));
|
||||
}
|
||||
else
|
||||
{
|
||||
frm.DebugLog(string.Format("Opened file FAILED: \"{0}\"", Info.FileName));
|
||||
frm.DebugLog($"Opened file FAILED: \"{Info.FileName}\"");
|
||||
|
||||
frm.DebugFileEvent(FileEvents.OpenedFailed(Info.FileName));
|
||||
}
|
||||
|
@ -522,7 +604,7 @@ namespace CxbxDebugger
|
|||
var Found = frm.FileHandles.Find(FileInfo => FileInfo.Handle == Info.Handle);
|
||||
if (Found != null)
|
||||
{
|
||||
frm.DebugLog(string.Format("Reading {0} byte(s) from: {1}", Info.Length, Found.FileName));
|
||||
frm.DebugLog($"Reading {Info.Length} byte(s) from: {Found.FileName}");
|
||||
frm.DebugFileEvent(FileEvents.Read(Found.FileName, Info.Length, Info.Offset));
|
||||
}
|
||||
}
|
||||
|
@ -532,7 +614,7 @@ namespace CxbxDebugger
|
|||
var Found = frm.FileHandles.Find(FileInfo => FileInfo.Handle == Info.Handle);
|
||||
if (Found != null)
|
||||
{
|
||||
frm.DebugLog(string.Format("Writing {0} byte(s) to: {1}", Info.Length, Found.FileName));
|
||||
frm.DebugLog($"Writing {Info.Length} byte(s) to: {Found.FileName}");
|
||||
frm.DebugFileEvent(FileEvents.Write(Found.FileName, Info.Length, Info.Offset));
|
||||
}
|
||||
}
|
||||
|
@ -546,17 +628,12 @@ namespace CxbxDebugger
|
|||
|
||||
frm.DebugFileEvent(FileEvents.Closed(Found.FileName));
|
||||
|
||||
frm.DebugLog(string.Format("Closed file: \"{0}\"", Found.FileName));
|
||||
frm.DebugLog($"Closed file: \"{Found.FileName}\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void toolStripButton1_Click(object sender, EventArgs e)
|
||||
{
|
||||
StartDebugging();
|
||||
}
|
||||
|
||||
private void Suspend(string Reason)
|
||||
private void Suspend(DebugState State, string Detail)
|
||||
{
|
||||
if (DebuggerInst != null)
|
||||
{
|
||||
|
@ -572,7 +649,7 @@ namespace CxbxDebugger
|
|||
PopulateThreadList(cbThreads, null);
|
||||
}
|
||||
|
||||
lblStatus.Text = string.Format("Suspended ({0})", Reason);
|
||||
SetDebugState(State, Detail);
|
||||
|
||||
cbThreads.Enabled = true;
|
||||
cbFrames.Enabled = true;
|
||||
|
@ -593,22 +670,12 @@ namespace CxbxDebugger
|
|||
}
|
||||
}
|
||||
|
||||
lblStatus.Text = "Running";
|
||||
SetDebugState(DebugState.Running);
|
||||
|
||||
cbThreads.Enabled = false;
|
||||
cbFrames.Enabled = false;
|
||||
}
|
||||
|
||||
private void toolStripButton2_Click(object sender, EventArgs e)
|
||||
{
|
||||
Suspend("manually triggered");
|
||||
}
|
||||
|
||||
private void toolStripButton3_Click(object sender, EventArgs e)
|
||||
{
|
||||
Resume();
|
||||
}
|
||||
|
||||
struct CallstackInfo
|
||||
{
|
||||
public uint InstructionPointer;
|
||||
|
@ -741,8 +808,8 @@ namespace CxbxDebugger
|
|||
{
|
||||
if (EP != 0)
|
||||
{
|
||||
string LinkName = string.Format("{0} +{1:x}", Name, Address - EP);
|
||||
string Link = string.Format("0x{0:x8}", Address);
|
||||
var LinkName = string.Format("{0} +{1:x}", Name, Address - EP);
|
||||
var Link = string.Format("0x{0:x8}", Address);
|
||||
|
||||
tb.InsertLink(LinkName, Link);
|
||||
}
|
||||
|
@ -833,9 +900,6 @@ namespace CxbxDebugger
|
|||
|
||||
private void btnDumpMemory_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (DebuggerInst == null)
|
||||
return;
|
||||
|
||||
if (diagSaveMemory.ShowDialog() == DialogResult.OK)
|
||||
{
|
||||
byte[] data = ReadMemory();
|
||||
|
@ -855,7 +919,7 @@ namespace CxbxDebugger
|
|||
int Index = cbThreads.SelectedIndex;
|
||||
if (Index == -1)
|
||||
return;
|
||||
|
||||
|
||||
CallstackDump.Clear();
|
||||
cbFrames.Items.Clear();
|
||||
|
||||
|
@ -974,17 +1038,6 @@ namespace CxbxDebugger
|
|||
fileWatchMan.SetEnabled(e.Index, e.NewValue == CheckState.Checked);
|
||||
}
|
||||
|
||||
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
|
||||
{
|
||||
if (keyData == Keys.F5)
|
||||
{
|
||||
StartDebugging();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void HandleDisasmGo()
|
||||
{
|
||||
uint addr = 0;
|
||||
|
@ -1045,7 +1098,7 @@ namespace CxbxDebugger
|
|||
{
|
||||
var li = lvCEMemory.Items.Add(string.Format("{0} 0x{1:x}", DataPatch.Module, DataPatch.Offset));
|
||||
li.SubItems.Add(DataPatch.Name);
|
||||
li.SubItems.Add(string.Format("{0} byte(s)", DataPatch.Patched.Length));
|
||||
li.SubItems.Add($"{DataPatch.Patched.Length} byte(s)");
|
||||
if (MainProcess != null)
|
||||
{
|
||||
li.SubItems.Add(patchMan.Read(MainProcess, DataPatch));
|
||||
|
@ -1104,7 +1157,7 @@ namespace CxbxDebugger
|
|||
|
||||
if (File.Exists(filename))
|
||||
{
|
||||
DebugLog(string.Format("Attempting to load \"{0}\"", filename));
|
||||
DebugLog($"Attempting to load \"{filename}\"");
|
||||
|
||||
CheatEngine.CheatTable ct_data = CheatEngine.CheatTableReader.FromFile(filename);
|
||||
if (ct_data != null)
|
||||
|
@ -1141,8 +1194,8 @@ namespace CxbxDebugger
|
|||
patchMan.Assembly.Add(DataPatch);
|
||||
}
|
||||
|
||||
DebugLog(string.Format("Loaded {0} auto-assembler entries", ct_data.CodeEntires.Count));
|
||||
DebugLog(string.Format("Loaded {0} cheat entries", ct_data.CheatEntries.Count));
|
||||
DebugLog($"Loaded {ct_data.CodeEntires.Count} auto-assembler entries");
|
||||
DebugLog($"Loaded {ct_data.CheatEntries.Count} cheat entries");
|
||||
|
||||
RefreshPatches();
|
||||
}
|
||||
|
@ -1151,7 +1204,7 @@ namespace CxbxDebugger
|
|||
|
||||
private void button5_Click(object sender, EventArgs e)
|
||||
{
|
||||
PatchType PatchType = (PatchType)cbDataFormat.SelectedIndex;
|
||||
var PatchType = (PatchType)cbDataFormat.SelectedIndex;
|
||||
|
||||
int PatchSize = PatchManager.PatchTypeLength(PatchType);
|
||||
if (PatchSize == 0)
|
||||
|
@ -1169,7 +1222,7 @@ namespace CxbxDebugger
|
|||
Patch DataPatch = new Patch();
|
||||
|
||||
DataPatch.DisplayAs = PatchType;
|
||||
DataPatch.Name = string.Format("Patched {0}", PatchType);
|
||||
DataPatch.Name = $"Patched {PatchType}";
|
||||
DataPatch.Module = "";
|
||||
DataPatch.Offset = addr;
|
||||
|
||||
|
@ -1234,5 +1287,60 @@ namespace CxbxDebugger
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public SessionState GetSessionState()
|
||||
{
|
||||
if (DebuggerWorkerThread == null)
|
||||
{
|
||||
return SessionState.Inactive;
|
||||
}
|
||||
else if (DebuggerWorkerThread.ThreadState == ThreadState.Stopped)
|
||||
{
|
||||
return SessionState.Ended;
|
||||
}
|
||||
|
||||
return SessionState.Running;
|
||||
}
|
||||
|
||||
public void StartSession()
|
||||
{
|
||||
if (GetSessionState() == SessionState.Inactive)
|
||||
{
|
||||
StartDebugging();
|
||||
}
|
||||
}
|
||||
|
||||
public void SuspendSession()
|
||||
{
|
||||
if (GetSessionState() == SessionState.Running)
|
||||
{
|
||||
Suspend(DebugState.Suspended, "By user");
|
||||
}
|
||||
}
|
||||
|
||||
public void ResumeSession()
|
||||
{
|
||||
Resume();
|
||||
}
|
||||
|
||||
private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
|
||||
{
|
||||
tabContainer.SelectedTab = tabWatch;
|
||||
}
|
||||
|
||||
private void linkLabel2_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
|
||||
{
|
||||
tabContainer.SelectedTab = tabMemory;
|
||||
}
|
||||
|
||||
private void linkLabel3_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
|
||||
{
|
||||
tabContainer.SelectedTab = tabDisassembly;
|
||||
}
|
||||
|
||||
public DebugStateInfo GetDebugStateInfo()
|
||||
{
|
||||
return StateInfo;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -118,16 +118,13 @@
|
|||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<metadata name="toolStrip1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
<metadata name="statusBar.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>122, 17</value>
|
||||
<value>534, 17</value>
|
||||
</metadata>
|
||||
<metadata name="diagSaveMemory.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>238, 17</value>
|
||||
<value>153, 17</value>
|
||||
</metadata>
|
||||
<metadata name="diagBrowseCT.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>384, 17</value>
|
||||
<value>357, 17</value>
|
||||
</metadata>
|
||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
||||
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
|
@ -0,0 +1,201 @@
|
|||
namespace CxbxDebugger
|
||||
{
|
||||
partial class CxbxDebuggerMain
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.components = new System.ComponentModel.Container();
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(CxbxDebuggerMain));
|
||||
this.menuStrip = new System.Windows.Forms.MenuStrip();
|
||||
this.fileMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.exitToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.debugToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.miStartDebugging = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.miSuspend = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.miResume = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.windowsMenu = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolTip = new System.Windows.Forms.ToolTip(this.components);
|
||||
this.statusStrip1 = new System.Windows.Forms.StatusStrip();
|
||||
this.lblStatusDeprecate = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.lblStatus = new System.Windows.Forms.ToolStripStatusLabel();
|
||||
this.menuStrip.SuspendLayout();
|
||||
this.statusStrip1.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// menuStrip
|
||||
//
|
||||
this.menuStrip.ImageScalingSize = new System.Drawing.Size(24, 24);
|
||||
this.menuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.fileMenu,
|
||||
this.debugToolStripMenuItem,
|
||||
this.windowsMenu});
|
||||
this.menuStrip.Location = new System.Drawing.Point(0, 0);
|
||||
this.menuStrip.MdiWindowListItem = this.windowsMenu;
|
||||
this.menuStrip.Name = "menuStrip";
|
||||
this.menuStrip.Padding = new System.Windows.Forms.Padding(4, 1, 0, 1);
|
||||
this.menuStrip.Size = new System.Drawing.Size(734, 24);
|
||||
this.menuStrip.TabIndex = 0;
|
||||
this.menuStrip.Text = "MenuStrip";
|
||||
//
|
||||
// fileMenu
|
||||
//
|
||||
this.fileMenu.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.exitToolStripMenuItem});
|
||||
this.fileMenu.ImageTransparentColor = System.Drawing.SystemColors.ActiveBorder;
|
||||
this.fileMenu.Name = "fileMenu";
|
||||
this.fileMenu.Size = new System.Drawing.Size(37, 22);
|
||||
this.fileMenu.Text = "&File";
|
||||
//
|
||||
// exitToolStripMenuItem
|
||||
//
|
||||
this.exitToolStripMenuItem.Name = "exitToolStripMenuItem";
|
||||
this.exitToolStripMenuItem.ShortcutKeyDisplayString = "Alt+F4";
|
||||
this.exitToolStripMenuItem.Size = new System.Drawing.Size(135, 22);
|
||||
this.exitToolStripMenuItem.Text = "E&xit";
|
||||
this.exitToolStripMenuItem.Click += new System.EventHandler(this.ExitToolsStripMenuItem_Click);
|
||||
//
|
||||
// debugToolStripMenuItem
|
||||
//
|
||||
this.debugToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.miStartDebugging,
|
||||
this.toolStripMenuItem1,
|
||||
this.miSuspend,
|
||||
this.miResume});
|
||||
this.debugToolStripMenuItem.Name = "debugToolStripMenuItem";
|
||||
this.debugToolStripMenuItem.Size = new System.Drawing.Size(54, 22);
|
||||
this.debugToolStripMenuItem.Text = "Debug";
|
||||
//
|
||||
// miStartDebugging
|
||||
//
|
||||
this.miStartDebugging.Image = global::CxbxDebugger.Properties.Resources.run;
|
||||
this.miStartDebugging.ImageTransparentColor = System.Drawing.Color.Magenta;
|
||||
this.miStartDebugging.Name = "miStartDebugging";
|
||||
this.miStartDebugging.ShortcutKeyDisplayString = "F5";
|
||||
this.miStartDebugging.Size = new System.Drawing.Size(117, 22);
|
||||
this.miStartDebugging.Text = "&Start";
|
||||
this.miStartDebugging.Click += new System.EventHandler(this.startDebuggingToolStripMenuItem_Click);
|
||||
//
|
||||
// toolStripMenuItem1
|
||||
//
|
||||
this.toolStripMenuItem1.Name = "toolStripMenuItem1";
|
||||
this.toolStripMenuItem1.Size = new System.Drawing.Size(114, 6);
|
||||
//
|
||||
// miSuspend
|
||||
//
|
||||
this.miSuspend.Image = global::CxbxDebugger.Properties.Resources.pause;
|
||||
this.miSuspend.ImageTransparentColor = System.Drawing.Color.Magenta;
|
||||
this.miSuspend.Name = "miSuspend";
|
||||
this.miSuspend.Size = new System.Drawing.Size(117, 22);
|
||||
this.miSuspend.Text = "&Break";
|
||||
this.miSuspend.Click += new System.EventHandler(this.suspendToolStripMenuItem_Click);
|
||||
//
|
||||
// miResume
|
||||
//
|
||||
this.miResume.Image = global::CxbxDebugger.Properties.Resources.run;
|
||||
this.miResume.ImageTransparentColor = System.Drawing.Color.Magenta;
|
||||
this.miResume.Name = "miResume";
|
||||
this.miResume.Size = new System.Drawing.Size(117, 22);
|
||||
this.miResume.Text = "&Resume";
|
||||
this.miResume.Click += new System.EventHandler(this.resumeToolStripMenuItem_Click);
|
||||
//
|
||||
// windowsMenu
|
||||
//
|
||||
this.windowsMenu.Name = "windowsMenu";
|
||||
this.windowsMenu.Size = new System.Drawing.Size(68, 22);
|
||||
this.windowsMenu.Text = "&Windows";
|
||||
//
|
||||
// statusStrip1
|
||||
//
|
||||
this.statusStrip1.ImageScalingSize = new System.Drawing.Size(24, 24);
|
||||
this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.lblStatusDeprecate,
|
||||
this.lblStatus});
|
||||
this.statusStrip1.LayoutStyle = System.Windows.Forms.ToolStripLayoutStyle.VerticalStackWithOverflow;
|
||||
this.statusStrip1.Location = new System.Drawing.Point(0, 339);
|
||||
this.statusStrip1.Name = "statusStrip1";
|
||||
this.statusStrip1.Padding = new System.Windows.Forms.Padding(1, 0, 9, 0);
|
||||
this.statusStrip1.Size = new System.Drawing.Size(734, 61);
|
||||
this.statusStrip1.TabIndex = 2;
|
||||
this.statusStrip1.Text = "statusStrip1";
|
||||
//
|
||||
// lblStatusDeprecate
|
||||
//
|
||||
this.lblStatusDeprecate.BackColor = System.Drawing.Color.Yellow;
|
||||
this.lblStatusDeprecate.Name = "lblStatusDeprecate";
|
||||
this.lblStatusDeprecate.Size = new System.Drawing.Size(723, 15);
|
||||
this.lblStatusDeprecate.Spring = true;
|
||||
this.lblStatusDeprecate.Text = "WARNING: cxbxr-debugger will eventually be removed from upstream branch.";
|
||||
this.lblStatusDeprecate.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
//
|
||||
// lblStatus
|
||||
//
|
||||
this.lblStatus.Name = "lblStatus";
|
||||
this.lblStatus.Size = new System.Drawing.Size(723, 15);
|
||||
this.lblStatus.Text = "Ready";
|
||||
//
|
||||
// CxbxDebuggerMain
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
|
||||
this.ClientSize = new System.Drawing.Size(734, 361);
|
||||
this.Controls.Add(this.statusStrip1);
|
||||
this.Controls.Add(this.menuStrip);
|
||||
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
|
||||
this.IsMdiContainer = true;
|
||||
this.MainMenuStrip = this.menuStrip;
|
||||
this.Name = "CxbxDebuggerMain";
|
||||
this.Text = "cxbx-debugger";
|
||||
this.menuStrip.ResumeLayout(false);
|
||||
this.menuStrip.PerformLayout();
|
||||
this.statusStrip1.ResumeLayout(false);
|
||||
this.statusStrip1.PerformLayout();
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
private System.Windows.Forms.MenuStrip menuStrip;
|
||||
private System.Windows.Forms.ToolStripMenuItem fileMenu;
|
||||
private System.Windows.Forms.ToolStripMenuItem exitToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem windowsMenu;
|
||||
private System.Windows.Forms.ToolTip toolTip;
|
||||
private System.Windows.Forms.ToolStripMenuItem debugToolStripMenuItem;
|
||||
private System.Windows.Forms.ToolStripMenuItem miStartDebugging;
|
||||
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem1;
|
||||
private System.Windows.Forms.ToolStripMenuItem miSuspend;
|
||||
private System.Windows.Forms.ToolStripMenuItem miResume;
|
||||
private System.Windows.Forms.StatusStrip statusStrip1;
|
||||
private System.Windows.Forms.ToolStripStatusLabel lblStatusDeprecate;
|
||||
private System.Windows.Forms.ToolStripStatusLabel lblStatus;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,156 @@
|
|||
// Written by x1nixmzeng for the Cxbx-Reloaded project
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace CxbxDebugger
|
||||
{
|
||||
public partial class CxbxDebuggerMain : Form, IDebugContainerWindow
|
||||
{
|
||||
public CxbxDebuggerMain(string[] args)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
var StartupArgs = new string[args.Length - 1];
|
||||
Array.Copy(args, 1, StartupArgs, 0, args.Length - 1);
|
||||
|
||||
// Setup session without initially running the game
|
||||
AddDebugSession(StartupArgs, false);
|
||||
|
||||
#if FALSE
|
||||
AddDebugSession(new string[] { }, false);
|
||||
#endif
|
||||
}
|
||||
|
||||
private void ExitToolsStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
private void startDebuggingToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (ActiveMdiChild is IDebugWindow)
|
||||
{
|
||||
(ActiveMdiChild as IDebugWindow).StartSession();
|
||||
}
|
||||
}
|
||||
|
||||
private void suspendToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (ActiveMdiChild is IDebugWindow)
|
||||
{
|
||||
(ActiveMdiChild as IDebugWindow).SuspendSession();
|
||||
}
|
||||
}
|
||||
|
||||
private void resumeToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (ActiveMdiChild is IDebugWindow)
|
||||
{
|
||||
(ActiveMdiChild as IDebugWindow).ResumeSession();
|
||||
}
|
||||
}
|
||||
|
||||
public void AddDebugSession(string[] Arguments, bool StartAutomatically)
|
||||
{
|
||||
var SessionWindow = CreateNewSessionWindow(Arguments);
|
||||
|
||||
if (StartAutomatically)
|
||||
{
|
||||
SessionWindow.StartSession();
|
||||
}
|
||||
}
|
||||
|
||||
public void ReportGameTitle(string GameTitle)
|
||||
{
|
||||
Text = $"cxbx-debugger ({GameTitle})";
|
||||
}
|
||||
|
||||
private IDebugWindow CreateNewSessionWindow(string[] Arguments)
|
||||
{
|
||||
var childForm = new CxbxDebuggerInstance(this, Arguments);
|
||||
childForm.WindowState = FormWindowState.Maximized;
|
||||
childForm.TextChanged += (sender, e) => { OnSessionWindowRenamed(sender as Form); };
|
||||
childForm.Activated += (sender, e) => { OnSessionWindowActivated(sender as IDebugWindow); };
|
||||
childForm.Show();
|
||||
|
||||
return childForm;
|
||||
}
|
||||
|
||||
private void OnSessionWindowActivated(IDebugWindow child)
|
||||
{
|
||||
var state = child.GetDebugStateInfo();
|
||||
RefreshStatusText(state);
|
||||
}
|
||||
|
||||
private void OnSessionWindowRenamed(Form form)
|
||||
{
|
||||
// https://stackoverflow.com/questions/1347734/mdi-window-list-not-updating-child-title-bar-texts
|
||||
|
||||
ActivateMdiChild(null);
|
||||
ActivateMdiChild(form);
|
||||
}
|
||||
|
||||
public void ReportStatus(IDebugWindow Window, DebugState State, string Detail)
|
||||
{
|
||||
if (Window == ActiveMdiChild)
|
||||
{
|
||||
RefreshStatusText(new DebugStateInfo() { State = State, Detail = Detail });
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshStatusText(DebugStateInfo stateInfo)
|
||||
{
|
||||
var stateString = "";
|
||||
var canSuspend = false;
|
||||
var canResume = false;
|
||||
var canRun = false;
|
||||
|
||||
switch (stateInfo.State)
|
||||
{
|
||||
case DebugState.Unknown:
|
||||
stateString = "No valid Xbe was loaded. Invalid session.";
|
||||
break;
|
||||
|
||||
case DebugState.Idle:
|
||||
stateString = "Ready";
|
||||
canRun = true;
|
||||
break;
|
||||
|
||||
case DebugState.Suspended:
|
||||
stateString = "Suspended";
|
||||
canResume = true;
|
||||
break;
|
||||
|
||||
case DebugState.Running:
|
||||
stateString = "Running";
|
||||
canSuspend = true;
|
||||
break;
|
||||
|
||||
case DebugState.Terminated:
|
||||
stateString = "Terminated";
|
||||
//canRun = true; // Uncomment to allow restarted sessions
|
||||
break;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(stateInfo.Detail))
|
||||
{
|
||||
stateString += $" - {stateInfo.Detail}";
|
||||
}
|
||||
|
||||
miStartDebugging.Enabled = canRun;
|
||||
miSuspend.Enabled = canSuspend;
|
||||
miResume.Enabled = canResume;
|
||||
lblStatus.Text = stateString;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -9,6 +9,7 @@ using WinDebug = VsChromium.Core.Win32.Debugging;
|
|||
using System.Runtime.InteropServices;
|
||||
using WinLowLevel = LowLevelDesign.Win32.Windows.NativeMethods;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CxbxDebugger
|
||||
{
|
||||
|
@ -32,13 +33,18 @@ namespace CxbxDebugger
|
|||
string[] args = new string[] { };
|
||||
string Target = "";
|
||||
|
||||
public string TargetPath
|
||||
{
|
||||
get { return Target; }
|
||||
}
|
||||
|
||||
RunState State = RunState.NotLaunched;
|
||||
|
||||
DebuggerMessages.DebuggerInit InitParams = new DebuggerMessages.DebuggerInit();
|
||||
|
||||
DebuggerInstance DebugInstance;
|
||||
|
||||
List<IDebuggerGeneralEvents> GeneralEvents = new List<IDebuggerGeneralEvents>();
|
||||
List<IDebuggerSessionEvents> SessionEvents = new List<IDebuggerSessionEvents>();
|
||||
List<IDebuggerProcessEvents> ProcessEvents = new List<IDebuggerProcessEvents>();
|
||||
List<IDebuggerThreadEvents> ThreadEvents = new List<IDebuggerThreadEvents>();
|
||||
List<IDebuggerModuleEvents> ModuleEvents = new List<IDebuggerModuleEvents>();
|
||||
|
@ -71,30 +77,29 @@ namespace CxbxDebugger
|
|||
Init();
|
||||
}
|
||||
|
||||
public Debugger(string[] x_args)
|
||||
public Debugger(string[] launchArgs)
|
||||
{
|
||||
Init();
|
||||
|
||||
if (x_args == null)
|
||||
return;
|
||||
|
||||
// Copy all arguments
|
||||
args = x_args;
|
||||
|
||||
// Keep quotes for any strings that may contain spaces
|
||||
int scratch;
|
||||
for (int i = 0; i < args.Length; ++i)
|
||||
// Copy XBE path without the quotes
|
||||
var loadArg = Array.FindIndex(launchArgs, x => x == "/load");
|
||||
if (loadArg != -1)
|
||||
{
|
||||
if (int.TryParse(args[i], out scratch) == false)
|
||||
{
|
||||
args[i] = string.Format("\"{0}\"", args[i]);
|
||||
}
|
||||
Target = launchArgs[loadArg + 1].Trim(new char[] { '"' });
|
||||
}
|
||||
|
||||
// Copy XBE path without the quotes
|
||||
if(x_args.Length > 2)
|
||||
args = new string[launchArgs.Length];
|
||||
|
||||
for (int i = 0; i < launchArgs.Length; ++i)
|
||||
{
|
||||
Target = x_args[2].Trim(new char[] { '"' });
|
||||
var arg = launchArgs[i];
|
||||
|
||||
if (arg.Contains(" "))
|
||||
{
|
||||
arg = string.Format($"\"{arg}\"");
|
||||
}
|
||||
|
||||
args[i] = arg;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -104,7 +109,7 @@ namespace CxbxDebugger
|
|||
bpStall.Set();
|
||||
|
||||
// Remove all events
|
||||
GeneralEvents.Clear();
|
||||
SessionEvents.Clear();
|
||||
ProcessEvents.Clear();
|
||||
ThreadEvents.Clear();
|
||||
ModuleEvents.Clear();
|
||||
|
@ -173,14 +178,19 @@ namespace CxbxDebugger
|
|||
if (CanLaunch() == false)
|
||||
throw new Exception("Unable to launch in this state");
|
||||
|
||||
if (args.Length == 0)
|
||||
return false;
|
||||
|
||||
var DebugCreationFlags =
|
||||
WinProcesses.ProcessCreationFlags.DEBUG_ONLY_THIS_PROCESS |
|
||||
WinProcesses.ProcessCreationFlags.CREATE_NEW_CONSOLE;
|
||||
|
||||
|
||||
var launchArgs = new StringBuilder(string.Join(" ", args));
|
||||
|
||||
bool bRet = WinProcesses.NativeMethods.CreateProcess
|
||||
(
|
||||
null,
|
||||
new StringBuilder(string.Join(" ", args)),
|
||||
launchArgs,
|
||||
null,
|
||||
null,
|
||||
false,
|
||||
|
@ -196,11 +206,15 @@ namespace CxbxDebugger
|
|||
// Store so they can be marshalled and closed correctly
|
||||
hProcess = new WinProcesses.SafeProcessHandle(stProcessInfo.hProcess);
|
||||
hThread = new WinProcesses.SafeThreadHandle(stProcessInfo.hThread);
|
||||
|
||||
|
||||
bContinue = true;
|
||||
|
||||
State = RunState.Running;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception($"Failed to launch loader '{launchArgs}'");
|
||||
}
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
@ -308,10 +322,7 @@ namespace CxbxDebugger
|
|||
Thread.StartAddress = DebugInfo.lpStartAddress;
|
||||
Thread.ThreadBase = DebugInfo.lpThreadLocalBase;
|
||||
|
||||
foreach (IDebuggerThreadEvents Event in ThreadEvents )
|
||||
{
|
||||
Event.OnThreadCreate(Thread);
|
||||
}
|
||||
Parallel.ForEach(ThreadEvents, Event => Event.OnThreadCreate(Thread));
|
||||
}
|
||||
|
||||
private void HandleExitThread(WinDebug.DEBUG_EVENT DebugEvent)
|
||||
|
@ -328,10 +339,7 @@ namespace CxbxDebugger
|
|||
{
|
||||
uint ExitCode = DebugInfo.dwExitCode;
|
||||
|
||||
foreach (IDebuggerThreadEvents Event in ThreadEvents)
|
||||
{
|
||||
Event.OnThreadExit(TargetThread, ExitCode);
|
||||
}
|
||||
Parallel.ForEach(ThreadEvents, Event => Event.OnThreadExit(TargetThread, ExitCode));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -364,26 +372,17 @@ namespace CxbxDebugger
|
|||
DebugInstance = new DebuggerInstance(Process);
|
||||
RegisterEventInterfaces(DebugInstance);
|
||||
|
||||
foreach (IDebuggerProcessEvents Event in ProcessEvents)
|
||||
{
|
||||
Event.OnProcessCreate(Process);
|
||||
}
|
||||
Parallel.ForEach(ProcessEvents, Event => Event.OnProcessCreate(Process));
|
||||
|
||||
foreach (IDebuggerThreadEvents Event in ThreadEvents)
|
||||
{
|
||||
Event.OnThreadCreate(MainThread);
|
||||
}
|
||||
|
||||
Parallel.ForEach(ThreadEvents, Event => Event.OnThreadCreate(MainThread));
|
||||
|
||||
var XboxModule = new DebuggerModule();
|
||||
|
||||
XboxModule.Path = Target;
|
||||
XboxModule.ImageBase = DebugInfo.lpBaseOfImage;
|
||||
XboxModule.Core = true;
|
||||
|
||||
foreach (IDebuggerModuleEvents Event in ModuleEvents)
|
||||
{
|
||||
Event.OnModuleLoaded(XboxModule);
|
||||
}
|
||||
Parallel.ForEach(ModuleEvents, Event => Event.OnModuleLoaded(XboxModule));
|
||||
}
|
||||
|
||||
private void HandleExitProcess(WinDebug.DEBUG_EVENT DebugEvent)
|
||||
|
@ -400,10 +399,7 @@ namespace CxbxDebugger
|
|||
|
||||
if (TargetProcess != null)
|
||||
{
|
||||
foreach (IDebuggerProcessEvents Event in ProcessEvents)
|
||||
{
|
||||
Event.OnProcessExit(TargetProcess, ExitCode);
|
||||
}
|
||||
Parallel.ForEach(ProcessEvents, Event => Event.OnProcessExit(TargetProcess, ExitCode));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -421,10 +417,7 @@ namespace CxbxDebugger
|
|||
Module.Path = ResolveProcessPath(DebugInfo.hFile);
|
||||
Module.ImageBase = DebugInfo.lpBaseOfDll;
|
||||
|
||||
foreach (IDebuggerModuleEvents Event in ModuleEvents)
|
||||
{
|
||||
Event.OnModuleLoaded(Module);
|
||||
}
|
||||
Parallel.ForEach(ModuleEvents, Event => Event.OnModuleLoaded(Module));
|
||||
}
|
||||
|
||||
private void HandleUnloadDll(WinDebug.DEBUG_EVENT DebugEvent)
|
||||
|
@ -440,10 +433,7 @@ namespace CxbxDebugger
|
|||
|
||||
if (TargetModule != null)
|
||||
{
|
||||
foreach (IDebuggerModuleEvents Event in ModuleEvents)
|
||||
{
|
||||
Event.OnModuleUnloaded(TargetModule);
|
||||
}
|
||||
Parallel.ForEach(ModuleEvents, Event => Event.OnModuleUnloaded(TargetModule));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -453,10 +443,7 @@ namespace CxbxDebugger
|
|||
|
||||
string debugString = ReadProcessString(DebugInfo.lpDebugStringData, DebugInfo.nDebugStringLength, DebugInfo.fUnicode == 1);
|
||||
|
||||
foreach(IDebuggerOutputEvents Event in OutputEvents)
|
||||
{
|
||||
Event.OnDebugOutput(debugString);
|
||||
}
|
||||
Parallel.ForEach(OutputEvents, Event => Event.OnDebugOutput(debugString));
|
||||
}
|
||||
|
||||
private void HandleException(WinDebug.DEBUG_EVENT DebugEvent)
|
||||
|
@ -477,12 +464,28 @@ namespace CxbxDebugger
|
|||
}
|
||||
break;
|
||||
|
||||
case ExceptionCode.PrivilegedInstruction:
|
||||
{
|
||||
// Seeing this frequently called in Win10
|
||||
|
||||
ContinueStatus = WinDebug.CONTINUE_STATUS.DBG_EXCEPTION_NOT_HANDLED;
|
||||
}
|
||||
break;
|
||||
|
||||
case ExceptionCode.StatusHandleNotClosable:
|
||||
{
|
||||
// Seeing this frequently called in Win10
|
||||
|
||||
ContinueStatus = WinDebug.CONTINUE_STATUS.DBG_EXCEPTION_NOT_HANDLED;
|
||||
}
|
||||
break;
|
||||
|
||||
case (ExceptionCode)DebuggerMessages.ReportType.OVERRIDE_EXCEPTION:
|
||||
{
|
||||
var Thread = DebugInstance.MainProcess.FindThread((uint)DebugEvent.dwThreadId);
|
||||
if (Thread != null)
|
||||
{
|
||||
var Query = DebuggerMessages.GetExceptionHandledQuery(Thread, DebugInfo.ExceptionRecord.ExceptionInformation);
|
||||
var Query = DebuggerMessages.GetExceptionHandledQuery(Thread, new DebuggerMessages.DataProcessor(DebugInfo.ExceptionRecord.ExceptionInformation));
|
||||
|
||||
bool Handled = false;
|
||||
foreach (IDebuggerExceptionEvents Event in ExceptionEvents)
|
||||
|
@ -501,7 +504,7 @@ namespace CxbxDebugger
|
|||
var Thread = DebugInstance.MainProcess.FindThread((uint)DebugEvent.dwThreadId);
|
||||
if (Thread != null)
|
||||
{
|
||||
var Report = DebuggerMessages.GetHLECacheReport(Thread, DebugInfo.ExceptionRecord.ExceptionInformation);
|
||||
var Report = DebuggerMessages.GetHLECacheReport(Thread, new DebuggerMessages.DataProcessor(DebugInfo.ExceptionRecord.ExceptionInformation));
|
||||
SetupHLECacheProvider(Report.FileName);
|
||||
}
|
||||
}
|
||||
|
@ -512,7 +515,7 @@ namespace CxbxDebugger
|
|||
var Thread = DebugInstance.MainProcess.FindThread((uint)DebugEvent.dwThreadId);
|
||||
if (Thread != null)
|
||||
{
|
||||
var Report = DebuggerMessages.GetKernelPatchReport(Thread, DebugInfo.ExceptionRecord.ExceptionInformation);
|
||||
var Report = DebuggerMessages.GetKernelPatchReport(Thread, new DebuggerMessages.DataProcessor(DebugInfo.ExceptionRecord.ExceptionInformation));
|
||||
|
||||
KernelSymbolProvider.AddKernelSymbolFromMessage(Report);
|
||||
}
|
||||
|
@ -524,12 +527,9 @@ namespace CxbxDebugger
|
|||
var Thread = DebugInstance.MainProcess.FindThread((uint)DebugEvent.dwThreadId);
|
||||
if (Thread != null)
|
||||
{
|
||||
var Report = DebuggerMessages.GetFileOpenedReport(Thread, DebugInfo.ExceptionRecord.ExceptionInformation);
|
||||
var Report = DebuggerMessages.GetFileOpenedReport(Thread, new DebuggerMessages.DataProcessor(DebugInfo.ExceptionRecord.ExceptionInformation));
|
||||
|
||||
foreach (IDebuggerFileEvents Event in FileEvents)
|
||||
{
|
||||
Event.OnFileOpened(Report);
|
||||
}
|
||||
Parallel.ForEach(FileEvents, Event => Event.OnFileOpened(Report));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -539,12 +539,9 @@ namespace CxbxDebugger
|
|||
var Thread = DebugInstance.MainProcess.FindThread((uint)DebugEvent.dwThreadId);
|
||||
if (Thread != null)
|
||||
{
|
||||
var Report = DebuggerMessages.GetFileReadReport(Thread, DebugInfo.ExceptionRecord.ExceptionInformation);
|
||||
var Report = DebuggerMessages.GetFileReadReport(Thread, new DebuggerMessages.DataProcessor(DebugInfo.ExceptionRecord.ExceptionInformation));
|
||||
|
||||
foreach (IDebuggerFileEvents Event in FileEvents)
|
||||
{
|
||||
Event.OnFileRead(Report);
|
||||
}
|
||||
Parallel.ForEach(FileEvents, Event => Event.OnFileRead(Report));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -554,12 +551,9 @@ namespace CxbxDebugger
|
|||
var Thread = DebugInstance.MainProcess.FindThread((uint)DebugEvent.dwThreadId);
|
||||
if (Thread != null)
|
||||
{
|
||||
var Report = DebuggerMessages.GetFileWriteReport(Thread, DebugInfo.ExceptionRecord.ExceptionInformation);
|
||||
var Report = DebuggerMessages.GetFileWriteReport(Thread, new DebuggerMessages.DataProcessor(DebugInfo.ExceptionRecord.ExceptionInformation));
|
||||
|
||||
foreach (IDebuggerFileEvents Event in FileEvents)
|
||||
{
|
||||
Event.OnFileWrite(Report);
|
||||
}
|
||||
Parallel.ForEach(FileEvents, Event => Event.OnFileWrite(Report));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -569,13 +563,10 @@ namespace CxbxDebugger
|
|||
var Thread = DebugInstance.MainProcess.FindThread((uint)DebugEvent.dwThreadId);
|
||||
if (Thread != null)
|
||||
{
|
||||
var Report = DebuggerMessages.GetFileClosedReport(Thread, DebugInfo.ExceptionRecord.ExceptionInformation);
|
||||
var Report = DebuggerMessages.GetFileClosedReport(Thread, new DebuggerMessages.DataProcessor(DebugInfo.ExceptionRecord.ExceptionInformation));
|
||||
if (Report != null)
|
||||
{
|
||||
foreach (IDebuggerFileEvents Event in FileEvents)
|
||||
{
|
||||
Event.OnFileClosed(Report);
|
||||
}
|
||||
Parallel.ForEach(FileEvents, Event => Event.OnFileClosed(Report));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -586,14 +577,23 @@ namespace CxbxDebugger
|
|||
var Thread = DebugInstance.MainProcess.FindThread((uint)DebugEvent.dwThreadId);
|
||||
if (Thread != null)
|
||||
{
|
||||
var Report = DebuggerMessages.GetDebuggerInitReport(Thread, DebugInfo.ExceptionRecord.ExceptionInformation);
|
||||
var Report = DebuggerMessages.GetDebuggerInitReport(Thread, new DebuggerMessages.DataProcessor(DebugInfo.ExceptionRecord.ExceptionInformation));
|
||||
|
||||
InitParams = Report;
|
||||
|
||||
foreach (IDebuggerGeneralEvents Event in GeneralEvents)
|
||||
{
|
||||
Event.OnDebugTitleLoaded(InitParams.Title);
|
||||
}
|
||||
Parallel.ForEach(SessionEvents, Event => Event.OnDebugTitleLoaded(InitParams.Title));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case (ExceptionCode)DebuggerMessages.ReportType.DEBUGGER_NEW_TARGET:
|
||||
{
|
||||
var Thread = DebugInstance.MainProcess.FindThread((uint)DebugEvent.dwThreadId);
|
||||
if (Thread != null)
|
||||
{
|
||||
var Report = DebuggerMessages.GetDebuggerNewTargetReport(Thread, new DebuggerMessages.DataProcessor(DebugInfo.ExceptionRecord.ExceptionInformation));
|
||||
|
||||
Parallel.ForEach(SessionEvents, Event => Event.OnDebugTargetChanged(Report.CommandLine));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -603,7 +603,7 @@ namespace CxbxDebugger
|
|||
var Thread = DebugInstance.MainProcess.FindThread((uint)DebugEvent.dwThreadId);
|
||||
if (Thread != null)
|
||||
{
|
||||
var Report = DebuggerMessages.GetMSVCThreadName(Thread, DebugInfo.ExceptionRecord.ExceptionInformation);
|
||||
var Report = DebuggerMessages.GetMSVCThreadName(Thread, new DebuggerMessages.DataProcessor(DebugInfo.ExceptionRecord.ExceptionInformation));
|
||||
if(Report != null)
|
||||
{
|
||||
// Resolve the ThreadId of an invalid ID to the current thread name
|
||||
|
@ -618,10 +618,7 @@ namespace CxbxDebugger
|
|||
// Update the resolved thread name
|
||||
ResolvedThread.DebugName = Report.Name;
|
||||
|
||||
foreach (IDebuggerThreadEvents Event in ThreadEvents)
|
||||
{
|
||||
Event.OnThreadNamed(Thread);
|
||||
}
|
||||
Parallel.ForEach(ThreadEvents, Event => Event.OnThreadNamed(Thread));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -639,10 +636,7 @@ namespace CxbxDebugger
|
|||
|
||||
bpStall.Reset();
|
||||
|
||||
foreach (IDebuggerExceptionEvents Event in ExceptionEvents)
|
||||
{
|
||||
Event.OnBreakpoint(Thread, BpAddr, BpCode, FirstChance);
|
||||
}
|
||||
Parallel.ForEach(ExceptionEvents, Event => Event.OnBreakpoint(Thread, BpAddr, BpCode, FirstChance));
|
||||
|
||||
bpStall.WaitOne();
|
||||
}
|
||||
|
@ -669,10 +663,7 @@ namespace CxbxDebugger
|
|||
WinDebug.DEBUG_EVENT DbgEvt = new WinDebug.DEBUG_EVENT();
|
||||
ContinueStatus = WinDebug.CONTINUE_STATUS.DBG_CONTINUE;
|
||||
|
||||
foreach (IDebuggerGeneralEvents Event in GeneralEvents)
|
||||
{
|
||||
Event.OnDebugStart();
|
||||
}
|
||||
Parallel.ForEach(SessionEvents, Event => Event.OnDebugStart());
|
||||
|
||||
// Loop until told to stop
|
||||
while (bContinue == true)
|
||||
|
@ -729,10 +720,7 @@ namespace CxbxDebugger
|
|||
|
||||
State = RunState.Ended;
|
||||
|
||||
foreach (IDebuggerGeneralEvents Event in GeneralEvents)
|
||||
{
|
||||
Event.OnDebugEnd();
|
||||
}
|
||||
Parallel.ForEach(SessionEvents, Event => Event.OnDebugEnd());
|
||||
}
|
||||
|
||||
public DebuggerSymbol ResolveSymbol(uint Address)
|
||||
|
@ -752,8 +740,8 @@ namespace CxbxDebugger
|
|||
|
||||
public void RegisterEventInterfaces(object EventClass)
|
||||
{
|
||||
IDebuggerGeneralEvents GeneralListener = EventClass as IDebuggerGeneralEvents;
|
||||
if(GeneralListener != null ) GeneralEvents.Add(GeneralListener);
|
||||
IDebuggerSessionEvents SessionListener = EventClass as IDebuggerSessionEvents;
|
||||
if(SessionListener != null ) SessionEvents.Add(SessionListener);
|
||||
|
||||
IDebuggerProcessEvents ProcessListener = EventClass as IDebuggerProcessEvents;
|
||||
if (ProcessListener != null) ProcessEvents.Add(ProcessListener);
|
||||
|
|
|
@ -5,11 +5,12 @@ using System;
|
|||
|
||||
namespace CxbxDebugger
|
||||
{
|
||||
public interface IDebuggerGeneralEvents
|
||||
public interface IDebuggerSessionEvents
|
||||
{
|
||||
void OnDebugStart();
|
||||
void OnDebugEnd();
|
||||
void OnDebugTitleLoaded(string Title);
|
||||
void OnDebugTargetChanged(string CommandLine);
|
||||
}
|
||||
|
||||
public interface IDebuggerProcessEvents
|
||||
|
|
|
@ -9,15 +9,20 @@ namespace CxbxDebugger
|
|||
{
|
||||
public enum ReportType : uint
|
||||
{
|
||||
HLECACHE_FILE = 0x00deed00,
|
||||
KERNEL_PATCH = 0x00deed01,
|
||||
FILE_OPENED = 0x00deed02,
|
||||
FILE_READ = 0x00deed03,
|
||||
FILE_CLOSED = 0x00deed04,
|
||||
DEBUGGER_INIT = 0x00deed05,
|
||||
FILE_WRITE = 0x00deed06,
|
||||
HLECACHE_FILE = 0x1000,
|
||||
|
||||
OVERRIDE_EXCEPTION = 0x00ceed01,
|
||||
KERNEL_PATCH = 0x2000,
|
||||
|
||||
FILE_OPENED = 0x3000,
|
||||
|
||||
FILE_READ = 0x3001,
|
||||
FILE_WRITE = 0x3002,
|
||||
FILE_CLOSED = 0x3003,
|
||||
|
||||
DEBUGGER_INIT = 0x4000,
|
||||
DEBUGGER_NEW_TARGET = 0x4001,
|
||||
|
||||
OVERRIDE_EXCEPTION = 0x5000,
|
||||
|
||||
// Exception code from https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
|
||||
MS_VC_EXCEPTION = 0x406D1388,
|
||||
|
@ -29,22 +34,38 @@ namespace CxbxDebugger
|
|||
WCHAR,
|
||||
};
|
||||
|
||||
public class DataProcessor
|
||||
{
|
||||
uint[] SourceData;
|
||||
uint SourceIndex;
|
||||
|
||||
public DataProcessor(uint[] Data)
|
||||
{
|
||||
SourceData = Data;
|
||||
SourceIndex = 0;
|
||||
}
|
||||
|
||||
public uint Pop()
|
||||
{
|
||||
return SourceData[SourceIndex++];
|
||||
}
|
||||
}
|
||||
|
||||
public class HLECache
|
||||
{
|
||||
public string FileName { get; set; }
|
||||
}
|
||||
|
||||
public static HLECache GetHLECacheReport(DebuggerThread Context, uint[] Data)
|
||||
public static HLECache GetHLECacheReport(DebuggerThread Context, DataProcessor Data)
|
||||
{
|
||||
HLECache Report = new HLECache();
|
||||
|
||||
StringType Type = (StringType)Data[0];
|
||||
|
||||
var Type = (StringType)Data.Pop();
|
||||
if (Type != StringType.CHAR)
|
||||
throw new Exception("GetHLECacheReport expects a string message");
|
||||
|
||||
uint Length = Data[1];
|
||||
IntPtr MessagePtr = new IntPtr(Data[2]);
|
||||
var Length = Data.Pop(); ;
|
||||
var MessagePtr = new IntPtr(Data.Pop());
|
||||
|
||||
Report.FileName = Context.OwningProcess.ReadString(MessagePtr, Length);
|
||||
|
||||
|
@ -57,20 +78,19 @@ namespace CxbxDebugger
|
|||
public IntPtr Address { get; set; }
|
||||
}
|
||||
|
||||
public static KernelPatch GetKernelPatchReport(DebuggerThread Context, uint[] Data)
|
||||
public static KernelPatch GetKernelPatchReport(DebuggerThread Context, DataProcessor Data)
|
||||
{
|
||||
KernelPatch Report = new KernelPatch();
|
||||
|
||||
StringType Type = (StringType)Data[0];
|
||||
|
||||
var Type = (StringType)Data.Pop();
|
||||
if (Type != StringType.CHAR)
|
||||
throw new Exception("GetKernelPatchReport expects a string message");
|
||||
|
||||
uint Length = Data[1];
|
||||
IntPtr MessagePtr = new IntPtr(Data[2]);
|
||||
var Length = Data.Pop();
|
||||
var MessagePtr = new IntPtr(Data.Pop());
|
||||
|
||||
Report.Name = Context.OwningProcess.ReadString(MessagePtr, Length);
|
||||
Report.Address = new IntPtr(Data[3]);
|
||||
Report.Address = new IntPtr(Data.Pop());
|
||||
|
||||
return Report;
|
||||
}
|
||||
|
@ -82,23 +102,21 @@ namespace CxbxDebugger
|
|||
public bool Succeeded { get; set; }
|
||||
}
|
||||
|
||||
public static FileOpened GetFileOpenedReport(DebuggerThread Context, uint[] Data)
|
||||
public static FileOpened GetFileOpenedReport(DebuggerThread Context, DataProcessor Data)
|
||||
{
|
||||
FileOpened Report = new FileOpened();
|
||||
|
||||
Report.Handle = new IntPtr(Data[0]);
|
||||
|
||||
StringType Type = (StringType)Data[1];
|
||||
Report.Handle = new IntPtr(Data.Pop());
|
||||
|
||||
var Type = (StringType)Data.Pop();
|
||||
if (Type != StringType.WCHAR)
|
||||
throw new Exception("GetFileOpenedReport expects a widestring message");
|
||||
|
||||
uint Length = Data[2];
|
||||
IntPtr MessagePtr = new IntPtr(Data[3]);
|
||||
var Length = Data.Pop();
|
||||
var MessagePtr = new IntPtr(Data.Pop());
|
||||
|
||||
Report.FileName = Context.OwningProcess.ReadWString(MessagePtr, Length);
|
||||
|
||||
Report.Succeeded = Data[4] != 0;
|
||||
Report.Succeeded = Data.Pop() != 0;
|
||||
|
||||
return Report;
|
||||
}
|
||||
|
@ -110,13 +128,13 @@ namespace CxbxDebugger
|
|||
public uint Offset { get; set; }
|
||||
}
|
||||
|
||||
public static FileRead GetFileReadReport(DebuggerThread Context, uint[] Data)
|
||||
public static FileRead GetFileReadReport(DebuggerThread Context, DataProcessor Data)
|
||||
{
|
||||
FileRead Report = new FileRead();
|
||||
|
||||
Report.Handle = new IntPtr(Data[0]);
|
||||
Report.Length = Data[1];
|
||||
Report.Offset = Data[2];
|
||||
Report.Handle = new IntPtr(Data.Pop());
|
||||
Report.Length = Data.Pop();
|
||||
Report.Offset = Data.Pop();
|
||||
|
||||
return Report;
|
||||
}
|
||||
|
@ -128,13 +146,13 @@ namespace CxbxDebugger
|
|||
public uint Offset { get; set; }
|
||||
}
|
||||
|
||||
public static FileWrite GetFileWriteReport(DebuggerThread Context, uint[] Data)
|
||||
public static FileWrite GetFileWriteReport(DebuggerThread Context, DataProcessor Data)
|
||||
{
|
||||
FileWrite Report = new FileWrite();
|
||||
|
||||
Report.Handle = new IntPtr(Data[0]);
|
||||
Report.Length = Data[1];
|
||||
Report.Offset = Data[2];
|
||||
Report.Handle = new IntPtr(Data.Pop());
|
||||
Report.Length = Data.Pop();
|
||||
Report.Offset = Data.Pop();
|
||||
|
||||
return Report;
|
||||
}
|
||||
|
@ -144,18 +162,20 @@ namespace CxbxDebugger
|
|||
public IntPtr Handle { get; set; }
|
||||
}
|
||||
|
||||
public static FileClosed GetFileClosedReport(DebuggerThread Context, uint[] Data)
|
||||
public static FileClosed GetFileClosedReport(DebuggerThread Context, DataProcessor Data)
|
||||
{
|
||||
// TODO: Restructure this library
|
||||
uint InvalidHandle = (uint)VsChromium.Core.Win32.Handles.NativeMethods.INVALID_HANDLE_VALUE;
|
||||
|
||||
var Handle = Data.Pop();
|
||||
|
||||
// Skip invalid file handles
|
||||
if (Data[0] == InvalidHandle)
|
||||
if (Handle == InvalidHandle)
|
||||
return null;
|
||||
|
||||
FileClosed Report = new FileClosed();
|
||||
|
||||
Report.Handle = new IntPtr(Data[0]);
|
||||
Report.Handle = new IntPtr(Handle);
|
||||
|
||||
return Report;
|
||||
}
|
||||
|
@ -169,59 +189,78 @@ namespace CxbxDebugger
|
|||
public IntPtr ParameterBase { get; set; }
|
||||
}
|
||||
|
||||
public static ExceptionHandledQuery GetExceptionHandledQuery(DebuggerThread Context, uint[] Data)
|
||||
public static ExceptionHandledQuery GetExceptionHandledQuery(DebuggerThread Context, DataProcessor Data)
|
||||
{
|
||||
ExceptionHandledQuery Query = new ExceptionHandledQuery();
|
||||
|
||||
Query.ReponseAddr = new IntPtr(Data[0]);
|
||||
Query.ExceptionAddress = Data[1];
|
||||
Query.ExceptionCode = Data[2];
|
||||
Query.ParameterCount = Data[3];
|
||||
Query.ParameterBase = new IntPtr(Data[4]);
|
||||
Query.ReponseAddr = new IntPtr(Data.Pop());
|
||||
Query.ExceptionAddress = Data.Pop();
|
||||
Query.ExceptionCode = Data.Pop();
|
||||
Query.ParameterCount = Data.Pop();
|
||||
Query.ParameterBase = new IntPtr(Data.Pop());
|
||||
|
||||
return Query;
|
||||
}
|
||||
|
||||
public class DebuggerInit
|
||||
{
|
||||
public uint TitleID { get; set; }
|
||||
public string Title { get; set; }
|
||||
}
|
||||
|
||||
public static DebuggerInit GetDebuggerInitReport(DebuggerThread Context, uint[] Data)
|
||||
public static DebuggerInit GetDebuggerInitReport(DebuggerThread Context, DataProcessor Data)
|
||||
{
|
||||
DebuggerInit Report = new DebuggerInit();
|
||||
|
||||
Report.TitleID = Data[0];
|
||||
|
||||
StringType Type = (StringType)Data[1];
|
||||
StringType Type = (StringType)Data.Pop();
|
||||
|
||||
if (Type != StringType.CHAR)
|
||||
throw new Exception("GetDebuggerInitReport expects a string message");
|
||||
|
||||
uint Length = Data[2];
|
||||
IntPtr MessagePtr = new IntPtr(Data[3]);
|
||||
uint Length = Data.Pop();
|
||||
IntPtr MessagePtr = new IntPtr(Data.Pop());
|
||||
|
||||
Report.Title = Context.OwningProcess.ReadString(MessagePtr, Length);
|
||||
|
||||
return Report;
|
||||
}
|
||||
|
||||
public class DebuggerNewTarget
|
||||
{
|
||||
public string CommandLine { get; set; }
|
||||
}
|
||||
|
||||
public static DebuggerNewTarget GetDebuggerNewTargetReport(DebuggerThread Context, DataProcessor Data)
|
||||
{
|
||||
var Report = new DebuggerNewTarget();
|
||||
|
||||
StringType Type = (StringType)Data.Pop();
|
||||
|
||||
if (Type != StringType.CHAR)
|
||||
throw new Exception("GetDebuggerInitReport expects a string message");
|
||||
|
||||
uint Length = Data.Pop();
|
||||
IntPtr MessagePtr = new IntPtr(Data.Pop());
|
||||
|
||||
Report.CommandLine = Context.OwningProcess.ReadString(MessagePtr, Length);
|
||||
|
||||
return Report;
|
||||
}
|
||||
|
||||
public class MSVCThreadName
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public uint ThreadId { get; set; }
|
||||
}
|
||||
|
||||
public static MSVCThreadName GetMSVCThreadName(DebuggerThread Context, uint[] Data)
|
||||
public static MSVCThreadName GetMSVCThreadName(DebuggerThread Context, DataProcessor Data)
|
||||
{
|
||||
uint Type = Data[0];
|
||||
var Type = Data.Pop();
|
||||
if (Type != 0x1000)
|
||||
return null;
|
||||
|
||||
string ReportName = "";
|
||||
|
||||
IntPtr MessagePtr = new IntPtr(Data[1]);
|
||||
IntPtr MessagePtr = new IntPtr(Data.Pop());
|
||||
if (MessagePtr != IntPtr.Zero)
|
||||
{
|
||||
ReportName = Context.OwningProcess.ReadString(MessagePtr);
|
||||
|
@ -230,7 +269,7 @@ namespace CxbxDebugger
|
|||
MSVCThreadName Report = new MSVCThreadName();
|
||||
|
||||
Report.Name = ReportName;
|
||||
Report.ThreadId = Data[2];
|
||||
Report.ThreadId = Data.Pop();
|
||||
|
||||
return Report;
|
||||
}
|
||||
|
|
|
@ -114,6 +114,12 @@ namespace CxbxDebugger
|
|||
if (ebp == 0 || ReturnAddr == ebp)
|
||||
break;
|
||||
|
||||
if ((ReturnAddr & 0x80000000) != 0)
|
||||
break;
|
||||
|
||||
if ((ebp & 0x80000000) != 0)
|
||||
break;
|
||||
|
||||
CallstackCache.AddFrame(new DebuggerStackFrame(new IntPtr(ReturnAddr), new IntPtr(ebp)));
|
||||
}
|
||||
while (CallstackCache.CanCollect);
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
// Written by x1nixmzeng for the Cxbx-Reloaded project
|
||||
//
|
||||
|
||||
namespace CxbxDebugger
|
||||
{
|
||||
public enum SessionState
|
||||
{
|
||||
Inactive,
|
||||
Running,
|
||||
Ended,
|
||||
}
|
||||
|
||||
public enum DebugState
|
||||
{
|
||||
Unknown,
|
||||
Idle,
|
||||
Suspended,
|
||||
Breakpoint,
|
||||
Running,
|
||||
Terminated,
|
||||
}
|
||||
|
||||
public struct DebugStateInfo
|
||||
{
|
||||
public DebugState State;
|
||||
public string Detail;
|
||||
}
|
||||
|
||||
public interface IDebugWindow
|
||||
{
|
||||
void StartSession();
|
||||
|
||||
void SuspendSession();
|
||||
|
||||
void ResumeSession();
|
||||
|
||||
SessionState GetSessionState();
|
||||
|
||||
DebugStateInfo GetDebugStateInfo();
|
||||
}
|
||||
|
||||
public interface IDebugContainerWindow
|
||||
{
|
||||
void AddDebugSession(string[] Arguments, bool StartAutomatically);
|
||||
|
||||
void ReportGameTitle(string GameTitle);
|
||||
|
||||
void ReportStatus(IDebugWindow Window, DebugState Status, string Detail);
|
||||
}
|
||||
|
||||
}
|
|
@ -18,6 +18,7 @@ namespace CxbxDebugger
|
|||
Application.SetCompatibleTextRenderingDefault(false);
|
||||
|
||||
string[] args = Environment.GetCommandLineArgs();
|
||||
#if !DEBUG
|
||||
if( args.Length == 1 )
|
||||
{
|
||||
// TODO: Valid usage message
|
||||
|
@ -25,8 +26,9 @@ namespace CxbxDebugger
|
|||
Application.Exit();
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
Application.Run(new Form1());
|
||||
Application.Run(new CxbxDebuggerMain(args));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -345,6 +345,10 @@ namespace CxbxDebugger
|
|||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
StatusHandleNotClosable = 0xC0000235,
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
GuardPageViolation = 0x80000001,
|
||||
/// <summary>
|
||||
///
|
||||
|
|
|
@ -2,10 +2,25 @@
|
|||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
#include "Version.h"
|
||||
#include "CxbxVersion.h"
|
||||
#include <string>
|
||||
|
||||
/*! version string dependent on trace flag */
|
||||
#ifndef _DEBUG_TRACE
|
||||
const char* CxbxVersionStr = _GIT_VERSION " (" __DATE__ ")";
|
||||
const char *CxbxrHashBuild = _GIT_VERSION;
|
||||
#else
|
||||
const char* CxbxVersionStr = _GIT_VERSION "-Trace (" __DATE__ ")";
|
||||
const char *CxbxrHashBuild = _GIT_VERSION "-Trace";
|
||||
#endif
|
||||
|
||||
static constexpr const char *GitVersionStr = _GIT_VERSION;
|
||||
static constexpr size_t GitVersionLength = std::char_traits<char>::length(GitVersionStr);
|
||||
static_assert(GitVersionLength < GitVersionMaxLength);
|
||||
|
||||
const char *const GetGitVersionStr() {
|
||||
return GitVersionStr;
|
||||
}
|
||||
|
||||
const size_t GetGitVersionLength() {
|
||||
return GitVersionLength;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#include "version.h"
|
||||
|
||||
extern const char* CxbxVersionStr;
|
||||
extern const char *CxbxrHashBuild;
|
||||
|
||||
// Note: GitVersionMaxLength should be large enough to accomodate the longest git version string we can practically expect to have. This is necessary
|
||||
// to avoid possible mismatches in the string length which can happen if the user mixes different cxbxr versions
|
||||
inline constexpr size_t GitVersionMaxLength = 80;
|
||||
const char *const GetGitVersionStr();
|
||||
const size_t GetGitVersionLength();
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include <Windows.h>
|
||||
|
||||
// Default to High Performance Mode on machines with dual graphics
|
||||
__declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; // AMD
|
||||
__declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; // NVIDIA
|
||||
#include <Windows.h>
|
||||
|
||||
// Default to High Performance Mode on machines with dual graphics
|
||||
__declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; // AMD
|
||||
__declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; // NVIDIA
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
// ******************************************************************
|
||||
// *
|
||||
// * This file is part of Cxbx-Reloaded.
|
||||
// *
|
||||
// * Cxbx-Reloaded is free software; you can redistribute it
|
||||
// * and/or modify it under the terms of the GNU General Public
|
||||
// * License as published by the Free Software Foundation; either
|
||||
// * version 2 of the license, or (at your option) any later version.
|
||||
// *
|
||||
// * This program 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 recieved a copy of the GNU General Public License
|
||||
// * along with this program; see the file COPYING.
|
||||
// * If not, write to the Free Software Foundation, Inc.,
|
||||
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
|
||||
// *
|
||||
// * (c) 2017-2019 Patrick van Logchem <pvanlogchem@gmail.com>
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
#include <Windows.h> // For PAGE_READWRITE, PAGE_EXECUTE_READWRITE, and PAGE_NOACCESS
|
||||
|
||||
#include "util/std_extend.hpp"
|
||||
#include "AddressRanges.h"
|
||||
|
||||
// NOTE: Cannot be use in the header file.
|
||||
// For InitialMemoryProtection field only. Memory page protection usage, for use by VirtualAlloc
|
||||
// Shortend symbol aliasses for memory page protection
|
||||
#define PROT_UNH 0 // UNHANDLED
|
||||
#define PROT_RW PAGE_READWRITE
|
||||
#define PROT_XRW PAGE_EXECUTE_READWRITE
|
||||
#define PROT_NAC PAGE_NOACCESS
|
||||
|
||||
const _XboxAddressRanges XboxAddressRanges[] = {
|
||||
#ifdef DEBUG
|
||||
#define RANGE_ENTRY(START, END, SIZE, PROT, FLAGS, COMMENT) { START, END, SIZE, PROT, FLAGS, COMMENT }
|
||||
#else
|
||||
#define RANGE_ENTRY(START, END, SIZE, PROT, FLAGS, COMMENT) { START, SIZE, PROT, FLAGS }
|
||||
#endif
|
||||
// See https://xboxdevwiki.net/Memory
|
||||
// and https://xboxdevwiki.net/Boot_Process#Paging
|
||||
// Entry : Start , End , Size , Protect , RangeFlags , Comment
|
||||
RANGE_ENTRY(USER_ADDRESS1_BASE, USER_ADDRESS1_END, USER_ADDRESS1_SIZE, PROT_XRW, SYSTEM_ALL | MAY_FAIL, "MemLowVirtual (General Xbox type) lower 64 MiB Optional (already reserved via virtual_memory_placeholder)"),
|
||||
RANGE_ENTRY(USER_ADDRESS2_BASE, USER_ADDRESS2_END, USER_ADDRESS2_SIZE, PROT_XRW, SYSTEM_128MB | MAY_FAIL, "MemLowVirtual (Chihiro / DevKit) ^ + upper 64 MiB"),
|
||||
RANGE_ENTRY(PHYSICAL_MAP1_BASE, PHYSICAL_MAP1_END, PHYSICAL_MAP1_SIZE, PROT_UNH, SYSTEM_ALL , "MemPhysical (General Xbox type) lower 64 MiB"),
|
||||
RANGE_ENTRY(PHYSICAL_MAP2_BASE, PHYSICAL_MAP2_END, PHYSICAL_MAP2_SIZE, PROT_UNH, SYSTEM_128MB , "MemPhysical (Chihiro / DevKit) ^ + upper 64 MiB"),
|
||||
RANGE_ENTRY(DEVKIT_MEMORY_BASE, DEVKIT_MEMORY_END, DEVKIT_MEMORY_SIZE, PROT_NAC, SYSTEM_DEVKIT , "DevKitMemory"), // TODO : Check reserved range (might behave like MemTiled)
|
||||
RANGE_ENTRY(PAGE_TABLES_BASE , PAGE_TABLES_END , PAGE_TABLES_SIZE , PROT_RW , SYSTEM_ALL , "MemPageTable"), // See PAGE_TABLES_SIZE, which contains one 4 byte entry per PAGE_SIZE
|
||||
RANGE_ENTRY(SYSTEM_MEMORY_BASE, SYSTEM_MEMORY_END, SYSTEM_MEMORY_SIZE, PROT_RW , SYSTEM_ALL | MAY_FAIL, "SystemMemory Optional"), // TODO : Check reserved range (might behave like MemTiled)
|
||||
RANGE_ENTRY(TILED_MEMORY_BASE , TILED_MEMORY_END , TILED_MEMORY_SIZE , PROT_UNH, SYSTEM_ALL , "MemTiled Optional (even though it can't be reserved, MapViewOfFileEx to this range still works!?)"),
|
||||
RANGE_ENTRY(NV2A_DEVICE1_BASE , NV2A_DEVICE1_END , NV2A_DEVICE1_SIZE , PROT_NAC, SYSTEM_ALL , "DeviceNV2A_a (GPU)"),
|
||||
RANGE_ENTRY(NV2A_PRAMIN_BASE , NV2A_PRAMIN_END , NV2A_PRAMIN_SIZE1 , PROT_RW , SYSTEM_ALL , "MemNV2APRAMIN"),
|
||||
RANGE_ENTRY(NV2A_DEVICE2_BASE , NV2A_DEVICE2_END , NV2A_DEVICE2_SIZE , PROT_NAC, SYSTEM_ALL , "DeviceNV2A_b (GPU)"),
|
||||
RANGE_ENTRY(APU_DEVICE_BASE , APU_DEVICE_END , APU_DEVICE_SIZE , PROT_NAC, SYSTEM_ALL , "DeviceAPU"),
|
||||
RANGE_ENTRY(AC97_DEVICE_BASE , AC97_DEVICE_END , AC97_DEVICE_SIZE , PROT_NAC, SYSTEM_ALL , "DeviceAC97 (ACI)"),
|
||||
RANGE_ENTRY(USB_DEVICE_BASE , USB_DEVICE_END , USB_DEVICE_SIZE , PROT_NAC, SYSTEM_ALL , "DeviceUSB"),
|
||||
RANGE_ENTRY(NVNET_DEVICE_BASE , NVNET_DEVICE_END , NVNET_DEVICE_SIZE , PROT_NAC, SYSTEM_ALL , "DeviceNVNet"),
|
||||
RANGE_ENTRY(FLASH_DEVICE1_BASE, FLASH_DEVICE1_END, FLASH_DEVICEN_SIZE, PROT_NAC, SYSTEM_ALL , "DeviceFlash_a (Flash mirror 1)"),
|
||||
RANGE_ENTRY(FLASH_DEVICE2_BASE, FLASH_DEVICE2_END, FLASH_DEVICEN_SIZE, PROT_NAC, SYSTEM_ALL , "DeviceFlash_b (Flash mirror 2)"),
|
||||
RANGE_ENTRY(FLASH_DEVICE3_BASE, FLASH_DEVICE3_END, FLASH_DEVICEN_SIZE, PROT_NAC, SYSTEM_ALL | MAY_FAIL, "DeviceFlash_c (Flash mirror 3)"), // this region fails reservation when running under Ubuntu with wine, so it must be allowed to fail
|
||||
RANGE_ENTRY(FLASH_DEVICE4_BASE, FLASH_DEVICE4_END, FLASH_DEVICEN_SIZE, PROT_NAC, SYSTEM_ALL | MAY_FAIL, "DeviceFlash_d (Flash mirror 4) Optional (will probably fail reservation, which is acceptable - the 3 other mirrors work just fine"),
|
||||
#undef RANGE_ENTRY
|
||||
};
|
||||
|
||||
const size_t XboxAddressRanges_size = ARRAY_SIZE(XboxAddressRanges);
|
||||
|
||||
bool AddressRangeMatchesFlags(const size_t index, const unsigned int flags)
|
||||
{
|
||||
return XboxAddressRanges[index].RangeFlags & flags;
|
||||
}
|
||||
|
||||
bool IsOptionalAddressRange(const size_t index)
|
||||
{
|
||||
return AddressRangeMatchesFlags(index, MAY_FAIL);
|
||||
}
|
||||
|
||||
unsigned int AddressRangeGetSystemFlags(const size_t index)
|
||||
{
|
||||
return XboxAddressRanges[index].RangeFlags & SYSTEM_ALL;
|
||||
}
|
||||
|
||||
bool VerifyWow64()
|
||||
{
|
||||
typedef BOOL(WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
|
||||
BOOL bIsWow64 = FALSE;
|
||||
HMODULE hKernel32 = GetModuleHandle(TEXT("kernel32"));
|
||||
LPFN_ISWOW64PROCESS fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(hKernel32, "IsWow64Process");
|
||||
if (fnIsWow64Process != nullptr) {
|
||||
HANDLE hCurrentProcess = GetCurrentProcess();
|
||||
fnIsWow64Process(hCurrentProcess, &bIsWow64);
|
||||
}
|
||||
|
||||
return (bIsWow64 != FALSE);
|
||||
}
|
|
@ -0,0 +1,211 @@
|
|||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
// ******************************************************************
|
||||
// *
|
||||
// * This file is part of Cxbx-Reloaded.
|
||||
// *
|
||||
// * Cxbx-Reloaded is free software; you can redistribute it
|
||||
// * and/or modify it under the terms of the GNU General Public
|
||||
// * License as published by the Free Software Foundation; either
|
||||
// * version 2 of the license, or (at your option) any later version.
|
||||
// *
|
||||
// * This program 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 recieved a copy of the GNU General Public License
|
||||
// * along with this program; see the file COPYING.
|
||||
// * If not, write to the Free Software Foundation, Inc.,
|
||||
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
|
||||
// *
|
||||
// * (c) 2017-2019 Patrick van Logchem <pvanlogchem@gmail.com>
|
||||
// * (c) 2019 ergo720
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
#pragma once
|
||||
|
||||
#include <cstdint> // For uint32_t
|
||||
|
||||
#define KiB(x) ((x) * 1024 ) // = 0x00000400
|
||||
#define MiB(x) ((x) * KiB(1024)) // = 0x00100000
|
||||
|
||||
// TODO: Convert the rest of defines to constexpr or const in AddressRanges.h file in master/develop branch.
|
||||
#define USER_ADDRESS1_BASE 0x00010000
|
||||
#define USER_ADDRESS1_SIZE (MiB(64) - KiB(64)) // = 0x03FF0000
|
||||
#define USER_ADDRESS1_END (USER_ADDRESS1_BASE + USER_ADDRESS1_SIZE - 1) // 0x03FFFFFF
|
||||
|
||||
#define USER_ADDRESS2_BASE 0x04000000
|
||||
#define USER_ADDRESS2_SIZE (MiB(64)) // = 0x04000000
|
||||
#define USER_ADDRESS2_END (USER_ADDRESS2_BASE + USER_ADDRESS2_SIZE - 1) // 0x07FFFFFF
|
||||
|
||||
// Base addresses of various components
|
||||
// Segaboot entry point xor address
|
||||
inline const uint32_t SEGABOOT_EP_XOR = 0x40000000;
|
||||
// Kernel Segment Zero
|
||||
#define KSEG0_BASE 0x80000000
|
||||
|
||||
#define PHYSICAL_MAP_BASE 0x80000000
|
||||
#define PHYSICAL_MAP_SIZE (MiB(256)) // = 0x10000000
|
||||
#define PHYSICAL_MAP_END (PHYSICAL_MAP_BASE + PHYSICAL_MAP_SIZE - 1) // 0x8FFFFFFF
|
||||
|
||||
inline constexpr uint32_t PHYSICAL_MAP1_BASE = 0x80000000;
|
||||
inline constexpr uint32_t PHYSICAL_MAP1_SIZE = (MiB(64)); // = 0x04000000
|
||||
inline constexpr uint32_t PHYSICAL_MAP1_END = (PHYSICAL_MAP1_BASE + PHYSICAL_MAP1_SIZE - 1); // 0x83FFFFFF
|
||||
|
||||
inline constexpr uint32_t PHYSICAL_MAP2_BASE = 0x84000000;
|
||||
inline constexpr uint32_t PHYSICAL_MAP2_SIZE = (MiB(64)); // = 0x04000000
|
||||
inline constexpr uint32_t PHYSICAL_MAP2_END = (PHYSICAL_MAP2_BASE + PHYSICAL_MAP2_SIZE - 1); // 0x8FFFFFFF
|
||||
|
||||
#define CONTIGUOUS_MEMORY_BASE KSEG0_BASE // = 0x80000000
|
||||
#define XBOX_CONTIGUOUS_MEMORY_SIZE (MiB(64))
|
||||
#define CHIHIRO_CONTIGUOUS_MEMORY_SIZE (MiB(128))
|
||||
|
||||
inline constexpr uint32_t DEVKIT_MEMORY_BASE = 0xB0000000;
|
||||
inline constexpr uint32_t DEVKIT_MEMORY_SIZE = (MiB(256)); // = 0x10000000
|
||||
inline constexpr uint32_t DEVKIT_MEMORY_END = (DEVKIT_MEMORY_BASE + DEVKIT_MEMORY_SIZE - 1); // 0xBFFFFFFF
|
||||
|
||||
inline constexpr uint32_t PAGE_TABLES_BASE = 0xC0000000;
|
||||
inline constexpr uint32_t PAGE_TABLES_SIZE = (MiB(4)); // = 0x00400000
|
||||
inline constexpr uint32_t PAGE_TABLES_END = (PAGE_TABLES_BASE + PAGE_TABLES_SIZE - 1); // 0xC03FFFFF
|
||||
|
||||
inline constexpr uint32_t SYSTEM_MEMORY_BASE = 0xD0000000;
|
||||
inline constexpr uint32_t SYSTEM_MEMORY_SIZE = (MiB(512)); // = 0x20000000
|
||||
inline constexpr uint32_t SYSTEM_MEMORY_END = (SYSTEM_MEMORY_BASE + SYSTEM_MEMORY_SIZE - 1); // 0xEFFFFFFF
|
||||
|
||||
inline constexpr uint32_t TILED_MEMORY_BASE = 0xF0000000;
|
||||
inline constexpr uint32_t TILED_MEMORY_SIZE = (MiB(64)); // = 0x04000000
|
||||
inline constexpr uint32_t TILED_MEMORY_END = (TILED_MEMORY_BASE + TILED_MEMORY_SIZE - 1); // 0xF3FFFFFF
|
||||
|
||||
#define XBOX_WRITE_COMBINED_BASE 0xF0000000 // WC (The WC memory is another name of the tiled memory)
|
||||
#define XBOX_WRITE_COMBINED_SIZE (MiB(128)) // = 0x08000000
|
||||
#define XBOX_WRITE_COMBINED_END (XBOX_WRITE_COMBINED_BASE + XBOX_WRITE_COMBINED_SIZE - 1) // 0xF7FFFFFF
|
||||
|
||||
#define XBOX_UNCACHED_BASE 0xF8000000 // UC
|
||||
#define XBOX_UNCACHED_SIZE (MiB(128 - 4)) // = 0x07C00000
|
||||
#define XBOX_UNCACHED_END (XBOX_UNCACHED_BASE + XBOX_UNCACHED_SIZE - 1) // - 0xFFBFFFFF
|
||||
|
||||
inline constexpr uint32_t NV2A_DEVICE1_BASE = 0xFD000000;
|
||||
inline constexpr uint32_t NV2A_DEVICE1_SIZE = (MiB(7)); // = 0x00700000
|
||||
inline constexpr uint32_t NV2A_DEVICE1_END = (NV2A_DEVICE1_BASE + NV2A_DEVICE1_SIZE - 1); // 0xFD6FFFFF
|
||||
|
||||
inline constexpr uint32_t NV2A_PRAMIN_BASE = 0xFD700000;
|
||||
inline constexpr uint32_t NV2A_PRAMIN_SIZE1 = (MiB(1)); // = 0x00100000 // TODO: Might be best to merge PCIDevice.h's address ranges into this header file.
|
||||
inline constexpr uint32_t NV2A_PRAMIN_END = (NV2A_PRAMIN_BASE + NV2A_PRAMIN_SIZE1 - 1); // 0xFD7FFFFF
|
||||
|
||||
inline constexpr uint32_t NV2A_DEVICE2_BASE = 0xFD800000;
|
||||
inline constexpr uint32_t NV2A_DEVICE2_SIZE = (MiB(8)); // = 0x00800000
|
||||
inline constexpr uint32_t NV2A_DEVICE2_END = (NV2A_DEVICE2_BASE + NV2A_DEVICE2_SIZE - 1); // 0xFDFFFFFF
|
||||
|
||||
inline constexpr uint32_t APU_DEVICE_BASE = 0xFE800000;
|
||||
inline constexpr uint32_t APU_DEVICE_SIZE = (KiB(512)); // = 0x00080000
|
||||
inline constexpr uint32_t APU_DEVICE_END = (APU_DEVICE_BASE + APU_DEVICE_SIZE - 1); // 0xFE87FFFF
|
||||
|
||||
inline constexpr uint32_t AC97_DEVICE_BASE = 0xFEC00000;
|
||||
inline constexpr uint32_t AC97_DEVICE_SIZE = (KiB(4)); // = 0x0001000
|
||||
inline constexpr uint32_t AC97_DEVICE_END = (AC97_DEVICE_BASE + AC97_DEVICE_SIZE - 1); // 0xFEC00FFF
|
||||
|
||||
inline constexpr uint32_t USB_DEVICE_BASE = 0xFED00000;
|
||||
inline constexpr uint32_t USB_DEVICE_SIZE = (KiB(4)); // = 0x0001000
|
||||
inline constexpr uint32_t USB_DEVICE_END = (USB_DEVICE_BASE + USB_DEVICE_SIZE - 1); // 0xFED00FFF
|
||||
|
||||
inline constexpr uint32_t NVNET_DEVICE_BASE = 0xFEF00000;
|
||||
inline constexpr uint32_t NVNET_DEVICE_SIZE = (KiB(1)); // = 0x00000400
|
||||
inline constexpr uint32_t NVNET_DEVICE_END = (NVNET_DEVICE_BASE + NVNET_DEVICE_SIZE - 1); // 0xFEF003FF
|
||||
|
||||
inline constexpr uint32_t FLASH_DEVICEN_SIZE = (MiB(4)); // = 0x00400000
|
||||
inline constexpr uint32_t FLASH_DEVICE1_BASE = 0xFF000000;
|
||||
inline constexpr uint32_t FLASH_DEVICE1_END = (FLASH_DEVICE1_BASE + FLASH_DEVICEN_SIZE - 1); // 0xFF3FFFFF
|
||||
|
||||
inline constexpr uint32_t FLASH_DEVICE2_BASE = 0xFF400000;
|
||||
inline constexpr uint32_t FLASH_DEVICE2_END = (FLASH_DEVICE2_BASE + FLASH_DEVICEN_SIZE - 1); // 0xFF7FFFFF
|
||||
|
||||
inline constexpr uint32_t FLASH_DEVICE3_BASE = 0xFF800000;
|
||||
inline constexpr uint32_t FLASH_DEVICE3_END = (FLASH_DEVICE3_BASE + FLASH_DEVICEN_SIZE - 1); // 0xFFBFFFFF
|
||||
|
||||
inline constexpr uint32_t FLASH_DEVICE4_BASE = 0xFFC00000;
|
||||
inline constexpr uint32_t FLASH_DEVICE4_END = (FLASH_DEVICE4_BASE - 1 + FLASH_DEVICEN_SIZE); // 0xFFFFFFFF // -1 must be before size to remove compiler warning.
|
||||
|
||||
// Miscellaneous base addresses
|
||||
#define XBE_IMAGE_BASE 0x00010000
|
||||
#define PAGE_DIRECTORY_BASE 0xC0300000
|
||||
#define NV2A_INIT_VECTOR 0xFF000008
|
||||
|
||||
// Define virtual base and alternate virtual base of kernel
|
||||
#define XBOX_KERNEL_BASE (PHYSICAL_MAP_BASE + XBE_IMAGE_BASE)
|
||||
#define KERNEL_PHYSICAL_ADDRESS XBE_IMAGE_BASE // = 0x10000
|
||||
#define KERNEL_SIZE sizeof(DUMMY_KERNEL)
|
||||
#define KERNEL_STACK_SIZE 12288 // 0x03000, needed by PsCreateSystemThreadEx, however the current implementation doesn't use it
|
||||
|
||||
// Miscellaneous memory variables
|
||||
// Xbox pages are (1 << 12) = 0x00001000 = 4096 bytes in size. Large pages are 4 MiB instead
|
||||
// NOTE: PAGE_SIZE is also defined in xfile.h (oxdk) and linux_wrapper.h (oxdk)
|
||||
#define PAGE_SHIFT 12 // 2^12 = 4 KiB
|
||||
#define PAGE_SIZE (1 << PAGE_SHIFT) // = 0x00001000 = KiB(4)
|
||||
#define PAGE_MASK (PAGE_SIZE - 1)
|
||||
|
||||
#define LARGE_PAGE_SHIFT 22 // 2^22 = 4 MiB
|
||||
#define LARGE_PAGE_SIZE (1 << LARGE_PAGE_SHIFT) // = 0x00400000 = 4 MiB
|
||||
#define LARGE_PAGE_MASK (LARGE_PAGE_SIZE - 1)
|
||||
|
||||
#define BYTES_IN_PHYSICAL_MAP (MiB(256)) // this refers to the system RAM physical window 0x80000000 - 0x8FFFFFFF
|
||||
#define MAXIMUM_ZERO_BITS 21 // for XbAllocateVirtualMemory
|
||||
#define MAX_VIRTUAL_ADDRESS 0xFFFFFFFF
|
||||
|
||||
#define LOWEST_USER_ADDRESS XBE_IMAGE_BASE // = 0x00010000
|
||||
#define HIGHEST_USER_ADDRESS 0x7FFEFFFF
|
||||
#define HIGHEST_VMA_ADDRESS (HIGHEST_USER_ADDRESS - X64KB) // for NtAllocateVirtualMemory
|
||||
#define USER_MEMORY_SIZE (HIGHEST_USER_ADDRESS - LOWEST_USER_ADDRESS + 1) // 0x7FFE0000 = 2 GiB - 128 KiB
|
||||
|
||||
// Memory size per system
|
||||
#define XBOX_MEMORY_SIZE (MiB(64))
|
||||
#define CHIHIRO_MEMORY_SIZE (MiB(128))
|
||||
|
||||
// Common page calculations
|
||||
#define ROUND_UP_4K(size) (((size) + PAGE_MASK) & (~PAGE_MASK))
|
||||
#define ROUND_UP(size, alignment) (((size) + (alignment - 1)) & (~(alignment - 1)))
|
||||
#define ROUND_DOWN_4K(size) ((size) & (~PAGE_MASK))
|
||||
#define ROUND_DOWN(size, alignment) ((size) & (~(alignment - 1)))
|
||||
#define CHECK_ALIGNMENT(size, alignment) (((size) % (alignment)) == 0)
|
||||
#define PAGE_ALIGN(address) ROUND_DOWN_4K(address)
|
||||
|
||||
// Windows' address space allocation granularity;
|
||||
// See https://blogs.msdn.microsoft.com/oldnewthing/20031008-00/?p=42223
|
||||
const int BLOCK_SIZE = KiB(64);
|
||||
|
||||
extern const struct _XboxAddressRanges {
|
||||
uint32_t Start;
|
||||
#ifdef DEBUG
|
||||
uint32_t End; // TODO : Add validation that this End corresponds to specified Size
|
||||
#endif
|
||||
uint32_t Size;
|
||||
unsigned long InitialMemoryProtection; // Memory page protection, for use by VirtualAlloc
|
||||
// Shortend symbol aliasses for memory page protection
|
||||
#define PROT_UNH 0 // UNHANDLED
|
||||
#define PROT_RW PAGE_READWRITE
|
||||
#define PROT_XRW PAGE_EXECUTE_READWRITE
|
||||
#define PROT_NAC PAGE_NOACCESS
|
||||
|
||||
unsigned int RangeFlags;
|
||||
// Range flags (used for system selection and optional marker)
|
||||
#define MAY_FAIL (1 << 0) // Optional (may fail address range reservation)
|
||||
#define SYSTEM_XBOX (1 << 1)
|
||||
#define SYSTEM_DEVKIT (1 << 2)
|
||||
#define SYSTEM_CHIHIRO (1 << 3)
|
||||
// Short-hand for sets of system configurations
|
||||
#define SYSTEM_ALL (SYSTEM_XBOX | SYSTEM_DEVKIT | SYSTEM_CHIHIRO)
|
||||
#define SYSTEM_128MB ( SYSTEM_DEVKIT | SYSTEM_CHIHIRO)
|
||||
#ifdef DEBUG
|
||||
const char *Comment;
|
||||
#endif
|
||||
} XboxAddressRanges[];
|
||||
|
||||
extern const size_t XboxAddressRanges_size;
|
||||
|
||||
extern bool AddressRangeMatchesFlags(const size_t index, const unsigned int flags);
|
||||
extern bool IsOptionalAddressRange(const size_t index);
|
||||
extern unsigned int AddressRangeGetSystemFlags(const size_t index);
|
||||
|
||||
extern bool VerifyWow64();
|
|
@ -37,19 +37,19 @@ namespace CxbxDebugger
|
|||
// Note: Keep the top 3-bits empty as they are used internally
|
||||
enum ReportType : DWORD
|
||||
{
|
||||
// Debugger report codes:
|
||||
HLECACHE_FILE = 0x1000,
|
||||
|
||||
HLECACHE_FILE = 0x00deed00,
|
||||
KERNEL_PATCH = 0x00deed01,
|
||||
FILE_OPENED = 0x00deed02,
|
||||
FILE_READ = 0x00deed03,
|
||||
FILE_CLOSED = 0x00deed04,
|
||||
DEBUGGER_INIT = 0x00deed05,
|
||||
FILE_WRITE = 0x00deed06,
|
||||
KERNEL_PATCH = 0x2000,
|
||||
|
||||
// Debugger query codes:
|
||||
FILE_OPENED = 0x3000,
|
||||
FILE_READ = 0x3001,
|
||||
FILE_WRITE = 0x3002,
|
||||
FILE_CLOSED = 0x3003,
|
||||
|
||||
OVERRIDE_EXCEPTION = 0x00ceed01,
|
||||
DEBUGGER_INIT = 0x4000,
|
||||
DEBUGGER_NEW_TARGET = 0x4001,
|
||||
|
||||
OVERRIDE_EXCEPTION = 0x5000,
|
||||
};
|
||||
|
||||
bool IsAttached()
|
||||
|
@ -128,8 +128,10 @@ namespace CxbxDebugger
|
|||
case Internal::KERNEL_PATCH:
|
||||
case Internal::FILE_OPENED:
|
||||
case Internal::FILE_READ:
|
||||
case Internal::FILE_WRITE:
|
||||
case Internal::FILE_CLOSED:
|
||||
case Internal::DEBUGGER_INIT:
|
||||
case Internal::DEBUGGER_NEW_TARGET:
|
||||
return true;
|
||||
|
||||
case Internal::OVERRIDE_EXCEPTION:
|
||||
|
@ -148,12 +150,20 @@ namespace CxbxDebugger
|
|||
{
|
||||
Internal::ReportHelper Report(Internal::DEBUGGER_INIT);
|
||||
|
||||
Report.Add(0); // unused
|
||||
Report.AddString(XbeTitle);
|
||||
|
||||
Report.Send();
|
||||
}
|
||||
|
||||
void ReportNewTarget(const char* CommandLine)
|
||||
{
|
||||
Internal::ReportHelper Report(Internal::DEBUGGER_NEW_TARGET);
|
||||
|
||||
Report.AddString(CommandLine);
|
||||
|
||||
Report.Send();
|
||||
}
|
||||
|
||||
void ReportHLECacheFile(const char* Filename)
|
||||
{
|
||||
Internal::ReportHelper Report(Internal::HLECACHE_FILE);
|
||||
|
|
|
@ -36,6 +36,7 @@ namespace CxbxDebugger
|
|||
// Report helpers:
|
||||
|
||||
void ReportDebuggerInit(const char* XbeTitle);
|
||||
void ReportNewTarget(const char* CommandLine);
|
||||
|
||||
void ReportHLECacheFile(const char* Filename);
|
||||
void ReportKernelPatch(const char* ImportName, DWORD Address);
|
||||
|
|
|
@ -27,12 +27,8 @@
|
|||
#define LOG_PREFIX CXBXR_MODULE::EEPR
|
||||
#define LOG_PREFIX_INIT CXBXR_MODULE::INIT
|
||||
|
||||
// prevent name collisions
|
||||
namespace xboxkrnl
|
||||
{
|
||||
#include <xboxkrnl/xboxkrnl.h> // For XC_VALUE_INDEX and XBOX_EEPROM
|
||||
};
|
||||
|
||||
#include <core\kernel\exports\xboxkrnl.h> // For XC_VALUE_INDEX and XBOX_EEPROM
|
||||
#include "cxbxr.hpp" // For CxbxrAbort
|
||||
#include <stdio.h> // For printf
|
||||
#include <shlobj.h> // For HANDLE, CreateFile, CreateFileMapping, MapViewOfFile
|
||||
#include <random>
|
||||
|
@ -40,14 +36,13 @@ namespace xboxkrnl
|
|||
#include "EmuEEPROM.h" // For EEPROMInfo, EEPROMInfos
|
||||
#include "core\kernel\support\Emu.h" // For EmuWarning
|
||||
#include "..\..\src\devices\LED.h" // For SetLEDSequence
|
||||
#include "..\core\kernel\init\CxbxKrnl.h"
|
||||
|
||||
xboxkrnl::XBOX_EEPROM *EEPROM = nullptr; // Set using CxbxRestoreEEPROM()
|
||||
xbox::XBOX_EEPROM *EEPROM = nullptr; // Set using CxbxRestoreEEPROM()
|
||||
|
||||
// Default value (NA), overwritten with the actual content in the eeprom by CxbxRestoreEEPROM
|
||||
xboxkrnl::ULONG XboxFactoryGameRegion = XC_GAME_REGION_NA;
|
||||
xbox::ulong_xt XboxFactoryGameRegion = XC_GAME_REGION_NA;
|
||||
|
||||
const EEPROMInfo* EmuFindEEPROMInfo(xboxkrnl::XC_VALUE_INDEX index)
|
||||
const EEPROMInfo* EmuFindEEPROMInfo(xbox::XC_VALUE_INDEX index)
|
||||
{
|
||||
for (int i = 0; EEPROMInfos[i].index != XC_END_MARKER; i++)
|
||||
if (EEPROMInfos[i].index == index)
|
||||
|
@ -79,7 +74,7 @@ static void EepromCRC(unsigned char *crc, unsigned char *data, long dataLen) {
|
|||
free(CRC_Data);
|
||||
}
|
||||
|
||||
void gen_section_CRCs(xboxkrnl::XBOX_EEPROM* eeprom) {
|
||||
void gen_section_CRCs(xbox::XBOX_EEPROM* eeprom) {
|
||||
const long Factory_size = sizeof(eeprom->FactorySettings) - sizeof(eeprom->FactorySettings.Checksum);
|
||||
const long User_size = sizeof(eeprom->UserSettings) - sizeof(eeprom->UserSettings.Checksum);
|
||||
EepromCRC(
|
||||
|
@ -94,9 +89,10 @@ void gen_section_CRCs(xboxkrnl::XBOX_EEPROM* eeprom) {
|
|||
);
|
||||
}
|
||||
|
||||
xboxkrnl::XBOX_EEPROM *CxbxRestoreEEPROM(char *szFilePath_EEPROM_bin)
|
||||
#ifdef CXBXR_EMU
|
||||
xbox::XBOX_EEPROM *CxbxRestoreEEPROM(char *szFilePath_EEPROM_bin)
|
||||
{
|
||||
xboxkrnl::XBOX_EEPROM *pEEPROM;
|
||||
xbox::XBOX_EEPROM *pEEPROM;
|
||||
|
||||
// First, try to open an existing EEPROM.bin file :
|
||||
HANDLE hFileEEPROM = CreateFile(szFilePath_EEPROM_bin,
|
||||
|
@ -126,7 +122,7 @@ xboxkrnl::XBOX_EEPROM *CxbxRestoreEEPROM(char *szFilePath_EEPROM_bin)
|
|||
}
|
||||
|
||||
// Make sure EEPROM.bin is at least 256 bytes in size
|
||||
SetFilePointer(hFileEEPROM, 256, nullptr, FILE_BEGIN);
|
||||
SetFilePointer(hFileEEPROM, EEPROM_SIZE, nullptr, FILE_BEGIN);
|
||||
SetEndOfFile(hFileEEPROM);
|
||||
|
||||
HANDLE hFileMappingEEPROM = CreateFileMapping(
|
||||
|
@ -145,14 +141,12 @@ xboxkrnl::XBOX_EEPROM *CxbxRestoreEEPROM(char *szFilePath_EEPROM_bin)
|
|||
LARGE_INTEGER len_li;
|
||||
GetFileSizeEx(hFileEEPROM, &len_li);
|
||||
unsigned int FileSize = len_li.u.LowPart;
|
||||
if (FileSize != 256)
|
||||
{
|
||||
CxbxKrnlCleanup("%s : EEPROM.bin file is not 256 bytes large!\n", __func__);
|
||||
return nullptr;
|
||||
if (FileSize != 256) {
|
||||
CxbxrAbort("%s : EEPROM.bin file is not 256 bytes large!\n", __func__);
|
||||
}
|
||||
|
||||
// Map EEPROM.bin contents into memory :
|
||||
pEEPROM = (xboxkrnl::XBOX_EEPROM *)MapViewOfFile(
|
||||
pEEPROM = (xbox::XBOX_EEPROM *)MapViewOfFile(
|
||||
hFileMappingEEPROM,
|
||||
FILE_MAP_READ | FILE_MAP_WRITE,
|
||||
/* dwFileOffsetHigh */0,
|
||||
|
@ -184,11 +178,11 @@ xboxkrnl::XBOX_EEPROM *CxbxRestoreEEPROM(char *szFilePath_EEPROM_bin)
|
|||
}
|
||||
|
||||
// Read the HDD (and eventually also the online) keys stored in the eeprom file. Users can input them in the eeprom menu
|
||||
memcpy(xboxkrnl::XboxHDKey, pEEPROM->EncryptedSettings.HDKey, xboxkrnl::XBOX_KEY_LENGTH);
|
||||
memcpy(xbox::XboxHDKey, pEEPROM->EncryptedSettings.HDKey, xbox::XBOX_KEY_LENGTH);
|
||||
|
||||
// Verify the checksum of the eeprom header
|
||||
UCHAR Checksum[20] = { 0 };
|
||||
xboxkrnl::XcHMAC(xboxkrnl::XboxEEPROMKey, 16, pEEPROM->EncryptedSettings.Confounder, 8, pEEPROM->EncryptedSettings.HDKey, 20, Checksum);
|
||||
xbox::XcHMAC(xbox::XboxEEPROMKey, 16, pEEPROM->EncryptedSettings.Confounder, 8, pEEPROM->EncryptedSettings.HDKey, 20, Checksum);
|
||||
if (memcmp(Checksum, pEEPROM->EncryptedSettings.Checksum, 20))
|
||||
{
|
||||
// The checksums do not match. Log this error and flash the LED (red, off, red, off)
|
||||
|
@ -198,21 +192,51 @@ xboxkrnl::XBOX_EEPROM *CxbxRestoreEEPROM(char *szFilePath_EEPROM_bin)
|
|||
|
||||
return pEEPROM;
|
||||
}
|
||||
#endif
|
||||
|
||||
void EmuEEPROMReset(xboxkrnl::XBOX_EEPROM* eeprom)
|
||||
void EmuEEPROMReset(xbox::XBOX_EEPROM* eeprom)
|
||||
{
|
||||
memset(eeprom, 0, sizeof(xboxkrnl::XBOX_EEPROM));
|
||||
memset(eeprom, 0, sizeof(xbox::XBOX_EEPROM));
|
||||
|
||||
// Set Factory Settings
|
||||
// Setup random number generator
|
||||
std::random_device rd;
|
||||
std::mt19937 gen(rd());
|
||||
std::uniform_int_distribution<> randomDis(0, 255);
|
||||
|
||||
// Factory Settings
|
||||
eeprom->FactorySettings.AVRegion = AV_STANDARD_NTSC_M | AV_FLAGS_60Hz;
|
||||
memcpy(eeprom->FactorySettings.SerialNumber, "Cxbx-R ", 12);
|
||||
// TODO: Ethernet Address
|
||||
// TODO: Online Key
|
||||
|
||||
// Encrypted Section
|
||||
// Generate a random serial number
|
||||
std::uniform_int_distribution<> serialDis(0, 9);
|
||||
std::string serial = "";
|
||||
for (int i = 0; i < 12; i++) {
|
||||
serial += std::to_string(serialDis(gen));
|
||||
}
|
||||
memset(eeprom->FactorySettings.SerialNumber, 0, 12);
|
||||
strncpy((char*)eeprom->FactorySettings.SerialNumber, serial.c_str(), 12);
|
||||
|
||||
// Generate a random mac address, starting with the Microsoft prefix
|
||||
eeprom->FactorySettings.EthernetAddr[0] = 0x00;
|
||||
eeprom->FactorySettings.EthernetAddr[1] = 0x50;
|
||||
eeprom->FactorySettings.EthernetAddr[2] = 0xF2;
|
||||
for (int i = 3; i < 6; i++) {
|
||||
eeprom->FactorySettings.EthernetAddr[i] = randomDis(gen);
|
||||
}
|
||||
|
||||
// Generate a random Online Key
|
||||
for (int i = 0; i < 16; i++) {
|
||||
eeprom->FactorySettings.OnlineKey[i] = randomDis(gen);
|
||||
}
|
||||
|
||||
// Encrypted Settings
|
||||
eeprom->EncryptedSettings.GameRegion = XC_GAME_REGION_NA;
|
||||
// TODO: HDD Key
|
||||
xboxkrnl::XcHMAC(xboxkrnl::XboxEEPROMKey, 16, eeprom->EncryptedSettings.Confounder, 8, eeprom->EncryptedSettings.HDKey, 20, eeprom->EncryptedSettings.Checksum);
|
||||
|
||||
// Generate a random HDD Key
|
||||
for (int i = 0; i < 16; i++) {
|
||||
eeprom->EncryptedSettings.HDKey[i] = randomDis(gen);
|
||||
}
|
||||
|
||||
xbox::XcHMAC(xbox::XboxEEPROMKey, 16, eeprom->EncryptedSettings.Confounder, 8, eeprom->EncryptedSettings.HDKey, 20, eeprom->EncryptedSettings.Checksum);
|
||||
|
||||
// User Settings
|
||||
eeprom->UserSettings.Language = XC_LANGUAGE_ENGLISH; // = English
|
||||
|
@ -222,34 +246,5 @@ void EmuEEPROMReset(xboxkrnl::XBOX_EEPROM* eeprom)
|
|||
eeprom->UserSettings.ParentalControlMovies = XC_PC_MAX; // = XC_PRTL_CRTL_MAX
|
||||
eeprom->UserSettings.MiscFlags = 0; // No automatic power down
|
||||
|
||||
// Online Settings
|
||||
|
||||
// Setup the Serial and Mac Generators
|
||||
std::random_device rd;
|
||||
std::mt19937 gen(rd());
|
||||
std::uniform_int_distribution<> serialDis (0, 9);
|
||||
std::uniform_int_distribution<> macOnlineDis(0, 255);
|
||||
|
||||
// Generate a random serial number
|
||||
std::string serial = "";
|
||||
for (int i = 0; i < 12; i++) {
|
||||
serial += std::to_string(serialDis(gen));
|
||||
}
|
||||
memset(eeprom->FactorySettings.SerialNumber, 0, 12);
|
||||
strncpy((char*)eeprom->FactorySettings.SerialNumber, serial.c_str(), 12);
|
||||
|
||||
// Generate a random mac address
|
||||
eeprom->FactorySettings.EthernetAddr[0] = 0x00;
|
||||
eeprom->FactorySettings.EthernetAddr[1] = 0x50;
|
||||
eeprom->FactorySettings.EthernetAddr[2] = 0xF2;
|
||||
for (int i = 3; i < 6; i++) {
|
||||
eeprom->FactorySettings.EthernetAddr[i] = macOnlineDis(gen);
|
||||
}
|
||||
|
||||
// Generate a random Online Key
|
||||
for (int i = 0; i < 16; i++) {
|
||||
eeprom->FactorySettings.OnlineKey[i] = macOnlineDis(gen);
|
||||
}
|
||||
|
||||
// TODO: TimeZone Settings
|
||||
}
|
||||
|
|
|
@ -27,61 +27,55 @@
|
|||
#ifndef EMU_EEPROM_H
|
||||
#define EMU_EEPROM_H
|
||||
|
||||
// prevent name collisions
|
||||
namespace xboxkrnl
|
||||
{
|
||||
#undef _WIN32 // Compile-in REG_DWORD and friends, since we lack a <windows> include here
|
||||
#include <xboxkrnl/xboxkrnl.h> // For XC_VALUE_INDEX and XBOX_EEPROM
|
||||
#define _WIN32
|
||||
};
|
||||
#include <core\kernel\exports\xboxkrnl.h> // For XC_VALUE_INDEX and XBOX_EEPROM
|
||||
|
||||
#define EEPROM_SIZE sizeof(xboxkrnl::XBOX_EEPROM)
|
||||
#define EEPROM_SIZE sizeof(xbox::XBOX_EEPROM)
|
||||
|
||||
typedef struct EEPROMInfo {
|
||||
xboxkrnl::XC_VALUE_INDEX index;
|
||||
xbox::XC_VALUE_INDEX index;
|
||||
int value_offset;
|
||||
int value_type;
|
||||
int value_length;
|
||||
} EEPROMInfo;
|
||||
|
||||
#define XC_END_MARKER (xboxkrnl::XC_VALUE_INDEX)-1
|
||||
#define XC_END_MARKER (xbox::XC_VALUE_INDEX)-1
|
||||
|
||||
#define EEPROM_INFO_ENTRY(XC, Member, REG_Type) \
|
||||
{ xboxkrnl::XC, offsetof(xboxkrnl::XBOX_EEPROM, Member), REG_Type, sizeof(((xboxkrnl::XBOX_EEPROM *)0)->Member) }
|
||||
{ xbox::XC, offsetof(xbox::XBOX_EEPROM, Member), REG_Type, sizeof(((xbox::XBOX_EEPROM *)0)->Member) }
|
||||
|
||||
static const EEPROMInfo EEPROMInfos[] = {
|
||||
EEPROM_INFO_ENTRY(XC_TIMEZONE_BIAS, UserSettings.TimeZoneBias, REG_DWORD),
|
||||
EEPROM_INFO_ENTRY(XC_TZ_STD_NAME, UserSettings.TimeZoneStdName, REG_BINARY),
|
||||
EEPROM_INFO_ENTRY(XC_TZ_STD_DATE, UserSettings.TimeZoneStdDate, REG_DWORD),
|
||||
EEPROM_INFO_ENTRY(XC_TZ_STD_BIAS, UserSettings.TimeZoneStdBias, REG_DWORD),
|
||||
EEPROM_INFO_ENTRY(XC_TZ_DLT_NAME, UserSettings.TimeZoneDltName, REG_BINARY),
|
||||
EEPROM_INFO_ENTRY(XC_TZ_DLT_DATE, UserSettings.TimeZoneDltDate, REG_DWORD),
|
||||
EEPROM_INFO_ENTRY(XC_TZ_DLT_BIAS, UserSettings.TimeZoneDltBias, REG_DWORD),
|
||||
EEPROM_INFO_ENTRY(XC_LANGUAGE, UserSettings.Language, REG_DWORD),
|
||||
EEPROM_INFO_ENTRY(XC_VIDEO, UserSettings.VideoFlags, REG_DWORD),
|
||||
EEPROM_INFO_ENTRY(XC_AUDIO, UserSettings.AudioFlags, REG_DWORD),
|
||||
EEPROM_INFO_ENTRY(XC_P_CONTROL_GAMES, UserSettings.ParentalControlGames, REG_DWORD), // Zapper queries this. TODO : Should this be REG_NONE?
|
||||
EEPROM_INFO_ENTRY(XC_P_CONTROL_PASSWORD, UserSettings.ParentalControlPassword, REG_DWORD),
|
||||
EEPROM_INFO_ENTRY(XC_P_CONTROL_MOVIES, UserSettings.ParentalControlMovies, REG_DWORD), // Xbox Dashboard queries this.
|
||||
EEPROM_INFO_ENTRY(XC_ONLINE_IP_ADDRESS, UserSettings.OnlineIpAddress, REG_DWORD),
|
||||
EEPROM_INFO_ENTRY(XC_ONLINE_DNS_ADDRESS, UserSettings.OnlineDnsAddress, REG_DWORD),
|
||||
EEPROM_INFO_ENTRY(XC_ONLINE_DEFAULT_GATEWAY_ADDRESS, UserSettings.OnlineDefaultGatewayAddress, REG_DWORD),
|
||||
EEPROM_INFO_ENTRY(XC_ONLINE_SUBNET_ADDRESS, UserSettings.OnlineSubnetMask, REG_DWORD),
|
||||
EEPROM_INFO_ENTRY(XC_MISC, UserSettings.MiscFlags, REG_DWORD),
|
||||
EEPROM_INFO_ENTRY(XC_DVD_REGION, UserSettings.DvdRegion, REG_DWORD),
|
||||
EEPROM_INFO_ENTRY(XC_MAX_OS, UserSettings, REG_BINARY),
|
||||
EEPROM_INFO_ENTRY(XC_TIMEZONE_BIAS, UserSettings.TimeZoneBias, xbox::reg_dword),
|
||||
EEPROM_INFO_ENTRY(XC_TZ_STD_NAME, UserSettings.TimeZoneStdName, xbox::reg_binary),
|
||||
EEPROM_INFO_ENTRY(XC_TZ_STD_DATE, UserSettings.TimeZoneStdDate, xbox::reg_dword),
|
||||
EEPROM_INFO_ENTRY(XC_TZ_STD_BIAS, UserSettings.TimeZoneStdBias, xbox::reg_dword),
|
||||
EEPROM_INFO_ENTRY(XC_TZ_DLT_NAME, UserSettings.TimeZoneDltName, xbox::reg_binary),
|
||||
EEPROM_INFO_ENTRY(XC_TZ_DLT_DATE, UserSettings.TimeZoneDltDate, xbox::reg_dword),
|
||||
EEPROM_INFO_ENTRY(XC_TZ_DLT_BIAS, UserSettings.TimeZoneDltBias, xbox::reg_dword),
|
||||
EEPROM_INFO_ENTRY(XC_LANGUAGE, UserSettings.Language, xbox::reg_dword),
|
||||
EEPROM_INFO_ENTRY(XC_VIDEO, UserSettings.VideoFlags, xbox::reg_dword),
|
||||
EEPROM_INFO_ENTRY(XC_AUDIO, UserSettings.AudioFlags, xbox::reg_dword),
|
||||
EEPROM_INFO_ENTRY(XC_P_CONTROL_GAMES, UserSettings.ParentalControlGames, xbox::reg_dword), // Zapper queries this. TODO : Should this be xbox::reg_none?
|
||||
EEPROM_INFO_ENTRY(XC_P_CONTROL_PASSWORD, UserSettings.ParentalControlPassword, xbox::reg_dword),
|
||||
EEPROM_INFO_ENTRY(XC_P_CONTROL_MOVIES, UserSettings.ParentalControlMovies, xbox::reg_dword), // Xbox Dashboard queries this.
|
||||
EEPROM_INFO_ENTRY(XC_ONLINE_IP_ADDRESS, UserSettings.OnlineIpAddress, xbox::reg_dword),
|
||||
EEPROM_INFO_ENTRY(XC_ONLINE_DNS_ADDRESS, UserSettings.OnlineDnsAddress, xbox::reg_dword),
|
||||
EEPROM_INFO_ENTRY(XC_ONLINE_DEFAULT_GATEWAY_ADDRESS, UserSettings.OnlineDefaultGatewayAddress, xbox::reg_dword),
|
||||
EEPROM_INFO_ENTRY(XC_ONLINE_SUBNET_ADDRESS, UserSettings.OnlineSubnetMask, xbox::reg_dword),
|
||||
EEPROM_INFO_ENTRY(XC_MISC, UserSettings.MiscFlags, xbox::reg_dword),
|
||||
EEPROM_INFO_ENTRY(XC_DVD_REGION, UserSettings.DvdRegion, xbox::reg_dword),
|
||||
EEPROM_INFO_ENTRY(XC_MAX_OS, UserSettings, xbox::reg_binary),
|
||||
// XC_MAX_OS is called to return a complete XBOX_USER_SETTINGS structure
|
||||
//
|
||||
// One example is from XapipQueryTimeZoneInformation(, REG_DWORD, sizeof(DWORD), where it is used to
|
||||
// One example is from XapipQueryTimeZoneInformation(, xbox::reg_dword, sizeof(DWORD), where it is used to
|
||||
// detect the local timezone information.
|
||||
EEPROM_INFO_ENTRY(XC_FACTORY_SERIAL_NUMBER, FactorySettings.SerialNumber, REG_BINARY),
|
||||
EEPROM_INFO_ENTRY(XC_FACTORY_ETHERNET_ADDR, FactorySettings.EthernetAddr, REG_BINARY),
|
||||
EEPROM_INFO_ENTRY(XC_FACTORY_ONLINE_KEY, FactorySettings.OnlineKey, REG_BINARY),
|
||||
EEPROM_INFO_ENTRY(XC_FACTORY_AV_REGION, FactorySettings.AVRegion, REG_DWORD),
|
||||
// Note : XC_FACTORY_GAME_REGION is linked to a separate ULONG XboxFactoryGameRegion (of type REG_DWORD)
|
||||
EEPROM_INFO_ENTRY(XC_FACTORY_GAME_REGION, EncryptedSettings.GameRegion, REG_DWORD),
|
||||
EEPROM_INFO_ENTRY(XC_ENCRYPTED_SECTION, EncryptedSettings, REG_BINARY),
|
||||
{ xboxkrnl::XC_MAX_ALL, 0, REG_BINARY, sizeof(xboxkrnl::XBOX_EEPROM) },
|
||||
EEPROM_INFO_ENTRY(XC_FACTORY_SERIAL_NUMBER, FactorySettings.SerialNumber, xbox::reg_binary),
|
||||
EEPROM_INFO_ENTRY(XC_FACTORY_ETHERNET_ADDR, FactorySettings.EthernetAddr, xbox::reg_binary),
|
||||
EEPROM_INFO_ENTRY(XC_FACTORY_ONLINE_KEY, FactorySettings.OnlineKey, xbox::reg_binary),
|
||||
EEPROM_INFO_ENTRY(XC_FACTORY_AV_REGION, FactorySettings.AVRegion, xbox::reg_dword),
|
||||
// Note : XC_FACTORY_GAME_REGION is linked to a separate ULONG XboxFactoryGameRegion (of type xbox::reg_dword)
|
||||
EEPROM_INFO_ENTRY(XC_FACTORY_GAME_REGION, EncryptedSettings.GameRegion, xbox::reg_dword),
|
||||
EEPROM_INFO_ENTRY(XC_ENCRYPTED_SECTION, EncryptedSettings, xbox::reg_binary),
|
||||
{ xbox::XC_MAX_ALL, 0, xbox::reg_binary, sizeof(xbox::XBOX_EEPROM) },
|
||||
{ XC_END_MARKER }
|
||||
};
|
||||
|
||||
|
@ -145,16 +139,16 @@ static const EEPROMInfo EEPROMInfos[] = {
|
|||
#define DVD_REGION_RESERVED 7
|
||||
#define DVD_REGION_INTERNATIONAL 8
|
||||
|
||||
extern xboxkrnl::XBOX_EEPROM *CxbxRestoreEEPROM(char *szFilePath_EEPROM_bin);
|
||||
extern xbox::XBOX_EEPROM *CxbxRestoreEEPROM(char *szFilePath_EEPROM_bin);
|
||||
|
||||
extern const EEPROMInfo* EmuFindEEPROMInfo(xboxkrnl::XC_VALUE_INDEX index);
|
||||
extern const EEPROMInfo* EmuFindEEPROMInfo(xbox::XC_VALUE_INDEX index);
|
||||
|
||||
extern xboxkrnl::XBOX_EEPROM *EEPROM;
|
||||
extern xbox::XBOX_EEPROM *EEPROM;
|
||||
|
||||
extern xboxkrnl::ULONG XboxFactoryGameRegion;
|
||||
extern xbox::ulong_xt XboxFactoryGameRegion;
|
||||
|
||||
extern void EmuEEPROMReset(xboxkrnl::XBOX_EEPROM* eeprom);
|
||||
extern void EmuEEPROMReset(xbox::XBOX_EEPROM* eeprom);
|
||||
|
||||
void gen_section_CRCs(xboxkrnl::XBOX_EEPROM*);
|
||||
void gen_section_CRCs(xbox::XBOX_EEPROM*);
|
||||
|
||||
#endif // EMU_EEPROM_H
|
||||
|
|
|
@ -27,14 +27,14 @@
|
|||
|
||||
#include "common\Error.h"
|
||||
|
||||
const std::string& Error::GetError()
|
||||
const std::string Error::GetError()
|
||||
{
|
||||
return m_strError;
|
||||
return std::string(m_szError);
|
||||
}
|
||||
|
||||
bool Error::HasError() const
|
||||
{
|
||||
return HasFatalError() || !m_strError.empty();
|
||||
return HasFatalError() || (m_szError[0] != '\0');
|
||||
}
|
||||
|
||||
bool Error::HasFatalError() const
|
||||
|
@ -46,7 +46,7 @@ bool Error::ClearError()
|
|||
{
|
||||
if (m_bFatal) { return false; }
|
||||
|
||||
m_strError.clear();
|
||||
m_szError[0] = '\0';
|
||||
m_bFatal = false;
|
||||
|
||||
return true;
|
||||
|
@ -54,11 +54,17 @@ bool Error::ClearError()
|
|||
|
||||
void Error::SetError(const std::string& strError)
|
||||
{
|
||||
m_strError = strError;
|
||||
// assert(strError.length()) < sizeof(m_szError));
|
||||
|
||||
memset(m_szError, '\0', sizeof(m_szError));
|
||||
memcpy(m_szError, strError.c_str(), strError.length());
|
||||
}
|
||||
|
||||
void Error::SetFatalError(const std::string& strError)
|
||||
{
|
||||
m_strError = strError;
|
||||
// assert(strError.length()) < sizeof(m_szError));
|
||||
|
||||
memset(m_szError, '\0', sizeof(m_szError));
|
||||
memcpy(m_szError, strError.c_str(), strError.length());
|
||||
m_bFatal = true;
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
class Error
|
||||
{
|
||||
public:
|
||||
const std::string& GetError();
|
||||
const std::string GetError();
|
||||
|
||||
bool HasError() const;
|
||||
bool HasFatalError() const;
|
||||
|
@ -42,15 +42,15 @@ public:
|
|||
|
||||
protected:
|
||||
// protected constructor so this class must be inherited from
|
||||
Error() : m_bFatal(false) { }
|
||||
Error() : m_szError("\0"), m_bFatal(false) { }
|
||||
|
||||
// protected so only derived class may set an error
|
||||
void SetError(const std::string& strStrError);
|
||||
void SetFatalError(const std::string& strError);
|
||||
|
||||
private:
|
||||
std::string m_strError;
|
||||
bool m_bFatal;
|
||||
char m_szError[60]; // Cannot be std::string, which sizeof() differs between builds
|
||||
uint32_t m_bFatal; // Cannot be bool, to avoid bit packing altering memory layout
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,187 @@
|
|||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
// ******************************************************************
|
||||
// *
|
||||
// * This file is part of the Cxbx-Reloaded project.
|
||||
// *
|
||||
// * Cxbx and Cxbe are free software; you can redistribute them
|
||||
// * and/or modify them under the terms of the GNU General Public
|
||||
// * License as published by the Free Software Foundation; either
|
||||
// * version 2 of the license, or (at your option) any later version.
|
||||
// *
|
||||
// * This program 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 recieved a copy of the GNU General Public License
|
||||
// * along with this program; see the file COPYING.
|
||||
// * If not, write to the Free Software Foundation, Inc.,
|
||||
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
#define LOG_PREFIX CXBXR_MODULE::FILE
|
||||
#define LOG_PREFIX_INIT CXBXR_MODULE::INIT
|
||||
|
||||
#include <filesystem>
|
||||
#include "common/cxbxr.hpp"
|
||||
#include "Settings.hpp"
|
||||
#include "EmuShared.h"
|
||||
#include "xxhash.h" // for XXH3_64bits
|
||||
#include "core/kernel/common/xbox.h"
|
||||
#include "Logging.h"
|
||||
|
||||
char szFilePath_CxbxReloaded_Exe[MAX_PATH] = { 0 };
|
||||
char szFilePath_EEPROM_bin[MAX_PATH] = { 0 };
|
||||
|
||||
std::string g_DataFilePath;
|
||||
std::string g_DiskBasePath;
|
||||
std::string g_MuBasePath;
|
||||
|
||||
//TODO: Possible move CxbxResolveHostToFullPath inline function someplace else if become useful elsewhere.
|
||||
// Let filesystem library clean it up for us, including resolve host's symbolic link path.
|
||||
// Since internal kernel do translate to full path than preserved host symoblic link path.
|
||||
void CxbxResolveHostToFullPath(std::filesystem::path& file_path, std::string_view finish_error_sentence) {
|
||||
std::error_code error;
|
||||
std::filesystem::path sanityPath = std::filesystem::canonical(file_path, error);
|
||||
if (error) {
|
||||
|
||||
// The MS implementation of std::filesystem::canonical internally calls GetFinalPathNameByHandleW, which fails with ERROR_FILE_NOT_FOUND when called
|
||||
// on a file inside a mounted xiso under Windows with the xbox-iso-vfs tool because of this known dokany bug https://github.com/dokan-dev/dokany/issues/343
|
||||
EmuLogInit(LOG_LEVEL::WARNING, "Could not resolve to %s: %s, dokany in use? The error was: %s",
|
||||
finish_error_sentence.data(), file_path.string().c_str(), error.message().c_str());
|
||||
|
||||
sanityPath = std::filesystem::absolute(std::filesystem::weakly_canonical(file_path, error), error);
|
||||
if (error) {
|
||||
CxbxrAbortEx(LOG_PREFIX_INIT, "Could not resolve to %s: %s. The error was: %s", finish_error_sentence.data(), file_path.string().c_str(), error.message().c_str());
|
||||
}
|
||||
}
|
||||
file_path = sanityPath;
|
||||
}
|
||||
// TODO: Eventually, we should remove this function to start using std::filesystem::path method for all host paths.
|
||||
void CxbxResolveHostToFullPath(std::string& file_path, std::string_view finish_error_sentence) {
|
||||
std::filesystem::path sanityPath(file_path);
|
||||
CxbxResolveHostToFullPath(sanityPath, finish_error_sentence);
|
||||
file_path = sanityPath.string();
|
||||
}
|
||||
|
||||
// NOTE: Do NOT modify g_<custom>BasePath variables after this call!
|
||||
void CxbxrInitFilePaths()
|
||||
{
|
||||
if (g_Settings) {
|
||||
g_DataFilePath = g_Settings->GetDataLocation();
|
||||
}
|
||||
else {
|
||||
char dataLoc[MAX_PATH];
|
||||
g_EmuShared->GetDataLocation(dataLoc);
|
||||
g_DataFilePath = dataLoc;
|
||||
}
|
||||
|
||||
// Make sure our data folder exists :
|
||||
bool result = std::filesystem::exists(g_DataFilePath);
|
||||
if (!result && !std::filesystem::create_directory(g_DataFilePath)) {
|
||||
CxbxrAbort("%s : Couldn't create Cxbx-Reloaded's data folder!", __func__);
|
||||
}
|
||||
|
||||
// Make sure the EmuDisk folder exists
|
||||
g_DiskBasePath = g_DataFilePath + "\\EmuDisk";
|
||||
result = std::filesystem::exists(g_DiskBasePath);
|
||||
if (!result && !std::filesystem::create_directory(g_DiskBasePath)) {
|
||||
CxbxrAbort("%s : Couldn't create Cxbx-Reloaded EmuDisk folder!", __func__);
|
||||
}
|
||||
CxbxResolveHostToFullPath(g_DiskBasePath, "Cxbx-Reloaded's EmuDisk directory");
|
||||
g_DiskBasePath = std::filesystem::path(g_DiskBasePath).append("").string();
|
||||
|
||||
// Make sure the EmuDMu folder exists
|
||||
g_MuBasePath = g_DataFilePath + "\\EmuMu";
|
||||
result = std::filesystem::exists(g_MuBasePath);
|
||||
if (!result && !std::filesystem::create_directory(g_MuBasePath)) {
|
||||
CxbxrAbort("%s : Couldn't create Cxbx-Reloaded EmuMu folder!", __func__);
|
||||
}
|
||||
CxbxResolveHostToFullPath(g_MuBasePath, "Cxbx-Reloaded's EmuMu directory");
|
||||
g_MuBasePath = std::filesystem::path(g_MuBasePath).append("").string();
|
||||
|
||||
snprintf(szFilePath_EEPROM_bin, MAX_PATH, "%s\\EEPROM.bin", g_DataFilePath.c_str());
|
||||
|
||||
GetModuleFileName(GetModuleHandle(nullptr), szFilePath_CxbxReloaded_Exe, MAX_PATH);
|
||||
}
|
||||
|
||||
// Loads a keys.bin file as generated by dump-xbox
|
||||
// See https://github.com/JayFoxRox/xqemu-tools/blob/master/dump-xbox.c
|
||||
void LoadXboxKeys()
|
||||
{
|
||||
std::string keys_path = g_DataFilePath + "\\keys.bin";
|
||||
|
||||
// Attempt to open Keys.bin
|
||||
FILE* fp = fopen(keys_path.c_str(), "rb");
|
||||
|
||||
if (fp != nullptr) {
|
||||
// Determine size of Keys.bin
|
||||
xbox::XBOX_KEY_DATA keys[2];
|
||||
fseek(fp, 0, SEEK_END);
|
||||
long size = ftell(fp);
|
||||
rewind(fp);
|
||||
|
||||
// If the size of Keys.bin is correct (two keys), read it
|
||||
if (size == xbox::XBOX_KEY_LENGTH * 2) {
|
||||
fread(keys, xbox::XBOX_KEY_LENGTH, 2, fp);
|
||||
|
||||
memcpy(xbox::XboxEEPROMKey, &keys[0], xbox::XBOX_KEY_LENGTH);
|
||||
memcpy(xbox::XboxCertificateKey, &keys[1], xbox::XBOX_KEY_LENGTH);
|
||||
}
|
||||
else {
|
||||
EmuLog(LOG_LEVEL::WARNING, "Keys.bin has an incorrect filesize. Should be %d bytes", xbox::XBOX_KEY_LENGTH * 2);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return;
|
||||
}
|
||||
|
||||
// If we didn't already exit the function, keys.bin could not be loaded
|
||||
EmuLog(LOG_LEVEL::WARNING, "Failed to load Keys.bin. Cxbx-Reloaded will be unable to read Save Data from a real Xbox");
|
||||
}
|
||||
|
||||
static HANDLE hMapDataHash = nullptr;
|
||||
|
||||
bool CxbxrLockFilePath()
|
||||
{
|
||||
std::stringstream filePathHash("Local\\");
|
||||
uint64_t hashValue = XXH3_64bits(g_DataFilePath.c_str(), g_DataFilePath.length() + 1);
|
||||
if (!hashValue) {
|
||||
CxbxrAbort("%s : Couldn't generate Cxbx-Reloaded's data folder hash!", __func__);
|
||||
}
|
||||
|
||||
filePathHash << std::hex << hashValue;
|
||||
|
||||
hMapDataHash = CreateFileMapping(
|
||||
INVALID_HANDLE_VALUE, // Paging file
|
||||
nullptr, // default security attributes
|
||||
PAGE_READONLY, // readonly access
|
||||
0, // size: high 32 bits
|
||||
/*Dummy size*/4, // size: low 32 bits
|
||||
filePathHash.str().c_str() // name of map object
|
||||
);
|
||||
|
||||
if (hMapDataHash == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (GetLastError() == ERROR_ALREADY_EXISTS) {
|
||||
PopupError(nullptr, "Data path directory is currently in use.\nUse a different data path directory or stop emulation from another process.");
|
||||
CloseHandle(hMapDataHash);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CxbxrUnlockFilePath()
|
||||
{
|
||||
// Close opened file path lockdown shared memory.
|
||||
if (hMapDataHash) {
|
||||
CloseHandle(hMapDataHash);
|
||||
hMapDataHash = nullptr;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
// ******************************************************************
|
||||
// *
|
||||
// * This file is part of the Cxbx-Reloaded project.
|
||||
// *
|
||||
// * Cxbx and Cxbe are free software; you can redistribute them
|
||||
// * and/or modify them under the terms of the GNU General Public
|
||||
// * License as published by the Free Software Foundation; either
|
||||
// * version 2 of the license, or (at your option) any later version.
|
||||
// *
|
||||
// * This program 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 recieved a copy of the GNU General Public License
|
||||
// * along with this program; see the file COPYING.
|
||||
// * If not, write to the Free Software Foundation, Inc.,
|
||||
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
#pragma once
|
||||
|
||||
extern char szFilePath_CxbxReloaded_Exe[MAX_PATH];
|
||||
extern char szFilePath_EEPROM_bin[MAX_PATH];
|
||||
|
||||
extern std::string g_DataFilePath;
|
||||
extern std::string g_DiskBasePath;
|
||||
extern std::string g_MuBasePath;
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
//TODO: Possible move CxbxResolveHostToFullPath inline function someplace else if become useful elsewhere.
|
||||
// Let filesystem library clean it up for us, including resolve host's symbolic link path.
|
||||
// Since internal kernel do translate to full path than preserved host symoblic link path.
|
||||
void CxbxResolveHostToFullPath(std::filesystem::path& file_path, std::string_view finish_error_sentence);
|
||||
|
||||
// TODO: Eventually, we should remove this function to start using std::filesystem::path method for all host paths.
|
||||
void CxbxResolveHostToFullPath(std::string& file_path, std::string_view finish_error_sentence);
|
||||
|
||||
// NOTE: Do NOT modify g_<custom>BasePath variables after this call!
|
||||
void CxbxrInitFilePaths();
|
||||
|
||||
// Loads a keys.bin file as generated by dump-xbox
|
||||
// See https://github.com/JayFoxRox/xqemu-tools/blob/master/dump-xbox.c
|
||||
void LoadXboxKeys();
|
||||
|
||||
bool CxbxrLockFilePath();
|
||||
|
||||
void CxbxrUnlockFilePath();
|
|
@ -38,6 +38,7 @@ typedef enum class _IPC_UPDATE_GUI {
|
|||
, XBOX_LED_COLOUR
|
||||
, LOG_ENABLED
|
||||
, KRNL_IS_READY
|
||||
, OVERLAY
|
||||
} IPC_UPDATE_GUI;
|
||||
|
||||
void ipc_send_gui_update(IPC_UPDATE_GUI command, const unsigned int value);
|
||||
|
@ -48,10 +49,11 @@ void ipc_send_gui_update(IPC_UPDATE_GUI command, const unsigned int value);
|
|||
// ******************************************************************
|
||||
|
||||
typedef enum class _IPC_UPDATE_KERNEL {
|
||||
CONFIG_LOGGING_SYNC = 0
|
||||
, CONFIG_INPUT_SYNC
|
||||
CONFIG_LOGGING_SYNC = 0,
|
||||
CONFIG_INPUT_SYNC,
|
||||
CONFIG_CHANGE_TIME
|
||||
} IPC_UPDATE_KERNEL;
|
||||
|
||||
void ipc_send_kernel_update(IPC_UPDATE_KERNEL command, const unsigned int value, const unsigned int hwnd);
|
||||
void ipc_send_kernel_update(IPC_UPDATE_KERNEL command, const int value, const unsigned int hwnd);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -27,117 +27,122 @@
|
|||
|
||||
#include <windows.h> // for PULONG
|
||||
|
||||
#include "Logging.h"
|
||||
#include "common\Settings.hpp"
|
||||
#include "Logging.h"
|
||||
#include "common\Settings.hpp"
|
||||
#include "EmuShared.h"
|
||||
|
||||
// For thread_local, see : https://en.cppreference.com/w/cpp/language/storage_duration
|
||||
// TODO : Use Boost.Format https://www.boost.org/doc/libs/1_53_0/libs/format/index.html
|
||||
thread_local std::string _logThreadPrefix;
|
||||
|
||||
std::atomic_bool g_EnabledModules[to_underlying(CXBXR_MODULE::MAX)] = { false };
|
||||
const char* g_EnumModules2String[to_underlying(CXBXR_MODULE::MAX)] = {
|
||||
"CXBXR ",
|
||||
"XBE ",
|
||||
"INIT ",
|
||||
"VMEM ",
|
||||
"PMEM ",
|
||||
"GUI ",
|
||||
"EEPR ",
|
||||
"RSA ",
|
||||
"POOLMEM ",
|
||||
"D3D8 ",
|
||||
"D3DST ",
|
||||
"D3DCVT ",
|
||||
"DSOUND ",
|
||||
"XAPI ",
|
||||
"XACT ",
|
||||
"XGRP ",
|
||||
"XONLINE ",
|
||||
"FS ",
|
||||
"PSHB ",
|
||||
"PXSH ",
|
||||
"VTXSH ",
|
||||
"VSHCACHE",
|
||||
"VTXB ",
|
||||
"DINP ",
|
||||
"XINP ",
|
||||
"SDL ",
|
||||
"FILE ",
|
||||
"X86 ",
|
||||
"HLE ",
|
||||
"NET ",
|
||||
"MCPX ",
|
||||
"NV2A ",
|
||||
"SMC ",
|
||||
"OHCI ",
|
||||
"USB ",
|
||||
"HUB ",
|
||||
"XIDCTRL ",
|
||||
"ADM ",
|
||||
"INPSYS ",
|
||||
"DSBUFFER",
|
||||
"DSSTREAM",
|
||||
"DS3DCALC",
|
||||
"XMO ",
|
||||
"KRNL ",
|
||||
"LOG ",
|
||||
"XBOX ",
|
||||
"XBDM ",
|
||||
"AV ",
|
||||
"DBG ",
|
||||
"EX ",
|
||||
"FSC ",
|
||||
"HAL ",
|
||||
"IO ",
|
||||
"KD ",
|
||||
"KE ",
|
||||
"KI ",
|
||||
"MM ",
|
||||
"NT ",
|
||||
"OB ",
|
||||
"PS ",
|
||||
"RTL ",
|
||||
"XC ",
|
||||
"XE ",
|
||||
};
|
||||
std::atomic_int g_CurrentLogLevel = to_underlying(LOG_LEVEL::INFO);
|
||||
|
||||
const char log_debug[] = "DEBUG: ";
|
||||
const char log_info[] = "INFO : ";
|
||||
const char log_warn[] = "WARN : ";
|
||||
const char log_error[] = "ERROR: ";
|
||||
const char log_fatal[] = "FATAL: ";
|
||||
const char log_unkwn[] = "???? : ";
|
||||
|
||||
// Do not use EmuLogOutput function outside of this file.
|
||||
void EmuLogOutput(CXBXR_MODULE cxbxr_module, LOG_LEVEL level, const char *szWarningMessage, va_list argp)
|
||||
thread_local std::string _logThreadPrefix;
|
||||
|
||||
std::atomic_bool g_EnabledModules[to_underlying(CXBXR_MODULE::MAX)] = { false };
|
||||
const char* g_EnumModules2String[to_underlying(CXBXR_MODULE::MAX)] = {
|
||||
"CXBXR ",
|
||||
"XBE ",
|
||||
"INIT ",
|
||||
"VMEM ",
|
||||
"PMEM ",
|
||||
"GUI ",
|
||||
"EEPR ",
|
||||
"RSA ",
|
||||
"POOLMEM ",
|
||||
"D3D8 ",
|
||||
"D3DST ",
|
||||
"D3DCVT ",
|
||||
"DSOUND ",
|
||||
"XAPI ",
|
||||
"XACT ",
|
||||
"XGRP ",
|
||||
"XONLINE ",
|
||||
"FS ",
|
||||
"PSHB ",
|
||||
"PXSH ",
|
||||
"VTXSH ",
|
||||
"VSHCACHE",
|
||||
"VTXB ",
|
||||
"DINP ",
|
||||
"XINP ",
|
||||
"SDL ",
|
||||
"FILE ",
|
||||
"X86 ",
|
||||
"HLE ",
|
||||
"NET ",
|
||||
"MCPX ",
|
||||
"NV2A ",
|
||||
"SMC ",
|
||||
"OHCI ",
|
||||
"USB ",
|
||||
"HUB ",
|
||||
"XIDCTRL ",
|
||||
"ADM ",
|
||||
"INPSYS ",
|
||||
"DSBUFFER",
|
||||
"DSSTREAM",
|
||||
"DS3DCALC",
|
||||
"XMO ",
|
||||
"RINP ",
|
||||
"JVS ",
|
||||
"LIBUSB ",
|
||||
"KRNL ",
|
||||
"LOG ",
|
||||
"XBOX ",
|
||||
"XBDM ",
|
||||
"AV ",
|
||||
"DBG ",
|
||||
"EX ",
|
||||
"FSC ",
|
||||
"HAL ",
|
||||
"IO ",
|
||||
"KD ",
|
||||
"KE ",
|
||||
"KI ",
|
||||
"MM ",
|
||||
"NT ",
|
||||
"OB ",
|
||||
"PS ",
|
||||
"RTL ",
|
||||
"XC ",
|
||||
"XE ",
|
||||
};
|
||||
std::atomic_int g_CurrentLogLevel = to_underlying(LOG_LEVEL::INFO);
|
||||
std::atomic_bool g_CurrentLogPopupTestCase = true;
|
||||
static bool g_disablePopupMessages = false;
|
||||
|
||||
const char log_debug[] = "DEBUG: ";
|
||||
const char log_info[] = "INFO : ";
|
||||
const char log_warn[] = "WARN : ";
|
||||
const char log_error[] = "ERROR: ";
|
||||
const char log_fatal[] = "FATAL: ";
|
||||
const char log_unkwn[] = "???? : ";
|
||||
|
||||
// Do not use EmuLogOutput function outside of this file.
|
||||
void EmuLogOutput(CXBXR_MODULE cxbxr_module, LOG_LEVEL level, const char *szWarningMessage, const va_list argp)
|
||||
{
|
||||
LOG_THREAD_INIT;
|
||||
|
||||
const char* level_str;
|
||||
LOG_THREAD_INIT;
|
||||
|
||||
const char* level_str;
|
||||
switch (level) {
|
||||
default:
|
||||
level_str = log_unkwn;
|
||||
default:
|
||||
level_str = log_unkwn;
|
||||
break;
|
||||
case LOG_LEVEL::DEBUG:
|
||||
level_str = log_debug;
|
||||
case LOG_LEVEL::DEBUG:
|
||||
level_str = log_debug;
|
||||
break;
|
||||
case LOG_LEVEL::INFO:
|
||||
level_str = log_info;
|
||||
case LOG_LEVEL::INFO:
|
||||
level_str = log_info;
|
||||
break;
|
||||
case LOG_LEVEL::WARNING:
|
||||
level_str = log_warn;
|
||||
break;
|
||||
case LOG_LEVEL::ERROR2:
|
||||
level_str = log_error;
|
||||
case LOG_LEVEL::WARNING:
|
||||
level_str = log_warn;
|
||||
break;
|
||||
case LOG_LEVEL::FATAL:
|
||||
level_str = log_fatal;
|
||||
case LOG_LEVEL::ERROR2:
|
||||
level_str = log_error;
|
||||
break;
|
||||
case LOG_LEVEL::FATAL:
|
||||
level_str = log_fatal;
|
||||
break;
|
||||
}
|
||||
|
||||
std::cout << _logThreadPrefix << level_str
|
||||
std::cout << _logThreadPrefix << level_str
|
||||
<< g_EnumModules2String[to_underlying(cxbxr_module)];
|
||||
|
||||
vfprintf(stdout, szWarningMessage, argp);
|
||||
|
@ -145,16 +150,23 @@ void EmuLogOutput(CXBXR_MODULE cxbxr_module, LOG_LEVEL level, const char *szWarn
|
|||
fprintf(stdout, "\n");
|
||||
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
// print out a custom message to the console or kernel debug log file
|
||||
void NTAPI EmuLogEx(CXBXR_MODULE cxbxr_module, LOG_LEVEL level, const char *szWarningMessage, ...)
|
||||
}
|
||||
inline void EmuLogOutputEx(const CXBXR_MODULE cxbxr_module, const LOG_LEVEL level, const char *szWarningMessage, ...)
|
||||
{
|
||||
va_list argp;
|
||||
va_start(argp, szWarningMessage);
|
||||
EmuLogOutput(cxbxr_module, level, szWarningMessage, argp);
|
||||
va_end(argp);
|
||||
}
|
||||
|
||||
// print out a custom message to the console or kernel debug log file
|
||||
void EmuLogEx(CXBXR_MODULE cxbxr_module, LOG_LEVEL level, const char *szWarningMessage, ...)
|
||||
{
|
||||
if (szWarningMessage == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_CHECK_ENABLED_EX(cxbxr_module, level) {
|
||||
|
||||
LOG_CHECK_ENABLED_EX(cxbxr_module, level) {
|
||||
if (g_bPrintfOn) {
|
||||
|
||||
LOG_THREAD_INIT;
|
||||
|
@ -165,11 +177,11 @@ void NTAPI EmuLogEx(CXBXR_MODULE cxbxr_module, LOG_LEVEL level, const char *szWa
|
|||
EmuLogOutput(cxbxr_module, level, szWarningMessage, argp);
|
||||
|
||||
va_end(argp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NTAPI EmuLogInit(LOG_LEVEL level, const char *szWarningMessage, ...)
|
||||
}
|
||||
|
||||
void EmuLogInit(LOG_LEVEL level, const char *szWarningMessage, ...)
|
||||
{
|
||||
if (szWarningMessage == NULL) {
|
||||
return;
|
||||
|
@ -181,53 +193,156 @@ void NTAPI EmuLogInit(LOG_LEVEL level, const char *szWarningMessage, ...)
|
|||
EmuLogOutput(CXBXR_MODULE::INIT, level, szWarningMessage, argp);
|
||||
|
||||
va_end(argp);
|
||||
}
|
||||
|
||||
// Set up the logging variables for the GUI process
|
||||
inline void log_get_settings()
|
||||
{
|
||||
log_set_config(g_Settings->m_core.LogLevel, g_Settings->m_core.LoggedModules);
|
||||
}
|
||||
|
||||
inline void log_sync_config()
|
||||
{
|
||||
int LogLevel;
|
||||
unsigned int LoggedModules[NUM_INTEGERS_LOG];
|
||||
g_EmuShared->GetLogLv(&LogLevel);
|
||||
g_EmuShared->GetLogModules(LoggedModules);
|
||||
log_set_config(LogLevel, LoggedModules);
|
||||
}
|
||||
|
||||
void log_set_config(int LogLevel, unsigned int* LoggedModules)
|
||||
{
|
||||
g_CurrentLogLevel = LogLevel;
|
||||
for (unsigned int index = to_underlying(CXBXR_MODULE::CXBXR); index < to_underlying(CXBXR_MODULE::MAX); index++) {
|
||||
if (LoggedModules[index / 32] & (1 << (index % 32))) {
|
||||
g_EnabledModules[index] = true;
|
||||
}
|
||||
else {
|
||||
g_EnabledModules[index] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Generate active log filter output.
|
||||
void log_generate_active_filter_output(const CXBXR_MODULE cxbxr_module)
|
||||
}
|
||||
|
||||
// Set up the logging variables for the GUI process
|
||||
inline void log_get_settings()
|
||||
{
|
||||
LOG_THREAD_INIT;
|
||||
std::string generic_output_str = _logThreadPrefix + log_info + g_EnumModules2String[to_underlying(cxbxr_module)];
|
||||
|
||||
std::cout << generic_output_str << "Current log level: " << g_CurrentLogLevel << std::endl;
|
||||
|
||||
generic_output_str.append("Active log filter: ");
|
||||
for (unsigned int index = to_underlying(CXBXR_MODULE::CXBXR); index < to_underlying(CXBXR_MODULE::MAX); index++) {
|
||||
if (g_EnabledModules[index]) {
|
||||
std::cout << generic_output_str << g_EnumModules2String[index] << "\n";
|
||||
}
|
||||
}
|
||||
log_set_config(g_Settings->m_core.LogLevel, g_Settings->m_core.LoggedModules, g_Settings->m_core.bLogPopupTestCase);
|
||||
}
|
||||
|
||||
inline void log_sync_config()
|
||||
{
|
||||
int LogLevel;
|
||||
unsigned int LoggedModules[NUM_INTEGERS_LOG];
|
||||
bool LogPopupTestCase;
|
||||
g_EmuShared->GetLogLv(&LogLevel);
|
||||
g_EmuShared->GetLogModules(LoggedModules);
|
||||
g_EmuShared->GetLogPopupTestCase(&LogPopupTestCase);
|
||||
log_set_config(LogLevel, LoggedModules, LogPopupTestCase);
|
||||
}
|
||||
|
||||
void log_set_config(int LogLevel, unsigned int* LoggedModules, bool LogPopupTestCase)
|
||||
{
|
||||
g_CurrentLogLevel = LogLevel;
|
||||
for (unsigned int index = to_underlying(CXBXR_MODULE::CXBXR); index < to_underlying(CXBXR_MODULE::MAX); index++) {
|
||||
if (LoggedModules[index / 32] & (1 << (index % 32))) {
|
||||
g_EnabledModules[index] = true;
|
||||
}
|
||||
else {
|
||||
g_EnabledModules[index] = false;
|
||||
}
|
||||
}
|
||||
g_CurrentLogPopupTestCase = LogPopupTestCase;
|
||||
}
|
||||
|
||||
// Generate active log filter output.
|
||||
void log_generate_active_filter_output(const CXBXR_MODULE cxbxr_module)
|
||||
{
|
||||
LOG_THREAD_INIT;
|
||||
std::string generic_output_str = _logThreadPrefix + log_info + g_EnumModules2String[to_underlying(cxbxr_module)];
|
||||
|
||||
std::cout << generic_output_str << "Current log level: " << g_CurrentLogLevel << std::endl;
|
||||
|
||||
generic_output_str.append("Active log filter: ");
|
||||
for (unsigned int index = to_underlying(CXBXR_MODULE::CXBXR); index < to_underlying(CXBXR_MODULE::MAX); index++) {
|
||||
if (g_EnabledModules[index]) {
|
||||
std::cout << generic_output_str << g_EnumModules2String[index] << "\n";
|
||||
}
|
||||
}
|
||||
std::cout << std::flush;
|
||||
}
|
||||
|
||||
// Use kernel managed environment
|
||||
void log_init_popup_msg()
|
||||
{
|
||||
Settings::s_video vSettings;
|
||||
g_EmuShared->GetVideoSettings(&vSettings);
|
||||
g_disablePopupMessages = vSettings.bFullScreen;
|
||||
}
|
||||
|
||||
// TODO: Move PopupPlatformHandler into common GUI's window source code or use imgui in the future.
|
||||
// PopupPlatformHandler is intended to be use as internal wrapper function.
|
||||
static PopupReturn PopupPlatformHandler(const char* msg, const PopupReturn ret_default, const UINT uType, const HWND hWnd)
|
||||
{
|
||||
int ret = MessageBox(hWnd, msg, /*lpCaption=*/TEXT("Cxbx-Reloaded"), uType);
|
||||
|
||||
switch (ret) {
|
||||
default:
|
||||
case IDCANCEL:
|
||||
return PopupReturn::Cancel;
|
||||
case IDOK:
|
||||
return PopupReturn::Ok;
|
||||
case IDABORT:
|
||||
return PopupReturn::Abort;
|
||||
case IDRETRY:
|
||||
return PopupReturn::Retry;
|
||||
case IDIGNORE:
|
||||
return PopupReturn::Ignore;
|
||||
case IDYES:
|
||||
return PopupReturn::Yes;
|
||||
case IDNO:
|
||||
return PopupReturn::No;
|
||||
}
|
||||
}
|
||||
|
||||
PopupReturn PopupCustomEx(const void* hwnd, const CXBXR_MODULE cxbxr_module, const LOG_LEVEL level, const PopupIcon icon, const PopupButtons buttons, const PopupReturn ret_default, const char *message, ...)
|
||||
{
|
||||
UINT uType = MB_TOPMOST | MB_SETFOREGROUND;
|
||||
|
||||
// Make assert whenever the format string is null pointer which isn't allow in here.
|
||||
assert(message != nullptr);
|
||||
|
||||
switch (icon) {
|
||||
case PopupIcon::Warning: {
|
||||
uType |= MB_ICONWARNING;
|
||||
break;
|
||||
}
|
||||
case PopupIcon::Error: {
|
||||
uType |= MB_ICONERROR; // Note : MB_ICONERROR == MB_ICONSTOP == MB_ICONHAND
|
||||
break;
|
||||
}
|
||||
case PopupIcon::Info: {
|
||||
uType |= MB_ICONINFORMATION;
|
||||
break;
|
||||
}
|
||||
case PopupIcon::Question:
|
||||
case PopupIcon::Unknown:
|
||||
default: {
|
||||
uType |= MB_ICONQUESTION;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (buttons) {
|
||||
default:
|
||||
case PopupButtons::Ok:
|
||||
uType |= MB_OK;
|
||||
break;
|
||||
case PopupButtons::OkCancel:
|
||||
uType |= MB_OKCANCEL;
|
||||
break;
|
||||
case PopupButtons::AbortRetryIgnore:
|
||||
uType |= MB_ABORTRETRYIGNORE;
|
||||
break;
|
||||
case PopupButtons::YesNoCancel:
|
||||
uType |= MB_YESNOCANCEL;
|
||||
break;
|
||||
case PopupButtons::YesNo:
|
||||
uType |= MB_YESNO;
|
||||
break;
|
||||
case PopupButtons::RetryCancel:
|
||||
uType |= MB_RETRYCANCEL;
|
||||
break;
|
||||
}
|
||||
|
||||
va_list argp;
|
||||
va_start(argp, message);
|
||||
// allocate predicted buffer size then write to buffer afterward.
|
||||
std::string Buffer(1+std::vsnprintf(nullptr, 0, message, argp), '\0');
|
||||
vsnprintf(Buffer.data(), Buffer.size(), message, argp);
|
||||
va_end(argp);
|
||||
|
||||
EmuLogOutputEx(cxbxr_module, level, "Popup : %s", Buffer.c_str());
|
||||
|
||||
// If user is using exclusive fullscreen, we need to refrain all popups.
|
||||
if (g_disablePopupMessages) {
|
||||
return ret_default;
|
||||
}
|
||||
|
||||
return PopupPlatformHandler(Buffer.data(), ret_default, uType, (const HWND)hwnd);
|
||||
}
|
||||
|
||||
const bool needs_escape(const wint_t _char)
|
||||
{
|
||||
// Escaping is needed for control characters,
|
||||
|
@ -281,8 +396,13 @@ inline void output_wchar(std::ostream& os, wchar_t c)
|
|||
default: os << "\\x" << std::setfill('0') << std::setw(4) << std::right << std::hex << std::uppercase << (wint_t)c;
|
||||
}
|
||||
}
|
||||
else
|
||||
os << c;
|
||||
else {
|
||||
const wchar_t *wc = reinterpret_cast<const wchar_t *>(&c);
|
||||
std::string dst(2, '\0');
|
||||
std::mbstate_t ps{};
|
||||
std::wcsrtombs(dst.data(), &wc, 1, &ps);
|
||||
os << dst;
|
||||
}
|
||||
}
|
||||
|
||||
LOG_SANITIZE_HEADER(hex1, uint8_t)
|
||||
|
@ -341,7 +461,7 @@ LOG_SANITIZE_HEADER(sanitized_char_pointer, char *)
|
|||
while (*v && max_length--) {
|
||||
os << *v++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return os << "\"";
|
||||
}
|
||||
|
@ -355,7 +475,7 @@ LOG_SANITIZE_HEADER(sanitized_wchar_pointer, wchar_t *)
|
|||
return os << "NULL";
|
||||
|
||||
bool needsEscaping = false;
|
||||
int max_length = container.max;
|
||||
int max_length = container.max;
|
||||
while (*v && max_length--)
|
||||
if (needs_escape(*v++))
|
||||
{
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
// * If not, write to the Free Software Foundation, Inc.,
|
||||
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
|
||||
// *
|
||||
// * (c) 2016 Patrick van Logchem <pvanlogchem@gmail.com>
|
||||
// * (c) 2016 Patrick van Logchem <pvanlogchem@gmail.com>
|
||||
// * (c) 2019 ergo720
|
||||
// *
|
||||
// * All rights reserved
|
||||
|
@ -29,107 +29,162 @@
|
|||
#include <windows.h> // For DWORD
|
||||
#include <sstream> // For std::stringstream
|
||||
#include <iostream> // For std::cout
|
||||
#include <iomanip> // For std::setw
|
||||
#include <iomanip> // For std::setw
|
||||
#include <atomic> // For atomic_bool and atomic_uint
|
||||
#include "common\util\CxbxUtil.h" // For g_bPrintfOn and to_underlying
|
||||
|
||||
// NOTE: using ERROR2 since windows.h imports an ERROR macro which would conflict otherwise
|
||||
typedef enum class _LOG_LEVEL {
|
||||
DEBUG = 0,
|
||||
INFO,
|
||||
WARNING,
|
||||
ERROR2,
|
||||
FATAL,
|
||||
MAX,
|
||||
#include "common\util\CxbxUtil.h" // For g_bPrintfOn and to_underlying
|
||||
|
||||
// NOTE: using ERROR2 since windows.h imports an ERROR macro which would conflict otherwise
|
||||
typedef enum class _LOG_LEVEL {
|
||||
DEBUG = 0,
|
||||
INFO,
|
||||
WARNING,
|
||||
ERROR2,
|
||||
FATAL,
|
||||
MAX,
|
||||
}LOG_LEVEL;
|
||||
|
||||
typedef enum class _CXBXR_MODULE: unsigned int {
|
||||
// general
|
||||
CXBXR = 0,
|
||||
XBE,
|
||||
INIT,
|
||||
VMEM,
|
||||
PMEM,
|
||||
GUI,
|
||||
EEPR,
|
||||
RSA,
|
||||
POOLMEM,
|
||||
D3D8,
|
||||
D3DST,
|
||||
D3DCVT,
|
||||
DSOUND,
|
||||
XAPI,
|
||||
XACT,
|
||||
XGRP,
|
||||
XONLINE,
|
||||
FS,
|
||||
PSHB,
|
||||
PXSH,
|
||||
VTXSH,
|
||||
VSHCACHE,
|
||||
VTXB,
|
||||
DINP,
|
||||
XINP,
|
||||
SDL,
|
||||
FILE,
|
||||
X86,
|
||||
HLE,
|
||||
NET,
|
||||
MCPX,
|
||||
NV2A,
|
||||
SMC,
|
||||
OHCI,
|
||||
USB,
|
||||
HUB,
|
||||
XIDCTRL,
|
||||
ADM,
|
||||
INPSYS,
|
||||
DSBUFFER,
|
||||
DSSTREAM,
|
||||
DS3DCALC,
|
||||
XMO,
|
||||
// kernel
|
||||
KRNL,
|
||||
LOG,
|
||||
XBOX,
|
||||
XBDM,
|
||||
AV,
|
||||
DBG,
|
||||
EX,
|
||||
FSC,
|
||||
HAL,
|
||||
IO,
|
||||
KD,
|
||||
KE,
|
||||
KI,
|
||||
MM,
|
||||
NT,
|
||||
OB,
|
||||
PS,
|
||||
RTL,
|
||||
XC,
|
||||
XE,
|
||||
// max
|
||||
MAX,
|
||||
}CXBXR_MODULE;
|
||||
|
||||
extern std::atomic_bool g_EnabledModules[to_underlying(CXBXR_MODULE::MAX)];
|
||||
extern const char* g_EnumModules2String[to_underlying(CXBXR_MODULE::MAX)];
|
||||
extern std::atomic_int g_CurrentLogLevel;
|
||||
typedef enum class _CXBXR_MODULE: unsigned int {
|
||||
// general
|
||||
CXBXR = 0,
|
||||
XBE,
|
||||
INIT,
|
||||
VMEM,
|
||||
PMEM,
|
||||
GUI,
|
||||
EEPR,
|
||||
RSA,
|
||||
POOLMEM,
|
||||
D3D8,
|
||||
D3DST,
|
||||
D3DCVT,
|
||||
DSOUND,
|
||||
XAPI,
|
||||
XACT,
|
||||
XGRP,
|
||||
XONLINE,
|
||||
FS,
|
||||
PSHB,
|
||||
PXSH,
|
||||
VTXSH,
|
||||
VSHCACHE,
|
||||
VTXB,
|
||||
DINP,
|
||||
XINP,
|
||||
SDL,
|
||||
FILE,
|
||||
X86,
|
||||
HLE,
|
||||
NET,
|
||||
MCPX,
|
||||
NV2A,
|
||||
SMC,
|
||||
OHCI,
|
||||
USB,
|
||||
HUB,
|
||||
XIDCTRL,
|
||||
ADM,
|
||||
INPSYS,
|
||||
DSBUFFER,
|
||||
DSSTREAM,
|
||||
DS3DCALC,
|
||||
XMO,
|
||||
RINP,
|
||||
JVS,
|
||||
LIBUSB,
|
||||
// kernel
|
||||
KRNL,
|
||||
LOG,
|
||||
XBOX,
|
||||
XBDM,
|
||||
AV,
|
||||
DBG,
|
||||
EX,
|
||||
FSC,
|
||||
HAL,
|
||||
IO,
|
||||
KD,
|
||||
KE,
|
||||
KI,
|
||||
MM,
|
||||
NT,
|
||||
OB,
|
||||
PS,
|
||||
RTL,
|
||||
XC,
|
||||
XE,
|
||||
// max
|
||||
MAX,
|
||||
}CXBXR_MODULE;
|
||||
|
||||
// print out a log message to the console or kernel debug log file if level is high enough
|
||||
void NTAPI EmuLogEx(CXBXR_MODULE cxbxr_module, LOG_LEVEL level, const char *szWarningMessage, ...);
|
||||
void NTAPI EmuLogInit(LOG_LEVEL level, const char *szWarningMessage, ...);
|
||||
|
||||
#define EmuLog(level, fmt, ...) EmuLogEx(LOG_PREFIX, level, fmt, ##__VA_ARGS__)
|
||||
|
||||
extern inline void log_get_settings();
|
||||
|
||||
extern inline void log_sync_config();
|
||||
|
||||
void log_set_config(int LogLevel, unsigned int* LoggedModules);
|
||||
|
||||
void log_generate_active_filter_output(const CXBXR_MODULE cxbxr_module);
|
||||
extern std::atomic_bool g_EnabledModules[to_underlying(CXBXR_MODULE::MAX)];
|
||||
extern const char* g_EnumModules2String[to_underlying(CXBXR_MODULE::MAX)];
|
||||
extern std::atomic_int g_CurrentLogLevel;
|
||||
extern std::atomic_bool g_CurrentLogPopupTestCase;
|
||||
|
||||
// print out a log message to the console or kernel debug log file if level is high enough
|
||||
void EmuLogEx(CXBXR_MODULE cxbxr_module, LOG_LEVEL level, const char *szWarningMessage, ...);
|
||||
void EmuLogInit(LOG_LEVEL level, const char *szWarningMessage, ...);
|
||||
|
||||
#define EmuLog(level, fmt, ...) EmuLogEx(LOG_PREFIX, level, fmt, ##__VA_ARGS__)
|
||||
|
||||
extern inline void log_get_settings();
|
||||
|
||||
extern inline void log_sync_config();
|
||||
|
||||
void log_set_config(int LogLevel, unsigned int* LoggedModules, bool LogPopupTestCase);
|
||||
|
||||
void log_generate_active_filter_output(const CXBXR_MODULE cxbxr_module);
|
||||
|
||||
// Use emulation environment to manage popup messages
|
||||
// If log_init_popup_msg is not called at earliest point of emulation.
|
||||
// Then users will have a chance of popup message appear during start of emulation in full screen.
|
||||
void log_init_popup_msg();
|
||||
|
||||
typedef enum class _PopupIcon {
|
||||
Unknown = 0,
|
||||
Question,
|
||||
Info,
|
||||
Warning,
|
||||
Error
|
||||
} PopupIcon;
|
||||
|
||||
typedef enum class _PopupButtons {
|
||||
Unknown = 0,
|
||||
Ok,
|
||||
OkCancel,
|
||||
AbortRetryIgnore,
|
||||
YesNoCancel,
|
||||
YesNo,
|
||||
RetryCancel
|
||||
} PopupButtons;
|
||||
|
||||
typedef enum class _PopupReturn {
|
||||
Unknown = 0,
|
||||
Ok,
|
||||
Cancel,
|
||||
Abort,
|
||||
Retry,
|
||||
Ignore,
|
||||
Yes,
|
||||
No
|
||||
} PopupReturn;
|
||||
|
||||
PopupReturn PopupCustomEx(const void* hwnd, const CXBXR_MODULE cxbxr_module, const LOG_LEVEL level, const PopupIcon icon, const PopupButtons buttons, const PopupReturn ret_default, const char* message, ...);
|
||||
|
||||
#define PopupCustom(hwnd, level, icon, buttons, ret_default, fmt, ...) PopupCustomEx(hwnd, LOG_PREFIX, level, icon, buttons, ret_default, fmt, ## __VA_ARGS__)
|
||||
#define PopupQuestionEx(hwnd, level, buttons, ret_default, fmt, ...) PopupCustom(hwnd, level, PopupIcon::Question, buttons, ret_default, fmt, ## __VA_ARGS__)
|
||||
#define PopupQuestion(hwnd, fmt, ...) PopupQuestionEx(hwnd, LOG_LEVEL::INFO, PopupButtons::YesNoCancel, PopupReturn::Cancel, fmt, ## __VA_ARGS__)
|
||||
#define PopupInfoEx(hwnd, buttons, ret_default, fmt, ...) PopupCustom(hwnd, LOG_LEVEL::INFO, PopupIcon::Info, buttons, ret_default, fmt, ## __VA_ARGS__)
|
||||
#define PopupInfo(hwnd, fmt, ...) (void)PopupInfoEx(hwnd, PopupButtons::Ok, PopupReturn::Ok, fmt, ## __VA_ARGS__)
|
||||
#define PopupWarningEx(hwnd, buttons, ret_default, fmt, ...) PopupCustom(hwnd, LOG_LEVEL::WARNING, PopupIcon::Warning, buttons, ret_default, fmt, ## __VA_ARGS__)
|
||||
#define PopupWarning(hwnd, fmt, ...) (void)PopupWarningEx(hwnd, PopupButtons::Ok, PopupReturn::Ok, fmt, ## __VA_ARGS__)
|
||||
#define PopupErrorEx(hwnd, buttons, ret_default, fmt, ...) PopupCustom(hwnd, LOG_LEVEL::ERROR2, PopupIcon::Error, buttons, ret_default, fmt, ## __VA_ARGS__)
|
||||
#define PopupError(hwnd, fmt, ...) (void)PopupErrorEx(hwnd, PopupButtons::Ok, PopupReturn::Ok, fmt, ## __VA_ARGS__)
|
||||
#define PopupFatalEx(hwnd, buttons, ret_default, fmt, ...) PopupCustom(hwnd, LOG_LEVEL::FATAL, PopupIcon::Error, buttons, ret_default, fmt, ## __VA_ARGS__)
|
||||
#define PopupFatal(hwnd, fmt, ...) (void)PopupFatalEx(hwnd, PopupButtons::Ok, PopupReturn::Ok, fmt, ## __VA_ARGS__)
|
||||
|
||||
// For LOG_TEST_CASE
|
||||
extern inline void EmuLogOutputEx(const CXBXR_MODULE cxbxr_module, const LOG_LEVEL level, const char *szWarningMessage, ...);
|
||||
|
||||
//
|
||||
// __FILENAME__
|
||||
|
@ -170,9 +225,30 @@ extern inline void output_wchar(std::ostream& os, wchar_t c);
|
|||
// By default, sanitization functions simply return the given argument
|
||||
// (type and value) which results in calls to standard output writers.
|
||||
template<class T>
|
||||
inline T _log_sanitize(T value, int ignored_length = 0)
|
||||
inline auto _log_sanitize(T value, int ignored_length = 0)
|
||||
{
|
||||
return value;
|
||||
// This is necessary because C++20 has deleted the overloaded operator<< of ostream for wchar_t, char8_t, char16_t and char32_t.
|
||||
// The proper solution is to use wide strings in all our logging macros/functions, see https://github.com/Cxbx-Reloaded/Cxbx-Reloaded/issues/743
|
||||
if constexpr (std::is_same_v<xbox::wchar_xt, std::remove_cvref_t<std::remove_pointer_t<T>>>) {
|
||||
if constexpr (std::is_pointer_v<T>) {
|
||||
const wchar_t *wstr = reinterpret_cast<const wchar_t *>(value);
|
||||
std::size_t len = std::wcslen(wstr);
|
||||
std::string dst(len + 1, '\0');
|
||||
std::mbstate_t ps{};
|
||||
std::wcsrtombs(dst.data(), &wstr, len, &ps);
|
||||
return dst;
|
||||
}
|
||||
else {
|
||||
const wchar_t *wstr = reinterpret_cast<const wchar_t *>(&value);
|
||||
std::string dst(2, '\0');
|
||||
std::mbstate_t ps{};
|
||||
std::wcsrtombs(dst.data(), &wstr, 1, &ps);
|
||||
return dst;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0 // TODO FIXME : Disabled for now, as this is incorrectly called for INT types too
|
||||
|
@ -187,12 +263,12 @@ inline const char * _log_sanitize(BOOL value, int ignored_length = 0)
|
|||
#define LOG_SANITIZE_HEADER(C, T) \
|
||||
std::ostream& operator<<( \
|
||||
std::ostream& os, \
|
||||
const Sane##C& container) \
|
||||
const Sane##C& container) \
|
||||
|
||||
#define LOG_SANITIZE(C, T) \
|
||||
struct Sane##C \
|
||||
{ \
|
||||
T value; \
|
||||
T value; \
|
||||
int max; \
|
||||
Sane##C(T _v, int _m = 80) : value(_v), max(_m) { } \
|
||||
}; \
|
||||
|
@ -239,13 +315,13 @@ constexpr const char* remove_prefix(const char* str, const char *prefix) {
|
|||
return (str_skip_prefix(str, prefix) == str + str_length(prefix)) ? str_skip_prefix(str, prefix) : str;
|
||||
}
|
||||
|
||||
constexpr char* xtl_prefix = "XTL::";
|
||||
constexpr char* emupatch_prefix = "EmuPatch_"; // See #define EMUPATCH
|
||||
static constexpr const char* xbox_prefix = "xbox::";
|
||||
static constexpr const char* emupatch_prefix = "EmuPatch_"; // See #define EMUPATCH
|
||||
|
||||
constexpr const char* remove_emupatch_prefix(const char* str) {
|
||||
// return an empty string when str isn't given
|
||||
// skip XTL:: and/or EmuPatch_ prefix if present
|
||||
return remove_prefix(remove_prefix(str, xtl_prefix), emupatch_prefix);
|
||||
// skip xbox:: and/or EmuPatch_ prefix if present
|
||||
return remove_prefix(remove_prefix(str, xbox_prefix), emupatch_prefix);
|
||||
}
|
||||
|
||||
#define LOG_ARG_START "\n " << std::setfill(' ') << std::setw(20) << std::left
|
||||
|
@ -258,14 +334,14 @@ constexpr const char* remove_emupatch_prefix(const char* str) {
|
|||
// For thread_local, see : https://en.cppreference.com/w/cpp/language/storage_duration
|
||||
// TODO : Use Boost.Format https://www.boost.org/doc/libs/1_53_0/libs/format/index.html
|
||||
extern thread_local std::string _logThreadPrefix;
|
||||
|
||||
// Checks if this log should be printed or not
|
||||
#define LOG_CHECK_ENABLED_EX(cxbxr_module, level) \
|
||||
if (g_EnabledModules[to_underlying(cxbxr_module)] && to_underlying(level) >= g_CurrentLogLevel)
|
||||
|
||||
// Checks if this log should be printed or not
|
||||
#define LOG_CHECK_ENABLED(level) \
|
||||
LOG_CHECK_ENABLED_EX(LOG_PREFIX, level)
|
||||
// Checks if this log should be printed or not
|
||||
#define LOG_CHECK_ENABLED_EX(cxbxr_module, level) \
|
||||
if (g_EnabledModules[to_underlying(cxbxr_module)] && to_underlying(level) >= g_CurrentLogLevel)
|
||||
|
||||
// Checks if this log should be printed or not
|
||||
#define LOG_CHECK_ENABLED(level) \
|
||||
LOG_CHECK_ENABLED_EX(LOG_PREFIX, level)
|
||||
|
||||
#define LOG_THREAD_INIT \
|
||||
if (_logThreadPrefix.length() == 0) { \
|
||||
|
@ -296,7 +372,7 @@ extern thread_local std::string _logThreadPrefix;
|
|||
msg << _logThreadPrefix << _logFuncPrefix << "(";
|
||||
|
||||
#define LOG_FUNC_BEGIN \
|
||||
LOG_INIT \
|
||||
LOG_INIT \
|
||||
LOG_CHECK_ENABLED(LOG_LEVEL::DEBUG) { \
|
||||
LOG_FUNC_BEGIN_NO_INIT
|
||||
|
||||
|
@ -318,9 +394,47 @@ extern thread_local std::string _logThreadPrefix;
|
|||
// LOG_FUNC_END closes off function and optional argument logging
|
||||
#define LOG_FUNC_END \
|
||||
if (_had_arg) msg << "\n"; \
|
||||
msg << ");\n"; \
|
||||
msg << ");\n"; \
|
||||
std::cout << msg.str(); \
|
||||
} } while (0); \
|
||||
} } while (0); \
|
||||
}
|
||||
|
||||
#define LOG_FUNC_BEGIN_ARG_RESULT_NO_INIT \
|
||||
do { if(g_bPrintfOn) { \
|
||||
bool _had_arg = false; \
|
||||
std::stringstream msg; \
|
||||
msg << _logThreadPrefix << _logFuncPrefix << " returns OUT {";
|
||||
|
||||
#define LOG_FUNC_BEGIN_ARG_RESULT \
|
||||
LOG_CHECK_ENABLED(LOG_LEVEL::DEBUG) { \
|
||||
LOG_FUNC_BEGIN_ARG_RESULT_NO_INIT
|
||||
|
||||
// LOG_FUNC_ARG_RESULT writes output via all available ostream << operator overloads, sanitizing and adding detail where possible
|
||||
#define LOG_FUNC_ARG_RESULT(arg) \
|
||||
_had_arg = true; \
|
||||
msg << LOG_ARG_START << "*"#arg << " : "; \
|
||||
if (arg != nullptr) { \
|
||||
msg << _log_sanitize(*arg); \
|
||||
} else { \
|
||||
msg << "NOT SET"; \
|
||||
}
|
||||
|
||||
// LOG_FUNC_ARG_RESULT_TYPE writes result output using the overloaded << operator of the given type
|
||||
#define LOG_FUNC_ARG_RESULT_TYPE(type, arg) \
|
||||
_had_arg = true; \
|
||||
msg << LOG_ARG_START << "*"#arg << " : "; \
|
||||
if (arg != nullptr) { \
|
||||
msg << (type)*arg; \
|
||||
} else { \
|
||||
msg << "NOT SET"; \
|
||||
}
|
||||
|
||||
// LOG_FUNC_END_ARG_RESULT closes off function and optional argument result logging
|
||||
#define LOG_FUNC_END_ARG_RESULT \
|
||||
if (_had_arg) msg << "\n"; \
|
||||
msg << "};\n"; \
|
||||
std::cout << msg.str(); \
|
||||
} } while (0); \
|
||||
}
|
||||
|
||||
// LOG_FUNC_RESULT logs the function return result
|
||||
|
@ -333,23 +447,23 @@ extern thread_local std::string _logThreadPrefix;
|
|||
|
||||
// LOG_FORWARD indicates that an api is implemented by a forward to another API
|
||||
#define LOG_FORWARD(api) \
|
||||
LOG_INIT \
|
||||
LOG_INIT \
|
||||
LOG_CHECK_ENABLED(LOG_LEVEL::DEBUG) { \
|
||||
do { if(g_bPrintfOn) { \
|
||||
std::cout << _logThreadPrefix << _logFuncPrefix << " forwarding to "#api"...\n"; \
|
||||
} } while (0); \
|
||||
} } while (0); \
|
||||
}
|
||||
|
||||
// LOG_IGNORED indicates that Cxbx consiously ignores an api
|
||||
#define LOG_IGNORED() \
|
||||
do { \
|
||||
static bool b_echoOnce = true; \
|
||||
if(g_bPrintfOn && b_echoOnce) { \
|
||||
if(g_bPrintfOn && b_echoOnce) { \
|
||||
LOG_CHECK_ENABLED(LOG_LEVEL::INFO) { \
|
||||
LOG_THREAD_INIT \
|
||||
LOG_FUNC_INIT(__func__) \
|
||||
std::cout << _logThreadPrefix << "WARN: " << _logFuncPrefix << " ignored!\n"; \
|
||||
b_echoOnce = false; \
|
||||
b_echoOnce = false; \
|
||||
} \
|
||||
} \
|
||||
} while(0)
|
||||
|
@ -358,12 +472,12 @@ extern thread_local std::string _logThreadPrefix;
|
|||
#define LOG_UNIMPLEMENTED() \
|
||||
do { \
|
||||
static bool b_echoOnce = true; \
|
||||
if(g_bPrintfOn && b_echoOnce) { \
|
||||
if(g_bPrintfOn && b_echoOnce) { \
|
||||
LOG_CHECK_ENABLED(LOG_LEVEL::INFO) { \
|
||||
LOG_THREAD_INIT \
|
||||
LOG_FUNC_INIT(__func__) \
|
||||
std::cout << _logThreadPrefix << "WARN: " << _logFuncPrefix << " unimplemented!\n"; \
|
||||
b_echoOnce = false; \
|
||||
b_echoOnce = false; \
|
||||
} \
|
||||
} \
|
||||
} while(0)
|
||||
|
@ -372,12 +486,12 @@ extern thread_local std::string _logThreadPrefix;
|
|||
#define LOG_INCOMPLETE() \
|
||||
do { \
|
||||
static bool b_echoOnce = true; \
|
||||
if(g_bPrintfOn && b_echoOnce) { \
|
||||
if(g_bPrintfOn && b_echoOnce) { \
|
||||
LOG_CHECK_ENABLED(LOG_LEVEL::INFO) { \
|
||||
LOG_THREAD_INIT \
|
||||
LOG_FUNC_INIT(__func__) \
|
||||
std::cout << _logThreadPrefix << "WARN: " << _logFuncPrefix << " incomplete!\n"; \
|
||||
b_echoOnce = false; \
|
||||
b_echoOnce = false; \
|
||||
} \
|
||||
} \
|
||||
} while(0)
|
||||
|
@ -386,12 +500,12 @@ extern thread_local std::string _logThreadPrefix;
|
|||
#define LOG_NOT_SUPPORTED() \
|
||||
do { \
|
||||
static bool b_echoOnce = true; \
|
||||
if(g_bPrintfOn && b_echoOnce) { \
|
||||
if(g_bPrintfOn && b_echoOnce) { \
|
||||
LOG_CHECK_ENABLED(LOG_LEVEL::INFO) { \
|
||||
LOG_THREAD_INIT \
|
||||
LOG_FUNC_INIT(__func__) \
|
||||
std::cout << _logThreadPrefix << "WARN: " << _logFuncPrefix << " not supported!\n"; \
|
||||
b_echoOnce = false; \
|
||||
b_echoOnce = false; \
|
||||
} \
|
||||
} \
|
||||
} while(0)
|
||||
|
@ -518,6 +632,6 @@ LOGRENDER_HEADER_BY_REF(Type) \
|
|||
// An example type rendering, for PVOID
|
||||
//
|
||||
|
||||
LOGRENDER_HEADER_BY_REF(PVOID);
|
||||
LOGRENDER_HEADER_BY_REF(PVOID);
|
||||
|
||||
#endif _LOGGING_H
|
||||
|
|
|
@ -0,0 +1,324 @@
|
|||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
// ******************************************************************
|
||||
// *
|
||||
// * This file is part of Cxbx-Reloaded.
|
||||
// *
|
||||
// * Cxbx-Reloaded is free software; you can redistribute it
|
||||
// * and/or modify it under the terms of the GNU General Public
|
||||
// * License as published by the Free Software Foundation; either
|
||||
// * version 2 of the license, or (at your option) any later version.
|
||||
// *
|
||||
// * This program 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 recieved a copy of the GNU General Public License
|
||||
// * along with this program; see the file COPYING.
|
||||
// * If not, write to the Free Software Foundation, Inc.,
|
||||
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
|
||||
// *
|
||||
// * (c) 2017-2019 Patrick van Logchem <pvanlogchem@gmail.com>
|
||||
// * (c) 2019 ergo720
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
#include <Windows.h> // For DWORD, CALLBACK, VirtualAlloc, LPVOID, SIZE_T, HMODULE
|
||||
|
||||
// NOTE: Cannot be use in loader project due to force exclude std libraries.
|
||||
//#define DEBUG // Uncomment whenever need to verify memory leaks or bad configure.
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <cstdio> // For printf
|
||||
#endif
|
||||
#include <cstdint> // For uint32_t
|
||||
|
||||
#include "util/std_extend.hpp"
|
||||
#include "ReserveAddressRanges.h"
|
||||
#include "AddressRanges.h"
|
||||
|
||||
// Reserve an address range up to the extend of what the host allows.
|
||||
bool ReserveMemoryRange(int index, blocks_reserved_t blocks_reserved)
|
||||
{
|
||||
uint32_t Start = XboxAddressRanges[index].Start;
|
||||
int Size = XboxAddressRanges[index].Size;
|
||||
bool HadAnyFailure = false;
|
||||
|
||||
// Reserve this range in 64 KiB block increments, so that during emulation
|
||||
// our memory-management code can VirtualFree() each block individually :
|
||||
|
||||
const DWORD Protect = XboxAddressRanges[index].InitialMemoryProtection;
|
||||
bool NeedsReservationTracking = false;
|
||||
unsigned int arr_index = BLOCK_REGION_DEVKIT_INDEX_BEGIN;
|
||||
static HANDLE hFileMapping1;
|
||||
static HANDLE hFileMapping2;
|
||||
|
||||
#ifdef DEBUG
|
||||
std::printf("DEBUG: ReserveMemoryRange call begin\n");
|
||||
std::printf(" : Comment = %s\n", XboxAddressRanges[index].Comment);
|
||||
#endif
|
||||
switch (Start) {
|
||||
case PHYSICAL_MAP1_BASE:
|
||||
hFileMapping1 = CreateFileMapping(
|
||||
INVALID_HANDLE_VALUE,
|
||||
nullptr,
|
||||
PAGE_EXECUTE_READWRITE,
|
||||
0,
|
||||
Size,
|
||||
nullptr);
|
||||
if (hFileMapping1 == nullptr) {
|
||||
HadAnyFailure = true;
|
||||
break;
|
||||
}
|
||||
[[fallthrough]];
|
||||
|
||||
case PHYSICAL_MAP2_BASE:
|
||||
case TILED_MEMORY_BASE: {
|
||||
static bool NeedsInitializationMap = true;
|
||||
|
||||
if (NeedsInitializationMap) {
|
||||
hFileMapping2 = CreateFileMapping(
|
||||
INVALID_HANDLE_VALUE,
|
||||
nullptr,
|
||||
PAGE_EXECUTE_READWRITE,
|
||||
0,
|
||||
Size,
|
||||
nullptr);
|
||||
if (hFileMapping2 == nullptr) {
|
||||
HadAnyFailure = true;
|
||||
break;
|
||||
}
|
||||
NeedsInitializationMap = false;
|
||||
}
|
||||
|
||||
LPVOID Result = MapViewOfFileEx(
|
||||
(Start == PHYSICAL_MAP1_BASE || Start == TILED_MEMORY_BASE) ? hFileMapping1 : hFileMapping2,
|
||||
(Start == PHYSICAL_MAP1_BASE || Start == PHYSICAL_MAP2_BASE) ?
|
||||
(FILE_MAP_READ | FILE_MAP_WRITE | FILE_MAP_EXECUTE) : (FILE_MAP_READ | FILE_MAP_WRITE),
|
||||
0,
|
||||
0,
|
||||
Size,
|
||||
(LPVOID)Start);
|
||||
#ifdef DEBUG
|
||||
std::printf(" : MapViewOfFile; Start = 0x%08X; Result = %p\n", Start, Result);
|
||||
#endif
|
||||
if (Result == nullptr) {
|
||||
HadAnyFailure = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SYSTEM_MEMORY_BASE:
|
||||
// If additional addresses need to be assign in region's block.
|
||||
// Then check for nonzero value.
|
||||
arr_index = BLOCK_REGION_SYSTEM_INDEX_BEGIN;
|
||||
[[fallthrough]];
|
||||
|
||||
case DEVKIT_MEMORY_BASE:
|
||||
// arr_index's default is BLOCK_REGION_DEVKIT_INDEX_BEGIN which is zero.
|
||||
// Any block region above zero should be place above this case to override zero value.
|
||||
//arr_index = BLOCK_REGION_DEVKIT_INDEX_BEGIN;
|
||||
NeedsReservationTracking = true;
|
||||
[[fallthrough]];
|
||||
|
||||
default: {
|
||||
while (Size > 0) {
|
||||
SIZE_T BlockSize = (SIZE_T)(Size > BLOCK_SIZE) ? BLOCK_SIZE : Size;
|
||||
LPVOID Result = VirtualAlloc((LPVOID)Start, BlockSize, MEM_RESERVE, Protect);
|
||||
if (Result == nullptr) {
|
||||
HadAnyFailure = true;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
std::printf(" : Start = %08X; Result = %p;\n", Start, Result);
|
||||
#endif
|
||||
// Handle the next block
|
||||
Start += BLOCK_SIZE;
|
||||
Size -= BLOCK_SIZE;
|
||||
if (NeedsReservationTracking) {
|
||||
if (Result != nullptr) {
|
||||
blocks_reserved[arr_index / 32] |= (1 << (arr_index % 32));
|
||||
#ifdef DEBUG
|
||||
std::printf(" : arr_index = 0x%08X; set bit = 0x%08X;\n", arr_index, (1 << (arr_index % 32)));
|
||||
std::printf(" : blocks_reserved[%08X] = 0x%08X\n", arr_index/32, blocks_reserved[arr_index/32]);
|
||||
#endif
|
||||
}
|
||||
arr_index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG
|
||||
std::printf(" : ReserveMemoryRange call end: HadAnyFailure = %d\n\n", HadAnyFailure);
|
||||
#endif
|
||||
|
||||
// Only a complete success when the entire request was reserved in a single range
|
||||
// (Otherwise, we have either a complete failure, or reserved it partially over multiple ranges)
|
||||
return !HadAnyFailure;
|
||||
}
|
||||
|
||||
// Free address range from the host.
|
||||
void FreeMemoryRange(int index, blocks_reserved_t blocks_reserved)
|
||||
{
|
||||
uint32_t Start = XboxAddressRanges[index].Start, _Start;
|
||||
int Size = XboxAddressRanges[index].Size;
|
||||
bool NeedsReservationTracking = false;
|
||||
unsigned int arr_index = BLOCK_REGION_DEVKIT_INDEX_BEGIN;
|
||||
#ifdef DEBUG
|
||||
std::printf("DEBUG: FreeMemoryRange call begin\n");
|
||||
std::printf(" : Comment = %s\n", XboxAddressRanges[index].Comment);
|
||||
#endif
|
||||
switch (Start) {
|
||||
case PHYSICAL_MAP1_BASE:
|
||||
case PHYSICAL_MAP2_BASE:
|
||||
case TILED_MEMORY_BASE: {
|
||||
(void)UnmapViewOfFile((LPVOID)Start);
|
||||
#ifdef DEBUG
|
||||
std::printf(" : UnmapViewOfFile; Start = 0x%08X\n", Start);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
case SYSTEM_MEMORY_BASE:
|
||||
// If additional addresses need to be assign in region's block.
|
||||
// Then check for nonzero value.
|
||||
arr_index = BLOCK_REGION_SYSTEM_INDEX_BEGIN;
|
||||
[[fallthrough]];
|
||||
case DEVKIT_MEMORY_BASE: {
|
||||
// arr_index's default is BLOCK_REGION_DEVKIT_INDEX_BEGIN which is zero.
|
||||
// Any block region above zero should be place above this case to override zero value.
|
||||
//arr_index = BLOCK_REGION_DEVKIT_INDEX_BEGIN;
|
||||
NeedsReservationTracking = true;
|
||||
}
|
||||
[[fallthrough]];
|
||||
|
||||
default: {
|
||||
while (Size > 0) {
|
||||
_Start = Start; // Require to silence C6001's warning complaint
|
||||
BOOL Result = VirtualFree((LPVOID)_Start, 0, MEM_RELEASE);
|
||||
#ifdef DEBUG
|
||||
std::printf(" : Start = %08X; Result = %d;\n", Start, Result);
|
||||
#endif
|
||||
// Handle the next block
|
||||
Start += BLOCK_SIZE;
|
||||
Size -= BLOCK_SIZE;
|
||||
if (NeedsReservationTracking) {
|
||||
if (Result != 0) {
|
||||
blocks_reserved[arr_index / 32] &= ~(1 << (arr_index % 32));
|
||||
#ifdef DEBUG
|
||||
std::printf(" : arr_index = 0x%08X; clear bit = 0x%08X;\n", arr_index, (1 << (arr_index % 32)));
|
||||
std::printf(" : blocks_reserved[%08X] = 0x%08X\n", arr_index/32, blocks_reserved[arr_index/32]);
|
||||
#endif
|
||||
}
|
||||
arr_index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG
|
||||
std::printf(" : FreeMemoryRange call end\n\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
bool ReserveAddressRanges(const unsigned int system, blocks_reserved_t blocks_reserved) {
|
||||
// Loop over all Xbox address ranges
|
||||
for (size_t i = 0; i < XboxAddressRanges_size; i++) {
|
||||
// Skip address ranges that don't match the given flags
|
||||
if (!AddressRangeMatchesFlags(i, system))
|
||||
continue;
|
||||
|
||||
// Try to reserve each address range
|
||||
if (ReserveMemoryRange(i, blocks_reserved))
|
||||
continue;
|
||||
|
||||
// Some ranges are allowed to fail reserving
|
||||
if (!IsOptionalAddressRange(i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FreeAddressRanges(const unsigned int system, unsigned int release_systems, blocks_reserved_t blocks_reserved) {
|
||||
// If reserved_systems is empty, then there's nothing to be freed up.
|
||||
if (release_systems == 0) {
|
||||
return;
|
||||
}
|
||||
// Loop over all Xbox address ranges
|
||||
for (size_t i = 0; i < XboxAddressRanges_size; i++) {
|
||||
// Skip address ranges that do match specific flag
|
||||
if (AddressRangeMatchesFlags(i, system))
|
||||
continue;
|
||||
|
||||
// Skip address ranges that doesn't match the reserved flags
|
||||
if (!AddressRangeMatchesFlags(i, release_systems))
|
||||
continue;
|
||||
|
||||
FreeMemoryRange(i, blocks_reserved);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool AttemptReserveAddressRanges(unsigned int* p_reserved_systems, blocks_reserved_t blocks_reserved) {
|
||||
|
||||
size_t iLast = 0;
|
||||
unsigned int reserved_systems = *p_reserved_systems, clear_systems = 0;
|
||||
// Loop over all Xbox address ranges
|
||||
for (size_t i = 0; i < XboxAddressRanges_size; i++) {
|
||||
|
||||
// Once back to original spot, let's resume.
|
||||
if (i == iLast && clear_systems) {
|
||||
reserved_systems &= ~clear_systems;
|
||||
if (reserved_systems == 0) {
|
||||
*p_reserved_systems = 0;
|
||||
return false;
|
||||
}
|
||||
// Resume virtual allocated range.
|
||||
clear_systems = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (clear_systems) {
|
||||
// Skip address ranges that doesn't match the given flags
|
||||
if (!AddressRangeMatchesFlags(i, clear_systems))
|
||||
continue;
|
||||
|
||||
// Release incompatible system's memory range
|
||||
FreeMemoryRange(i, blocks_reserved);
|
||||
}
|
||||
else {
|
||||
// Skip address ranges that don't match the given flags
|
||||
if (!AddressRangeMatchesFlags(i, reserved_systems))
|
||||
continue;
|
||||
|
||||
// Try to reserve each address range
|
||||
if (ReserveMemoryRange(i, blocks_reserved))
|
||||
continue;
|
||||
|
||||
// Some ranges are allowed to fail reserving
|
||||
if (!IsOptionalAddressRange(i)) {
|
||||
// If not, then let's free them and downgrade host's limitation.
|
||||
clear_systems = AddressRangeGetSystemFlags(i);
|
||||
iLast = i;
|
||||
i = -1; // Reset index back to zero after for statement's increment.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*p_reserved_systems = reserved_systems;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool isSystemFlagSupport(unsigned int reserved_systems, unsigned int assign_system)
|
||||
{
|
||||
if (reserved_systems & assign_system) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
// ******************************************************************
|
||||
// *
|
||||
// * This file is part of Cxbx-Reloaded.
|
||||
// *
|
||||
// * Cxbx-Reloaded is free software; you can redistribute it
|
||||
// * and/or modify it under the terms of the GNU General Public
|
||||
// * License as published by the Free Software Foundation; either
|
||||
// * version 2 of the license, or (at your option) any later version.
|
||||
// *
|
||||
// * This program 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 recieved a copy of the GNU General Public License
|
||||
// * along with this program; see the file COPYING.
|
||||
// * If not, write to the Free Software Foundation, Inc.,
|
||||
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
|
||||
// *
|
||||
// * (c) 2017-2019 Patrick van Logchem <pvanlogchem@gmail.com>
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
#pragma once
|
||||
|
||||
#include <cstdint> // For uint32_t
|
||||
|
||||
// First block section will be devkit region (256MiB) = 262144KiB / 64 KiB = 4096 bits needed -> 4096 / 32 (sizeof(uint32_t)) = 128 entries blocks_reserved array.
|
||||
// Next block section will be system region (512MiB) = 524288KiB / 64KiB = 8192 bits needed -> 8192 / 32 (sizeof(uint32_t)) = 256 entries of blocks_reserved array.
|
||||
// 1 bit per block_size (64KiB).
|
||||
typedef uint32_t blocks_reserved_t[384]; // 384 = 128 (devkit region) + 256 (system region)
|
||||
|
||||
inline constexpr uint32_t BLOCK_REGION_DEVKIT_INDEX_BEGIN = 0;
|
||||
inline constexpr uint32_t BLOCK_REGION_DEVKIT_INDEX_END = 4096;
|
||||
inline constexpr uint32_t BLOCK_REGION_SYSTEM_INDEX_BEGIN = 4096;
|
||||
inline constexpr uint32_t BLOCK_REGION_SYSTEM_INDEX_END = 12288;
|
||||
|
||||
extern bool ReserveAddressRanges(const unsigned int system, blocks_reserved_t blocks_reserved);
|
||||
|
||||
extern void FreeAddressRanges(const unsigned int system, unsigned int release_systems, blocks_reserved_t blocks_reserved);
|
||||
|
||||
extern bool AttemptReserveAddressRanges(unsigned int* p_reserved_systems, blocks_reserved_t blocks_reserved);
|
||||
|
||||
extern bool isSystemFlagSupport(unsigned int reserved_systems, unsigned int assign_system);
|
|
@ -1,53 +0,0 @@
|
|||
// ******************************************************************
|
||||
// *
|
||||
// * This file is part of the Cxbx project.
|
||||
// *
|
||||
// * Cxbx is free software; you can redistribute it
|
||||
// * and/or modify it under the terms of the GNU General Public
|
||||
// * License as published by the Free Software Foundation; either
|
||||
// * version 2 of the license, or (at your option) any later version.
|
||||
// *
|
||||
// * This program 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 recieved a copy of the GNU General Public License
|
||||
// * along with this program; see the file COPYING.
|
||||
// * If not, write to the Free Software Foundation, Inc.,
|
||||
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
|
||||
// *
|
||||
// * (c) 2016 Patrick van Logchem <pvanlogchem@gmail.com>
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
#ifndef RESERVEDMEMORY_H
|
||||
#define RESERVEDMEMORY_H
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include "EmuShared.h" // For XBE_MAX_VA, XBE_IMAGE_BASE and CXBX_BASE_OF_CODE
|
||||
|
||||
// The following code reserves virtual addresses from 0x00011000 upwards;
|
||||
#define VM_PLACEHOLDER_SIZE (XBE_MAX_VA - XBE_IMAGE_BASE - CXBX_BASE_OF_CODE)
|
||||
|
||||
// First, declare the '.text' section again :
|
||||
#pragma section(".text") // Note : 'read,write,execute' would cause a warning
|
||||
// Then place the following variable into the '.text' section :
|
||||
__declspec(allocate(".text"))
|
||||
// This variable *MUST* be this large, for it to take up address space
|
||||
// so that all other code and data in this module are placed outside of the
|
||||
// maximum virtual memory range.
|
||||
unsigned char virtual_memory_placeholder[VM_PLACEHOLDER_SIZE]; // = { OPCODE_NOP_90 };
|
||||
// TODO : Try to get the same result without enlarging our executable by 128 MB!
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // RESERVEDMEMORY_H
|
|
@ -27,12 +27,15 @@
|
|||
// *
|
||||
// ******************************************************************
|
||||
|
||||
#define LOG_PREFIX CXBXR_MODULE::CXBXR
|
||||
|
||||
#include "Settings.hpp"
|
||||
#include "core\kernel\support\Emu.h"
|
||||
#include "EmuShared.h"
|
||||
#include <filesystem>
|
||||
#include "common\input\InputManager.h"
|
||||
#include "common\input\layout_xbox_controller.h"
|
||||
#include "common\input\layout_xbox_device.h"
|
||||
#include <fstream>
|
||||
#include "common/util/cliConfig.hpp"
|
||||
|
||||
// TODO: Implement Qt support when real CPU emulation is available.
|
||||
#ifndef QT_VERSION // NOTE: Non-Qt will be using current directory for data
|
||||
|
@ -45,21 +48,28 @@ static_assert(false, "Please implement support for cross-platform's user profile
|
|||
#include <QStandardPaths> // for cross-platform's user profile support
|
||||
#endif
|
||||
|
||||
std::string g_exec_filepath;
|
||||
|
||||
// Individual library version
|
||||
uint16_t g_LibVersion_D3D8 = 0;
|
||||
uint16_t g_LibVersion_DSOUND = 0;
|
||||
|
||||
// NOTE: Update settings_version when add/edit/delete setting's structure.
|
||||
// NOTE: Update settings_version when conversion to setting's structure is required.
|
||||
// UPDATE: When settings are removed, use "if (use false && settings_version < {next_version}) {" statement
|
||||
// until existing settings require replacement or conversion. next_version input is a hardcode number.
|
||||
// Settings version 10 and later should consider as not backward compatible.
|
||||
// TODO: Add read-only state when using an older build and add a notification for will not be able save to file.
|
||||
// The sooner we do this, the better before version upgrade.
|
||||
///////////////////////////
|
||||
// * History:
|
||||
// * 2: (RadWolfie), initial version
|
||||
// * 3: (ergo720), added logging settings
|
||||
// * 4: (LukeUsher), added network settings
|
||||
// * 5: (ergo720), added new input gui settings and revision to core
|
||||
// * 6: (RadWolfie), added loader executable member to core, only for clean up loader expertimental setting
|
||||
// * 7: (RadWolfie), fix allowAdminPrivilege not align with other boolean members
|
||||
// * 8: (ergo720), added general input settings
|
||||
// * 9: (LukeUsher), replaced HardwareYUV with MaintainAspect
|
||||
///////////////////////////
|
||||
const unsigned int settings_version = 5;
|
||||
const unsigned int settings_version = 9;
|
||||
|
||||
Settings* g_Settings = nullptr;
|
||||
|
||||
|
@ -78,6 +88,9 @@ static struct {
|
|||
const char* RecentXbeFiles = "RecentXbeFiles";
|
||||
const char* DataStorageToggle = "DataStorageToggle";
|
||||
const char* DataCustomLocation = "DataCustomLocation";
|
||||
const char* IgnoreInvalidXbeSig = "IgnoreInvalidXbeSig";
|
||||
const char *IgnoreInvalidXbeSec = "IgnoreInvalidXbeSec";
|
||||
const char* ConsoleTypeToggle = "ConsoleTypeToggle";
|
||||
} sect_gui_keys;
|
||||
|
||||
static const char* section_core = "core";
|
||||
|
@ -89,6 +102,7 @@ static struct {
|
|||
const char* AllowAdminPrivilege = "AllowAdminPrivilege";
|
||||
const char* LoggedModules = "LoggedModules";
|
||||
const char* LogLevel = "LogLevel";
|
||||
const char* LogPopupTestCase = "LogPopupTestCase";
|
||||
} sect_core_keys;
|
||||
|
||||
static const char* section_video = "video";
|
||||
|
@ -98,10 +112,19 @@ static struct {
|
|||
const char* Direct3DDevice = "Direct3DDevice";
|
||||
const char* VSync = "VSync";
|
||||
const char* FullScreen = "FullScreen";
|
||||
const char* HardwareYUV = "HardwareYUV";
|
||||
const char* MaintainAspect = "MaintainAspect";
|
||||
const char* RenderResolution = "RenderResolution";
|
||||
} sect_video_keys;
|
||||
|
||||
static const char* section_overlay = "overlay";
|
||||
static struct {
|
||||
const char* build_hash = "Build Hash";
|
||||
const char* FPS = "FPS";
|
||||
const char* hle_lle_stats = "HLE/LLE Stats";
|
||||
const char* title_name = "Title Name";
|
||||
const char* file_name = "File Name";
|
||||
} sect_overlay_keys;
|
||||
|
||||
static const char* section_audio = "audio";
|
||||
static struct {
|
||||
const char* adapter = "adapter";
|
||||
|
@ -117,15 +140,24 @@ static struct {
|
|||
const char* adapter_name = "adapter_name";
|
||||
} sect_network_keys;
|
||||
|
||||
static const char *section_input_general = "input-general";
|
||||
static struct {
|
||||
const char *mo_axis_range = "MouseAxisRange";
|
||||
const char *mo_wheel_range = "MouseWheelRange";
|
||||
const char *ignore_kbmo_unfocus = "IgnoreKbMoUnfocus";
|
||||
} sect_input_general;
|
||||
|
||||
static const char* section_controller_dinput = "controller-dinput";
|
||||
static const char* section_controller_port = "controller-port";
|
||||
|
||||
static const char* section_input = "input-port-";
|
||||
static const char* section_input_port = "input-port-";
|
||||
static struct {
|
||||
const char* type = "Type";
|
||||
const char* device = "DeviceName";
|
||||
const char* config = "ProfileName";
|
||||
} sect_input;
|
||||
const char *top_slot = "TopSlot";
|
||||
const char *bottom_slot = "BottomSlot";
|
||||
} sect_input_port;
|
||||
|
||||
static const char* section_input_profiles = "input-profile-";
|
||||
static struct {
|
||||
|
@ -144,7 +176,9 @@ static struct {
|
|||
|
||||
std::string GenerateExecDirectoryStr()
|
||||
{
|
||||
return g_exec_filepath.substr(0, g_exec_filepath.find_last_of("\\/"));
|
||||
std::string exec_path;
|
||||
(void)cli_config::GetValue(cli_config::exec, &exec_path);
|
||||
return exec_path.substr(0, exec_path.find_last_of("\\/"));
|
||||
}
|
||||
|
||||
// NOTE: This function will be only have Qt support, std::filesystem doesn't have generic support.
|
||||
|
@ -203,74 +237,33 @@ bool Settings::Init()
|
|||
// Enter setup installer process
|
||||
if (!bRet) {
|
||||
|
||||
std::string saveFile;
|
||||
#ifdef RETRO_API_VERSION // TODO: Change me to #ifndef QT_VERSION
|
||||
// Can only have one option without Qt.
|
||||
saveFile = GenerateExecDirectoryStr();
|
||||
std::string setupFile;
|
||||
m_gui.DataStorageToggle = SetupFile(setupFile);
|
||||
|
||||
#else // Only support for Qt compile build.
|
||||
int iRet = MessageBox(nullptr, szSettings_save_user_option_message, "Cxbx-Reloaded", MB_YESNOCANCEL | MB_ICONQUESTION);
|
||||
|
||||
if (iRet == IDYES) {
|
||||
saveFile = GenerateExecDirectoryStr();
|
||||
m_gui.DataStorageToggle = CXBX_DATA_EXECDIR;
|
||||
}
|
||||
else if (iRet == IDNO){
|
||||
saveFile = GenerateUserProfileDirectoryStr();
|
||||
m_gui.DataStorageToggle = CXBX_DATA_APPDATA;
|
||||
if (saveFile.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if data directory exists.
|
||||
bRet = std::filesystem::exists(saveFile);
|
||||
if (!bRet) {
|
||||
// Then try create data directory.
|
||||
bRet = std::filesystem::create_directory(saveFile);
|
||||
if (!bRet) {
|
||||
// Unable to create a data directory
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (m_gui.DataStorageToggle == CXBX_DATA_INVALID) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
saveFile.append(szSettings_settings_file);
|
||||
|
||||
// Call LoadConfig, this will load the config, applying defaults for any missing fields
|
||||
bRet = LoadConfig();
|
||||
|
||||
if (!bRet) {
|
||||
MessageBox(nullptr, szSettings_setup_error, "Cxbx-Reloaded", MB_OK);
|
||||
PopupError(nullptr, szSettings_setup_error);
|
||||
return false;
|
||||
}
|
||||
|
||||
bRet = Save(saveFile);
|
||||
bRet = Save(setupFile);
|
||||
}
|
||||
return bRet;
|
||||
}
|
||||
|
||||
bool Settings::LoadUserConfig()
|
||||
{
|
||||
std::string fileSearch = GenerateExecDirectoryStr();
|
||||
std::string fileSearch;
|
||||
m_gui.DataStorageToggle = FindSettingsLocation(fileSearch);
|
||||
|
||||
fileSearch.append(szSettings_settings_file);
|
||||
|
||||
// Check and see if file exists from portable, current, directory.
|
||||
if (std::filesystem::exists(fileSearch) == false) {
|
||||
|
||||
fileSearch = GenerateUserProfileDirectoryStr();
|
||||
if (fileSearch.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
fileSearch.append(szSettings_settings_file);
|
||||
|
||||
// Check if the user profile directory settings file exists.
|
||||
if (std::filesystem::exists(fileSearch) == false) {
|
||||
return false;
|
||||
}
|
||||
if (m_gui.DataStorageToggle == CXBX_DATA_INVALID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return LoadFile(fileSearch);
|
||||
|
@ -347,6 +340,11 @@ bool Settings::LoadConfig()
|
|||
index++;
|
||||
}
|
||||
|
||||
m_gui.bIgnoreInvalidXbeSig = m_si.GetBoolValue(section_gui, sect_gui_keys.IgnoreInvalidXbeSig, /*Default=*/false);
|
||||
m_gui.bIgnoreInvalidXbeSec = m_si.GetBoolValue(section_gui, sect_gui_keys.IgnoreInvalidXbeSec, /*Default=*/false);
|
||||
|
||||
m_gui.ConsoleTypeToggle = (EMU_CONSOLE_TYPE)m_si.GetLongValue(section_gui, sect_gui_keys.ConsoleTypeToggle, /*Default=*/EMU_CONSOLE_TYPE_AUTO);
|
||||
|
||||
// ==== GUI End =============
|
||||
|
||||
// ==== Core Begin ==========
|
||||
|
@ -388,9 +386,14 @@ bool Settings::LoadConfig()
|
|||
m_core.LoggedModules[index] = 0;
|
||||
index++;
|
||||
}
|
||||
m_core.bLogPopupTestCase = m_si.GetBoolValue(section_core, sect_core_keys.LogPopupTestCase, /*Default=*/true);
|
||||
|
||||
// ==== Core End ============
|
||||
|
||||
// Delete/update legacy configs from previous revisions
|
||||
RemoveLegacyConfigs(m_core.Revision);
|
||||
m_core.Revision = settings_version;
|
||||
|
||||
// ==== Hack Begin ==========
|
||||
|
||||
m_hacks.DisablePixelShaders = m_si.GetBoolValue(section_hack, sect_hack_keys.DisablePixelShaders, /*Default=*/false);
|
||||
|
@ -415,7 +418,7 @@ bool Settings::LoadConfig()
|
|||
m_video.direct3DDevice = m_si.GetLongValue(section_video, sect_video_keys.Direct3DDevice, /*Default=*/0);
|
||||
m_video.bVSync = m_si.GetBoolValue(section_video, sect_video_keys.VSync, /*Default=*/false);
|
||||
m_video.bFullScreen = m_si.GetBoolValue(section_video, sect_video_keys.FullScreen, /*Default=*/false);
|
||||
m_video.bHardwareYUV = m_si.GetBoolValue(section_video, sect_video_keys.HardwareYUV, /*Default=*/false);
|
||||
m_video.bMaintainAspect = m_si.GetBoolValue(section_video, sect_video_keys.MaintainAspect, /*Default=*/true);
|
||||
m_video.renderScaleFactor = m_si.GetLongValue(section_video, sect_video_keys.RenderResolution, /*Default=*/1);
|
||||
|
||||
// ==== Video End ===========
|
||||
|
@ -460,39 +463,74 @@ bool Settings::LoadConfig()
|
|||
|
||||
// ==== Network End =========
|
||||
|
||||
// ==== Input Begin ====
|
||||
// ==== Input General Begin ====
|
||||
|
||||
m_input_general.MoAxisRange = m_si.GetLongValue(section_input_general, sect_input_general.mo_axis_range, MO_AXIS_DEFAULT_RANGE);
|
||||
m_input_general.MoWheelRange = m_si.GetLongValue(section_input_general, sect_input_general.mo_wheel_range, MO_WHEEL_DEFAULT_RANGE);
|
||||
m_input_general.IgnoreKbMoUnfocus = m_si.GetBoolValue(section_input_general, sect_input_general.ignore_kbmo_unfocus, true);
|
||||
|
||||
// ==== Input General End ==============
|
||||
|
||||
// ==== Input Port Begin ====
|
||||
|
||||
for (int port_num = 0; port_num < 4; port_num++) {
|
||||
std::string current_section = std::string(section_input) + std::to_string(port_num);
|
||||
int ret = m_si.GetLongValue(current_section.c_str(), sect_input.type, -2);
|
||||
if (ret == -2) {
|
||||
m_input[port_num].Type = to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID);
|
||||
continue;
|
||||
for (int slot = 0; slot < XBOX_CTRL_NUM_SLOTS; ++slot) {
|
||||
m_input_port[port_num].Type = to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID);
|
||||
m_input_port[port_num].SlotType[slot] = to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID);
|
||||
|
||||
std::string current_section = std::string(section_input_port) + std::to_string(port_num);
|
||||
int ret = m_si.GetLongValue(current_section.c_str(), sect_input_port.type, -2);
|
||||
if (ret == -2) {
|
||||
continue;
|
||||
}
|
||||
m_input_port[port_num].Type = ret;
|
||||
m_input_port[port_num].DeviceName = m_si.GetValue(current_section.c_str(), sect_input_port.device);
|
||||
m_input_port[port_num].ProfileName = TrimQuoteFromString(m_si.GetValue(current_section.c_str(), sect_input_port.config));
|
||||
ret = m_si.GetLongValue(current_section.c_str(), slot == 0 ? sect_input_port.top_slot : sect_input_port.bottom_slot, -2);
|
||||
if (ret == -2) {
|
||||
continue;
|
||||
}
|
||||
m_input_port[port_num].SlotType[slot] = ret;
|
||||
}
|
||||
m_input[port_num].Type = ret;
|
||||
m_input[port_num].DeviceName = m_si.GetValue(current_section.c_str(), sect_input.device);
|
||||
m_input[port_num].ProfileName = TrimQuoteFromString(m_si.GetValue(current_section.c_str(), sect_input.config));
|
||||
}
|
||||
|
||||
// ==== Input End ==============
|
||||
// ==== Input Port End ==============
|
||||
|
||||
// ==== Input Profile Begin ====
|
||||
|
||||
std::array<std::vector<std::string>, to_underlying(XBOX_INPUT_DEVICE::DEVICE_MAX)> control_names;
|
||||
|
||||
for (int device = 0; device < to_underlying(XBOX_INPUT_DEVICE::DEVICE_MAX); device++) {
|
||||
for (int device = 0; device < to_underlying(XBOX_INPUT_DEVICE::DEVICE_MAX); device++) {
|
||||
if (dev_num_buttons[device] == 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < dev_num_buttons[device]; i++) {
|
||||
char control_name[30];
|
||||
std::sprintf(control_name, sect_input_profiles.control, button_xbox_ctrl_names[i][0]);
|
||||
control_names[device].push_back(control_name);
|
||||
}
|
||||
const auto &lambda = [&control_names, &device](int num_buttons, const char *const ctrl_names[]) {
|
||||
for (int i = 0; i < num_buttons; i++) {
|
||||
char control_name[XBOX_BUTTON_NAME_LENGTH];
|
||||
std::sprintf(control_name, sect_input_profiles.control, ctrl_names[i]);
|
||||
control_names[device].push_back(control_name);
|
||||
}
|
||||
};
|
||||
|
||||
switch (device)
|
||||
{
|
||||
case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE):
|
||||
case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_S):
|
||||
case to_underlying(XBOX_INPUT_DEVICE::ARCADE_STICK):
|
||||
lambda(dev_num_buttons[device], button_xbox_ctrl_names);
|
||||
break;
|
||||
|
||||
case to_underlying(XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER):
|
||||
lambda(dev_num_buttons[device], button_sbc_names);
|
||||
break;
|
||||
|
||||
case to_underlying(XBOX_INPUT_DEVICE::LIGHTGUN):
|
||||
lambda(dev_num_buttons[device], button_lightgun_names);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: add the control names of the other devices
|
||||
|
||||
index = 0;
|
||||
while (true) {
|
||||
std::string current_section = std::string(section_input_profiles) + std::to_string(index);
|
||||
|
@ -513,9 +551,15 @@ bool Settings::LoadConfig()
|
|||
|
||||
// ==== Input Profile End ======
|
||||
|
||||
// Delete legacy configs from previous revisions
|
||||
RemoveLegacyConfigs(m_core.Revision);
|
||||
m_core.Revision = settings_version;
|
||||
// ==== Overlay Begin =========
|
||||
|
||||
m_overlay.build_hash = m_si.GetBoolValue(section_overlay, sect_overlay_keys.build_hash, false);
|
||||
m_overlay.fps = m_si.GetBoolValue(section_overlay, sect_overlay_keys.FPS, false);
|
||||
m_overlay.hle_lle_stats = m_si.GetBoolValue(section_overlay, sect_overlay_keys.hle_lle_stats, false);
|
||||
m_overlay.title_name = m_si.GetBoolValue(section_overlay, sect_overlay_keys.title_name, false);
|
||||
m_overlay.file_name = m_si.GetBoolValue(section_overlay, sect_overlay_keys.file_name, false);
|
||||
|
||||
// ==== Overlay End ===========
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -544,6 +588,11 @@ bool Settings::Save(std::string file_path)
|
|||
m_si.SetValue(section_gui, sect_gui_keys.RecentXbeFiles, m_gui.szRecentXbeFiles[i].c_str(), nullptr, false);
|
||||
}
|
||||
|
||||
m_si.SetBoolValue(section_gui, sect_gui_keys.IgnoreInvalidXbeSig, m_gui.bIgnoreInvalidXbeSig, nullptr, true);
|
||||
m_si.SetBoolValue(section_gui, sect_gui_keys.IgnoreInvalidXbeSec, m_gui.bIgnoreInvalidXbeSec, nullptr, true);
|
||||
|
||||
m_si.SetLongValue(section_gui, sect_gui_keys.ConsoleTypeToggle, m_gui.ConsoleTypeToggle, nullptr, true, true);
|
||||
|
||||
// ==== GUI End =============
|
||||
|
||||
// ==== Core Begin ==========
|
||||
|
@ -563,6 +612,7 @@ bool Settings::Save(std::string file_path)
|
|||
stream << "0x" << std::hex << m_core.LoggedModules[i];
|
||||
m_si.SetValue(section_core, sect_core_keys.LoggedModules, stream.str().c_str(), nullptr, false);
|
||||
}
|
||||
m_si.SetBoolValue(section_core, sect_core_keys.LogPopupTestCase, m_core.bLogPopupTestCase, nullptr, true);
|
||||
|
||||
// ==== Core End ============
|
||||
|
||||
|
@ -574,8 +624,9 @@ bool Settings::Save(std::string file_path)
|
|||
m_si.SetLongValue(section_video, sect_video_keys.Direct3DDevice, m_video.direct3DDevice, nullptr, true, true);
|
||||
m_si.SetBoolValue(section_video, sect_video_keys.VSync, m_video.bVSync, nullptr, true);
|
||||
m_si.SetBoolValue(section_video, sect_video_keys.FullScreen, m_video.bFullScreen, nullptr, true);
|
||||
m_si.SetBoolValue(section_video, sect_video_keys.HardwareYUV, m_video.bHardwareYUV, nullptr, true);
|
||||
m_si.SetBoolValue(section_video, sect_video_keys.MaintainAspect, m_video.bMaintainAspect, nullptr, true);
|
||||
m_si.SetLongValue(section_video, sect_video_keys.RenderResolution, m_video.renderScaleFactor, nullptr, false, true);
|
||||
|
||||
// ==== Video End ===========
|
||||
|
||||
// ==== Audio Begin =========
|
||||
|
@ -601,36 +652,63 @@ bool Settings::Save(std::string file_path)
|
|||
|
||||
// ==== Network End =========
|
||||
|
||||
// ==== Input Begin ====
|
||||
// ==== Input General Begin =======
|
||||
|
||||
m_si.SetLongValue(section_input_general, sect_input_general.mo_axis_range, m_input_general.MoAxisRange, nullptr, false, true);
|
||||
m_si.SetLongValue(section_input_general, sect_input_general.mo_wheel_range, m_input_general.MoWheelRange, nullptr, false, true);
|
||||
m_si.SetBoolValue(section_input_general, sect_input_general.ignore_kbmo_unfocus, m_input_general.IgnoreKbMoUnfocus, nullptr, true);
|
||||
|
||||
// ==== Input General End =========
|
||||
|
||||
// ==== Input Port Begin ====
|
||||
|
||||
for (int port_num = 0; port_num < 4; port_num++) {
|
||||
std::string current_section = std::string(section_input) + std::to_string(port_num);
|
||||
std::string quoted_prf_str = m_input[port_num].ProfileName.insert(0, "\"");
|
||||
std::string current_section = std::string(section_input_port) + std::to_string(port_num);
|
||||
std::string quoted_prf_str = m_input_port[port_num].ProfileName.insert(0, "\"");
|
||||
quoted_prf_str += "\"";
|
||||
m_si.SetLongValue(current_section.c_str(), sect_input.type, m_input[port_num].Type, nullptr, false, true);
|
||||
m_si.SetValue(current_section.c_str(), sect_input.device, m_input[port_num].DeviceName.c_str(), nullptr, true);
|
||||
m_si.SetValue(current_section.c_str(), sect_input.config, quoted_prf_str.c_str(), nullptr, true);
|
||||
m_si.SetLongValue(current_section.c_str(), sect_input_port.type, m_input_port[port_num].Type, nullptr, false, true);
|
||||
m_si.SetValue(current_section.c_str(), sect_input_port.device, m_input_port[port_num].DeviceName.c_str(), nullptr, true);
|
||||
m_si.SetValue(current_section.c_str(), sect_input_port.config, quoted_prf_str.c_str(), nullptr, true);
|
||||
m_si.SetLongValue(current_section.c_str(), sect_input_port.top_slot, m_input_port[port_num].SlotType[SLOT_TOP], nullptr, false, true);
|
||||
m_si.SetLongValue(current_section.c_str(), sect_input_port.bottom_slot, m_input_port[port_num].SlotType[SLOT_BOTTOM], nullptr, false, true);
|
||||
}
|
||||
|
||||
// ==== Input End ==============
|
||||
// ==== Input Port End ==============
|
||||
|
||||
// ==== Input Profile Begin ====
|
||||
|
||||
std::array<std::vector<std::string>, to_underlying(XBOX_INPUT_DEVICE::DEVICE_MAX)> control_names;
|
||||
for (int device = 0; device < to_underlying(XBOX_INPUT_DEVICE::DEVICE_MAX); device++) {
|
||||
for (int device = 0; device < to_underlying(XBOX_INPUT_DEVICE::DEVICE_MAX); device++) {
|
||||
if (dev_num_buttons[device] == 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < dev_num_buttons[device]; i++) {
|
||||
char control_name[30];
|
||||
std::sprintf(control_name, sect_input_profiles.control, button_xbox_ctrl_names[i][0]);
|
||||
control_names[device].push_back(control_name);
|
||||
}
|
||||
const auto &lambda = [&control_names, &device](int num_buttons, const char *const ctrl_names[]) {
|
||||
for (int i = 0; i < num_buttons; i++) {
|
||||
char control_name[XBOX_BUTTON_NAME_LENGTH];
|
||||
std::sprintf(control_name, sect_input_profiles.control, ctrl_names[i]);
|
||||
control_names[device].push_back(control_name);
|
||||
}
|
||||
};
|
||||
|
||||
switch (device)
|
||||
{
|
||||
case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE):
|
||||
case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_S):
|
||||
case to_underlying(XBOX_INPUT_DEVICE::ARCADE_STICK):
|
||||
lambda(dev_num_buttons[device], button_xbox_ctrl_names);
|
||||
break;
|
||||
|
||||
case to_underlying(XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER):
|
||||
lambda(dev_num_buttons[device], button_sbc_names);
|
||||
break;
|
||||
|
||||
case to_underlying(XBOX_INPUT_DEVICE::LIGHTGUN):
|
||||
lambda(dev_num_buttons[device], button_lightgun_names);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: add the control names of the other devices
|
||||
|
||||
int profile_num = 0;
|
||||
for (int i = 0; i < to_underlying(XBOX_INPUT_DEVICE::DEVICE_MAX); i++) {
|
||||
size_t vec_size = m_input_profiles[i].size();
|
||||
|
@ -666,6 +744,16 @@ bool Settings::Save(std::string file_path)
|
|||
|
||||
// ==== Input Profile End ======
|
||||
|
||||
// ==== Overlay Begin =======
|
||||
|
||||
m_si.SetBoolValue(section_overlay, sect_overlay_keys.build_hash, m_overlay.build_hash, nullptr, true);
|
||||
m_si.SetBoolValue(section_overlay, sect_overlay_keys.FPS, m_overlay.fps, nullptr, true);
|
||||
m_si.SetBoolValue(section_overlay, sect_overlay_keys.hle_lle_stats, m_overlay.hle_lle_stats, nullptr, true);
|
||||
m_si.SetBoolValue(section_overlay, sect_overlay_keys.title_name, m_overlay.title_name, nullptr, true);
|
||||
m_si.SetBoolValue(section_overlay, sect_overlay_keys.file_name, m_overlay.file_name, nullptr, true);
|
||||
|
||||
// ==== Overlay End =========
|
||||
|
||||
// ==== Hack Begin ==========
|
||||
|
||||
m_si.SetBoolValue(section_hack, sect_hack_keys.DisablePixelShaders, m_hacks.DisablePixelShaders, nullptr, true);
|
||||
|
@ -703,6 +791,7 @@ void Settings::SyncToEmulator()
|
|||
|
||||
// register Video settings
|
||||
g_EmuShared->SetVideoSettings(&m_video);
|
||||
g_EmuShared->SetOverlaySettings(&m_overlay);
|
||||
|
||||
// register Audio settings
|
||||
g_EmuShared->SetAudioSettings(&m_audio);
|
||||
|
@ -710,33 +799,43 @@ void Settings::SyncToEmulator()
|
|||
// register Network settings
|
||||
g_EmuShared->SetNetworkSettings(&m_network);
|
||||
|
||||
// register input settings
|
||||
// register xbox device input settings
|
||||
for (int i = 0; i < 4; i++) {
|
||||
g_EmuShared->SetInputDevTypeSettings(&m_input[i].Type, i);
|
||||
if (m_input[i].Type != to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)) {
|
||||
g_EmuShared->SetInputDevNameSettings(m_input[i].DeviceName.c_str(), i);
|
||||
auto it = std::find_if(m_input_profiles[m_input[i].Type].begin(),
|
||||
m_input_profiles[m_input[i].Type].end(), [this, i](const auto& profile) {
|
||||
if (profile.ProfileName == m_input[i].ProfileName) {
|
||||
return true;
|
||||
g_EmuShared->SetInputDevTypeSettings(&m_input_port[i].Type, i);
|
||||
g_EmuShared->SetInputSlotTypeSettings(&m_input_port[i].SlotType[SLOT_TOP], i, SLOT_TOP);
|
||||
g_EmuShared->SetInputSlotTypeSettings(&m_input_port[i].SlotType[SLOT_BOTTOM], i, SLOT_BOTTOM);
|
||||
if (m_input_port[i].Type != to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID)) {
|
||||
g_EmuShared->SetInputDevNameSettings(m_input_port[i].DeviceName.c_str(), i);
|
||||
if (m_input_port[i].Type < to_underlying(XBOX_INPUT_DEVICE::DEVICE_MAX)) {
|
||||
auto it = std::find_if(m_input_profiles[m_input_port[i].Type].begin(),
|
||||
m_input_profiles[m_input_port[i].Type].end(), [this, i](const auto &profile) {
|
||||
if (profile.ProfileName == m_input_port[i].ProfileName) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
if (it != m_input_profiles[m_input_port[i].Type].end()) {
|
||||
char controls_name[HIGHEST_NUM_BUTTONS][HOST_BUTTON_NAME_LENGTH];
|
||||
for (int index = 0; index < dev_num_buttons[m_input_port[i].Type]; index++) {
|
||||
strncpy(controls_name[index], it->ControlList[index].c_str(), 30);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
if (it != m_input_profiles[m_input[i].Type].end()) {
|
||||
char controls_name[XBOX_CTRL_NUM_BUTTONS][30];
|
||||
for (int index = 0; index < dev_num_buttons[m_input[i].Type]; index++) {
|
||||
strncpy(controls_name[index], it->ControlList[index].c_str(), 30);
|
||||
g_EmuShared->SetInputBindingsSettings(controls_name, dev_num_buttons[m_input_port[i].Type], i);
|
||||
}
|
||||
g_EmuShared->SetInputBindingsSettings(controls_name, XBOX_CTRL_NUM_BUTTONS, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// register Input general settings
|
||||
g_EmuShared->SetInputGeneralSettings(&m_input_general);
|
||||
|
||||
// register Hacks settings
|
||||
g_EmuShared->SetHackSettings(&m_hacks);
|
||||
|
||||
// register data location setting
|
||||
g_EmuShared->SetStorageLocation(GetDataLocation().c_str());
|
||||
g_EmuShared->SetDataLocation(GetDataLocation().c_str());
|
||||
|
||||
// reset title mount path
|
||||
g_EmuShared->SetTitleMountPath("");
|
||||
}
|
||||
|
||||
void verifyDebugFilePath(DebugMode& debug_mode, std::string& file_path)
|
||||
|
@ -820,17 +919,131 @@ std::string Settings::GetDataLocation()
|
|||
return m_current_data_location;
|
||||
}
|
||||
|
||||
// Detect where settings file is located and return default data mode.
|
||||
CXBX_DATA Settings::FindSettingsLocation(std::string& file_path_out)
|
||||
{
|
||||
std::string fileSearch = GenerateExecDirectoryStr();
|
||||
CXBX_DATA ret = CXBX_DATA_EXECDIR;
|
||||
|
||||
fileSearch.append(szSettings_settings_file);
|
||||
|
||||
// Check and see if file exists from portable, current, directory.
|
||||
if (std::filesystem::exists(fileSearch) == false) {
|
||||
|
||||
fileSearch = GenerateUserProfileDirectoryStr();
|
||||
if (fileSearch.size() == 0) {
|
||||
return CXBX_DATA_INVALID;
|
||||
}
|
||||
CXBX_DATA ret = CXBX_DATA_APPDATA;
|
||||
fileSearch.append(szSettings_settings_file);
|
||||
|
||||
// Check if the user profile directory settings file exists.
|
||||
if (std::filesystem::exists(fileSearch) == false) {
|
||||
return CXBX_DATA_INVALID;
|
||||
}
|
||||
}
|
||||
file_path_out = fileSearch;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Enter setup installer process
|
||||
CXBX_DATA Settings::SetupFile(std::string& file_path_out)
|
||||
{
|
||||
std::string setupFile;
|
||||
CXBX_DATA data_ret = CXBX_DATA_INVALID;
|
||||
#ifdef RETRO_API_VERSION // TODO: Change me to #ifndef QT_VERSION
|
||||
// Can only have one option without Qt.
|
||||
setupFile = GenerateExecDirectoryStr();
|
||||
|
||||
#else // Only support for Qt compile build.
|
||||
PopupReturn eRet = PopupQuestion(nullptr, szSettings_save_user_option_message);
|
||||
|
||||
if (eRet == PopupReturn::Yes) {
|
||||
setupFile = GenerateExecDirectoryStr();
|
||||
data_ret = CXBX_DATA_EXECDIR;
|
||||
}
|
||||
else if (eRet == PopupReturn::No) {
|
||||
setupFile = GenerateUserProfileDirectoryStr();
|
||||
data_ret = CXBX_DATA_APPDATA;
|
||||
if (setupFile.size() != 0) {
|
||||
// Check if data directory exists.
|
||||
if (!std::filesystem::exists(setupFile)) {
|
||||
// Then try create data directory.
|
||||
if (!std::filesystem::create_directory(setupFile)) {
|
||||
// Unable to create a data directory
|
||||
data_ret = CXBX_DATA_INVALID;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (data_ret == CXBX_DATA_INVALID) {
|
||||
PopupError(nullptr, szSettings_setup_error);
|
||||
}
|
||||
else {
|
||||
setupFile.append(szSettings_settings_file);
|
||||
// Create the file, that's it. Load the default configuration later on;
|
||||
std::ofstream createFile(setupFile);
|
||||
if (createFile.is_open()) {
|
||||
createFile.close();
|
||||
}
|
||||
file_path_out = setupFile;
|
||||
}
|
||||
|
||||
return data_ret;
|
||||
}
|
||||
|
||||
void Settings::RemoveLegacyConfigs(unsigned int CurrentRevision)
|
||||
{
|
||||
switch (CurrentRevision) {
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
if (CurrentRevision < 5) {
|
||||
m_si.Delete(section_controller_dinput, nullptr, true);
|
||||
m_si.Delete(section_controller_port, nullptr, true);
|
||||
break;
|
||||
case 5:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (CurrentRevision == 5) {
|
||||
m_si.Delete(section_core, "LoaderExperiment", true);
|
||||
}
|
||||
|
||||
|
||||
if (CurrentRevision < 8) {
|
||||
const std::string kb_str = "Keyboard";
|
||||
|
||||
for (unsigned port_num = 0; port_num < 4; ++port_num) {
|
||||
std::string current_section = std::string(section_input_port) + std::to_string(port_num);
|
||||
std::string device_name = m_si.GetValue(current_section.c_str(), sect_input_port.device, "");
|
||||
|
||||
if (device_name.ends_with(kb_str)) {
|
||||
device_name += "Mouse";
|
||||
m_si.SetValue(current_section.c_str(), sect_input_port.device, device_name.c_str(), nullptr, true);
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned index = 0; ; ++index) {
|
||||
std::string current_section = std::string(section_input_profiles) + std::to_string(index);
|
||||
if (m_si.GetSectionSize(current_section.c_str()) == -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
std::string device_name = m_si.GetValue(current_section.c_str(), sect_input_profiles.device, "");
|
||||
|
||||
// NOTE: with C++20, this can be simplified by simply calling device_name.ends_with()
|
||||
if (device_name.length() >= kb_str.length()) {
|
||||
if (device_name.compare(device_name.length() - kb_str.length(), kb_str.length(), kb_str) == 0) {
|
||||
device_name += "Mouse";
|
||||
m_si.SetValue(current_section.c_str(), sect_input_profiles.device, device_name.c_str(), nullptr, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(CurrentRevision < 9) {
|
||||
m_si.Delete(section_video, "HardwareYUV", true);
|
||||
}
|
||||
|
||||
// see settings_version for details.
|
||||
if(false && CurrentRevision < 10) {
|
||||
m_si.Delete(section_core, "LoaderExecutable", true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
|
||||
// *
|
||||
// * (c) 2002-2003 Aaron Robinson <caustik@caustik.com>
|
||||
// * (c) 2017-2018 RadWolfie
|
||||
// * (c) 2017-2018 RadWolfie
|
||||
// * (c) 2019 ergo720
|
||||
// *
|
||||
// * All rights reserved
|
||||
|
@ -26,33 +26,46 @@
|
|||
// ******************************************************************
|
||||
#ifndef SETTINGS_HPP
|
||||
#define SETTINGS_HPP
|
||||
#include "Cxbx.h"
|
||||
|
||||
#include "SimpleIni.h"
|
||||
#include "input\InputDevice.h"
|
||||
#include "SimpleIni.h"
|
||||
#include "common\input\InputManager.h"
|
||||
#include "common\util\CxbxUtil.h"
|
||||
#include <string>
|
||||
#include <array>
|
||||
|
||||
#include <string>
|
||||
#include <array>
|
||||
|
||||
#include "core/common/imgui/settings.h"
|
||||
|
||||
extern std::string g_exec_filepath;
|
||||
|
||||
// Individual library version
|
||||
extern uint16_t g_LibVersion_D3D8;
|
||||
|
||||
// Individual library version
|
||||
extern uint16_t g_LibVersion_D3D8;
|
||||
extern uint16_t g_LibVersion_DSOUND;
|
||||
|
||||
#define szSettings_alloc_error "ERROR: Unable to allocate Settings class."
|
||||
#define assert_check_shared_memory(type) \
|
||||
"Invalid "#type" size, please verify structure is align, not adding new member, or is using placeholder reserves." \
|
||||
" Otherwise, please perform versioning upgrade and update "#type" sizeof check."
|
||||
|
||||
// Toggle emulation console mode.
|
||||
typedef enum _EMU_CONSOLE_TYPE {
|
||||
EMU_CONSOLE_TYPE_AUTO = 0,
|
||||
EMU_CONSOLE_TYPE_RETAIL = 1,
|
||||
EMU_CONSOLE_TYPE_DEVKIT = 2,
|
||||
EMU_CONSOLE_TYPE_CHIHIRO = 3,
|
||||
} EMU_CONSOLE_TYPE;
|
||||
|
||||
// Cxbx-Reloaded's data storage location.
|
||||
typedef enum _CXBX_DATA {
|
||||
CXBX_DATA_INVALID = -1,
|
||||
CXBX_DATA_APPDATA = 0,
|
||||
CXBX_DATA_EXECDIR = 1,
|
||||
CXBX_DATA_CUSTOM = 2,
|
||||
} CXBX_DATA;
|
||||
|
||||
} CXBX_DATA;
|
||||
|
||||
// ******************************************************************
|
||||
// * Define number of integers required to store logging settings
|
||||
// ******************************************************************
|
||||
#define NUM_INTEGERS_LOG 2
|
||||
#define NUM_INTEGERS_LOG 3
|
||||
|
||||
enum {
|
||||
LLE_NONE = 0,
|
||||
|
@ -74,6 +87,8 @@ public:
|
|||
void SyncToEmulator();
|
||||
void Verify();
|
||||
std::string GetDataLocation();
|
||||
static CXBX_DATA FindSettingsLocation(std::string& file_path_out);
|
||||
static CXBX_DATA SetupFile(std::string& file_path_out);
|
||||
|
||||
// GUI settings
|
||||
struct s_gui {
|
||||
|
@ -82,23 +97,27 @@ public:
|
|||
std::string szRecentXbeFiles[10];
|
||||
unsigned int DataStorageToggle;
|
||||
std::string szCustomLocation = "";
|
||||
bool bIgnoreInvalidXbeSig;
|
||||
bool bIgnoreInvalidXbeSec;
|
||||
unsigned int ConsoleTypeToggle;
|
||||
} m_gui;
|
||||
|
||||
// Core settings
|
||||
struct s_core {
|
||||
struct s_core {
|
||||
unsigned int Revision;
|
||||
unsigned int FlagsLLE;
|
||||
DebugMode KrnlDebugMode;
|
||||
char szKrnlDebug[MAX_PATH] = "";
|
||||
char szStorageLocation[MAX_PATH] = "";
|
||||
bool allowAdminPrivilege;
|
||||
unsigned int LoggedModules[NUM_INTEGERS_LOG];
|
||||
char szStorageLocation[xbox::max_path] = "";
|
||||
unsigned int LoggedModules[NUM_INTEGERS_LOG];
|
||||
int LogLevel = 1;
|
||||
bool Reserved2 = 0;
|
||||
bool Reserved3 = 0;
|
||||
bool bUnused_WasUseLoaderExec;
|
||||
bool allowAdminPrivilege;
|
||||
bool bLogPopupTestCase;
|
||||
bool Reserved4 = 0;
|
||||
int Reserved99[10] = { 0 };
|
||||
} m_core;
|
||||
static_assert(sizeof(s_core) == 0x250, assert_check_shared_memory(s_core));
|
||||
|
||||
// Video settings
|
||||
struct s_video {
|
||||
|
@ -107,11 +126,12 @@ public:
|
|||
unsigned int direct3DDevice;
|
||||
bool bVSync;
|
||||
bool bFullScreen;
|
||||
bool bHardwareYUV;
|
||||
bool bMaintainAspect;
|
||||
bool Reserved3;
|
||||
int renderScaleFactor = 1;
|
||||
int Reserved99[9] = { 0 };
|
||||
} m_video;
|
||||
static_assert(sizeof(s_video) == 0x98, assert_check_shared_memory(s_video));
|
||||
|
||||
// Audio settings
|
||||
struct s_audio {
|
||||
|
@ -122,33 +142,45 @@ public:
|
|||
bool mute_on_unfocus;
|
||||
int Reserved99[14] = { 0 };
|
||||
} m_audio;
|
||||
|
||||
struct s_input {
|
||||
int Type;
|
||||
std::string DeviceName;
|
||||
std::string ProfileName;
|
||||
};
|
||||
std::array<s_input, 4> m_input;
|
||||
|
||||
struct s_input_profiles {
|
||||
int Type;
|
||||
std::string ProfileName;
|
||||
std::string DeviceName;
|
||||
std::vector<std::string> ControlList;
|
||||
};
|
||||
std::array<std::vector<s_input_profiles>, to_underlying(XBOX_INPUT_DEVICE::DEVICE_MAX)> m_input_profiles;
|
||||
|
||||
static_assert(sizeof(s_audio) == 0x4C, assert_check_shared_memory(s_audio));
|
||||
|
||||
// Input general settings
|
||||
struct s_input_general {
|
||||
long MoAxisRange;
|
||||
long MoWheelRange;
|
||||
bool IgnoreKbMoUnfocus;
|
||||
bool Reserved1[3];
|
||||
} m_input_general;
|
||||
static_assert(sizeof(s_input_general) == 0xC, assert_check_shared_memory(s_input_general));
|
||||
|
||||
struct s_input_port {
|
||||
int Type;
|
||||
int SlotType[XBOX_CTRL_NUM_SLOTS];
|
||||
std::string DeviceName;
|
||||
std::string ProfileName;
|
||||
};
|
||||
std::array<s_input_port, 4> m_input_port;
|
||||
|
||||
struct s_input_profiles {
|
||||
int Type;
|
||||
std::string ProfileName;
|
||||
std::string DeviceName;
|
||||
std::vector<std::string> ControlList;
|
||||
};
|
||||
std::array<std::vector<s_input_profiles>, to_underlying(XBOX_INPUT_DEVICE::DEVICE_MAX)> m_input_profiles;
|
||||
|
||||
// Network settings
|
||||
struct s_network {
|
||||
char adapter_name[MAX_PATH] = "";
|
||||
} m_network;
|
||||
static_assert(sizeof(s_network) == 0x104, assert_check_shared_memory(s_network));
|
||||
|
||||
// Hack settings
|
||||
// NOTE: When removing fields, replace them with place-holders
|
||||
// The size and order of this structure should *not* be allowed to change
|
||||
// Hack settings
|
||||
// NOTE: When removing fields, replace them with place-holders
|
||||
// The size and order of this structure should *not* be allowed to change
|
||||
// TODO: Fix IPC/Shared Memory so this isn't necessary
|
||||
struct s_hack {
|
||||
bool DisablePixelShaders;
|
||||
bool DisablePixelShaders;
|
||||
bool Reserved2;
|
||||
bool UseAllCores;
|
||||
bool SkipRdtscPatching;
|
||||
|
@ -158,8 +190,11 @@ public:
|
|||
bool Reserved8 = 0;
|
||||
int Reserved99[8] = { 0 };
|
||||
} m_hacks;
|
||||
static_assert(sizeof(s_hack) == 0x28, assert_check_shared_memory(s_hack));
|
||||
|
||||
private:
|
||||
overlay_settings m_overlay;
|
||||
|
||||
private:
|
||||
void RemoveLegacyConfigs(unsigned int CurrentRevision);
|
||||
std::string m_file_path = "";
|
||||
CSimpleIniA m_si;
|
||||
|
|
|
@ -24,149 +24,165 @@
|
|||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <core\kernel\exports\xboxkrnl.h>
|
||||
|
||||
#include <windows.h>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
#include <array>
|
||||
#include "Timer.h"
|
||||
#include "common\util\CxbxUtil.h"
|
||||
#include "core\kernel\init\CxbxKrnl.h"
|
||||
#ifdef __linux__
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
|
||||
// Virtual clocks will probably become useful once LLE CPU is implemented, but for now we don't need them.
|
||||
// See the QEMUClockType QEMU_CLOCK_VIRTUAL of XQEMU for more info.
|
||||
#define CLOCK_REALTIME 0
|
||||
//#define CLOCK_VIRTUALTIME 1
|
||||
#include "common\util\CxbxUtil.h"
|
||||
#include "core\kernel\support\EmuFS.h"
|
||||
#include "core\kernel\exports\EmuKrnlPs.hpp"
|
||||
#include "core\kernel\exports\EmuKrnl.h"
|
||||
#include "devices\Xbox.h"
|
||||
#include "devices\usb\OHCI.h"
|
||||
#include "core\hle\DSOUND\DirectSound\DirectSoundGlobal.hpp"
|
||||
|
||||
|
||||
// Vector storing all the timers created
|
||||
static std::vector<TimerObject*> TimerList;
|
||||
// The frequency of the high resolution clock of the host
|
||||
uint64_t HostClockFrequency;
|
||||
// Lock to acquire when accessing TimerList
|
||||
std::mutex TimerMtx;
|
||||
static std::atomic_uint64_t last_qpc; // last time when QPC was called
|
||||
static std::atomic_uint64_t exec_time; // total execution time in us since the emulation started
|
||||
static uint64_t pit_last; // last time when the pit time was updated
|
||||
static uint64_t pit_last_qpc; // last QPC time of the pit
|
||||
// The frequency of the high resolution clock of the host, and the start time
|
||||
int64_t HostQPCFrequency, HostQPCStartTime;
|
||||
|
||||
|
||||
// Returns the current time of the timer
|
||||
inline uint64_t GetTime_NS(TimerObject* Timer)
|
||||
void timer_init()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
LARGE_INTEGER li;
|
||||
QueryPerformanceCounter(&li);
|
||||
uint64_t Ret = Muldiv64(li.QuadPart, SCALE_S_IN_NS, (uint32_t)HostClockFrequency);
|
||||
#elif __linux__
|
||||
static struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
|
||||
uint64_t Ret = Muldiv64(ts.tv_sec, SCALE_S_IN_NS, 1) + ts.tv_nsec;
|
||||
#else
|
||||
#error "Unsupported OS"
|
||||
#endif
|
||||
return Ret;
|
||||
QueryPerformanceFrequency(reinterpret_cast<LARGE_INTEGER *>(&HostQPCFrequency));
|
||||
QueryPerformanceCounter(reinterpret_cast<LARGE_INTEGER *>(&HostQPCStartTime));
|
||||
pit_last_qpc = last_qpc = HostQPCStartTime;
|
||||
pit_last = get_now();
|
||||
|
||||
// Synchronize xbox system time with host time
|
||||
LARGE_INTEGER HostSystemTime;
|
||||
GetSystemTimeAsFileTime((LPFILETIME)&HostSystemTime);
|
||||
xbox::KeSystemTime.High2Time = HostSystemTime.u.HighPart;
|
||||
xbox::KeSystemTime.LowPart = HostSystemTime.u.LowPart;
|
||||
xbox::KeSystemTime.High1Time = HostSystemTime.u.HighPart;
|
||||
}
|
||||
|
||||
// Calculates the next expire time of the timer
|
||||
static inline uint64_t GetNextExpireTime(TimerObject* Timer)
|
||||
// More precise sleep, but with increased CPU usage
|
||||
void SleepPrecise(std::chrono::steady_clock::time_point targetTime)
|
||||
{
|
||||
return GetTime_NS(Timer) + Timer->ExpireTime_MS.load();
|
||||
using namespace std::chrono;
|
||||
// If we don't need to wait, return right away
|
||||
|
||||
// TODO use waitable timers?
|
||||
// TODO fetch the timer resolution to determine the sleep threshold?
|
||||
// TODO adaptive wait? https://blat-blatnik.github.io/computerBear/making-accurate-sleep-function/
|
||||
|
||||
// Try to sleep for as much of the wait as we can
|
||||
// to save CPU usage / power
|
||||
// We expect sleep to overshoot, so give ourselves some extra time
|
||||
// Note currently we ask Windows to give us 1ms timer resolution
|
||||
constexpr auto sleepThreshold = 2ms; // Minimum remaining time before we attempt to use sleep
|
||||
|
||||
auto sleepFor = (targetTime - sleepThreshold) - steady_clock::now();
|
||||
auto sleepMs = duration_cast<milliseconds>(sleepFor).count();
|
||||
|
||||
// Sleep if required
|
||||
if (sleepMs >= 0) {
|
||||
Sleep((DWORD)sleepMs);
|
||||
}
|
||||
|
||||
// Spin wait
|
||||
while (steady_clock::now() < targetTime) {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
// Deallocates the memory of the timer
|
||||
void Timer_Destroy(TimerObject* Timer)
|
||||
// NOTE: the pit device is not implemented right now, so we put this here
|
||||
static uint64_t pit_next(uint64_t now)
|
||||
{
|
||||
unsigned int index, i;
|
||||
std::lock_guard<std::mutex>lock(TimerMtx);
|
||||
|
||||
index = TimerList.size();
|
||||
for (i = 0; i < index; i++) {
|
||||
if (Timer == TimerList[i]) {
|
||||
index = i;
|
||||
constexpr uint64_t pit_period = 1000;
|
||||
uint64_t next = pit_last + pit_period;
|
||||
|
||||
if (now >= next) {
|
||||
xbox::KiClockIsr(now - pit_last);
|
||||
pit_last = get_now();
|
||||
return pit_period;
|
||||
}
|
||||
|
||||
return pit_last + pit_period - now; // time remaining until next clock interrupt
|
||||
}
|
||||
|
||||
static void update_non_periodic_events()
|
||||
{
|
||||
// update dsound
|
||||
dsound_worker();
|
||||
|
||||
// check for hw interrupts
|
||||
for (int i = 0; i < MAX_BUS_INTERRUPT_LEVEL; i++) {
|
||||
// If the interrupt is pending and connected, process it
|
||||
if (g_bEnableAllInterrupts && HalSystemInterrupts[i].IsPending() && EmuInterruptList[i] && EmuInterruptList[i]->Connected) {
|
||||
HalSystemInterrupts[i].Trigger(EmuInterruptList[i]);
|
||||
}
|
||||
}
|
||||
|
||||
assert(index != TimerList.size());
|
||||
delete Timer;
|
||||
TimerList.erase(TimerList.begin() + index);
|
||||
}
|
||||
|
||||
// Thread that runs the timer
|
||||
void ClockThread(TimerObject* Timer)
|
||||
{
|
||||
uint64_t NewExpireTime;
|
||||
|
||||
if (!Timer->Name.empty()) {
|
||||
CxbxSetThreadName(Timer->Name.c_str());
|
||||
}
|
||||
if (Timer->CpuAffinity != nullptr) {
|
||||
InitXboxThread(*Timer->CpuAffinity);
|
||||
}
|
||||
NewExpireTime = GetNextExpireTime(Timer);
|
||||
uint64_t get_now()
|
||||
{
|
||||
LARGE_INTEGER now;
|
||||
QueryPerformanceCounter(&now);
|
||||
uint64_t elapsed_us = now.QuadPart - last_qpc;
|
||||
last_qpc = now.QuadPart;
|
||||
elapsed_us *= 1000000;
|
||||
elapsed_us /= HostQPCFrequency;
|
||||
exec_time += elapsed_us;
|
||||
return exec_time;
|
||||
}
|
||||
|
||||
static uint64_t get_next(uint64_t now)
|
||||
{
|
||||
std::array<uint64_t, 5> next = {
|
||||
pit_next(now),
|
||||
g_NV2A->vblank_next(now),
|
||||
g_NV2A->ptimer_next(now),
|
||||
g_USB0->m_HostController->OHCI_next(now),
|
||||
dsound_next(now)
|
||||
};
|
||||
return *std::min_element(next.begin(), next.end());
|
||||
}
|
||||
|
||||
xbox::void_xt NTAPI system_events(xbox::PVOID arg)
|
||||
{
|
||||
// Testing shows that, if this thread has the same priority of the other xbox threads, it can take tens, even hundreds of ms to complete a single loop.
|
||||
// So we increase its priority to above normal, so that it scheduled more often
|
||||
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
|
||||
|
||||
// Always run this thread at dpc level to prevent it from ever executing APCs/DPCs
|
||||
xbox::KeRaiseIrqlToDpcLevel();
|
||||
|
||||
while (true) {
|
||||
if (GetTime_NS(Timer) > NewExpireTime) {
|
||||
if (Timer->Exit.load()) {
|
||||
Timer_Destroy(Timer);
|
||||
return;
|
||||
const uint64_t last_time = get_now();
|
||||
const uint64_t nearest_next = get_next(last_time);
|
||||
|
||||
while (true) {
|
||||
update_non_periodic_events();
|
||||
uint64_t elapsed_us = get_now() - last_time;
|
||||
if (elapsed_us >= nearest_next) {
|
||||
break;
|
||||
}
|
||||
Timer->Callback(Timer->Opaque);
|
||||
NewExpireTime = GetNextExpireTime(Timer);
|
||||
}
|
||||
Sleep(1); // prevent burning the cpu
|
||||
std::this_thread::yield();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Changes the expire time of a timer
|
||||
void Timer_ChangeExpireTime(TimerObject* Timer, uint64_t Expire_ms)
|
||||
int64_t Timer_GetScaledPerformanceCounter(int64_t Period)
|
||||
{
|
||||
Timer->ExpireTime_MS.store(Expire_ms);
|
||||
LARGE_INTEGER currentQPC;
|
||||
QueryPerformanceCounter(¤tQPC);
|
||||
|
||||
// Scale frequency with overflow avoidance, like in std::chrono
|
||||
// https://github.com/microsoft/STL/blob/6d2f8b0ed88ea6cba26cc2151f47f678442c1663/stl/inc/chrono#L703
|
||||
const int64_t currentTime = currentQPC.QuadPart - HostQPCStartTime;
|
||||
const int64_t whole = (currentTime / HostQPCFrequency) * Period;
|
||||
const int64_t part = (currentTime % HostQPCFrequency) * Period / HostQPCFrequency;
|
||||
|
||||
return whole + part;
|
||||
}
|
||||
|
||||
// Destroys the timer
|
||||
void Timer_Exit(TimerObject* Timer)
|
||||
{
|
||||
Timer->Exit.store(true);
|
||||
}
|
||||
|
||||
// Allocates the memory for the timer object
|
||||
TimerObject* Timer_Create(TimerCB Callback, void* Arg, std::string Name, unsigned long* Affinity)
|
||||
{
|
||||
std::lock_guard<std::mutex>lock(TimerMtx);
|
||||
TimerObject* pTimer = new TimerObject;
|
||||
pTimer->Type = CLOCK_REALTIME;
|
||||
pTimer->Callback = Callback;
|
||||
pTimer->ExpireTime_MS.store(0);
|
||||
pTimer->Exit.store(false);
|
||||
pTimer->Opaque = Arg;
|
||||
Name.empty() ? pTimer->Name = "Unnamed thread" : pTimer->Name = Name;
|
||||
pTimer->CpuAffinity = Affinity;
|
||||
TimerList.emplace_back(pTimer);
|
||||
|
||||
return pTimer;
|
||||
}
|
||||
|
||||
// Starts the timer
|
||||
// Expire_MS must be expressed in NS
|
||||
void Timer_Start(TimerObject* Timer, uint64_t Expire_MS)
|
||||
{
|
||||
Timer->ExpireTime_MS.store(Expire_MS);
|
||||
std::thread(ClockThread, Timer).detach();
|
||||
}
|
||||
|
||||
// Retrives the frequency of the high resolution clock of the host
|
||||
void Timer_Init()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
LARGE_INTEGER freq;
|
||||
QueryPerformanceFrequency(&freq);
|
||||
HostClockFrequency = freq.QuadPart;
|
||||
#elif __linux__
|
||||
ClockFrequency = 0;
|
||||
#else
|
||||
#error "Unsupported OS"
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -28,39 +28,24 @@
|
|||
#ifndef TIMER_H
|
||||
#define TIMER_H
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
|
||||
#define SCALE_S_IN_NS 1000000000
|
||||
#define SCALE_MS_IN_NS 1000000
|
||||
#define SCALE_US_IN_NS 1000
|
||||
#define SCALE_NS_IN_NS 1
|
||||
|
||||
#define SCALE_NS_IN_NS 1
|
||||
|
||||
#define SCALE_S_IN_US 1000000
|
||||
#define SCALE_MS_IN_US 1000
|
||||
#define SCALE_US_IN_US 1
|
||||
|
||||
/* typedef of the timer object and the callback function */
|
||||
typedef void(*TimerCB)(void*);
|
||||
typedef struct _TimerObject
|
||||
{
|
||||
int Type; // timer type
|
||||
std::atomic_uint64_t ExpireTime_MS; // when the timer expires (ms)
|
||||
std::atomic_bool Exit; // indicates that the timer should be destroyed
|
||||
TimerCB Callback; // function to call when the timer expires
|
||||
void* Opaque; // opaque argument to pass to the callback
|
||||
std::string Name; // the name of the timer thread (if any)
|
||||
unsigned long* CpuAffinity; // the cpu affinity of the timer thread (if any)
|
||||
}
|
||||
TimerObject;
|
||||
|
||||
extern uint64_t HostClockFrequency;
|
||||
extern int64_t HostQPCFrequency;
|
||||
|
||||
/* Timer exported functions */
|
||||
TimerObject* Timer_Create(TimerCB Callback, void* Arg, std::string Name, unsigned long* Affinity);
|
||||
void Timer_Start(TimerObject* Timer, uint64_t Expire_MS);
|
||||
void Timer_Exit(TimerObject* Timer);
|
||||
void Timer_ChangeExpireTime(TimerObject* Timer, uint64_t Expire_ms);
|
||||
inline uint64_t GetTime_NS(TimerObject* Timer);
|
||||
void Timer_Init();
|
||||
void timer_init();
|
||||
uint64_t get_now();
|
||||
int64_t Timer_GetScaledPerformanceCounter(int64_t Period);
|
||||
void SleepPrecise(std::chrono::steady_clock::time_point targetTime);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
// ******************************************************************
|
||||
// *
|
||||
// * This file is part of Cxbx-Reloaded.
|
||||
// *
|
||||
// * Cxbx-Reloaded is free software; you can redistribute it
|
||||
// * and/or modify it under the terms of the GNU General Public
|
||||
// * License as published by the Free Software Foundation; either
|
||||
// * version 2 of the license, or (at your option) any later version.
|
||||
// *
|
||||
// * This program 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 recieved a copy of the GNU General Public License
|
||||
// * along with this program; see the file COPYING.
|
||||
// * If not, write to the Free Software Foundation, Inc.,
|
||||
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
|
||||
// *
|
||||
// * (c) 2017-2019 Patrick van Logchem <pvanlogchem@gmail.com>
|
||||
// * (c) 2019 ego720
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
|
||||
#include "AddressRanges.h"
|
||||
#include "core\kernel\init\CxbxKrnl.h" // For CXBX_BASE_ADDR
|
||||
|
||||
bool VerifyBaseAddr()
|
||||
{
|
||||
/*! CXBX_BASE_ADDR is defined as 0x00010000, which is the base address of
|
||||
the cxbxr-ldr.exe host executable.
|
||||
Set in cxbxr-ldr.exe Project options, Linker, Advanced, Base Address */
|
||||
return ((UINT_PTR)GetModuleHandle(nullptr) == CXBX_BASE_ADDR);
|
||||
}
|
||||
|
||||
void UnreserveMemoryRange(const int index)
|
||||
{
|
||||
uint32_t Start = XboxAddressRanges[index].Start;
|
||||
int Size = XboxAddressRanges[index].Size;
|
||||
|
||||
while (Size > 0) {
|
||||
VirtualFree((LPVOID)Start, (SIZE_T)0, MEM_RELEASE); // To release, dwSize must be zero!
|
||||
Start += BLOCK_SIZE;
|
||||
Size -= BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
bool AllocateMemoryRange(const int index)
|
||||
{
|
||||
uint32_t Start = XboxAddressRanges[index].Start;
|
||||
int Size = XboxAddressRanges[index].Size;
|
||||
|
||||
while (Size > 0) {
|
||||
int BlockSize = (Size > BLOCK_SIZE) ? BLOCK_SIZE : Size;
|
||||
if (nullptr == VirtualAlloc((void*)Start, BlockSize, MEM_COMMIT, PAGE_READWRITE)) { // MEM_RESERVE already done by Cxbx-Loader.exe
|
||||
return false;
|
||||
}
|
||||
|
||||
Start += BLOCK_SIZE;
|
||||
Size -= BLOCK_SIZE;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
// ******************************************************************
|
||||
// *
|
||||
// * This file is part of Cxbx-Reloaded.
|
||||
// *
|
||||
// * Cxbx-Reloaded is free software; you can redistribute it
|
||||
// * and/or modify it under the terms of the GNU General Public
|
||||
// * License as published by the Free Software Foundation; either
|
||||
// * version 2 of the license, or (at your option) any later version.
|
||||
// *
|
||||
// * This program 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 recieved a copy of the GNU General Public License
|
||||
// * along with this program; see the file COPYING.
|
||||
// * If not, write to the Free Software Foundation, Inc.,
|
||||
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
|
||||
// *
|
||||
// * (c) 2017-2019 Patrick van Logchem <pvanlogchem@gmail.com>
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
#pragma once
|
||||
|
||||
extern bool VerifyBaseAddr();
|
||||
|
||||
extern void UnreserveMemoryRange(const int index);
|
||||
extern bool AllocateMemoryRange(const int index);
|
|
@ -0,0 +1,51 @@
|
|||
// ******************************************************************
|
||||
// *
|
||||
// * This file is part of the Cxbx project.
|
||||
// *
|
||||
// * Cxbx and Cxbe are free software; you can redistribute them
|
||||
// * and/or modify them under the terms of the GNU General Public
|
||||
// * License as published by the Free Software Foundation; either
|
||||
// * version 2 of the license, or (at your option) any later version.
|
||||
// *
|
||||
// * This program 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 recieved a copy of the GNU General Public License
|
||||
// * along with this program; see the file COPYING.
|
||||
// * If not, write to the Free Software Foundation, Inc.,
|
||||
// * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
// *
|
||||
// * (c) 2020 RadWolfie
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
// Convert frequency to pitch helper
|
||||
static inline int32_t converter_freq2pitch(uint32_t freq) {
|
||||
// NOTE: pitch = 0 is equal to 48 KHz.
|
||||
/* For research purpose of how to convert frequency to pitch and back to frequency.
|
||||
// Edit hertz variable to see the result.
|
||||
float hertz = 12000.0f;
|
||||
|
||||
float hertzRatio = 48000.0f; // base frequency
|
||||
float pitchRatio = 4096.0f; // pitch per octave
|
||||
|
||||
// Convert hertz to pitch
|
||||
float pitch = log2(hertz / hertzRatio) * pitchRatio;
|
||||
|
||||
// Convert pitch to hertz
|
||||
hertz = exp((pitch / pitchRatio) * log(2)) * hertzRatio;*/
|
||||
return static_cast<int32_t>(log2(freq / 48000.0f) * 4096.0f);
|
||||
}
|
||||
|
||||
// Convert pitch to frequency helper
|
||||
static inline uint32_t converter_pitch2freq(int32_t pitch) {
|
||||
//* See research documentation above for conversion example.
|
||||
return static_cast<uint32_t>(exp((pitch / 4096.0f) * log(2)) * 48000.0f);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -23,42 +23,42 @@
|
|||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
|
||||
#ifndef EMUDES_H
|
||||
#define EMUDES_H
|
||||
|
||||
#define MBEDTLS_DES_KEY_SIZE 8
|
||||
|
||||
#define MBEDTLS_DES_ENCRYPT 1
|
||||
#define MBEDTLS_DES_DECRYPT 0
|
||||
|
||||
#define MBEDTLS_ERR_DES_INVALID_INPUT_LENGTH -0x0032 /**< The data input has an invalid length. */
|
||||
|
||||
/**
|
||||
* \brief DES context structure
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t sk[32]; /*!< DES subkeys */
|
||||
}
|
||||
mbedtls_des_context;
|
||||
|
||||
/**
|
||||
* \brief Triple-DES context structure
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t sk[96]; /*!< 3DES subkeys */
|
||||
}
|
||||
mbedtls_des3_context;
|
||||
|
||||
void mbedtls_des_key_set_parity(unsigned char* Key, unsigned long KeyLenght);
|
||||
void mbedtls_des_setkey_enc(mbedtls_des_context* ctx, const unsigned char key[MBEDTLS_DES_KEY_SIZE]);
|
||||
void mbedtls_des_crypt_ecb(mbedtls_des_context* ctx, const unsigned char input[8], unsigned char output[8], unsigned long encrypt);
|
||||
int mbedtls_des_crypt_cbc(mbedtls_des_context* ctx, unsigned long mode, unsigned long length, unsigned char iv[8], const unsigned char* input, unsigned char* output);
|
||||
void mbedtls_des3_set3key_enc(mbedtls_des3_context* ctx, const unsigned char key[MBEDTLS_DES_KEY_SIZE * 3]);
|
||||
void mbedtls_des3_crypt_ecb(mbedtls_des3_context* ctx, const unsigned char input[8], unsigned char output[8], unsigned long encrypt);
|
||||
int mbedtls_des3_crypt_cbc(mbedtls_des3_context* ctx, unsigned long mode, unsigned long length, unsigned char iv[8], const unsigned char *input, unsigned char *output);
|
||||
|
||||
#endif EMUDES_H
|
||||
// ******************************************************************
|
||||
|
||||
#ifndef EMUDES_H
|
||||
#define EMUDES_H
|
||||
|
||||
#define MBEDTLS_DES_KEY_SIZE 8
|
||||
|
||||
#define MBEDTLS_DES_ENCRYPT 1
|
||||
#define MBEDTLS_DES_DECRYPT 0
|
||||
|
||||
#define MBEDTLS_ERR_DES_INVALID_INPUT_LENGTH -0x0032 /**< The data input has an invalid length. */
|
||||
|
||||
/**
|
||||
* \brief DES context structure
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t sk[32]; /*!< DES subkeys */
|
||||
}
|
||||
mbedtls_des_context;
|
||||
|
||||
/**
|
||||
* \brief Triple-DES context structure
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
uint32_t sk[96]; /*!< 3DES subkeys */
|
||||
}
|
||||
mbedtls_des3_context;
|
||||
|
||||
void mbedtls_des_key_set_parity(unsigned char* Key, unsigned long KeyLenght);
|
||||
void mbedtls_des_setkey_enc(mbedtls_des_context* ctx, const unsigned char key[MBEDTLS_DES_KEY_SIZE]);
|
||||
void mbedtls_des_crypt_ecb(mbedtls_des_context* ctx, const unsigned char input[8], unsigned char output[8], unsigned long encrypt);
|
||||
int mbedtls_des_crypt_cbc(mbedtls_des_context* ctx, unsigned long mode, unsigned long length, unsigned char iv[8], const unsigned char* input, unsigned char* output);
|
||||
void mbedtls_des3_set3key_enc(mbedtls_des3_context* ctx, const unsigned char key[MBEDTLS_DES_KEY_SIZE * 3]);
|
||||
void mbedtls_des3_crypt_ecb(mbedtls_des3_context* ctx, const unsigned char input[8], unsigned char output[8], unsigned long encrypt);
|
||||
int mbedtls_des3_crypt_cbc(mbedtls_des3_context* ctx, unsigned long mode, unsigned long length, unsigned char iv[8], const unsigned char *input, unsigned char *output);
|
||||
|
||||
#endif EMUDES_H
|
||||
|
|
|
@ -1,161 +1,161 @@
|
|||
// ******************************************************************
|
||||
// *
|
||||
// * This file is part of the Cxbx project.
|
||||
// *
|
||||
// * Cxbx and Cxbe are free software; you can redistribute them
|
||||
// * and/or modify them under the terms of the GNU General Public
|
||||
// * License as published by the Free Software Foundation; either
|
||||
// * version 2 of the license, or (at your option) any later version.
|
||||
// *
|
||||
// * This program 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 recieved a copy of the GNU General Public License
|
||||
// * along with this program; see the file COPYING.
|
||||
// * If not, write to the Free Software Foundation, Inc.,
|
||||
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
|
||||
// *
|
||||
// * (c) 2018 ergo720
|
||||
// * (c) 2019 Jannik Vogel
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
|
||||
// Acknowledgment:
|
||||
// verify_hash, RSApkcs1paddingtable and RSA_PUBLIC_KEY are from the
|
||||
// file xboxlib.c of the xbedump tool (and that file only, GPLv2).
|
||||
// https://github.com/XboxDev/xbedump/blob/master/xboxlib.c
|
||||
// mbedtls_swap_endianness is extracted from mbedtls_mpi_read_binary used in the file bignum.h of ReactOS
|
||||
// https://github.com/reactos/reactos
|
||||
|
||||
// xboxlib.c license
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
/**
|
||||
* \file bignum.h
|
||||
*
|
||||
* \brief Multi-precision integer library
|
||||
*
|
||||
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* This file is part of mbed TLS (https://tls.mbed.org)
|
||||
*/
|
||||
|
||||
#define LOG_PREFIX CXBXR_MODULE::RSA
|
||||
|
||||
#include "EmuRsa.h"
|
||||
#include "core\kernel\support\Emu.h" // For EmuLog
|
||||
#include "tomcrypt.h"
|
||||
#include "tommath.h"
|
||||
|
||||
#define CHK_MP_RET(x) do { int ret = (x); if (ret != MP_OKAY) return false; } while(0)
|
||||
|
||||
|
||||
// ******************************************************************
|
||||
// *
|
||||
// * This file is part of the Cxbx project.
|
||||
// *
|
||||
// * Cxbx and Cxbe are free software; you can redistribute them
|
||||
// * and/or modify them under the terms of the GNU General Public
|
||||
// * License as published by the Free Software Foundation; either
|
||||
// * version 2 of the license, or (at your option) any later version.
|
||||
// *
|
||||
// * This program 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 recieved a copy of the GNU General Public License
|
||||
// * along with this program; see the file COPYING.
|
||||
// * If not, write to the Free Software Foundation, Inc.,
|
||||
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
|
||||
// *
|
||||
// * (c) 2018 ergo720
|
||||
// * (c) 2019 Jannik Vogel
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
|
||||
// Acknowledgment:
|
||||
// verify_hash, RSApkcs1paddingtable and RSA_PUBLIC_KEY are from the
|
||||
// file xboxlib.c of the xbedump tool (and that file only, GPLv2).
|
||||
// https://github.com/XboxDev/xbedump/blob/master/xboxlib.c
|
||||
// mbedtls_swap_endianness is extracted from mbedtls_mpi_read_binary used in the file bignum.h of ReactOS
|
||||
// https://github.com/reactos/reactos
|
||||
|
||||
// xboxlib.c license
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
/**
|
||||
* \file bignum.h
|
||||
*
|
||||
* \brief Multi-precision integer library
|
||||
*
|
||||
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
|
||||
* SPDX-License-Identifier: GPL-2.0
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* This file is part of mbed TLS (https://tls.mbed.org)
|
||||
*/
|
||||
|
||||
#define LOG_PREFIX CXBXR_MODULE::RSA
|
||||
|
||||
#include "EmuRsa.h"
|
||||
#include "core\kernel\support\Emu.h" // For EmuLog
|
||||
#include "tomcrypt.h"
|
||||
#include "tommath.h"
|
||||
|
||||
#define CHK_MP_RET(x) do { int ret = (x); if (ret != MP_OKAY) return false; } while(0)
|
||||
|
||||
|
||||
const unsigned char RSApkcs1paddingtable[3][16] = {
|
||||
{ 0x0F, 0x14,0x04,0x00,0x05,0x1A,0x02,0x03,0x0E,0x2B,0x05,0x06,0x09,0x30,0x21,0x30 },
|
||||
{ 0x0D, 0x14,0x04,0x1A,0x02,0x03,0x0E,0x2B,0x05,0x06,0x07,0x30,0x1F,0x30,0x00,0x00 },
|
||||
{ 0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }
|
||||
};
|
||||
|
||||
// Move this to CxbxUtil.h if it's ever needed in other places of the emu as well
|
||||
void mbedtls_swap_endianness(const unsigned char* in_buf, unsigned char* out_buf, size_t size)
|
||||
{
|
||||
size_t i, j, n;
|
||||
uint32_t* out_buf_uint = (uint32_t*)out_buf;
|
||||
|
||||
memset(out_buf_uint, 0, size);
|
||||
|
||||
for (n = 0; n < size; n++)
|
||||
if (in_buf[n] != 0)
|
||||
break;
|
||||
|
||||
for (i = size, j = 0; i > n; i--, j++) {
|
||||
out_buf_uint[j / 4] |= ((uint32_t)in_buf[i - 1]) << ((j % 4) << 3);
|
||||
}
|
||||
}
|
||||
|
||||
void init_tom_lib()
|
||||
{
|
||||
// NOTE: init_LTM has been deprecated in favor to crypt_mp_init("L"). However, in the latest master branch crypt_mp_init
|
||||
// is still undefined.
|
||||
static bool need_init = true;
|
||||
if (need_init) {
|
||||
init_LTM();
|
||||
need_init = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool xbox_exp_mod(unsigned char* pA, const unsigned char* pB, const unsigned char* pC, const unsigned char* pD,
|
||||
size_t a_size, size_t b_size, size_t c_size, size_t d_size)
|
||||
{
|
||||
mp_int a, b, c, d;
|
||||
CHK_MP_RET(mp_init(&a));
|
||||
CHK_MP_RET(mp_init(&b));
|
||||
CHK_MP_RET(mp_init(&c));
|
||||
CHK_MP_RET(mp_init(&d));
|
||||
CHK_MP_RET(mp_import(&b, 1, -1, b_size, 0, 0, pB));
|
||||
CHK_MP_RET(mp_import(&c, 1, -1, c_size, 0, 0, pC));
|
||||
CHK_MP_RET(mp_import(&d, 1, -1, d_size, 0, 0, pD));
|
||||
|
||||
CHK_MP_RET(mp_exptmod(&b, &c, &d, &a));
|
||||
|
||||
CHK_MP_RET(mp_export(pA, NULL, -1, a_size, 0, 0, &a));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool xbox_rsa_public(const unsigned char* in_buf, unsigned char* out_buf, RSA_PUBLIC_KEY key)
|
||||
{
|
||||
rsa_key tom_key;
|
||||
unsigned char in_buf_be[256] = { 0 };
|
||||
unsigned char out_buf_be[256] = { 0 };
|
||||
unsigned long out_len = 256;
|
||||
unsigned char modulus_be[256] = { 0 };
|
||||
unsigned char exp_be[4] = { 0 };
|
||||
|
||||
// We must swap the data since libtom expects the data to be in big endian
|
||||
mbedtls_swap_endianness (key.KeyData.Modulus, modulus_be, 256);
|
||||
mbedtls_swap_endianness (key.KeyData.Exponent, exp_be, 4);
|
||||
mbedtls_swap_endianness (in_buf, in_buf_be, 256);
|
||||
if (rsa_set_key(modulus_be, 256, exp_be, 4, NULL, 0, &tom_key) != CRYPT_OK) {
|
||||
EmuLog(LOG_LEVEL::WARNING, "Failed to load rsa key");
|
||||
return false;
|
||||
}
|
||||
if (rsa_exptmod(in_buf_be, 256, out_buf_be, &out_len, PK_PUBLIC, &tom_key) != CRYPT_OK) {
|
||||
EmuLog(LOG_LEVEL::WARNING, "rsa_exptmod failed");
|
||||
return false;
|
||||
}
|
||||
mbedtls_swap_endianness(out_buf_be, out_buf, 256);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool verify_hash(const unsigned char* hash, const unsigned char* decryptBuffer, RSA_PUBLIC_KEY key)
|
||||
{
|
||||
};
|
||||
|
||||
// Move this to CxbxUtil.h if it's ever needed in other places of the emu as well
|
||||
void mbedtls_swap_endianness(const unsigned char* in_buf, unsigned char* out_buf, size_t size)
|
||||
{
|
||||
size_t i, j, n;
|
||||
uint32_t* out_buf_uint = (uint32_t*)out_buf;
|
||||
|
||||
memset(out_buf_uint, 0, size);
|
||||
|
||||
for (n = 0; n < size; n++)
|
||||
if (in_buf[n] != 0)
|
||||
break;
|
||||
|
||||
for (i = size, j = 0; i > n; i--, j++) {
|
||||
out_buf_uint[j / 4] |= ((uint32_t)in_buf[i - 1]) << ((j % 4) << 3);
|
||||
}
|
||||
}
|
||||
|
||||
void init_tom_lib()
|
||||
{
|
||||
// NOTE: init_LTM has been deprecated in favor to crypt_mp_init("L"). However, in the latest master branch crypt_mp_init
|
||||
// is still undefined.
|
||||
static bool need_init = true;
|
||||
if (need_init) {
|
||||
init_LTM();
|
||||
need_init = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool xbox_exp_mod(unsigned char* pA, const unsigned char* pB, const unsigned char* pC, const unsigned char* pD,
|
||||
size_t a_size, size_t b_size, size_t c_size, size_t d_size)
|
||||
{
|
||||
mp_int a, b, c, d;
|
||||
CHK_MP_RET(mp_init(&a));
|
||||
CHK_MP_RET(mp_init(&b));
|
||||
CHK_MP_RET(mp_init(&c));
|
||||
CHK_MP_RET(mp_init(&d));
|
||||
CHK_MP_RET(mp_import(&b, 1, -1, b_size, 0, 0, pB));
|
||||
CHK_MP_RET(mp_import(&c, 1, -1, c_size, 0, 0, pC));
|
||||
CHK_MP_RET(mp_import(&d, 1, -1, d_size, 0, 0, pD));
|
||||
|
||||
CHK_MP_RET(mp_exptmod(&b, &c, &d, &a));
|
||||
|
||||
CHK_MP_RET(mp_export(pA, NULL, -1, a_size, 0, 0, &a));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool xbox_rsa_public(const unsigned char* in_buf, unsigned char* out_buf, RSA_PUBLIC_KEY key)
|
||||
{
|
||||
rsa_key tom_key;
|
||||
unsigned char in_buf_be[256] = { 0 };
|
||||
unsigned char out_buf_be[256] = { 0 };
|
||||
unsigned long out_len = 256;
|
||||
unsigned char modulus_be[256] = { 0 };
|
||||
unsigned char exp_be[4] = { 0 };
|
||||
|
||||
// We must swap the data since libtom expects the data to be in big endian
|
||||
mbedtls_swap_endianness (key.KeyData.Modulus, modulus_be, 256);
|
||||
mbedtls_swap_endianness (key.KeyData.Exponent, exp_be, 4);
|
||||
mbedtls_swap_endianness (in_buf, in_buf_be, 256);
|
||||
if (rsa_set_key(modulus_be, 256, exp_be, 4, NULL, 0, &tom_key) != CRYPT_OK) {
|
||||
EmuLog(LOG_LEVEL::WARNING, "Failed to load rsa key");
|
||||
return false;
|
||||
}
|
||||
if (rsa_exptmod(in_buf_be, 256, out_buf_be, &out_len, PK_PUBLIC, &tom_key) != CRYPT_OK) {
|
||||
EmuLog(LOG_LEVEL::WARNING, "rsa_exptmod failed");
|
||||
return false;
|
||||
}
|
||||
mbedtls_swap_endianness(out_buf_be, out_buf, 256);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool verify_hash(const unsigned char* hash, const unsigned char* decryptBuffer, RSA_PUBLIC_KEY key)
|
||||
{
|
||||
unsigned char cmphash[20];
|
||||
int a;
|
||||
int zero_position = 20;
|
||||
|
@ -192,5 +192,5 @@ bool verify_hash(const unsigned char* hash, const unsigned char* decryptBuffer,
|
|||
if (decryptBuffer[i] != 0xff) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1,55 +1,55 @@
|
|||
// ******************************************************************
|
||||
// *
|
||||
// * This file is part of the Cxbx project.
|
||||
// *
|
||||
// * Cxbx and Cxbe are free software; you can redistribute them
|
||||
// * and/or modify them under the terms of the GNU General Public
|
||||
// * License as published by the Free Software Foundation; either
|
||||
// * version 2 of the license, or (at your option) any later version.
|
||||
// *
|
||||
// * This program 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 recieved a copy of the GNU General Public License
|
||||
// * along with this program; see the file COPYING.
|
||||
// * If not, write to the Free Software Foundation, Inc.,
|
||||
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
|
||||
// *
|
||||
// * (c) 2018-2019 ergo720
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
|
||||
#ifndef EMURSA_H
|
||||
#define EMURSA_H
|
||||
|
||||
#include <cstdlib> // For size_t
|
||||
|
||||
#pragma pack(4)
|
||||
|
||||
typedef union _RSA_PUBLIC_KEY
|
||||
{
|
||||
unsigned char Default[284];
|
||||
struct {
|
||||
char Magic[4]; // "RSA1"
|
||||
unsigned int Bloblen; // 264 (Modulus + Exponent + Modulussize)
|
||||
unsigned char Bitlen[4]; // 2048
|
||||
unsigned int ModulusSize; // 255 (bytes in the Modulus)
|
||||
unsigned char Exponent[4]; // Public exponent
|
||||
unsigned char Modulus[256]; // Bit endian style
|
||||
unsigned char Unknown[8]; // ?
|
||||
}KeyData;
|
||||
} RSA_PUBLIC_KEY;
|
||||
|
||||
#pragma pack()
|
||||
|
||||
void init_tom_lib();
|
||||
bool xbox_exp_mod(unsigned char* pA, const unsigned char* pB, const unsigned char* pC, const unsigned char* pD,
|
||||
size_t a_size, size_t b_size, size_t c_size, size_t d_size);
|
||||
bool xbox_rsa_public(const unsigned char* in_buf, unsigned char* out_buf, RSA_PUBLIC_KEY key);
|
||||
bool verify_hash(const unsigned char* hash, const unsigned char* decryptBuffer, RSA_PUBLIC_KEY key);
|
||||
|
||||
#endif
|
||||
// ******************************************************************
|
||||
// *
|
||||
// * This file is part of the Cxbx project.
|
||||
// *
|
||||
// * Cxbx and Cxbe are free software; you can redistribute them
|
||||
// * and/or modify them under the terms of the GNU General Public
|
||||
// * License as published by the Free Software Foundation; either
|
||||
// * version 2 of the license, or (at your option) any later version.
|
||||
// *
|
||||
// * This program 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 recieved a copy of the GNU General Public License
|
||||
// * along with this program; see the file COPYING.
|
||||
// * If not, write to the Free Software Foundation, Inc.,
|
||||
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
|
||||
// *
|
||||
// * (c) 2018-2019 ergo720
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
|
||||
#ifndef EMURSA_H
|
||||
#define EMURSA_H
|
||||
|
||||
#include <cstdlib> // For size_t
|
||||
|
||||
#pragma pack(4)
|
||||
|
||||
typedef union _RSA_PUBLIC_KEY
|
||||
{
|
||||
unsigned char Default[284];
|
||||
struct {
|
||||
char Magic[4]; // "RSA1"
|
||||
unsigned int Bloblen; // 264 (Modulus + Exponent + Modulussize)
|
||||
unsigned char Bitlen[4]; // 2048
|
||||
unsigned int ModulusSize; // 255 (bytes in the Modulus)
|
||||
unsigned char Exponent[4]; // Public exponent
|
||||
unsigned char Modulus[256]; // Bit endian style
|
||||
unsigned char Unknown[8]; // ?
|
||||
}KeyData;
|
||||
} RSA_PUBLIC_KEY;
|
||||
|
||||
#pragma pack()
|
||||
|
||||
void init_tom_lib();
|
||||
bool xbox_exp_mod(unsigned char* pA, const unsigned char* pB, const unsigned char* pC, const unsigned char* pD,
|
||||
size_t a_size, size_t b_size, size_t c_size, size_t d_size);
|
||||
bool xbox_rsa_public(const unsigned char* in_buf, unsigned char* out_buf, RSA_PUBLIC_KEY key);
|
||||
bool verify_hash(const unsigned char* hash, const unsigned char* decryptBuffer, RSA_PUBLIC_KEY key);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -43,7 +43,7 @@ A million repetitions of "a"
|
|||
/* #define LITTLE_ENDIAN * This should be #define'd already, if true. */
|
||||
/* #define SHA1HANDSOFF * Copies data before messing with it. */
|
||||
|
||||
// Acknowledgment: Steve Reid
|
||||
// Acknowledgment: Steve Reid
|
||||
// https://github.com/clibs/sha1
|
||||
|
||||
#define SHA1HANDSOFF
|
||||
|
|
|
@ -0,0 +1,169 @@
|
|||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
// ******************************************************************
|
||||
// *
|
||||
// * This file is part of the Cxbx-Reloaded project.
|
||||
// *
|
||||
// * Cxbx and Cxbe are free software; you can redistribute them
|
||||
// * and/or modify them under the terms of the GNU General Public
|
||||
// * License as published by the Free Software Foundation; either
|
||||
// * version 2 of the license, or (at your option) any later version.
|
||||
// *
|
||||
// * This program 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 recieved a copy of the GNU General Public License
|
||||
// * along with this program; see the file COPYING.
|
||||
// * If not, write to the Free Software Foundation, Inc.,
|
||||
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
#define LOG_PREFIX CXBXR_MODULE::FILE
|
||||
|
||||
#ifdef CXBXR_EMU
|
||||
#include "core/kernel/support/EmuFile.h" // For g_io_mu_metadata
|
||||
#include "common/Timer.h" // For Timer_Shutdown
|
||||
#include "core/common/video/RenderBase.hpp" // For g_renderbase
|
||||
#include "core/kernel/memory-manager/VMManager.h"
|
||||
extern void CxbxrKrnlSuspendThreads();
|
||||
#endif
|
||||
|
||||
#include "cxbxr.hpp"
|
||||
|
||||
#include "EmuShared.h"
|
||||
#include "Settings.hpp"
|
||||
#include "Logging.h"
|
||||
#include "win32/WineEnv.h"
|
||||
|
||||
#include "Settings.hpp"
|
||||
|
||||
volatile bool g_bPrintfOn = true;
|
||||
|
||||
bool CreateSettings()
|
||||
{
|
||||
g_Settings = new Settings();
|
||||
if (g_Settings == nullptr) {
|
||||
PopupError(nullptr, szSettings_alloc_error);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!g_Settings->Init()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
log_get_settings();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HandleFirstLaunch()
|
||||
{
|
||||
bool bFirstLaunch;
|
||||
g_EmuShared->GetIsFirstLaunch(&bFirstLaunch);
|
||||
|
||||
/* check if process is launch with elevated access then prompt for continue on or not. */
|
||||
if (!bFirstLaunch) {
|
||||
if (!CreateSettings()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Wine will always run programs as administrator by default, it can be safely disregard.
|
||||
// Since Wine doesn't use root permission. Unless user is running Wine as root.
|
||||
bool bElevated = CxbxrIsElevated();
|
||||
if (bElevated && !isWineEnv() && !g_Settings->m_core.allowAdminPrivilege) {
|
||||
PopupReturn ret = PopupWarningEx(nullptr, PopupButtons::YesNo, PopupReturn::No,
|
||||
"Cxbx-Reloaded has detected that it has been launched with Administrator rights.\n"
|
||||
"\nThis is dangerous, as a maliciously modified Xbox titles could take control of your system.\n"
|
||||
"\nAre you sure you want to continue?");
|
||||
if (ret != PopupReturn::Yes) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
g_EmuShared->SetIsFirstLaunch(true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[[noreturn]] void CxbxrShutDown(bool is_reboot)
|
||||
{
|
||||
if (!is_reboot) {
|
||||
// Clear all kernel boot flags. These (together with the shared memory) persist until Cxbx-Reloaded is closed otherwise.
|
||||
int BootFlags = 0;
|
||||
g_EmuShared->SetBootFlags(&BootFlags);
|
||||
}
|
||||
|
||||
// NOTE: This causes a hang when exiting while NV2A is processing
|
||||
// This is okay for now: It won't leak memory or resources since TerminateProcess will free everything
|
||||
// delete g_NV2A; // TODO : g_pXbox
|
||||
|
||||
// Shutdown the input device manager
|
||||
g_InputDeviceManager.Shutdown();
|
||||
|
||||
#ifdef CXBXR_EMU
|
||||
// NOTE: this code causes freezes/crashes at shutdown, so avoid for now
|
||||
// This is very important process to prevent false positive report and allow IDEs to continue debug multiple reboots.
|
||||
//CxbxrKrnlSuspendThreads();
|
||||
|
||||
if (g_io_mu_metadata) {
|
||||
delete g_io_mu_metadata;
|
||||
g_io_mu_metadata = nullptr;
|
||||
}
|
||||
|
||||
// Shutdown the render manager
|
||||
if (g_renderbase != nullptr) {
|
||||
g_renderbase->Shutdown();
|
||||
g_renderbase = nullptr;
|
||||
}
|
||||
|
||||
// NOTE: Require to be after g_renderbase's shutdown process.
|
||||
// NOTE: Must be last step of shutdown process and before CxbxUnlockFilePath call!
|
||||
// Shutdown the memory manager
|
||||
g_VMManager.Shutdown();
|
||||
|
||||
CxbxrUnlockFilePath();
|
||||
|
||||
if (CxbxKrnl_hEmuParent != NULL && !is_reboot) {
|
||||
SendMessage(CxbxKrnl_hEmuParent, WM_PARENTNOTIFY, WM_DESTROY, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
EmuShared::Cleanup();
|
||||
|
||||
TerminateProcess(GetCurrentProcess(), 0);
|
||||
}
|
||||
|
||||
[[noreturn]] void CxbxrAbortEx(CXBXR_MODULE cxbxr_module, const char* szErrorMessage, ...)
|
||||
{
|
||||
// print out error message (if exists)
|
||||
if (szErrorMessage != NULL)
|
||||
{
|
||||
char szBuffer2[1024];
|
||||
va_list argp;
|
||||
|
||||
va_start(argp, szErrorMessage);
|
||||
vsprintf(szBuffer2, szErrorMessage, argp);
|
||||
va_end(argp);
|
||||
|
||||
(void)PopupCustomEx(nullptr, cxbxr_module, LOG_LEVEL::FATAL, PopupIcon::Error, PopupButtons::Ok, PopupReturn::Ok, "Received Fatal Message:\n\n* %s\n", szBuffer2); // Will also EmuLogEx
|
||||
}
|
||||
|
||||
EmuLogInit(LOG_LEVEL::INFO, "MAIN: Terminating Process");
|
||||
fflush(stdout);
|
||||
|
||||
// cleanup debug output
|
||||
{
|
||||
FreeConsole();
|
||||
|
||||
char buffer[16];
|
||||
|
||||
if (GetConsoleTitle(buffer, 16) != NULL)
|
||||
freopen("nul", "w", stdout);
|
||||
}
|
||||
|
||||
CxbxrShutDown();
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
// ******************************************************************
|
||||
// *
|
||||
// * This file is part of the Cxbx-Reloaded project.
|
||||
// *
|
||||
// * Cxbx and Cxbe are free software; you can redistribute them
|
||||
// * and/or modify them under the terms of the GNU General Public
|
||||
// * License as published by the Free Software Foundation; either
|
||||
// * version 2 of the license, or (at your option) any later version.
|
||||
// *
|
||||
// * This program 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 recieved a copy of the GNU General Public License
|
||||
// * along with this program; see the file COPYING.
|
||||
// * If not, write to the Free Software Foundation, Inc.,
|
||||
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <optional>
|
||||
|
||||
#include "Logging.h"
|
||||
|
||||
bool CreateSettings();
|
||||
|
||||
bool HandleFirstLaunch();
|
||||
|
||||
// TODO: Eventually, we should remove this function to start using std::filesystem::path method for all host paths.
|
||||
void CxbxResolveHostToFullPath(std::string& file_path, std::string_view finish_error_sentence);
|
||||
|
||||
// Loads a keys.bin file as generated by dump-xbox
|
||||
// See https://github.com/JayFoxRox/xqemu-tools/blob/master/dump-xbox.c
|
||||
void LoadXboxKeys();
|
||||
|
||||
bool CxbxrLockFilePath();
|
||||
|
||||
void CxbxrUnlockFilePath();
|
||||
|
||||
// Hybrid functions depending on specific platforms
|
||||
bool CxbxrIsElevated();
|
||||
|
||||
std::optional<std::string> CxbxrExec(bool useDebugger, void** hProcess, bool requestHandleProcess);
|
||||
|
||||
/*! cleanup emulation */
|
||||
[[noreturn]] void CxbxrAbortEx(CXBXR_MODULE cxbxr_module, const char* szErrorMessage, ...);
|
||||
|
||||
#define CxbxrAbort(fmt, ...) CxbxrAbortEx(LOG_PREFIX, fmt, ##__VA_ARGS__)
|
||||
|
||||
/*! terminate gracefully the emulation */
|
||||
[[noreturn]] void CxbxrShutDown(bool is_reboot = false);
|
|
@ -27,8 +27,8 @@
|
|||
|
||||
#include "Button.h"
|
||||
#include "InputWindow.h"
|
||||
#include "layout_xbox_controller.h" // TODO: Needs a better fix for custom input device support.
|
||||
#include "..\..\gui\ResCxbx.h"
|
||||
#include "layout_xbox_device.h" // TODO: Needs a better fix for custom input device support.
|
||||
#include "gui/resource/ResCxbx.h"
|
||||
|
||||
|
||||
void Button::EnableButton(bool enable) const
|
||||
|
@ -51,27 +51,41 @@ void Button::GetText(char* const text, size_t size) const
|
|||
SendMessage(m_button_hwnd, WM_GETTEXT, size, reinterpret_cast<LPARAM>(text));
|
||||
}
|
||||
|
||||
std::string Button::GetName(int api, int idx) const
|
||||
void Button::AddTooltip(HWND hwnd, HWND tooltip_hwnd, std::string_view text) const
|
||||
{
|
||||
assert(api == XINPUT_DEFAULT || api == DINPUT_DEFAULT);
|
||||
return button_xbox_ctrl_names[idx][api];
|
||||
assert((hwnd != NULL) && (tooltip_hwnd != NULL));
|
||||
|
||||
std::string tooltip_text(text);
|
||||
TOOLINFO tool = { 0 };
|
||||
tool.cbSize = sizeof(tool);
|
||||
tool.hwnd = hwnd;
|
||||
tool.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
|
||||
tool.uId = reinterpret_cast<UINT_PTR>(m_button_hwnd);
|
||||
tool.lpszText = tooltip_text.data();
|
||||
SendMessage(tooltip_hwnd, TTM_ADDTOOL, 0, reinterpret_cast<LPARAM>(&tool));
|
||||
}
|
||||
|
||||
LRESULT CALLBACK ButtonSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
|
||||
LRESULT CALLBACK ButtonDukeSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
|
||||
{
|
||||
switch (uMsg)
|
||||
{
|
||||
// Remove the window subclass when this window is destroyed
|
||||
case WM_NCDESTROY: {
|
||||
RemoveWindowSubclass(hWnd, ButtonSubclassProc, uIdSubclass);
|
||||
RemoveWindowSubclass(hWnd, ButtonDukeSubclassProc, uIdSubclass);
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_RBUTTONDOWN: {
|
||||
reinterpret_cast<Button*>(dwRefData)->ClearText();
|
||||
g_InputWindow->UpdateProfile(std::string(), BUTTON_CLEAR);
|
||||
if (reinterpret_cast<Button*>(dwRefData)->GetId() == IDC_SET_MOTOR) {
|
||||
g_InputWindow->UpdateProfile(std::string(), RUMBLE_CLEAR);
|
||||
Button *button = reinterpret_cast<Button *>(dwRefData);
|
||||
if (wParam & MK_SHIFT) {
|
||||
static_cast<DukeInputWindow *>(button->GetWnd())->SwapMoCursorAxis(button);
|
||||
}
|
||||
else if (!(wParam & ~MK_RBUTTON)) {
|
||||
button->ClearText();
|
||||
static_cast<DukeInputWindow *>(button->GetWnd())->UpdateProfile(std::string(), BUTTON_CLEAR);
|
||||
if (button->GetId() == IDC_SET_MOTOR) {
|
||||
static_cast<DukeInputWindow *>(button->GetWnd())->UpdateProfile(std::string(), RUMBLE_CLEAR);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -80,3 +94,47 @@ LRESULT CALLBACK ButtonSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM
|
|||
|
||||
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
LRESULT CALLBACK ButtonSbcSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
|
||||
{
|
||||
switch (uMsg)
|
||||
{
|
||||
// Remove the window subclass when this window is destroyed
|
||||
case WM_NCDESTROY: {
|
||||
RemoveWindowSubclass(hWnd, ButtonSbcSubclassProc, uIdSubclass);
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_RBUTTONDOWN: {
|
||||
Button *button = reinterpret_cast<Button *>(dwRefData);
|
||||
button->ClearText();
|
||||
static_cast<SbcInputWindow *>(button->GetWnd())->UpdateProfile(std::string(), BUTTON_CLEAR);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
LRESULT CALLBACK ButtonLightgunSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
|
||||
{
|
||||
switch (uMsg)
|
||||
{
|
||||
// Remove the window subclass when this window is destroyed
|
||||
case WM_NCDESTROY: {
|
||||
RemoveWindowSubclass(hWnd, ButtonLightgunSubclassProc, uIdSubclass);
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_RBUTTONDOWN: {
|
||||
Button *button = reinterpret_cast<Button *>(dwRefData);
|
||||
button->ClearText();
|
||||
static_cast<LightgunInputWindow *>(button->GetWnd())->UpdateProfile(std::string(), BUTTON_CLEAR);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
|
|
@ -31,27 +31,36 @@
|
|||
#include <Commctrl.h>
|
||||
#include <string>
|
||||
|
||||
#define LIGHTGUN_NUM_BUTTONS 17
|
||||
#define XBOX_CTRL_NUM_BUTTONS 25
|
||||
#define SBC_NUM_BUTTONS 56
|
||||
#define HIGHEST_NUM_BUTTONS SBC_NUM_BUTTONS
|
||||
|
||||
#define XBOX_BUTTON_NAME_LENGTH 30
|
||||
#define HOST_BUTTON_NAME_LENGTH 30
|
||||
|
||||
/* Represents the gui buttons of the xbox device currently being configured */
|
||||
class Button
|
||||
{
|
||||
public:
|
||||
Button(int id, int index, HWND hwnd) : m_id(id), m_index(index), m_button_hwnd(GetDlgItem(hwnd, m_id)) {};
|
||||
Button(int id, int index, HWND hwnd, void *wnd) : m_id(id), m_index(index), m_button_hwnd(GetDlgItem(hwnd, m_id)), m_wnd(wnd) {};
|
||||
void EnableButton(bool enable) const;
|
||||
void UpdateText(const char* text) const;
|
||||
void ClearText() const;
|
||||
void GetText(char* const text, size_t size) const;
|
||||
std::string GetName(int api, int idx) const;
|
||||
int GetId() const { return m_id; }
|
||||
int GetIndex() const { return m_index; }
|
||||
void *GetWnd() const { return m_wnd; }
|
||||
void AddTooltip(HWND hwnd, HWND tooltip_hwnd, std::string_view text) const;
|
||||
|
||||
|
||||
private:
|
||||
int m_id;
|
||||
int m_index;
|
||||
HWND m_button_hwnd;
|
||||
void *m_wnd;
|
||||
};
|
||||
|
||||
LRESULT CALLBACK ButtonSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);
|
||||
LRESULT CALLBACK ButtonDukeSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);
|
||||
LRESULT CALLBACK ButtonSbcSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);
|
||||
LRESULT CALLBACK ButtonLightgunSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include "DInputKeyboardMouse.h"
|
||||
#include "InputManager.h"
|
||||
#include "core\kernel\support\Emu.h"
|
||||
#include <algorithm>
|
||||
|
||||
// Unfortunately, sdl doesn't seem to be able to capture keyboard/mouse input from windows it didn't create (we currently use
|
||||
// win32 for that). So unless we create sdl windows, we will have to keep dinput around to handle keyboard/mouse input.
|
||||
|
@ -51,8 +52,6 @@ namespace DInput
|
|||
#include "DInputKeyboardCodes.h"
|
||||
};
|
||||
|
||||
bool bKbMoEnumerated = false;
|
||||
|
||||
void InitKeyboardMouse(IDirectInput8* idi8)
|
||||
{
|
||||
// From Dolphin: "mouse and keyboard are a combined device, to allow shift+click and stuff
|
||||
|
@ -60,26 +59,27 @@ namespace DInput
|
|||
// other devices so there can be a separated Keyboard and mouse, as well as combined KeyboardMouse"
|
||||
|
||||
LPDIRECTINPUTDEVICE8 kb_device = nullptr;
|
||||
//LPDIRECTINPUTDEVICE8 mo_device = nullptr;
|
||||
LPDIRECTINPUTDEVICE8 mo_device = nullptr;
|
||||
|
||||
if (SUCCEEDED(idi8->CreateDevice(GUID_SysKeyboard, &kb_device, nullptr)) &&
|
||||
SUCCEEDED(kb_device->SetDataFormat(&c_dfDIKeyboard)) &&
|
||||
SUCCEEDED(kb_device->SetCooperativeLevel(nullptr, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE))) //&&
|
||||
//SUCCEEDED(idi8->CreateDevice(GUID_SysMouse, &mo_device, nullptr)) &&
|
||||
//SUCCEEDED(mo_device->SetDataFormat(&c_dfDIMouse2)) &&
|
||||
//SUCCEEDED(mo_device->SetCooperativeLevel(nullptr, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE)))
|
||||
SUCCEEDED(kb_device->SetCooperativeLevel(nullptr, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE)) &&
|
||||
SUCCEEDED(idi8->CreateDevice(GUID_SysMouse, &mo_device, nullptr)) &&
|
||||
SUCCEEDED(mo_device->SetDataFormat(&c_dfDIMouse2)) &&
|
||||
SUCCEEDED(mo_device->SetCooperativeLevel(nullptr, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE)))
|
||||
{
|
||||
g_InputDeviceManager.AddDevice(std::make_shared<KeyboardMouse>(kb_device));
|
||||
g_InputDeviceManager.AddDevice(std::make_shared<KeyboardMouse>(kb_device, mo_device));
|
||||
bKbMoEnumerated = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (kb_device)
|
||||
if (kb_device) {
|
||||
kb_device->Release();
|
||||
#if 0
|
||||
if (mo_device)
|
||||
}
|
||||
|
||||
if (mo_device) {
|
||||
mo_device->Release();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void PopulateDevices()
|
||||
|
@ -104,36 +104,46 @@ namespace DInput
|
|||
PopulateDevices();
|
||||
}
|
||||
|
||||
KeyboardMouse::KeyboardMouse(const LPDIRECTINPUTDEVICE8 kb_device)
|
||||
: m_kb_device(kb_device)//, m_mo_device(mo_device)
|
||||
KeyboardMouse::KeyboardMouse(const LPDIRECTINPUTDEVICE8 kb_device, const LPDIRECTINPUTDEVICE8 mo_device)
|
||||
: m_kb_device(kb_device), m_mo_device(mo_device)
|
||||
{
|
||||
m_kb_device->Acquire();
|
||||
//m_mo_device->Acquire();
|
||||
m_mo_device->Acquire();
|
||||
|
||||
memset(&m_state_in, 0, sizeof(m_state_in));
|
||||
std::memset(&m_state_in, 0, sizeof(m_state_in));
|
||||
|
||||
// KEYBOARD
|
||||
// add keys
|
||||
for (uint8_t i = 0; i < sizeof(named_keys) / sizeof(*named_keys); ++i) {
|
||||
AddInput(new Key(i, m_state_in.keyboard[named_keys[i].code]));
|
||||
}
|
||||
#if 0
|
||||
|
||||
// MOUSE
|
||||
// get caps
|
||||
DIDEVCAPS mouse_caps;
|
||||
memset(&mouse_caps, 0, sizeof(mouse_caps));
|
||||
std::memset(&mouse_caps, 0, sizeof(mouse_caps));
|
||||
mouse_caps.dwSize = sizeof(mouse_caps);
|
||||
m_mo_device->GetCapabilities(&mouse_caps);
|
||||
|
||||
// mouse buttons
|
||||
for (unsigned char i = 0; i < mouse_caps.dwButtons; ++i) {
|
||||
AddInput(new Button(i, m_state_in.mouse.rgbButtons[i]));
|
||||
}
|
||||
|
||||
// cursor, with a hax for-loop
|
||||
for (unsigned int i = 0; i < 4; ++i) {
|
||||
AddInput(new Cursor(!!(i & 2), (&m_state_in.cursor.x)[i / 2], !!(i & 1)));
|
||||
// mouse axes
|
||||
for (unsigned int i = 0; i < mouse_caps.dwAxes; ++i) {
|
||||
const LONG &ax = (&m_state_in.mouse.lX)[i];
|
||||
|
||||
// each axis gets a negative and a positive input instance associated with it
|
||||
AddInput(new Axis(i, ax, (2 == i) ? mo_wheel_range_neg : mo_axis_range_neg));
|
||||
AddInput(new Axis(i, ax, (2 == i) ? mo_wheel_range_pos : mo_axis_range_pos));
|
||||
}
|
||||
#endif
|
||||
|
||||
// mouse cursor
|
||||
AddInput(new Cursor(0, m_state_in.cursor.x, -1.0));
|
||||
AddInput(new Cursor(0, m_state_in.cursor.x, 1.0));
|
||||
AddInput(new Cursor(1, m_state_in.cursor.y, -1.0));
|
||||
AddInput(new Cursor(1, m_state_in.cursor.y, 1.0));
|
||||
}
|
||||
|
||||
KeyboardMouse::~KeyboardMouse()
|
||||
|
@ -141,85 +151,66 @@ namespace DInput
|
|||
// kb
|
||||
m_kb_device->Unacquire();
|
||||
m_kb_device->Release();
|
||||
#if 0
|
||||
|
||||
// mouse
|
||||
m_mo_device->Unacquire();
|
||||
m_mo_device->Release();
|
||||
#endif
|
||||
}
|
||||
|
||||
void GetMousePos(ControlState* const x, ControlState* const y)
|
||||
{
|
||||
POINT point = { 1, 1 };
|
||||
GetCursorPos(&point);
|
||||
// Get the cursor position relative to the upper left corner of the current window
|
||||
HWND hwnd = WindowFromPoint(point);
|
||||
DWORD processId;
|
||||
GetWindowThreadProcessId(hwnd, &processId);
|
||||
if (processId == GetCurrentProcessId())
|
||||
{
|
||||
ScreenToClient(hwnd, &point);
|
||||
|
||||
// Get the size of the current window.
|
||||
RECT rect;
|
||||
GetClientRect(hwnd, &rect);
|
||||
// Width and height is the size of the rendering window
|
||||
unsigned int win_width = rect.right - rect.left;
|
||||
unsigned int win_height = rect.bottom - rect.top;
|
||||
|
||||
// Return the mouse position as a range from -1 to 1
|
||||
*x = (ControlState)point.x / (ControlState)win_width * 2 - 1;
|
||||
*y = (ControlState)point.y / (ControlState)win_height * 2 - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
*x = (ControlState)0;
|
||||
*y = (ControlState)0;
|
||||
}
|
||||
}
|
||||
|
||||
bool KeyboardMouse::UpdateInput()
|
||||
{
|
||||
// Update keyboard and mouse button states
|
||||
if (static_cast<uint8_t>(mo_leave_wnd) & static_cast<uint8_t>(IgnoreKbMoUnfocus)) {
|
||||
std::memset(&m_state_in, 0, sizeof(m_state_in));
|
||||
return true;
|
||||
}
|
||||
|
||||
DIMOUSESTATE2 tmp_mouse;
|
||||
|
||||
HRESULT kb_hr = m_kb_device->GetDeviceState(sizeof(m_state_in.keyboard), &m_state_in.keyboard);
|
||||
//HRESULT mo_hr = m_mo_device->GetDeviceState(sizeof(m_state_in.mouse), &m_state_in.mouse);
|
||||
HRESULT mo_hr = m_mo_device->GetDeviceState(sizeof(tmp_mouse), &tmp_mouse);
|
||||
|
||||
if (DIERR_INPUTLOST == kb_hr || DIERR_NOTACQUIRED == kb_hr) {
|
||||
m_kb_device->Acquire();
|
||||
}
|
||||
#if 0
|
||||
|
||||
if (DIERR_INPUTLOST == mo_hr || DIERR_NOTACQUIRED == mo_hr) {
|
||||
m_mo_device->Acquire();
|
||||
}
|
||||
#endif
|
||||
if (SUCCEEDED(kb_hr)) //&& SUCCEEDED(mo_hr))
|
||||
|
||||
if (SUCCEEDED(kb_hr) && SUCCEEDED(mo_hr))
|
||||
{
|
||||
#if 0
|
||||
ControlState temp_x, temp_y;
|
||||
// NOTE: the /= 2 will cause the mouse input to naturally decay to zero if the mouse did not change its position
|
||||
for (unsigned int i = 0; i < 3; ++i) {
|
||||
((&m_state_in.mouse.lX)[i] += (&tmp_mouse.lX)[i]) /= 2;
|
||||
}
|
||||
|
||||
// Update absolute mouse position
|
||||
GetMousePos(&m_state_in.cursor.x, &m_state_in.cursor.y);
|
||||
std::memcpy(m_state_in.mouse.rgbButtons, tmp_mouse.rgbButtons, sizeof(m_state_in.mouse.rgbButtons));
|
||||
UpdateCursorPosition();
|
||||
|
||||
// Save current absolute mouse position
|
||||
temp_x = m_state_in.cursor.x;
|
||||
temp_y = m_state_in.cursor.y;
|
||||
|
||||
// Update relative mouse motion
|
||||
m_state_in.cursor.x -= m_state_in.cursor.last_x;
|
||||
m_state_in.cursor.y -= m_state_in.cursor.last_y;
|
||||
|
||||
// Update previous absolute mouse position
|
||||
m_state_in.cursor.last_x = temp_x;
|
||||
m_state_in.cursor.last_y = temp_y;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void KeyboardMouse::UpdateCursorPosition()
|
||||
{
|
||||
POINT point = {};
|
||||
GetCursorPos(&point);
|
||||
ScreenToClient(m_hwnd, &point);
|
||||
RECT rect;
|
||||
GetClientRect(m_hwnd, &rect);
|
||||
const auto width = std::max(rect.right - rect.left, 1l);
|
||||
const auto height = std::max(rect.bottom - rect.top, 1l);
|
||||
|
||||
// Convert the window client coordinates to normalized device coordinates
|
||||
m_state_in.cursor.x = ((2 * static_cast<ControlState>(point.x)) / width) - 1;
|
||||
m_state_in.cursor.y = ((-2 * static_cast<ControlState>(point.y)) / height) + 1;
|
||||
}
|
||||
|
||||
std::string KeyboardMouse::GetDeviceName() const
|
||||
{
|
||||
return "Keyboard";
|
||||
return "KeyboardMouse";
|
||||
}
|
||||
|
||||
std::string KeyboardMouse::GetAPI() const
|
||||
|
@ -237,11 +228,19 @@ namespace DInput
|
|||
return std::string("Click ") + char('0' + m_index);
|
||||
}
|
||||
|
||||
std::string KeyboardMouse::Axis::GetName() const
|
||||
{
|
||||
static char tmpstr[] = "Axis ..";
|
||||
tmpstr[5] = (char)('X' + m_index);
|
||||
tmpstr[6] = (m_range < 0 ? '-' : '+');
|
||||
return tmpstr;
|
||||
}
|
||||
|
||||
std::string KeyboardMouse::Cursor::GetName() const
|
||||
{
|
||||
static char tmpstr[] = "Cursor ..";
|
||||
tmpstr[7] = (char)('X' + m_index);
|
||||
tmpstr[8] = (m_positive ? '+' : '-');
|
||||
tmpstr[8] = (m_range == 1.0 ? '+' : '-');
|
||||
return tmpstr;
|
||||
}
|
||||
|
||||
|
@ -255,8 +254,13 @@ namespace DInput
|
|||
return (m_button != 0);
|
||||
}
|
||||
|
||||
ControlState KeyboardMouse::Axis::GetState() const
|
||||
{
|
||||
return std::clamp(ControlState(m_axis) / m_range, 0.0, 1.0);
|
||||
}
|
||||
|
||||
ControlState KeyboardMouse::Cursor::GetState() const
|
||||
{
|
||||
return std::max(0.0, ControlState(m_axis) / (m_positive ? 1.0 : -1.0));
|
||||
return std::max(0.0, m_cursor / m_range);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,18 +34,25 @@
|
|||
|
||||
namespace DInput
|
||||
{
|
||||
extern bool bKbMoEnumerated;
|
||||
inline bool bKbMoEnumerated = false;
|
||||
inline bool mo_leave_wnd = false;
|
||||
inline bool IgnoreKbMoUnfocus = true;
|
||||
inline LONG mo_axis_range_pos = 0;
|
||||
inline LONG mo_axis_range_neg = 0;
|
||||
inline LONG mo_wheel_range_pos = 0;
|
||||
inline LONG mo_wheel_range_neg = 0;
|
||||
void GetDeviceChanges();
|
||||
void PopulateDevices();
|
||||
|
||||
class KeyboardMouse : public InputDevice
|
||||
{
|
||||
public:
|
||||
KeyboardMouse(const LPDIRECTINPUTDEVICE8 kb_device);
|
||||
KeyboardMouse(const LPDIRECTINPUTDEVICE8 kb_device, const LPDIRECTINPUTDEVICE8 mo_device);
|
||||
~KeyboardMouse();
|
||||
std::string GetDeviceName() const override;
|
||||
std::string GetAPI() const override;
|
||||
bool UpdateInput() override;
|
||||
void SetHwnd(HWND hwnd) { m_hwnd = hwnd; }
|
||||
|
||||
|
||||
private:
|
||||
|
@ -73,19 +80,34 @@ namespace DInput
|
|||
const uint8_t m_index;
|
||||
};
|
||||
|
||||
class Cursor : public Input
|
||||
// gives mouse input based on relative motion
|
||||
class Axis : public Input
|
||||
{
|
||||
public:
|
||||
Cursor(uint8_t index, const ControlState& axis, const bool positive)
|
||||
: m_axis(axis), m_index(index), m_positive(positive) {}
|
||||
Axis(uint8_t index, const LONG &axis, const LONG &range) : m_axis(axis), m_range(range), m_index(index) {}
|
||||
std::string GetName() const override;
|
||||
bool IsDetectable() override { return true; }
|
||||
ControlState GetState() const override;
|
||||
|
||||
private:
|
||||
const ControlState& m_axis;
|
||||
const LONG &m_axis;
|
||||
const LONG &m_range;
|
||||
const uint8_t m_index;
|
||||
};
|
||||
|
||||
// gives mouse input based on cursor position relative to the rendering window
|
||||
class Cursor : public Input
|
||||
{
|
||||
public:
|
||||
Cursor(uint8_t index, const ControlState &cursor, const ControlState range)
|
||||
: m_cursor(cursor), m_index(index), m_range(range) {}
|
||||
std::string GetName() const override;
|
||||
ControlState GetState() const override;
|
||||
bool IsDetectable() const override { return false; }
|
||||
|
||||
private:
|
||||
const ControlState &m_cursor;
|
||||
const ControlState m_range;
|
||||
const uint8_t m_index;
|
||||
const bool m_positive;
|
||||
};
|
||||
|
||||
struct State
|
||||
|
@ -94,12 +116,15 @@ namespace DInput
|
|||
DIMOUSESTATE2 mouse;
|
||||
struct
|
||||
{
|
||||
ControlState x, y, last_x, last_y;
|
||||
ControlState x, y;
|
||||
} cursor;
|
||||
};
|
||||
|
||||
void UpdateCursorPosition();
|
||||
|
||||
const LPDIRECTINPUTDEVICE8 m_kb_device;
|
||||
//const LPDIRECTINPUTDEVICE8 m_mo_device;
|
||||
const LPDIRECTINPUTDEVICE8 m_mo_device;
|
||||
State m_state_in;
|
||||
HWND m_hwnd;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -25,35 +25,64 @@
|
|||
// *
|
||||
// ******************************************************************
|
||||
|
||||
#include"Button.h"
|
||||
#include <algorithm>
|
||||
#include "Button.h"
|
||||
#include "InputManager.h"
|
||||
#include "layout_xbox_controller.h"
|
||||
#include "..\..\gui\ResCxbx.h"
|
||||
#include "layout_xbox_device.h"
|
||||
#include "gui/resource/ResCxbx.h"
|
||||
|
||||
|
||||
EmuDevice::EmuDevice(int type, HWND hwnd)
|
||||
static const char *tooltip_text_toggle = "Left-click: start input detection\nRight-click: clear binding\nShift + right-click: toggle mouse input mode";
|
||||
static const char *tooltip_text_no_toggle = "Left-click: start input detection\nRight-click: clear binding";
|
||||
|
||||
EmuDevice::EmuDevice(int type, HWND hwnd, void *wnd)
|
||||
{
|
||||
m_hwnd = hwnd;
|
||||
CreateTooltipWindow();
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE):
|
||||
case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_S): {
|
||||
m_hwnd = hwnd;
|
||||
for (int i = 0; i < ARRAY_SIZE(button_xbox_ctrl_id); i++) {
|
||||
m_buttons.push_back(new Button(button_xbox_ctrl_id[i], i, hwnd));
|
||||
case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE):
|
||||
case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_S):
|
||||
case to_underlying(XBOX_INPUT_DEVICE::ARCADE_STICK): {
|
||||
for (size_t i = 0; i < ARRAY_SIZE(button_xbox_ctrl_id); i++) {
|
||||
m_buttons.push_back(new Button(button_xbox_ctrl_id[i], i, hwnd, wnd));
|
||||
m_buttons.back()->AddTooltip(m_hwnd, m_tooltip_hwnd, tooltip_text_toggle);
|
||||
|
||||
// Install the subclass for the button control
|
||||
SetWindowSubclass(GetDlgItem(hwnd, button_xbox_ctrl_id[i]), ButtonSubclassProc, 0, reinterpret_cast<DWORD_PTR>(m_buttons[i]));
|
||||
SetWindowSubclass(GetDlgItem(hwnd, button_xbox_ctrl_id[i]), ButtonDukeSubclassProc, 0, reinterpret_cast<DWORD_PTR>(m_buttons[i]));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case to_underlying(XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER): {
|
||||
for (size_t i = 0; i < ARRAY_SIZE(button_sbc_id); i++) {
|
||||
m_buttons.push_back(new Button(button_sbc_id[i], i, hwnd, wnd));
|
||||
m_buttons.back()->AddTooltip(m_hwnd, m_tooltip_hwnd, tooltip_text_no_toggle);
|
||||
|
||||
// Install the subclass for the button control
|
||||
SetWindowSubclass(GetDlgItem(hwnd, button_sbc_id[i]), ButtonSbcSubclassProc, 0, reinterpret_cast<DWORD_PTR>(m_buttons[i]));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case to_underlying(XBOX_INPUT_DEVICE::LIGHTGUN): {
|
||||
for (size_t i = 0; i < ARRAY_SIZE(button_lightgun_id); i++) {
|
||||
m_buttons.push_back(new Button(button_lightgun_id[i], i, hwnd, wnd));
|
||||
m_buttons.back()->AddTooltip(m_hwnd, m_tooltip_hwnd, tooltip_text_no_toggle);
|
||||
|
||||
// Install the subclass for the button control
|
||||
SetWindowSubclass(GetDlgItem(hwnd, button_lightgun_id[i]), ButtonLightgunSubclassProc, 0, reinterpret_cast<DWORD_PTR>(m_buttons[i]));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
EmuDevice::~EmuDevice()
|
||||
{
|
||||
DestroyWindow(m_tooltip_hwnd);
|
||||
for (auto button : m_buttons) {
|
||||
delete button;
|
||||
}
|
||||
|
@ -76,10 +105,11 @@ Button* EmuDevice::FindButtonByIndex(int index)
|
|||
return m_buttons[index];
|
||||
}
|
||||
|
||||
void EmuDevice::BindDefault(int api)
|
||||
template<size_t size>
|
||||
void EmuDevice::BindDefault(const std::array<const char *, size> &arr)
|
||||
{
|
||||
std::for_each(m_buttons.begin(), m_buttons.end(), [&api](const auto button) {
|
||||
button->UpdateText(button->GetName(api, button->GetIndex()).c_str());
|
||||
std::for_each(m_buttons.begin(), m_buttons.end(), [&arr](const auto button) {
|
||||
button->UpdateText(arr[button->GetIndex()]);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -89,3 +119,20 @@ void EmuDevice::ClearButtons()
|
|||
button->ClearText();
|
||||
});
|
||||
}
|
||||
|
||||
void EmuDevice::CreateTooltipWindow()
|
||||
{
|
||||
m_tooltip_hwnd = CreateWindow(TOOLTIPS_CLASS, NULL,
|
||||
WS_POPUP | TTS_ALWAYSTIP,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
m_hwnd, NULL,
|
||||
GetModuleHandle(NULL), NULL);
|
||||
|
||||
SendMessage(m_tooltip_hwnd, TTM_ACTIVATE, TRUE, 0);
|
||||
SendMessage(m_tooltip_hwnd, TTM_SETMAXTIPWIDTH, 0, 500);
|
||||
SendMessage(m_tooltip_hwnd, TTM_SETDELAYTIME, TTDT_AUTOPOP, 15000);
|
||||
}
|
||||
|
||||
template void EmuDevice::BindDefault(const std::array<const char*, XBOX_CTRL_NUM_BUTTONS>& arr);
|
||||
template void EmuDevice::BindDefault(const std::array<const char *, LIGHTGUN_NUM_BUTTONS> &arr);
|
||||
|
|
|
@ -29,21 +29,29 @@
|
|||
|
||||
#include "Button.h"
|
||||
#include "common\util\CxbxUtil.h"
|
||||
#include <array>
|
||||
|
||||
|
||||
/* Represents the guest device currently being configured in the gui */
|
||||
class EmuDevice
|
||||
{
|
||||
public:
|
||||
EmuDevice(int type, HWND hwnd);
|
||||
EmuDevice(int type, HWND hwnd, void *wnd);
|
||||
~EmuDevice();
|
||||
Button* FindButtonById(int id);
|
||||
Button* FindButtonByIndex(int index);
|
||||
void BindDefault(int api);
|
||||
template<size_t size>
|
||||
void BindDefault(const std::array<const char *, size> &arr);
|
||||
void ClearButtons();
|
||||
|
||||
|
||||
private:
|
||||
void CreateTooltipWindow();
|
||||
|
||||
std::vector<Button*> m_buttons;
|
||||
HWND m_hwnd;
|
||||
HWND m_tooltip_hwnd;
|
||||
};
|
||||
|
||||
extern template void EmuDevice::BindDefault(const std::array<const char *, XBOX_CTRL_NUM_BUTTONS> &arr);
|
||||
extern template void EmuDevice::BindDefault(const std::array<const char *, LIGHTGUN_NUM_BUTTONS> &arr);
|
||||
|
|
|
@ -33,8 +33,10 @@
|
|||
// https://github.com/dolphin-emu/dolphin
|
||||
|
||||
#include "InputDevice.h"
|
||||
#include "InputManager.h"
|
||||
#include "common\util\CxbxUtil.h"
|
||||
#include <algorithm>
|
||||
#include <charconv>
|
||||
|
||||
|
||||
std::string GetInputDeviceName(int dev_type)
|
||||
|
@ -43,46 +45,53 @@ std::string GetInputDeviceName(int dev_type)
|
|||
|
||||
switch (dev_type)
|
||||
{
|
||||
case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE): {
|
||||
case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE):
|
||||
str = "MS Gamepad Duke";
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_S): {
|
||||
case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_S):
|
||||
str = "MS Gamepad S";
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
case to_underlying(XBOX_INPUT_DEVICE::LIGHT_GUN): {
|
||||
str = "Light gun";
|
||||
}
|
||||
break;
|
||||
case to_underlying(XBOX_INPUT_DEVICE::LIGHTGUN):
|
||||
str = "EMS TopGun II";
|
||||
break;
|
||||
|
||||
case to_underlying(XBOX_INPUT_DEVICE::STEERING_WHEEL): {
|
||||
case to_underlying(XBOX_INPUT_DEVICE::STEERING_WHEEL):
|
||||
str = "Steering wheel";
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
case to_underlying(XBOX_INPUT_DEVICE::MEMORY_UNIT): {
|
||||
case to_underlying(XBOX_INPUT_DEVICE::MEMORY_UNIT):
|
||||
str = "Memory unit";
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
case to_underlying(XBOX_INPUT_DEVICE::IR_DONGLE): {
|
||||
case to_underlying(XBOX_INPUT_DEVICE::IR_DONGLE):
|
||||
str = "IR dongle";
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
case to_underlying(XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER): {
|
||||
case to_underlying(XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER):
|
||||
str = "Steel battalion controller";
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
case to_underlying(XBOX_INPUT_DEVICE::ARCADE_STICK):
|
||||
str = "Arcade joystick";
|
||||
break;
|
||||
|
||||
case to_underlying(XBOX_INPUT_DEVICE::HW_STEEL_BATTALION_CONTROLLER):
|
||||
str = "Passthrough steel battalion controller";
|
||||
break;
|
||||
|
||||
case to_underlying(XBOX_INPUT_DEVICE::HW_XBOX_CONTROLLER):
|
||||
str = "Passthrough original xbox gamepad";
|
||||
break;
|
||||
|
||||
case to_underlying(XBOX_INPUT_DEVICE::DEVICE_INVALID):
|
||||
case to_underlying(XBOX_INPUT_DEVICE::DEVICE_MAX): {
|
||||
str = "None";
|
||||
break;
|
||||
|
||||
case to_underlying(XBOX_INPUT_DEVICE::DEVICE_MAX):
|
||||
str = "Invalid";
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
default:
|
||||
str = "Unknown";
|
||||
|
@ -91,6 +100,33 @@ std::string GetInputDeviceName(int dev_type)
|
|||
return str;
|
||||
}
|
||||
|
||||
std::string PortUserFormat(std::string_view port)
|
||||
{
|
||||
int port_num, slot;
|
||||
PortStr2Int(port, &port_num, &slot);
|
||||
++port_num;
|
||||
if (slot != PORT_INVALID) {
|
||||
++slot;
|
||||
return std::to_string(port_num) + "." + std::to_string(slot);
|
||||
}
|
||||
else {
|
||||
return std::to_string(port_num);
|
||||
}
|
||||
}
|
||||
|
||||
void PortStr2Int(std::string_view port, int *port_num, int *slot)
|
||||
{
|
||||
*slot = PORT_INVALID;
|
||||
auto ret = std::from_chars(port.data(), port.data() + port.size(), *port_num);
|
||||
assert(ret.ec != std::errc::invalid_argument);
|
||||
if (ret.ptr != port.data() + port.size()) {
|
||||
++ret.ptr;
|
||||
ret = std::from_chars(ret.ptr, port.data() + port.size(), *slot);
|
||||
assert(ret.ec != std::errc::invalid_argument);
|
||||
assert(ret.ptr == port.data() + port.size());
|
||||
}
|
||||
}
|
||||
|
||||
// Destructor, delete all inputs/outputs on device destruction
|
||||
InputDevice::~InputDevice()
|
||||
{
|
||||
|
@ -131,3 +167,31 @@ const std::vector<InputDevice::IoControl*> InputDevice::GetIoControls()
|
|||
});
|
||||
return vec;
|
||||
}
|
||||
|
||||
const auto InputDevice::FindPort(std::string_view Port) const
|
||||
{
|
||||
return std::find_if(m_XboxPort.begin(), m_XboxPort.end(), [Port](std::string_view CurrPort) {
|
||||
if (CurrPort == Port) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
void InputDevice::SetPort2(std::string_view Port, bool Connect)
|
||||
{
|
||||
if (Connect) {
|
||||
m_XboxPort.emplace_back(Port);
|
||||
}
|
||||
else {
|
||||
const auto &it = FindPort(Port);
|
||||
if (it != m_XboxPort.end()) {
|
||||
m_XboxPort.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool InputDevice::GetPort(std::string_view Port) const
|
||||
{
|
||||
return FindPort(Port) != m_XboxPort.end() ? true : false;
|
||||
}
|
||||
|
|
|
@ -36,18 +36,11 @@
|
|||
#include <condition_variable>
|
||||
#include "SDL.h"
|
||||
|
||||
#define PORT_INVALID -1
|
||||
#define PORT_1 0
|
||||
#define PORT_2 1
|
||||
#define PORT_3 2
|
||||
#define PORT_4 3
|
||||
|
||||
#define PORT_INC(port) ((port) + 1)
|
||||
#define PORT_DEC(port) ((port) - 1)
|
||||
|
||||
#define DIRECTION_IN 0
|
||||
#define DIRECTION_OUT 1
|
||||
|
||||
#define MO_AXIS_DEFAULT_RANGE 10l
|
||||
#define MO_WHEEL_DEFAULT_RANGE 80l
|
||||
|
||||
typedef double ControlState;
|
||||
|
||||
|
@ -56,20 +49,30 @@ typedef enum class _XBOX_INPUT_DEVICE : int {
|
|||
DEVICE_INVALID = -1,
|
||||
MS_CONTROLLER_DUKE,
|
||||
MS_CONTROLLER_S,
|
||||
LIGHT_GUN,
|
||||
LIGHTGUN,
|
||||
STEERING_WHEEL,
|
||||
MEMORY_UNIT,
|
||||
IR_DONGLE,
|
||||
STEEL_BATTALION_CONTROLLER,
|
||||
ARCADE_STICK,
|
||||
DEVICE_MAX,
|
||||
// Devices with the HW_ prefix (= hardware) indicate a real xbox device. Always add these after DEVICE_MAX
|
||||
HW_STEEL_BATTALION_CONTROLLER,
|
||||
HW_XBOX_CONTROLLER,
|
||||
}
|
||||
XBOX_INPUT_DEVICE;
|
||||
|
||||
// Lookup array used to translate a gui port to an xbox usb port and vice versa
|
||||
extern int Gui2XboxPortArray[4];
|
||||
// Flags that indicate that WM_MOUSELEAVE and WM_MOUSEMOVE respectively are being tracked in the rendering window procedure
|
||||
inline bool g_bIsTrackingMoLeave = false;
|
||||
inline bool g_bIsTrackingMoMove = false;
|
||||
|
||||
// Global function used to retrieve the printable name of a xid type
|
||||
|
||||
// Retrieves the printable name of a xid type
|
||||
std::string GetInputDeviceName(int dev_type);
|
||||
// Converts the port number in the user format
|
||||
std::string PortUserFormat(std::string_view);
|
||||
// Extracts port and slot number from a port formatted as a string
|
||||
void PortStr2Int(std::string_view port, int *port_num, int *slot);
|
||||
|
||||
/* Abstract class which represents a host device usable for input/output */
|
||||
class InputDevice
|
||||
|
@ -87,7 +90,7 @@ public:
|
|||
{
|
||||
public:
|
||||
virtual ControlState GetState() const = 0;
|
||||
virtual bool IsDetectable() { return true; }
|
||||
virtual bool IsDetectable() const { return true; };
|
||||
};
|
||||
|
||||
class Output : public IoControl
|
||||
|
@ -117,9 +120,12 @@ public:
|
|||
// sets the ID of this device
|
||||
void SetId(int ID) { m_ID = ID; }
|
||||
// retrieves the port this device is attached to
|
||||
bool GetPort(int Port) const { return m_XboxPort[Port]; }
|
||||
bool GetPort(std::string_view Port) const;
|
||||
// sets the port this device is attached to
|
||||
void SetPort(int Port, bool Connect) { m_XboxPort[Port] = Connect; }
|
||||
// NOTE: using SetPort2 to avoid a collision with the SetPort macro provided by Windows headers
|
||||
void SetPort2(std::string_view Port, bool Connect);
|
||||
// retuns true if it is a libusb device, false otherwise
|
||||
virtual bool IsLibusb() const { return false; };
|
||||
|
||||
|
||||
protected:
|
||||
|
@ -127,6 +133,8 @@ protected:
|
|||
void AddInput(Input* const In);
|
||||
// adds an output control to the device
|
||||
void AddOutput(Output* const Out);
|
||||
// searches for a port
|
||||
const auto FindPort(std::string_view Port) const;
|
||||
// indicates that the device has new input data available
|
||||
bool m_bDirty;
|
||||
// lock for the bindings map
|
||||
|
@ -134,52 +142,32 @@ protected:
|
|||
|
||||
public:
|
||||
// retrieves the map of input bindings
|
||||
const std::map<int, IoControl*> GetBindings() const {
|
||||
const std::map<int, IoControl*> GetBindings(const std::string &Port) const {
|
||||
std::lock_guard<std::mutex> lck(m_BindingsMtx);
|
||||
return m_Bindings;
|
||||
return m_Bindings.find(Port)->second;
|
||||
}
|
||||
// sets a pair in the map of the input bindings
|
||||
void SetBindings(int XButton, IoControl* Control) {
|
||||
void SetBindings(int XButton, IoControl* Control, const std::string &Port) {
|
||||
std::lock_guard<std::mutex> lck(m_BindingsMtx);
|
||||
m_Bindings[XButton] = Control;
|
||||
m_Bindings[Port][XButton] = Control;
|
||||
}
|
||||
|
||||
protected:
|
||||
class FullAnalogSurface : public Input
|
||||
{
|
||||
public:
|
||||
FullAnalogSurface(Input* Low, Input* High) : m_Low(*Low), m_High(*High) {}
|
||||
ControlState GetState() const override
|
||||
{
|
||||
return (1 + m_High.GetState() - m_Low.GetState()) / 2;
|
||||
}
|
||||
|
||||
std::string GetName() const override { return m_Low.GetName() + *m_High.GetName().rbegin(); }
|
||||
|
||||
private:
|
||||
Input& m_Low;
|
||||
Input& m_High;
|
||||
};
|
||||
|
||||
void AddAnalogInputs(Input* Low, Input* High)
|
||||
{
|
||||
AddInput(Low);
|
||||
AddInput(High);
|
||||
AddInput(new FullAnalogSurface(Low, High));
|
||||
AddInput(new FullAnalogSurface(High, Low));
|
||||
// clears all input bindings for the specified xbox port
|
||||
void ClearBindings(const std::string &Port) {
|
||||
std::lock_guard<std::mutex> lck(m_BindingsMtx);
|
||||
m_Bindings[Port].clear();
|
||||
}
|
||||
|
||||
private:
|
||||
// arbitrary ID assigned by to the device
|
||||
// arbitrary ID assigned to the device
|
||||
int m_ID;
|
||||
// all the input controls detected and usable on this device
|
||||
std::vector<Input*> m_Inputs;
|
||||
// all the output controls detected and usable on this device
|
||||
std::vector<Output*> m_Outputs;
|
||||
// xbox port(s) this device is attached to
|
||||
bool m_XboxPort[4] = { false };
|
||||
// button bindings to the xbox device buttons
|
||||
std::map<int, IoControl*> m_Bindings;
|
||||
std::vector<std::string> m_XboxPort;
|
||||
// per xbox port button bindings to the xbox device buttons
|
||||
std::unordered_map<std::string, std::map<int, IoControl*>> m_Bindings;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -31,17 +31,62 @@
|
|||
#include <thread>
|
||||
#include "InputDevice.h"
|
||||
#include "EmuDevice.h"
|
||||
#include <imgui.h>
|
||||
|
||||
// Prevent a collision with the SetPort provided by Windows
|
||||
#ifdef WIN32
|
||||
#undef SetPort
|
||||
#endif
|
||||
#define PORT_INVALID -1
|
||||
#define PORT_1 0
|
||||
#define PORT_2 1
|
||||
#define PORT_3 2
|
||||
#define PORT_4 3
|
||||
#define XBOX_NUM_PORTS 4
|
||||
|
||||
#define SLOT_TOP 0
|
||||
#define SLOT_BOTTOM 1
|
||||
#define XBOX_CTRL_NUM_SLOTS 2
|
||||
|
||||
#define CTRL_OFFSET 0
|
||||
#define MU_OFFSET 4
|
||||
#define MAX_DEVS (XBOX_NUM_PORTS + XBOX_CTRL_NUM_SLOTS * XBOX_NUM_PORTS)
|
||||
|
||||
#define XID_PACKET_HEADER 2
|
||||
|
||||
#define LIGHTGUN_GRIP_DELAY 30
|
||||
|
||||
extern int dev_num_buttons[to_underlying(XBOX_INPUT_DEVICE::DEVICE_MAX)];
|
||||
|
||||
inline XBOX_INPUT_DEVICE input_support_list[] = {
|
||||
XBOX_INPUT_DEVICE::DEVICE_INVALID,
|
||||
XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE,
|
||||
XBOX_INPUT_DEVICE::MS_CONTROLLER_S,
|
||||
XBOX_INPUT_DEVICE::LIGHTGUN,
|
||||
XBOX_INPUT_DEVICE::STEEL_BATTALION_CONTROLLER,
|
||||
XBOX_INPUT_DEVICE::ARCADE_STICK,
|
||||
XBOX_INPUT_DEVICE::HW_XBOX_CONTROLLER,
|
||||
XBOX_INPUT_DEVICE::HW_STEEL_BATTALION_CONTROLLER,
|
||||
};
|
||||
|
||||
inline XBOX_INPUT_DEVICE slot_support_list[] = {
|
||||
XBOX_INPUT_DEVICE::DEVICE_INVALID,
|
||||
XBOX_INPUT_DEVICE::MEMORY_UNIT,
|
||||
// Microphone
|
||||
// Phantasy star online keyboard
|
||||
};
|
||||
|
||||
#pragma pack(1)
|
||||
|
||||
// xpad in/out buffers stripped of the first two bytes
|
||||
// Class-specific xid descriptor, used by libusb
|
||||
struct XidDesc {
|
||||
uint8_t bLength;
|
||||
uint8_t bDescriptorType;
|
||||
uint16_t bcdXid;
|
||||
uint8_t bType;
|
||||
uint8_t bSubType;
|
||||
uint8_t bMaxInputReportSize;
|
||||
uint8_t bMaxOutputReportSize;
|
||||
uint16_t wAlternateProductIds[4];
|
||||
};
|
||||
|
||||
// xpad in/out buffers stripped of the first two bytes as used by xinput
|
||||
struct XpadInput {
|
||||
uint16_t wButtons;
|
||||
uint8_t bAnalogButtons[8];
|
||||
|
@ -56,16 +101,119 @@ struct XpadOutput {
|
|||
uint16_t right_actuator_strength;
|
||||
};
|
||||
|
||||
// xpad in/out buffers as used by xid
|
||||
struct XidGamepadInput {
|
||||
uint8_t bReportId;
|
||||
uint8_t bLength;
|
||||
XpadInput InBuffer;
|
||||
};
|
||||
|
||||
struct XidGamepadOutput {
|
||||
uint8_t bReportId;
|
||||
uint8_t bLength;
|
||||
XpadOutput OutBuffer;
|
||||
};
|
||||
|
||||
// same as above, but for the SBC
|
||||
struct SBCInput {
|
||||
uint16_t wButtons[3];
|
||||
uint8_t bPad1;
|
||||
uint8_t sAimingX;
|
||||
uint8_t bPad2;
|
||||
uint8_t sAimingY;
|
||||
uint8_t bPad3;
|
||||
int8_t sRotationLever;
|
||||
uint8_t bPad4;
|
||||
int8_t sSightChangeX;
|
||||
uint8_t bPad5;
|
||||
int8_t sSightChangeY;
|
||||
uint8_t bPad6;
|
||||
uint8_t wLeftPedal;
|
||||
uint8_t bPad7;
|
||||
uint8_t wMiddlePedal;
|
||||
uint8_t bPad8;
|
||||
uint8_t wRightPedal;
|
||||
uint8_t ucTunerDial;
|
||||
uint8_t ucGearLever;
|
||||
};
|
||||
|
||||
struct SBCOutput {
|
||||
uint8_t LedState[20];
|
||||
};
|
||||
|
||||
struct XidSBCInput {
|
||||
uint8_t bReportId;
|
||||
uint8_t bLength;
|
||||
SBCInput InBuffer;
|
||||
};
|
||||
|
||||
struct XidSBCOutput {
|
||||
uint8_t bReportId;
|
||||
uint8_t bLength;
|
||||
SBCOutput OutBuffer;
|
||||
};
|
||||
|
||||
#pragma pack()
|
||||
|
||||
struct LightGunData {
|
||||
xbox::short_xt offset_x;
|
||||
xbox::short_xt offset_y;
|
||||
xbox::short_xt offset_upp_x;
|
||||
xbox::short_xt offset_upp_y;
|
||||
uint8_t last_in_state;
|
||||
uint8_t last_turbo;
|
||||
uint8_t turbo_delay;
|
||||
uint8_t turbo;
|
||||
uint8_t laser;
|
||||
};
|
||||
|
||||
struct SbcData {
|
||||
uint16_t last_in_state;
|
||||
};
|
||||
|
||||
union InputBuff {
|
||||
XidGamepadInput ctrl;
|
||||
XidSBCInput sbc;
|
||||
};
|
||||
|
||||
struct DeviceInfo {
|
||||
xbox::HANDLE hHandle; // device handle returned by xapi
|
||||
bool bAutoPoll; // autopoll on/off, as instructed by the title in XInputOpen
|
||||
bool bAutoPollDefault; // default autopoll value, depending on device type
|
||||
uint8_t ucType; // xapi type
|
||||
uint8_t ucSubType; // xapi subtype
|
||||
uint8_t ucInputStateSize; // input state size in bytes, does not include dwPacketNumber
|
||||
uint8_t ucFeedbackSize; // feedback size in bytes, does not include FeedbackHeader
|
||||
uint32_t dwPacketNumber; // increases by one when the input state changes
|
||||
InputBuff buff; // input buffer
|
||||
// device-specific additional data
|
||||
union {
|
||||
LightGunData ligthgun;
|
||||
SbcData sbc;
|
||||
};
|
||||
};
|
||||
|
||||
struct DeviceState {
|
||||
std::string port;
|
||||
int port_idx;
|
||||
XBOX_INPUT_DEVICE type;
|
||||
bool bPendingRemoval;
|
||||
bool bSignaled;
|
||||
DeviceInfo info;
|
||||
DeviceState *slots[XBOX_CTRL_NUM_SLOTS];
|
||||
DeviceState *upstream;
|
||||
};
|
||||
|
||||
extern DeviceState g_devs[MAX_DEVS];
|
||||
|
||||
|
||||
class InputDeviceManager
|
||||
{
|
||||
public:
|
||||
void Initialize(bool is_gui);
|
||||
void Initialize(bool is_gui, HWND hwnd);
|
||||
void Shutdown();
|
||||
// read/write the input/output from/to the device attached to the supplied xbox port
|
||||
bool UpdateXboxPortInput(int usb_port, void* Buffer, int Direction, int xid_type);
|
||||
bool UpdateXboxPortInput(int port, void *buffer, int direction, int type);
|
||||
// add the device to the list of availble devices
|
||||
void AddDevice(std::shared_ptr<InputDevice> Device);
|
||||
// remove the device from the list of availble devices
|
||||
|
@ -73,26 +221,38 @@ public:
|
|||
// update device list
|
||||
void RefreshDevices();
|
||||
// get the name of the devices currently detected
|
||||
std::vector<std::string> GetDeviceList() const;
|
||||
std::vector<std::string> GetDeviceList(std::function<bool(const InputDevice *)> Callback) const;
|
||||
// find device from its gui name
|
||||
std::shared_ptr<InputDevice> FindDevice(const std::string& QualifiedName) const;
|
||||
// find device from its sdl id
|
||||
std::shared_ptr<InputDevice> FindDevice(SDL_JoystickID id) const;
|
||||
// find device from its xbox port
|
||||
std::shared_ptr<InputDevice> FindDevice(int usb_port, int dummy) const;
|
||||
std::shared_ptr<InputDevice> FindDevice(std::string_view port) const;
|
||||
// attach/detach guest devices to the emulated machine
|
||||
void UpdateDevices(int port, bool ack);
|
||||
void UpdateDevices(std::string_view port, bool ack);
|
||||
// update input options
|
||||
void UpdateOpt(bool is_gui);
|
||||
// device hotplug event handler
|
||||
void HotplugHandler(bool is_sdl);
|
||||
// converts xinput -> screen coordinates to display the lightgun laser on the rendering window
|
||||
ImVec2 CalcLaserPos(int port);
|
||||
|
||||
|
||||
private:
|
||||
// update input for an xbox controller
|
||||
bool UpdateInputXpad(std::shared_ptr<InputDevice>& Device, void* Buffer, int Direction);
|
||||
bool UpdateInputXpad(std::shared_ptr<InputDevice>& Device, void* Buffer, int Direction, const std::string &Port);
|
||||
// update input for a lightgun
|
||||
bool UpdateInputLightgun(std::shared_ptr<InputDevice> &Device, void *Buffer, int Direction, int Port_num, const std::string &Port);
|
||||
// update input for a Steel Battalion controller
|
||||
bool UpdateInputSBC(std::shared_ptr<InputDevice>& Device, void* Buffer, int Direction, int Port_num, const std::string &Port);
|
||||
// update input for a passthrough xbox device
|
||||
bool UpdateInputHw(std::shared_ptr<InputDevice> &Device, void *Buffer, int Direction);
|
||||
// bind a host device to an emulated device
|
||||
void BindHostDevice(int port, int usb_port, int type);
|
||||
void BindHostDevice(int type, std::string_view port);
|
||||
// connect a device to the emulated machine
|
||||
void ConnectDevice(int port, int usb_port, int type);
|
||||
void ConnectDevice(DeviceState *dev, DeviceState *upstream, int type, std::string_view port);
|
||||
// disconnect a device from the emulated machine
|
||||
void DisconnectDevice(int port, int usb_port, bool ack);
|
||||
void DisconnectDevice(DeviceState *dev, std::string_view port, bool ack);
|
||||
|
||||
// all enumerated devices currently detected and supported
|
||||
std::vector<std::shared_ptr<InputDevice>> m_Devices;
|
||||
|
@ -104,12 +264,14 @@ private:
|
|||
std::thread m_PollingThread;
|
||||
// used to indicate that the manager is shutting down
|
||||
bool m_bPendingShutdown;
|
||||
// handle of the rendering or the input gui window
|
||||
HWND m_hwnd;
|
||||
};
|
||||
|
||||
extern InputDeviceManager g_InputDeviceManager;
|
||||
|
||||
// hle input functions
|
||||
bool ConstructHleInputDevice(int Type, int Port);
|
||||
void DestructHleInputDevice(int Port);
|
||||
void ConstructHleInputDevice(DeviceState *dev, DeviceState *upstream, int type, std::string_view port);
|
||||
void DestructHleInputDevice(DeviceState *dev);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -25,79 +25,17 @@
|
|||
// *
|
||||
// ******************************************************************
|
||||
|
||||
#define LOG_PREFIX CXBXR_MODULE::GUI
|
||||
|
||||
#include "InputWindow.h"
|
||||
#include "..\..\gui\ResCxbx.h"
|
||||
#include "gui/resource/ResCxbx.h"
|
||||
#include "common\IPCHybrid.hpp"
|
||||
#include "EmuShared.h"
|
||||
#include "Logging.h"
|
||||
#include <future>
|
||||
|
||||
#define INPUT_TIMEOUT 5000
|
||||
#define OUTPUT_TIMEOUT 3000
|
||||
|
||||
|
||||
constexpr ControlState INPUT_DETECT_THRESHOLD = 0.55; // arbitrary number, using what Dolphin uses
|
||||
InputWindow* g_InputWindow = nullptr;
|
||||
|
||||
|
||||
void InputWindow::Initialize(HWND hwnd, int port_num, int dev_type)
|
||||
{
|
||||
// Save window/device specific variables
|
||||
m_hwnd_window = hwnd;
|
||||
m_hwnd_device_list = GetDlgItem(m_hwnd_window, IDC_DEVICE_LIST);
|
||||
m_hwnd_profile_list = GetDlgItem(m_hwnd_window, IDC_XID_PROFILE_NAME);
|
||||
m_hwnd_default = GetDlgItem(m_hwnd_window, IDC_XID_DEFAULT);
|
||||
m_dev_type = dev_type;
|
||||
m_max_num_buttons = dev_num_buttons[dev_type];
|
||||
m_port_num = port_num;
|
||||
m_bHasChanges = false;
|
||||
m_bIsBinding = false;
|
||||
|
||||
// Set window icon
|
||||
SetClassLong(m_hwnd_window, GCL_HICON, (LONG)LoadIcon(GetModuleHandle(nullptr), MAKEINTRESOURCE(IDI_CXBX)));
|
||||
|
||||
// Set window title
|
||||
std::string title;
|
||||
switch (m_dev_type)
|
||||
{
|
||||
case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_DUKE): {
|
||||
title += "Xbox Controller Duke at port ";
|
||||
}
|
||||
break;
|
||||
|
||||
case to_underlying(XBOX_INPUT_DEVICE::MS_CONTROLLER_S): {
|
||||
title += "Xbox Controller S at port ";
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
SendMessage(m_hwnd_window, WM_SETTEXT, 0,
|
||||
reinterpret_cast<LPARAM>((title + std::to_string(PORT_INC(m_port_num))).c_str()));
|
||||
|
||||
// Set the maximum profile name lenght the user can enter in the profile combobox
|
||||
SendMessage(m_hwnd_profile_list, CB_LIMITTEXT, 49, 0);
|
||||
|
||||
// construct emu device
|
||||
m_DeviceConfig = new EmuDevice(m_dev_type, m_hwnd_window);
|
||||
|
||||
// Enumerate devices
|
||||
UpdateDeviceList();
|
||||
|
||||
// Load currently saved profile for this port/device type
|
||||
LoadDefaultProfile();
|
||||
|
||||
// Load currently selected host device
|
||||
UpdateCurrentDevice();
|
||||
|
||||
// Load rumble binding
|
||||
char rumble[30];
|
||||
m_DeviceConfig->FindButtonByIndex(m_max_num_buttons - 1)->GetText(rumble, sizeof(rumble));
|
||||
m_rumble = rumble;
|
||||
|
||||
// Install the subclass for the profile combobox
|
||||
SetWindowSubclass(GetWindow(m_hwnd_profile_list, GW_CHILD), ProfileNameSubclassProc, 0, 0);
|
||||
}
|
||||
constexpr ControlState INPUT_DETECT_THRESHOLD = 0.35; // NOTE: this should probably be made user configurable
|
||||
|
||||
InputWindow::~InputWindow()
|
||||
{
|
||||
|
@ -108,10 +46,10 @@ InputWindow::~InputWindow()
|
|||
bool InputWindow::IsProfileSaved()
|
||||
{
|
||||
if (m_bHasChanges) {
|
||||
int ret = MessageBox(m_hwnd_window, "Current configuration is not saved. Save before closing?", "Cxbx-Reloaded", MB_YESNOCANCEL | MB_ICONWARNING | MB_APPLMODAL);
|
||||
PopupReturn ret = PopupQuestion(m_hwnd_window, "Current configuration is not saved. Save before closing?");
|
||||
switch (ret)
|
||||
{
|
||||
case IDYES: {
|
||||
case PopupReturn::Yes: {
|
||||
char name[50];
|
||||
SendMessage(m_hwnd_profile_list, WM_GETTEXT, sizeof(name), reinterpret_cast<LPARAM>(name));
|
||||
if (SaveProfile(std::string(name))) {
|
||||
|
@ -120,17 +58,18 @@ bool InputWindow::IsProfileSaved()
|
|||
return false;
|
||||
}
|
||||
|
||||
case IDNO: {
|
||||
case PopupReturn::No: {
|
||||
return true;
|
||||
}
|
||||
|
||||
case IDCANCEL:
|
||||
case PopupReturn::Cancel:
|
||||
default: {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -139,16 +78,22 @@ void InputWindow::UpdateDeviceList()
|
|||
g_InputDeviceManager.RefreshDevices();
|
||||
|
||||
// Populate device list
|
||||
LRESULT num_devices = SendMessage(m_hwnd_device_list, CB_GETCOUNT, 0, 0);
|
||||
for (int i = 0; i < num_devices; i++) {
|
||||
for (int i = 0; i < m_num_devices; i++) {
|
||||
SendMessage(m_hwnd_device_list, CB_DELETESTRING, 0, 0);
|
||||
}
|
||||
|
||||
std::vector<std::string> dev_list = g_InputDeviceManager.GetDeviceList();
|
||||
// Add everything but libusb devices
|
||||
std::vector<std::string> dev_list = g_InputDeviceManager.GetDeviceList([](const auto &Device) {
|
||||
if (Device->IsLibusb()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
for (const auto& str : dev_list) {
|
||||
SendMessage(m_hwnd_device_list, CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(str.c_str()));
|
||||
++m_num_devices;
|
||||
}
|
||||
if (!dev_list.empty()) {
|
||||
if (m_num_devices) {
|
||||
SendMessage(m_hwnd_device_list, CB_SETCURSEL, 0, 0);
|
||||
}
|
||||
|
||||
|
@ -183,7 +128,7 @@ InputDevice::Input* InputWindow::DetectInput(InputDevice* const Device, int ms)
|
|||
Device->UpdateInput();
|
||||
std::vector<bool>::iterator state = initial_states.begin();
|
||||
for (; i != e && s == e; i++, state++) {
|
||||
if ((*i)->IsDetectable() && (*i)->GetState() > INPUT_DETECT_THRESHOLD) {
|
||||
if ((*i)->IsDetectable() && ((*i)->GetState() > INPUT_DETECT_THRESHOLD)) {
|
||||
if (*state == false) {
|
||||
// input was not initially pressed or it was but released afterwards
|
||||
s = i;
|
||||
|
@ -205,56 +150,6 @@ InputDevice::Input* InputWindow::DetectInput(InputDevice* const Device, int ms)
|
|||
return nullptr; // no input
|
||||
}
|
||||
|
||||
void InputWindow::BindButton(int ControlID)
|
||||
{
|
||||
// Check if binding thread is still active
|
||||
// testcase: spacebar and enter keys; without this fix will cause repeat binding result.
|
||||
if (m_bIsBinding) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto dev = g_InputDeviceManager.FindDevice(m_host_dev);
|
||||
if (dev != nullptr) {
|
||||
m_bIsBinding = true;
|
||||
|
||||
// Don't block the message processing loop
|
||||
std::thread([this, dev, ControlID]() {
|
||||
EnableWindow(m_hwnd_window, FALSE);
|
||||
char current_text[30];
|
||||
Button* xbox_button = m_DeviceConfig->FindButtonById(ControlID);
|
||||
xbox_button->GetText(current_text, sizeof(current_text));
|
||||
xbox_button->UpdateText("...");
|
||||
std::future<InputDevice::Input*> fut = std::async(std::launch::async, &InputWindow::DetectInput, this, dev.get(), INPUT_TIMEOUT);
|
||||
InputDevice::Input* dev_button = fut.get();
|
||||
if (dev_button) {
|
||||
xbox_button->UpdateText(dev_button->GetName().c_str());
|
||||
m_bHasChanges = true;
|
||||
}
|
||||
else {
|
||||
xbox_button->UpdateText(current_text);
|
||||
}
|
||||
m_bIsBinding = false;
|
||||
EnableWindow(m_hwnd_window, TRUE);
|
||||
}).detach();
|
||||
}
|
||||
}
|
||||
|
||||
void InputWindow::BindDefault()
|
||||
{
|
||||
int api = EnableDefaultButton();
|
||||
if (api != -1) {
|
||||
m_DeviceConfig->BindDefault(api);
|
||||
m_bHasChanges = true;
|
||||
}
|
||||
}
|
||||
|
||||
void InputWindow::ClearBindings()
|
||||
{
|
||||
m_DeviceConfig->ClearButtons();
|
||||
m_rumble = std::string();
|
||||
m_bHasChanges = true;
|
||||
}
|
||||
|
||||
int InputWindow::EnableDefaultButton()
|
||||
{
|
||||
if (std::strncmp(m_host_dev.c_str(), "XInput", std::strlen("XInput")) == 0) {
|
||||
|
@ -271,6 +166,65 @@ int InputWindow::EnableDefaultButton()
|
|||
}
|
||||
}
|
||||
|
||||
void InputWindow::BindButton(int ControlID, bool auto_swap)
|
||||
{
|
||||
// Check if binding thread is still active
|
||||
// testcase: spacebar and enter keys; without this fix will cause repeat binding result.
|
||||
if (m_bIsBinding) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto dev = g_InputDeviceManager.FindDevice(m_host_dev);
|
||||
if (dev != nullptr) {
|
||||
m_bIsBinding = true;
|
||||
|
||||
// Don't block the message processing loop
|
||||
std::thread([this, dev, ControlID, auto_swap]() {
|
||||
EnableWindow(m_hwnd_window, FALSE);
|
||||
char current_text[HOST_BUTTON_NAME_LENGTH];
|
||||
Button* xbox_button = m_DeviceConfig->FindButtonById(ControlID);
|
||||
xbox_button->GetText(current_text, sizeof(current_text));
|
||||
xbox_button->UpdateText("...");
|
||||
std::future<InputDevice::Input*> fut = std::async(std::launch::async, &InputWindow::DetectInput, this, dev.get(), INPUT_TIMEOUT);
|
||||
InputDevice::Input* dev_button = fut.get();
|
||||
if (dev_button) {
|
||||
xbox_button->UpdateText(dev_button->GetName().c_str());
|
||||
if (auto_swap) {
|
||||
SwapMoCursorAxis(xbox_button);
|
||||
}
|
||||
m_bHasChanges = true;
|
||||
}
|
||||
else {
|
||||
xbox_button->UpdateText(current_text);
|
||||
}
|
||||
m_bIsBinding = false;
|
||||
EnableWindow(m_hwnd_window, TRUE);
|
||||
}).detach();
|
||||
}
|
||||
}
|
||||
|
||||
void InputWindow::UpdateProfile(const std::string &name, int command)
|
||||
{
|
||||
switch (command)
|
||||
{
|
||||
case PROFILE_LOAD:
|
||||
LoadProfile(name);
|
||||
break;
|
||||
|
||||
case PROFILE_SAVE:
|
||||
SaveProfile(name);
|
||||
break;
|
||||
|
||||
case PROFILE_DELETE:
|
||||
DeleteProfile(name);
|
||||
break;
|
||||
|
||||
case BUTTON_CLEAR:
|
||||
m_bHasChanges = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
InputWindow::ProfileIt InputWindow::FindProfile(const std::string& name)
|
||||
{
|
||||
auto it = std::find_if(g_Settings->m_input_profiles[m_dev_type].begin(),
|
||||
|
@ -280,40 +234,6 @@ InputWindow::ProfileIt InputWindow::FindProfile(const std::string& name)
|
|||
return it;
|
||||
}
|
||||
|
||||
void InputWindow::UpdateProfile(const std::string& name, int command)
|
||||
{
|
||||
switch (command)
|
||||
{
|
||||
case PROFILE_LOAD: {
|
||||
LoadProfile(name);
|
||||
}
|
||||
break;
|
||||
|
||||
case PROFILE_SAVE: {
|
||||
SaveProfile(name);
|
||||
}
|
||||
break;
|
||||
|
||||
case PROFILE_DELETE: {
|
||||
DeleteProfile(name);
|
||||
}
|
||||
break;
|
||||
|
||||
case RUMBLE_CLEAR: {
|
||||
m_rumble = std::string();
|
||||
}
|
||||
break;
|
||||
|
||||
case BUTTON_CLEAR: {
|
||||
m_bHasChanges = true;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void InputWindow::LoadProfile(const std::string& name)
|
||||
{
|
||||
ProfileIt profile = FindProfile(name);
|
||||
|
@ -334,19 +254,19 @@ void InputWindow::LoadProfile(const std::string& name)
|
|||
for (int index = 0; index < m_max_num_buttons; index++) {
|
||||
m_DeviceConfig->FindButtonByIndex(index)->UpdateText(profile->ControlList[index].c_str());
|
||||
}
|
||||
g_Settings->m_input[m_port_num].DeviceName = profile->DeviceName;
|
||||
g_Settings->m_input[m_port_num].ProfileName = profile->ProfileName;
|
||||
g_Settings->m_input_port[m_port_num].DeviceName = profile->DeviceName;
|
||||
g_Settings->m_input_port[m_port_num].ProfileName = profile->ProfileName;
|
||||
m_bHasChanges = false;
|
||||
}
|
||||
|
||||
bool InputWindow::SaveProfile(const std::string& name)
|
||||
{
|
||||
if (name == std::string()) {
|
||||
MessageBox(m_hwnd_window, "Cannot save. Profile name must not be empty", "Cxbx-Reloaded", MB_OK | MB_ICONSTOP | MB_APPLMODAL);
|
||||
PopupError(m_hwnd_window, "Cannot save. Profile name must not be empty.");
|
||||
return false;
|
||||
}
|
||||
if (m_host_dev == std::string()) {
|
||||
MessageBox(m_hwnd_window, "Cannot save. No input devices detected", "Cxbx-Reloaded", MB_OK | MB_ICONSTOP | MB_APPLMODAL);
|
||||
PopupError(m_hwnd_window, "Cannot save. No input devices detected.", "Cxbx-Reloaded");
|
||||
return false;
|
||||
}
|
||||
OverwriteProfile(name);
|
||||
|
@ -355,15 +275,16 @@ bool InputWindow::SaveProfile(const std::string& name)
|
|||
profile.ProfileName = name;
|
||||
profile.DeviceName = m_host_dev;
|
||||
for (int index = 0; index < m_max_num_buttons; index++) {
|
||||
char dev_button[30];
|
||||
char dev_button[HOST_BUTTON_NAME_LENGTH];
|
||||
m_DeviceConfig->FindButtonByIndex(index)->GetText(dev_button, sizeof(dev_button));
|
||||
profile.ControlList.push_back(dev_button);
|
||||
}
|
||||
SendMessage(m_hwnd_profile_list, CB_SETCURSEL, SendMessage(m_hwnd_profile_list, CB_ADDSTRING, 0,
|
||||
reinterpret_cast<LPARAM>(profile.ProfileName.c_str())), 0);
|
||||
g_Settings->m_input[m_port_num].DeviceName = profile.DeviceName;
|
||||
g_Settings->m_input[m_port_num].ProfileName = profile.ProfileName;
|
||||
g_Settings->m_input_port[m_port_num].DeviceName = profile.DeviceName;
|
||||
g_Settings->m_input_port[m_port_num].ProfileName = profile.ProfileName;
|
||||
g_Settings->m_input_profiles[m_dev_type].push_back(std::move(profile));
|
||||
|
||||
m_bHasChanges = false;
|
||||
return true;
|
||||
}
|
||||
|
@ -376,16 +297,16 @@ void InputWindow::DeleteProfile(const std::string& name)
|
|||
}
|
||||
SendMessage(m_hwnd_profile_list, CB_DELETESTRING, SendMessage(m_hwnd_profile_list, CB_FINDSTRINGEXACT, 1,
|
||||
reinterpret_cast<LPARAM>(profile->ProfileName.c_str())), 0);
|
||||
if (profile->ProfileName == g_Settings->m_input[m_port_num].ProfileName) {
|
||||
if (profile->ProfileName == g_Settings->m_input_port[m_port_num].ProfileName) {
|
||||
SendMessage(m_hwnd_profile_list, CB_SETCURSEL, -1, 0);
|
||||
UpdateCurrentDevice();
|
||||
ClearBindings();
|
||||
g_Settings->m_input[m_port_num].DeviceName = "";
|
||||
g_Settings->m_input[m_port_num].ProfileName = "";
|
||||
g_Settings->m_input_port[m_port_num].DeviceName = "";
|
||||
g_Settings->m_input_port[m_port_num].ProfileName = "";
|
||||
m_bHasChanges = false;
|
||||
}
|
||||
else {
|
||||
LoadProfile(g_Settings->m_input[m_port_num].ProfileName);
|
||||
LoadProfile(g_Settings->m_input_port[m_port_num].ProfileName);
|
||||
}
|
||||
g_Settings->m_input_profiles[m_dev_type].erase(profile);
|
||||
}
|
||||
|
@ -408,84 +329,85 @@ void InputWindow::LoadDefaultProfile()
|
|||
SendMessage(m_hwnd_profile_list, CB_ADDSTRING, 0,
|
||||
reinterpret_cast<LPARAM>(g_Settings->m_input_profiles[m_dev_type][index].ProfileName.c_str()));
|
||||
}
|
||||
LoadProfile(g_Settings->m_input[m_port_num].ProfileName);
|
||||
LoadProfile(g_Settings->m_input_port[m_port_num].ProfileName);
|
||||
}
|
||||
|
||||
void InputWindow::UpdateCurrentDevice()
|
||||
{
|
||||
char device_name[50];
|
||||
SendMessage(m_hwnd_device_list, WM_GETTEXT, sizeof(device_name), reinterpret_cast<LPARAM>(device_name));
|
||||
m_host_dev = device_name;
|
||||
if (m_num_devices) {
|
||||
char device_name[50];
|
||||
SendMessage(m_hwnd_device_list, WM_GETTEXT, sizeof(device_name), reinterpret_cast<LPARAM>(device_name));
|
||||
m_host_dev = device_name;
|
||||
}
|
||||
else {
|
||||
m_host_dev = "";
|
||||
}
|
||||
|
||||
EnableDefaultButton();
|
||||
}
|
||||
|
||||
void InputWindow::InitRumble(HWND hwnd)
|
||||
void InputWindow::SwapMoCursorAxis(Button *button)
|
||||
{
|
||||
m_hwnd_rumble = hwnd;
|
||||
m_hwnd_rumble_list = GetDlgItem(m_hwnd_rumble, IDC_RUMBLE_LIST);
|
||||
SendMessage(m_hwnd_rumble_list, CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(""));
|
||||
auto dev = g_InputDeviceManager.FindDevice(m_host_dev);
|
||||
if (dev != nullptr) {
|
||||
auto outputs = dev->GetOutputs();
|
||||
for (const auto out : outputs) {
|
||||
SendMessage(m_hwnd_rumble_list, CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(out->GetName().c_str()));
|
||||
// Axis X+ <-> Cursor X+
|
||||
// Axis X- <-> Cursor X-
|
||||
// Axis Y+ <-> Cursor Y-
|
||||
// Axis Y- <-> Cursor Y+
|
||||
if (m_host_dev.ends_with("KeyboardMouse")) {
|
||||
assert(button != nullptr);
|
||||
char control_name[HOST_BUTTON_NAME_LENGTH];
|
||||
button->GetText(control_name, sizeof(control_name));
|
||||
if (std::string_view(control_name).starts_with("Axis")) {
|
||||
switch (control_name[5])
|
||||
{
|
||||
case 'X':
|
||||
if (control_name[6] == '+') {
|
||||
button->UpdateText("Cursor X+");
|
||||
}
|
||||
else {
|
||||
button->UpdateText("Cursor X-");
|
||||
}
|
||||
m_bHasChanges = true;
|
||||
break;
|
||||
|
||||
case 'Y':
|
||||
if (control_name[6] == '+') {
|
||||
button->UpdateText("Cursor Y-");
|
||||
}
|
||||
else {
|
||||
button->UpdateText("Cursor Y+");
|
||||
}
|
||||
m_bHasChanges = true;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (std::string_view(control_name).starts_with("Cursor")) {
|
||||
switch (control_name[7])
|
||||
{
|
||||
case 'X':
|
||||
if (control_name[8] == '+') {
|
||||
button->UpdateText("Axis X+");
|
||||
}
|
||||
else {
|
||||
button->UpdateText("Axis X-");
|
||||
}
|
||||
m_bHasChanges = true;
|
||||
break;
|
||||
|
||||
case 'Y':
|
||||
if (control_name[8] == '+') {
|
||||
button->UpdateText("Axis Y-");
|
||||
}
|
||||
else {
|
||||
button->UpdateText("Axis Y+");
|
||||
}
|
||||
m_bHasChanges = true;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
SendMessage(m_hwnd_rumble_list, CB_SETCURSEL, SendMessage(m_hwnd_rumble_list, CB_FINDSTRINGEXACT, 1,
|
||||
reinterpret_cast<LPARAM>(m_rumble.c_str())), 0);
|
||||
}
|
||||
|
||||
void InputWindow::UpdateRumble(int command)
|
||||
{
|
||||
switch (command)
|
||||
{
|
||||
case RUMBLE_SET: {
|
||||
char rumble[30];
|
||||
SendMessage(m_hwnd_rumble_list, WM_GETTEXT, sizeof(rumble), reinterpret_cast<LPARAM>(rumble));
|
||||
m_rumble = rumble;
|
||||
}
|
||||
break;
|
||||
|
||||
case RUMBLE_UPDATE: {
|
||||
m_DeviceConfig->FindButtonByIndex(m_max_num_buttons - 1)->UpdateText(m_rumble.c_str());
|
||||
}
|
||||
break;
|
||||
|
||||
case RUMBLE_TEST: {
|
||||
DetectOutput(OUTPUT_TIMEOUT);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void InputWindow::DetectOutput(int ms)
|
||||
{
|
||||
if (m_rumble == std::string()) {
|
||||
return;
|
||||
}
|
||||
auto dev = g_InputDeviceManager.FindDevice(m_host_dev);
|
||||
if (dev != nullptr) {
|
||||
// Don't block the message processing loop
|
||||
std::thread([this, dev, ms]() {
|
||||
EnableWindow(m_hwnd_rumble, FALSE);
|
||||
SendMessage(m_hwnd_rumble_list, WM_SETTEXT, 0, reinterpret_cast<LPARAM>("..."));
|
||||
auto outputs = dev->GetOutputs();
|
||||
for (const auto out : outputs) {
|
||||
if (out->GetName() == m_rumble) {
|
||||
out->SetState(1.0, 1.0);
|
||||
}
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
|
||||
for (const auto out : outputs) {
|
||||
if (out->GetName() == m_rumble) {
|
||||
out->SetState(0.0, 0.0);
|
||||
}
|
||||
}
|
||||
SendMessage(m_hwnd_rumble_list, WM_SETTEXT, 0, reinterpret_cast<LPARAM>("Test"));
|
||||
EnableWindow(m_hwnd_rumble, TRUE);
|
||||
}).detach();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,8 +40,11 @@
|
|||
#define RUMBLE_CLEAR 7
|
||||
#define BUTTON_CLEAR 8
|
||||
|
||||
#define XINPUT_DEFAULT 1
|
||||
#define DINPUT_DEFAULT 2
|
||||
#define XINPUT_DEFAULT 0
|
||||
#define DINPUT_DEFAULT 1
|
||||
|
||||
#define INPUT_TIMEOUT 5000
|
||||
#define OUTPUT_TIMEOUT 3000
|
||||
|
||||
LRESULT CALLBACK ProfileNameSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);
|
||||
|
||||
|
@ -49,30 +52,28 @@ LRESULT CALLBACK ProfileNameSubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LP
|
|||
class InputWindow
|
||||
{
|
||||
public:
|
||||
void Initialize(HWND hwnd, int port_num, int dev_type);
|
||||
void InitRumble(HWND hwnd);
|
||||
virtual void Initialize(HWND hwnd, int port_num, int dev_type) = 0;
|
||||
~InputWindow();
|
||||
void UpdateDeviceList();
|
||||
void BindButton(int ControlID);
|
||||
void BindDefault();
|
||||
void ClearBindings();
|
||||
void UpdateProfile(const std::string& name, int command);
|
||||
void UpdateRumble(int command);
|
||||
virtual void UpdateDeviceList();
|
||||
void BindButton(int ControlID, bool auto_swap = false);
|
||||
virtual void ClearBindings() = 0;
|
||||
virtual void UpdateProfile(const std::string& name, int command);
|
||||
void UpdateCurrentDevice();
|
||||
bool IsProfileSaved();
|
||||
void SwapMoCursorAxis(Button *button);
|
||||
|
||||
|
||||
private:
|
||||
protected:
|
||||
typedef std::vector<Settings::s_input_profiles>::iterator ProfileIt;
|
||||
InputDevice::Input* DetectInput(InputDevice* const Device, int ms);
|
||||
void DetectOutput(int ms);
|
||||
ProfileIt FindProfile(const std::string& name);
|
||||
void LoadProfile(const std::string& name);
|
||||
bool SaveProfile(const std::string& name);
|
||||
void DeleteProfile(const std::string& name);
|
||||
void OverwriteProfile(const std::string& name);
|
||||
void LoadDefaultProfile();
|
||||
int EnableDefaultButton();
|
||||
virtual int EnableDefaultButton();
|
||||
|
||||
|
||||
// xbox device under configuration
|
||||
EmuDevice* m_DeviceConfig;
|
||||
|
@ -82,12 +83,10 @@ private:
|
|||
HWND m_hwnd_device_list;
|
||||
// handle of the profile list combobox
|
||||
HWND m_hwnd_profile_list;
|
||||
// handle of the rumble window
|
||||
HWND m_hwnd_rumble;
|
||||
// handle of the rumble combobox
|
||||
HWND m_hwnd_rumble_list;
|
||||
// handle of the default bindings button
|
||||
HWND m_hwnd_default;
|
||||
// number of devices displayed in the device list combobox
|
||||
int m_num_devices;
|
||||
// type of the device
|
||||
int m_dev_type;
|
||||
// num of buttons of device under configuration
|
||||
|
@ -96,12 +95,71 @@ private:
|
|||
int m_port_num;
|
||||
// host device under configuration
|
||||
std::string m_host_dev;
|
||||
// currently selected rumble control
|
||||
std::string m_rumble;
|
||||
// indicates if the current profile has unsaved changes
|
||||
bool m_bHasChanges;
|
||||
// prevent current input attempt to set the previous input at same time
|
||||
std::atomic<bool> m_bIsBinding;
|
||||
};
|
||||
|
||||
extern InputWindow* g_InputWindow;
|
||||
class DukeInputWindow : public InputWindow
|
||||
{
|
||||
public:
|
||||
void Initialize(HWND hwnd, int port_num, int dev_type) override;
|
||||
void InitRumble(HWND hwnd);
|
||||
void UpdateRumble(int command);
|
||||
void BindDefault();
|
||||
void ClearBindings() override;
|
||||
void UpdateProfile(const std::string &name, int command) override;
|
||||
void SaveSlotConfig();
|
||||
|
||||
|
||||
private:
|
||||
void DetectOutput(int ms);
|
||||
|
||||
// handle of the rumble window
|
||||
HWND m_hwnd_rumble;
|
||||
// handle of the rumble combobox
|
||||
HWND m_hwnd_rumble_list;
|
||||
// handles of the slot combobox
|
||||
HWND m_hwnd_slot_list[XBOX_CTRL_NUM_SLOTS];
|
||||
// currently selected rumble control
|
||||
std::string m_rumble;
|
||||
};
|
||||
|
||||
class SbcInputWindow : public InputWindow
|
||||
{
|
||||
public:
|
||||
void Initialize(HWND hwnd, int port_num, int dev_type) override;
|
||||
~SbcInputWindow();
|
||||
void ClearBindings() override;
|
||||
|
||||
|
||||
private:
|
||||
int EnableDefaultButton() override;
|
||||
};
|
||||
|
||||
class LibusbInputWindow : public InputWindow
|
||||
{
|
||||
public:
|
||||
void Initialize(HWND hwnd, int port_num, int dev_type) override;
|
||||
~LibusbInputWindow();
|
||||
void ClearBindings() override;
|
||||
void UpdateDeviceList() override;
|
||||
void TestInput();
|
||||
|
||||
|
||||
private:
|
||||
int EnableDefaultButton() override;
|
||||
|
||||
// handle of the test button
|
||||
HWND m_hwnd_device_test;
|
||||
};
|
||||
|
||||
class LightgunInputWindow : public InputWindow
|
||||
{
|
||||
public:
|
||||
void Initialize(HWND hwnd, int port_num, int dev_type) override;
|
||||
~LightgunInputWindow();
|
||||
void BindDefault();
|
||||
void ClearBindings() override;
|
||||
};
|
||||
|
|
|
@ -0,0 +1,325 @@
|
|||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
// ******************************************************************
|
||||
// *
|
||||
// * This file is part of the Cxbx project.
|
||||
// *
|
||||
// * Cxbx and Cxbe are free software; you can redistribute them
|
||||
// * and/or modify them under the terms of the GNU General Public
|
||||
// * License as published by the Free Software Foundation; either
|
||||
// * version 2 of the license, or (at your option) any later version.
|
||||
// *
|
||||
// * This program 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 recieved a copy of the GNU General Public License
|
||||
// * along with this program; see the file COPYING.
|
||||
// * If not, write to the Free Software Foundation, Inc.,
|
||||
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
|
||||
// *
|
||||
// * (c) 2021 ergo720
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
|
||||
#define LOG_PREFIX CXBXR_MODULE::LIBUSB
|
||||
|
||||
#include "LibusbDevice.h"
|
||||
#include "InputManager.h"
|
||||
#include "core\kernel\support\Emu.h"
|
||||
#include "core\hle\XAPI\Xapi.h"
|
||||
|
||||
// Sanity check: ensure that our libusb version is high enough for libusb_get_device_descriptor to succeed and to pass nullptr to libusb_interrupt_transfer
|
||||
static_assert(LIBUSB_API_VERSION >= 0x01000105);
|
||||
|
||||
|
||||
namespace Libusb
|
||||
{
|
||||
int InitStatus = NOT_INIT;
|
||||
|
||||
// These come from here https://github.com/xboxdrv/xboxdrv/blob/ac6ebb1228962220482ea03743cadbe18754246c/src/xpad_device.cpp#L29
|
||||
static constexpr uint16_t SupportedDevices_VidPid[][2] = { // vid, pid
|
||||
0x0d2f, 0x0002,
|
||||
0x045e, 0x0202,
|
||||
0x045e, 0x0285,
|
||||
0x045e, 0x0287,
|
||||
0x045e, 0x0289,
|
||||
0x046d, 0xca84,
|
||||
0x046d, 0xca88,
|
||||
0x05fd, 0x1007,
|
||||
0x05fd, 0x107a,
|
||||
0x0738, 0x4516,
|
||||
0x0738, 0x4522,
|
||||
0x0738, 0x4526,
|
||||
0x0738, 0x4536,
|
||||
0x0738, 0x4556,
|
||||
0x0c12, 0x8802,
|
||||
0x0c12, 0x8810,
|
||||
0x0c12, 0x9902,
|
||||
0x0e4c, 0x1097,
|
||||
0x0e4c, 0x2390,
|
||||
0x0e6f, 0x0003,
|
||||
0x0e6f, 0x0005,
|
||||
0x0e6f, 0x0006,
|
||||
0x0f30, 0x0202,
|
||||
0x0f30, 0x8888,
|
||||
0x102c, 0xff0c,
|
||||
0x044f, 0x0f07,
|
||||
0x0e8f, 0x3008,
|
||||
};
|
||||
|
||||
static constexpr const char *SupportedDevices_Name[] = {
|
||||
"Andamiro Pump It Up pad",
|
||||
"Microsoft X-Box pad v1 (US)",
|
||||
"Microsoft X-Box pad (Japan)",
|
||||
"Microsoft Xbox Controller S",
|
||||
"Microsoft X-Box pad v2 (US)",
|
||||
"Logitech Xbox Cordless Controller",
|
||||
"Logitech Compact Controller for Xbox",
|
||||
"Mad Catz Controller (unverified)",
|
||||
"InterAct 'PowerPad Pro' X-Box pad (Germany)",
|
||||
"Mad Catz Control Pad",
|
||||
"Mad Catz LumiCON",
|
||||
"Mad Catz Control Pad Pro",
|
||||
"Mad Catz MicroCON",
|
||||
"Mad Catz Lynx Wireless Controller",
|
||||
"Zeroplus Xbox Controller",
|
||||
"Zeroplus Xbox Controller",
|
||||
"HAMA VibraX - *FAULTY HARDWARE*",
|
||||
"Radica Gamester Controller",
|
||||
"Radica Games Jtech Controller",
|
||||
"Logic3 Freebird wireless Controller",
|
||||
"Eclipse wireless Controller",
|
||||
"Edge wireless Controller",
|
||||
"Joytech Advanced Controller",
|
||||
"BigBen XBMiniPad Controller",
|
||||
"Joytech Wireless Advanced Controller",
|
||||
"Thrustmaster, Inc. Controller",
|
||||
"Generic xbox control (dealextreme)",
|
||||
};
|
||||
|
||||
static_assert(ARRAY_SIZE(SupportedDevices_VidPid) == ARRAY_SIZE(SupportedDevices_Name));
|
||||
|
||||
void Init(std::mutex &Mtx)
|
||||
{
|
||||
std::unique_lock<std::mutex> lck(Mtx);
|
||||
|
||||
// We only use a single libusb session per cxbxr process, so we do not need to use a libusb context
|
||||
if (libusb_init(nullptr) != 0) {
|
||||
EmuLog(LOG_LEVEL::ERROR2, "Failed to initialize Libusb!");
|
||||
InitStatus = INIT_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
InitStatus = INIT_SUCCESS;
|
||||
}
|
||||
|
||||
void DeInit()
|
||||
{
|
||||
InitStatus = NOT_INIT;
|
||||
libusb_exit(nullptr);
|
||||
}
|
||||
|
||||
void PopulateDevices()
|
||||
{
|
||||
// NOTE: the libusb docs say that the list is always appended with a NULL element at the end
|
||||
libusb_device **List;
|
||||
ssize_t DevicesConnected = libusb_get_device_list(nullptr, &List) - 1;
|
||||
if (DevicesConnected < 0) {
|
||||
EmuLog(LOG_LEVEL::ERROR2, "Failed to enumerate devices. The error was: %s", libusb_strerror(DevicesConnected));
|
||||
return;
|
||||
}
|
||||
|
||||
for (ssize_t i = 0; i < DevicesConnected; ++i) {
|
||||
libusb_device *LibusbDev = List[i];
|
||||
libusb_device_descriptor Desc;
|
||||
libusb_get_device_descriptor(LibusbDev, &Desc); // always succeeds when LIBUSB_API_VERSION >= 0x01000102
|
||||
auto Device = std::make_shared<LibusbDevice>(&Desc, LibusbDev);
|
||||
if (Device->IsLibusb()) {
|
||||
g_InputDeviceManager.AddDevice(std::move(Device));
|
||||
}
|
||||
}
|
||||
|
||||
libusb_free_device_list(List, 1);
|
||||
}
|
||||
|
||||
void GetDeviceChanges()
|
||||
{
|
||||
g_InputDeviceManager.RemoveDevice([](const auto &Device) {
|
||||
return Device->IsLibusb();
|
||||
});
|
||||
PopulateDevices();
|
||||
}
|
||||
|
||||
LibusbDevice::LibusbDevice(libusb_device_descriptor *Desc, libusb_device *Dev)
|
||||
{
|
||||
m_Type = XBOX_INPUT_DEVICE::DEVICE_INVALID;
|
||||
|
||||
// The SBC's VID and PID are taken from https://xboxdevwiki.net/Xbox_Input_Devices#Steel_Battalion_Controller
|
||||
if ((Desc->idVendor == 0x0a7b) && (Desc->idProduct == 0xd000)) {
|
||||
m_Type = XBOX_INPUT_DEVICE::HW_STEEL_BATTALION_CONTROLLER;
|
||||
m_UcType = XINPUT_DEVTYPE_STEELBATTALION;
|
||||
m_UcSubType = XINPUT_DEVSUBTYPE_GC_GAMEPAD;
|
||||
m_Name = "Steel battalion controller";
|
||||
m_BufferInSize = sizeof(XidSBCInput);
|
||||
m_BufferOutSize = sizeof(XidSBCOutput);
|
||||
assert(Desc->bcdUSB == 0x110); // must be a usb 1.1 device
|
||||
}
|
||||
else {
|
||||
for (size_t i = 0; i < ARRAY_SIZE(SupportedDevices_VidPid); ++i) {
|
||||
if ((Desc->idVendor == SupportedDevices_VidPid[i][0]) && (Desc->idProduct == SupportedDevices_VidPid[i][1])) {
|
||||
m_Type = XBOX_INPUT_DEVICE::HW_XBOX_CONTROLLER;
|
||||
m_UcType = XINPUT_DEVTYPE_GAMEPAD;
|
||||
m_UcSubType = XINPUT_DEVSUBTYPE_GC_GAMEPAD;
|
||||
m_Name = SupportedDevices_Name[i];
|
||||
m_BufferInSize = sizeof(XidGamepadInput);
|
||||
m_BufferOutSize = sizeof(XidGamepadOutput);
|
||||
assert(Desc->bcdUSB == 0x110); // must be a usb 1.1 device
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_Type == XBOX_INPUT_DEVICE::DEVICE_INVALID) { return; }
|
||||
|
||||
// check if we are able to open device through libusb
|
||||
if (int err = libusb_open(Dev, &m_hDev)) {
|
||||
// Couldn't open device, create an error log report then don't use it.
|
||||
EmuLog(LOG_LEVEL::ERROR2, "Unable to open original xbox device \"%s\" (%hX:%hX), libusb's error was: %s",
|
||||
m_Name.c_str(), Desc->idVendor, Desc->idProduct, libusb_strerror(err));
|
||||
m_Type = XBOX_INPUT_DEVICE::DEVICE_INVALID;
|
||||
return;
|
||||
}
|
||||
// If we are able to open device, continue with query process.
|
||||
else {
|
||||
// Duke, S and SBC have 1 configuration, 1 interface and 2 endpoints (input and output) and use the default alternate setting zero.
|
||||
// The code below assumes that third-party controllers follow suit.
|
||||
libusb_config_descriptor *ConfDesc;
|
||||
if (libusb_get_active_config_descriptor(Dev, &ConfDesc) == 0) {
|
||||
if (ConfDesc->bNumInterfaces == 1) {
|
||||
auto Iface = ConfDesc->interface[0];
|
||||
if (Iface.num_altsetting == 1) {
|
||||
auto Setting = Iface.altsetting[0];
|
||||
m_IfaceNum = Setting.bInterfaceNumber;
|
||||
if (Setting.bNumEndpoints >= 1) {
|
||||
m_HasEndpointOut = false;
|
||||
for (uint8_t i = 0; i < Setting.bNumEndpoints; ++i) {
|
||||
auto Endpoint = Setting.endpoint[i];
|
||||
if (Endpoint.bEndpointAddress & 0x80) {
|
||||
m_EndpointIn = Endpoint.bEndpointAddress;
|
||||
m_IntervalIn = Endpoint.bInterval;
|
||||
}
|
||||
else {
|
||||
// third-party controllers that don't support rumble probably won't have an out endpoint
|
||||
m_EndpointOut = Endpoint.bEndpointAddress;
|
||||
m_IntervalOut = Endpoint.bInterval;
|
||||
m_HasEndpointOut = true;
|
||||
}
|
||||
}
|
||||
EmuLog(LOG_LEVEL::INFO, "Out endpoint %s", m_HasEndpointOut ? "present" : "not present");
|
||||
if (int err = libusb_claim_interface(m_hDev, m_IfaceNum)) {
|
||||
EmuLog(LOG_LEVEL::INFO, "Rejected device %s because libusb could not claim its interface. The error was: %s",
|
||||
m_Name.c_str(), libusb_strerror(err));
|
||||
m_Type = XBOX_INPUT_DEVICE::DEVICE_INVALID;
|
||||
}
|
||||
else {
|
||||
// Grab the xid descriptor so that we can report real type/subtype values back to the title when it calls XInputGetCapabilities
|
||||
XidDesc XidDesc;
|
||||
if (libusb_control_transfer(m_hDev, 0xC1, 6, 0x4200, m_IfaceNum, reinterpret_cast<uint8_t *>(&XidDesc), sizeof(XidDesc), m_IntervalIn)
|
||||
== sizeof(XidDesc)) { // submit a GET_DESCRIPTOR request
|
||||
|
||||
// Dump the xid descriptor to the log
|
||||
EmuLog(LOG_LEVEL::INFO, "Xid descriptor dump:\nbLength: %#010X\nbDescriptorType: %#010X\nbcdXid: %#010X\nbType: %#010X\n"
|
||||
"bSubType: %#010X\nbMaxInputReportSize: %#010X\nbMaxOutputReportSize: %#010X\nwAlternateProductIds[0]: %#010X\n"
|
||||
"wAlternateProductIds[1]: %#010X\nwAlternateProductIds[2]: %#010X\nwAlternateProductIds[3]: %#010X\n",
|
||||
XidDesc.bLength, XidDesc.bDescriptorType, XidDesc.bcdXid, XidDesc.bType, XidDesc.bSubType, XidDesc.bMaxInputReportSize, XidDesc.bMaxOutputReportSize,
|
||||
XidDesc.wAlternateProductIds[0], XidDesc.wAlternateProductIds[1], XidDesc.wAlternateProductIds[2], XidDesc.wAlternateProductIds[3]);
|
||||
|
||||
if (XidDesc.bDescriptorType == 0x42) {
|
||||
m_UcType = XidDesc.bType;
|
||||
m_UcSubType = XidDesc.bSubType;
|
||||
}
|
||||
else {
|
||||
EmuLog(LOG_LEVEL::INFO, "The xid descriptor for device %s reported an unexpected descriptor type, assuming a default subtype", m_Name);
|
||||
}
|
||||
}
|
||||
else {
|
||||
EmuLog(LOG_LEVEL::INFO, "Could not retrieve the xid descriptor for device %s, assuming a default subtype", m_Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
EmuLog(LOG_LEVEL::INFO, "Rejected device %s because of unexpected number of endpoints, bNumEndpoints: %d",
|
||||
m_Name.c_str(), Setting.bNumEndpoints);
|
||||
m_Type = XBOX_INPUT_DEVICE::DEVICE_INVALID;
|
||||
}
|
||||
}
|
||||
else {
|
||||
EmuLog(LOG_LEVEL::INFO, "Rejected device %s because of unexpected number of alternative settings, num_altsetting: %d",
|
||||
m_Name.c_str(), Iface.num_altsetting);
|
||||
m_Type = XBOX_INPUT_DEVICE::DEVICE_INVALID;
|
||||
}
|
||||
}
|
||||
else {
|
||||
EmuLog(LOG_LEVEL::INFO, "Rejected device %s because of unexpected number of interfaces, bNumInterfaces: %d",
|
||||
m_Name.c_str(), ConfDesc->bNumInterfaces);
|
||||
m_Type = XBOX_INPUT_DEVICE::DEVICE_INVALID;
|
||||
}
|
||||
libusb_free_config_descriptor(ConfDesc);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_Type == XBOX_INPUT_DEVICE::DEVICE_INVALID) { libusb_close(m_hDev); }
|
||||
}
|
||||
|
||||
LibusbDevice::~LibusbDevice()
|
||||
{
|
||||
if (m_Type != XBOX_INPUT_DEVICE::DEVICE_INVALID) {
|
||||
libusb_release_interface(m_hDev, m_IfaceNum);
|
||||
libusb_close(m_hDev);
|
||||
}
|
||||
}
|
||||
|
||||
bool LibusbDevice::UpdateInput()
|
||||
{
|
||||
// Dummy, it should never be called. It's only here to override the pure function UpdateInput in InputDevice
|
||||
assert(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LibusbDevice::ExecuteIo(void *Buffer, int Direction)
|
||||
{
|
||||
// NOTE: a SET_REPORT control transfer to the SBC doesn't seem to work, the parameters might not be appropriate for it... So, we use
|
||||
// the interrupt pipes for everything instead
|
||||
*static_cast<uint8_t *>(Buffer) = 0; // write bReportId
|
||||
if (Direction == DIRECTION_IN) {
|
||||
*(static_cast<uint8_t *>(Buffer) + 1) = m_BufferInSize; // write bLength
|
||||
if (libusb_interrupt_transfer(m_hDev, m_EndpointIn, static_cast<uint8_t *>(Buffer), m_BufferInSize, nullptr, m_IntervalIn) != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (m_HasEndpointOut) {
|
||||
*(static_cast<uint8_t *>(Buffer) + 1) = m_BufferOutSize; // write bLength
|
||||
if (libusb_interrupt_transfer(m_hDev, m_EndpointOut, static_cast<uint8_t *>(Buffer), m_BufferOutSize, nullptr, m_IntervalOut) != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string LibusbDevice::GetDeviceName() const
|
||||
{
|
||||
return m_Name;
|
||||
}
|
||||
|
||||
std::string LibusbDevice::GetAPI() const
|
||||
{
|
||||
return "Libusb";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
// ******************************************************************
|
||||
// *
|
||||
// * This file is part of the Cxbx project.
|
||||
// *
|
||||
// * Cxbx and Cxbe are free software; you can redistribute them
|
||||
// * and/or modify them under the terms of the GNU General Public
|
||||
// * License as published by the Free Software Foundation; either
|
||||
// * version 2 of the license, or (at your option) any later version.
|
||||
// *
|
||||
// * This program 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 recieved a copy of the GNU General Public License
|
||||
// * along with this program; see the file COPYING.
|
||||
// * If not, write to the Free Software Foundation, Inc.,
|
||||
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
|
||||
// *
|
||||
// * (c) 2021 ergo720
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "InputDevice.h"
|
||||
// Suppress warning in libusb about zero sized array
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4200)
|
||||
#include "libusb.h"
|
||||
#pragma warning(pop)
|
||||
|
||||
|
||||
namespace Libusb
|
||||
{
|
||||
typedef enum _INIT_STATUS : int
|
||||
{
|
||||
NOT_INIT = -2,
|
||||
INIT_ERROR,
|
||||
INIT_SUCCESS,
|
||||
}
|
||||
INIT_STATUS;
|
||||
|
||||
extern int InitStatus;
|
||||
|
||||
// initialize Libusb
|
||||
void Init(std::mutex &Mtx);
|
||||
// shutdown Libusb
|
||||
void DeInit();
|
||||
// refresh the device list in response to a refresh command from the input GUI
|
||||
void PopulateDevices();
|
||||
// update the device list
|
||||
void GetDeviceChanges();
|
||||
|
||||
class LibusbDevice : public InputDevice
|
||||
{
|
||||
public:
|
||||
~LibusbDevice();
|
||||
bool UpdateInput() override;
|
||||
bool ExecuteIo(void *Buffer, int Direction);
|
||||
|
||||
LibusbDevice(libusb_device_descriptor *Desc, libusb_device *Dev);
|
||||
|
||||
std::string GetDeviceName() const override;
|
||||
std::string GetAPI() const override;
|
||||
bool IsLibusb() const override { return m_Type != XBOX_INPUT_DEVICE::DEVICE_INVALID; }
|
||||
XBOX_INPUT_DEVICE GetLibusbType() const { return m_Type; }
|
||||
uint8_t GetUcType() { return m_UcType; }
|
||||
uint8_t GetUcSubType() { return m_UcSubType; }
|
||||
|
||||
|
||||
private:
|
||||
XBOX_INPUT_DEVICE m_Type;
|
||||
uint8_t m_UcType;
|
||||
uint8_t m_UcSubType;
|
||||
std::string m_Name;
|
||||
libusb_device_handle *m_hDev;
|
||||
unsigned char m_EndpointIn;
|
||||
unsigned char m_EndpointOut;
|
||||
uint8_t m_IntervalIn;
|
||||
uint8_t m_IntervalOut;
|
||||
uint8_t m_BufferInSize;
|
||||
uint8_t m_BufferOutSize;
|
||||
uint8_t m_IfaceNum;
|
||||
bool m_HasEndpointOut;
|
||||
};
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
// This is an open source non-commercial project. Dear PVS-Studio, please check it.
|
||||
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
|
||||
// ******************************************************************
|
||||
// *
|
||||
// * This file is part of the Cxbx project.
|
||||
// *
|
||||
// * Cxbx and Cxbe are free software; you can redistribute them
|
||||
// * and/or modify them under the terms of the GNU General Public
|
||||
// * License as published by the Free Software Foundation; either
|
||||
// * version 2 of the license, or (at your option) any later version.
|
||||
// *
|
||||
// * This program 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 recieved a copy of the GNU General Public License
|
||||
// * along with this program; see the file COPYING.
|
||||
// * If not, write to the Free Software Foundation, Inc.,
|
||||
// * 59 Temple Place - Suite 330, Bostom, MA 02111-1307, USA.
|
||||
// *
|
||||
// * (c) 2021 ergo720
|
||||
// *
|
||||
// * All rights reserved
|
||||
// *
|
||||
// ******************************************************************
|
||||
|
||||
#define LOG_PREFIX CXBXR_MODULE::RINP
|
||||
|
||||
#include "RawDevice.h"
|
||||
#include "Logging.h"
|
||||
#include <array>
|
||||
|
||||
// NOTE: we don't implement host input devices controlled by rawinput, we only use the api to detect device changes for xinput
|
||||
|
||||
namespace RawInput
|
||||
{
|
||||
int InitStatus = NOT_INIT;
|
||||
bool IgnoreHotplug = true;
|
||||
|
||||
void Init(std::mutex &Mtx, bool is_gui, HWND hwnd)
|
||||
{
|
||||
std::unique_lock<std::mutex> lck(Mtx);
|
||||
|
||||
if (is_gui) {
|
||||
// We don't need to monitor xinput device changes from the gui, because there we have the refresh button to detect changes
|
||||
InitStatus = INIT_SUCCESS;
|
||||
return;
|
||||
}
|
||||
|
||||
std::array<RAWINPUTDEVICE, 3> devices;
|
||||
// joystick devices
|
||||
devices[0].usUsagePage = 0x01;
|
||||
devices[0].usUsage = 0x04;
|
||||
devices[0].dwFlags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK;
|
||||
devices[0].hwndTarget = hwnd;
|
||||
// gamepad devices
|
||||
devices[1].usUsagePage = 0x01;
|
||||
devices[1].usUsage = 0x05;
|
||||
devices[1].dwFlags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK;
|
||||
devices[1].hwndTarget = hwnd;
|
||||
// multi axis controller devices
|
||||
devices[2].usUsagePage = 0x01;
|
||||
devices[2].usUsage = 0x08;
|
||||
devices[2].dwFlags = RIDEV_DEVNOTIFY | RIDEV_INPUTSINK;
|
||||
devices[2].hwndTarget = hwnd;
|
||||
|
||||
if (!RegisterRawInputDevices(devices.data(), static_cast<UINT>(devices.size()),
|
||||
static_cast<UINT>(sizeof(decltype(devices)::value_type))))
|
||||
{
|
||||
EmuLog(LOG_LEVEL::ERROR2, "RegisterRawInputDevices failed: %i", GetLastError());
|
||||
InitStatus = INIT_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
InitStatus = INIT_SUCCESS;
|
||||
}
|
||||
|
||||
void DeInit()
|
||||
{
|
||||
InitStatus = NOT_INIT;
|
||||
IgnoreHotplug = true;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue