diff --git a/duckstation-uwp.sln b/duckstation-uwp.sln
new file mode 100644
index 000000000..4011ac1d9
--- /dev/null
+++ b/duckstation-uwp.sln
@@ -0,0 +1,376 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29230.47
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "glad", "dep\glad\glad.vcxproj", "{43540154-9E1E-409C-834F-B84BE5621388}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Dependencies", "Dependencies", "{BA490C0E-497D-4634-A21E-E65012006385}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "imgui", "dep\imgui\imgui.vcxproj", "{BB08260F-6FBC-46AF-8924-090EE71360C6}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "common", "src\common\common.vcxproj", "{EE054E08-3799-4A59-A422-18259C105FFD}"
+ ProjectSection(ProjectDependencies) = postProject
+ {7F909E29-4808-4BD9-A60C-56C51A3AAEC2} = {7F909E29-4808-4BD9-A60C-56C51A3AAEC2}
+ {43540154-9E1E-409C-834F-B84BE5621388} = {43540154-9E1E-409C-834F-B84BE5621388}
+ {ED601289-AC1A-46B8-A8ED-17DB9EB73423} = {ED601289-AC1A-46B8-A8ED-17DB9EB73423}
+ {425D6C99-D1C8-43C2-B8AC-4D7B1D941017} = {425D6C99-D1C8-43C2-B8AC-4D7B1D941017}
+ {9C8DDEB0-2B8F-4F5F-BA86-127CDF27F035} = {9C8DDEB0-2B8F-4F5F-BA86-127CDF27F035}
+ {7FF9FDB9-D504-47DB-A16A-B08071999620} = {7FF9FDB9-D504-47DB-A16A-B08071999620}
+ {39F0ADFF-3A84-470D-9CF0-CA49E164F2F3} = {39F0ADFF-3A84-470D-9CF0-CA49E164F2F3}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core", "src\core\core.vcxproj", "{868B98C8-65A1-494B-8346-250A73A48C0A}"
+ ProjectSection(ProjectDependencies) = postProject
+ {EE054E08-3799-4A59-A422-18259C105FFD} = {EE054E08-3799-4A59-A422-18259C105FFD}
+ {BB08260F-6FBC-46AF-8924-090EE71360C6} = {BB08260F-6FBC-46AF-8924-090EE71360C6}
+ {8906836E-F06E-46E8-B11A-74E5E8C7B8FB} = {8906836E-F06E-46E8-B11A-74E5E8C7B8FB}
+ {ED601289-AC1A-46B8-A8ED-17DB9EB73423} = {ED601289-AC1A-46B8-A8ED-17DB9EB73423}
+ {09553C96-9F39-49BF-8AE6-7ACBD07C410C} = {09553C96-9F39-49BF-8AE6-7ACBD07C410C}
+ {9C8DDEB0-2B8F-4F5F-BA86-127CDF27F035} = {9C8DDEB0-2B8F-4F5F-BA86-127CDF27F035}
+ {7FF9FDB9-D504-47DB-A16A-B08071999620} = {7FF9FDB9-D504-47DB-A16A-B08071999620}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "stb", "dep\stb\stb.vcxproj", "{ED601289-AC1A-46B8-A8ED-17DB9EB73423}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "simpleini", "dep\simpleini\simpleini.vcxproj", "{3773F4CC-614E-4028-8595-22E08CA649E3}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tinyxml2", "dep\tinyxml2\tinyxml2.vcxproj", "{933118A9-68C5-47B4-B151-B03C93961623}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "minizip", "dep\minizip\minizip.vcxproj", "{8BDA439C-6358-45FB-9994-2FF083BABE06}"
+ ProjectSection(ProjectDependencies) = postProject
+ {7FF9FDB9-D504-47DB-A16A-B08071999620} = {7FF9FDB9-D504-47DB-A16A-B08071999620}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "dep\zlib\zlib.vcxproj", "{7FF9FDB9-D504-47DB-A16A-B08071999620}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libchdr", "dep\libchdr\libchdr.vcxproj", "{425D6C99-D1C8-43C2-B8AC-4D7B1D941017}"
+ ProjectSection(ProjectDependencies) = postProject
+ {DD944834-7899-4C1C-A4C1-064B5009D239} = {DD944834-7899-4C1C-A4C1-064B5009D239}
+ {7FF9FDB9-D504-47DB-A16A-B08071999620} = {7FF9FDB9-D504-47DB-A16A-B08071999620}
+ {97CBD3CB-CBC7-4D52-ABDE-F0AE7B794A5D} = {97CBD3CB-CBC7-4D52-ABDE-F0AE7B794A5D}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libFLAC", "dep\libFLAC\libFLAC.vcxproj", "{97CBD3CB-CBC7-4D52-ABDE-F0AE7B794A5D}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lzma", "dep\lzma\lzma.vcxproj", "{DD944834-7899-4C1C-A4C1-064B5009D239}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "frontend-common", "src\frontend-common\frontend-common.vcxproj", "{6245DEC8-D2DA-47EE-A373-CBD6FCF3ECE6}"
+ ProjectSection(ProjectDependencies) = postProject
+ {075CED82-6A20-46DF-94C7-9624AC9DDBEB} = {075CED82-6A20-46DF-94C7-9624AC9DDBEB}
+ {8BDA439C-6358-45FB-9994-2FF083BABE06} = {8BDA439C-6358-45FB-9994-2FF083BABE06}
+ {933118A9-68C5-47B4-B151-B03C93961623} = {933118A9-68C5-47B4-B151-B03C93961623}
+ {868B98C8-65A1-494B-8346-250A73A48C0A} = {868B98C8-65A1-494B-8346-250A73A48C0A}
+ {3773F4CC-614E-4028-8595-22E08CA649E3} = {3773F4CC-614E-4028-8595-22E08CA649E3}
+ {4BA0A6D4-3AE1-42B2-9347-096FD023FF64} = {4BA0A6D4-3AE1-42B2-9347-096FD023FF64}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xxhash", "dep\xxhash\xxhash.vcxproj", "{09553C96-9F39-49BF-8AE6-7ACBD07C410C}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "scmversion", "src\scmversion\scmversion.vcxproj", "{075CED82-6A20-46DF-94C7-9624AC9DDBEB}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "glslang", "dep\glslang\glslang.vcxproj", "{7F909E29-4808-4BD9-A60C-56C51A3AAEC2}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vulkan-loader", "dep\vulkan-loader\vulkan-loader.vcxproj", "{9C8DDEB0-2B8F-4F5F-BA86-127CDF27F035}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vixl", "dep\vixl\vixl.vcxproj", "{8906836E-F06E-46E8-B11A-74E5E8C7B8FB}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libsamplerate", "dep\libsamplerate\libsamplerate.vcxproj", "{39F0ADFF-3A84-470D-9CF0-CA49E164F2F3}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rcheevos", "dep\rcheevos\rcheevos.vcxproj", "{4BA0A6D4-3AE1-42B2-9347-096FD023FF64}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "duckstation-uwp", "src\duckstation-uwp\duckstation-uwp.vcxproj", "{E2A6CEA9-9537-4C61-B637-81F1F17EF638}"
+ ProjectSection(ProjectDependencies) = postProject
+ {6245DEC8-D2DA-47EE-A373-CBD6FCF3ECE6} = {6245DEC8-D2DA-47EE-A373-CBD6FCF3ECE6}
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ DebugUWP|ARM64 = DebugUWP|ARM64
+ DebugUWP|x64 = DebugUWP|x64
+ DebugUWP|x86 = DebugUWP|x86
+ ReleaseUWP|ARM64 = ReleaseUWP|ARM64
+ ReleaseUWP|x64 = ReleaseUWP|x64
+ ReleaseUWP|x86 = ReleaseUWP|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {43540154-9E1E-409C-834F-B84BE5621388}.DebugUWP|ARM64.ActiveCfg = DebugUWP|ARM64
+ {43540154-9E1E-409C-834F-B84BE5621388}.DebugUWP|ARM64.Build.0 = DebugUWP|ARM64
+ {43540154-9E1E-409C-834F-B84BE5621388}.DebugUWP|x64.ActiveCfg = DebugUWP|x64
+ {43540154-9E1E-409C-834F-B84BE5621388}.DebugUWP|x64.Build.0 = DebugUWP|x64
+ {43540154-9E1E-409C-834F-B84BE5621388}.DebugUWP|x86.ActiveCfg = DebugUWP|Win32
+ {43540154-9E1E-409C-834F-B84BE5621388}.DebugUWP|x86.Build.0 = DebugUWP|Win32
+ {43540154-9E1E-409C-834F-B84BE5621388}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64
+ {43540154-9E1E-409C-834F-B84BE5621388}.ReleaseUWP|ARM64.Build.0 = ReleaseUWP|ARM64
+ {43540154-9E1E-409C-834F-B84BE5621388}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64
+ {43540154-9E1E-409C-834F-B84BE5621388}.ReleaseUWP|x64.Build.0 = ReleaseUWP|x64
+ {43540154-9E1E-409C-834F-B84BE5621388}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32
+ {43540154-9E1E-409C-834F-B84BE5621388}.ReleaseUWP|x86.Build.0 = ReleaseUWP|Win32
+ {BB08260F-6FBC-46AF-8924-090EE71360C6}.DebugUWP|ARM64.ActiveCfg = DebugUWP|ARM64
+ {BB08260F-6FBC-46AF-8924-090EE71360C6}.DebugUWP|ARM64.Build.0 = DebugUWP|ARM64
+ {BB08260F-6FBC-46AF-8924-090EE71360C6}.DebugUWP|x64.ActiveCfg = DebugUWP|x64
+ {BB08260F-6FBC-46AF-8924-090EE71360C6}.DebugUWP|x64.Build.0 = DebugUWP|x64
+ {BB08260F-6FBC-46AF-8924-090EE71360C6}.DebugUWP|x86.ActiveCfg = DebugUWP|Win32
+ {BB08260F-6FBC-46AF-8924-090EE71360C6}.DebugUWP|x86.Build.0 = DebugUWP|Win32
+ {BB08260F-6FBC-46AF-8924-090EE71360C6}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64
+ {BB08260F-6FBC-46AF-8924-090EE71360C6}.ReleaseUWP|ARM64.Build.0 = ReleaseUWP|ARM64
+ {BB08260F-6FBC-46AF-8924-090EE71360C6}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64
+ {BB08260F-6FBC-46AF-8924-090EE71360C6}.ReleaseUWP|x64.Build.0 = ReleaseUWP|x64
+ {BB08260F-6FBC-46AF-8924-090EE71360C6}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32
+ {BB08260F-6FBC-46AF-8924-090EE71360C6}.ReleaseUWP|x86.Build.0 = ReleaseUWP|Win32
+ {EE054E08-3799-4A59-A422-18259C105FFD}.DebugUWP|ARM64.ActiveCfg = DebugUWP|ARM64
+ {EE054E08-3799-4A59-A422-18259C105FFD}.DebugUWP|ARM64.Build.0 = DebugUWP|ARM64
+ {EE054E08-3799-4A59-A422-18259C105FFD}.DebugUWP|x64.ActiveCfg = DebugUWP|x64
+ {EE054E08-3799-4A59-A422-18259C105FFD}.DebugUWP|x64.Build.0 = DebugUWP|x64
+ {EE054E08-3799-4A59-A422-18259C105FFD}.DebugUWP|x86.ActiveCfg = DebugUWP|Win32
+ {EE054E08-3799-4A59-A422-18259C105FFD}.DebugUWP|x86.Build.0 = DebugUWP|Win32
+ {EE054E08-3799-4A59-A422-18259C105FFD}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64
+ {EE054E08-3799-4A59-A422-18259C105FFD}.ReleaseUWP|ARM64.Build.0 = ReleaseUWP|ARM64
+ {EE054E08-3799-4A59-A422-18259C105FFD}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64
+ {EE054E08-3799-4A59-A422-18259C105FFD}.ReleaseUWP|x64.Build.0 = ReleaseUWP|x64
+ {EE054E08-3799-4A59-A422-18259C105FFD}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32
+ {EE054E08-3799-4A59-A422-18259C105FFD}.ReleaseUWP|x86.Build.0 = ReleaseUWP|Win32
+ {868B98C8-65A1-494B-8346-250A73A48C0A}.DebugUWP|ARM64.ActiveCfg = DebugUWP|ARM64
+ {868B98C8-65A1-494B-8346-250A73A48C0A}.DebugUWP|ARM64.Build.0 = DebugUWP|ARM64
+ {868B98C8-65A1-494B-8346-250A73A48C0A}.DebugUWP|x64.ActiveCfg = DebugUWP|x64
+ {868B98C8-65A1-494B-8346-250A73A48C0A}.DebugUWP|x64.Build.0 = DebugUWP|x64
+ {868B98C8-65A1-494B-8346-250A73A48C0A}.DebugUWP|x86.ActiveCfg = DebugUWP|Win32
+ {868B98C8-65A1-494B-8346-250A73A48C0A}.DebugUWP|x86.Build.0 = DebugUWP|Win32
+ {868B98C8-65A1-494B-8346-250A73A48C0A}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64
+ {868B98C8-65A1-494B-8346-250A73A48C0A}.ReleaseUWP|ARM64.Build.0 = ReleaseUWP|ARM64
+ {868B98C8-65A1-494B-8346-250A73A48C0A}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64
+ {868B98C8-65A1-494B-8346-250A73A48C0A}.ReleaseUWP|x64.Build.0 = ReleaseUWP|x64
+ {868B98C8-65A1-494B-8346-250A73A48C0A}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32
+ {868B98C8-65A1-494B-8346-250A73A48C0A}.ReleaseUWP|x86.Build.0 = ReleaseUWP|Win32
+ {ED601289-AC1A-46B8-A8ED-17DB9EB73423}.DebugUWP|ARM64.ActiveCfg = DebugUWP|ARM64
+ {ED601289-AC1A-46B8-A8ED-17DB9EB73423}.DebugUWP|ARM64.Build.0 = DebugUWP|ARM64
+ {ED601289-AC1A-46B8-A8ED-17DB9EB73423}.DebugUWP|x64.ActiveCfg = DebugUWP|x64
+ {ED601289-AC1A-46B8-A8ED-17DB9EB73423}.DebugUWP|x64.Build.0 = DebugUWP|x64
+ {ED601289-AC1A-46B8-A8ED-17DB9EB73423}.DebugUWP|x86.ActiveCfg = DebugUWP|Win32
+ {ED601289-AC1A-46B8-A8ED-17DB9EB73423}.DebugUWP|x86.Build.0 = DebugUWP|Win32
+ {ED601289-AC1A-46B8-A8ED-17DB9EB73423}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64
+ {ED601289-AC1A-46B8-A8ED-17DB9EB73423}.ReleaseUWP|ARM64.Build.0 = ReleaseUWP|ARM64
+ {ED601289-AC1A-46B8-A8ED-17DB9EB73423}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64
+ {ED601289-AC1A-46B8-A8ED-17DB9EB73423}.ReleaseUWP|x64.Build.0 = ReleaseUWP|x64
+ {ED601289-AC1A-46B8-A8ED-17DB9EB73423}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32
+ {ED601289-AC1A-46B8-A8ED-17DB9EB73423}.ReleaseUWP|x86.Build.0 = ReleaseUWP|Win32
+ {3773F4CC-614E-4028-8595-22E08CA649E3}.DebugUWP|ARM64.ActiveCfg = DebugUWP|ARM64
+ {3773F4CC-614E-4028-8595-22E08CA649E3}.DebugUWP|ARM64.Build.0 = DebugUWP|ARM64
+ {3773F4CC-614E-4028-8595-22E08CA649E3}.DebugUWP|x64.ActiveCfg = DebugUWP|x64
+ {3773F4CC-614E-4028-8595-22E08CA649E3}.DebugUWP|x64.Build.0 = DebugUWP|x64
+ {3773F4CC-614E-4028-8595-22E08CA649E3}.DebugUWP|x86.ActiveCfg = DebugUWP|Win32
+ {3773F4CC-614E-4028-8595-22E08CA649E3}.DebugUWP|x86.Build.0 = DebugUWP|Win32
+ {3773F4CC-614E-4028-8595-22E08CA649E3}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64
+ {3773F4CC-614E-4028-8595-22E08CA649E3}.ReleaseUWP|ARM64.Build.0 = ReleaseUWP|ARM64
+ {3773F4CC-614E-4028-8595-22E08CA649E3}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64
+ {3773F4CC-614E-4028-8595-22E08CA649E3}.ReleaseUWP|x64.Build.0 = ReleaseUWP|x64
+ {3773F4CC-614E-4028-8595-22E08CA649E3}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32
+ {3773F4CC-614E-4028-8595-22E08CA649E3}.ReleaseUWP|x86.Build.0 = ReleaseUWP|Win32
+ {933118A9-68C5-47B4-B151-B03C93961623}.DebugUWP|ARM64.ActiveCfg = DebugUWP|ARM64
+ {933118A9-68C5-47B4-B151-B03C93961623}.DebugUWP|ARM64.Build.0 = DebugUWP|ARM64
+ {933118A9-68C5-47B4-B151-B03C93961623}.DebugUWP|x64.ActiveCfg = DebugUWP|x64
+ {933118A9-68C5-47B4-B151-B03C93961623}.DebugUWP|x64.Build.0 = DebugUWP|x64
+ {933118A9-68C5-47B4-B151-B03C93961623}.DebugUWP|x86.ActiveCfg = DebugUWP|Win32
+ {933118A9-68C5-47B4-B151-B03C93961623}.DebugUWP|x86.Build.0 = DebugUWP|Win32
+ {933118A9-68C5-47B4-B151-B03C93961623}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64
+ {933118A9-68C5-47B4-B151-B03C93961623}.ReleaseUWP|ARM64.Build.0 = ReleaseUWP|ARM64
+ {933118A9-68C5-47B4-B151-B03C93961623}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64
+ {933118A9-68C5-47B4-B151-B03C93961623}.ReleaseUWP|x64.Build.0 = ReleaseUWP|x64
+ {933118A9-68C5-47B4-B151-B03C93961623}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32
+ {933118A9-68C5-47B4-B151-B03C93961623}.ReleaseUWP|x86.Build.0 = ReleaseUWP|Win32
+ {8BDA439C-6358-45FB-9994-2FF083BABE06}.DebugUWP|ARM64.ActiveCfg = DebugUWP|ARM64
+ {8BDA439C-6358-45FB-9994-2FF083BABE06}.DebugUWP|ARM64.Build.0 = DebugUWP|ARM64
+ {8BDA439C-6358-45FB-9994-2FF083BABE06}.DebugUWP|x64.ActiveCfg = DebugUWP|x64
+ {8BDA439C-6358-45FB-9994-2FF083BABE06}.DebugUWP|x64.Build.0 = DebugUWP|x64
+ {8BDA439C-6358-45FB-9994-2FF083BABE06}.DebugUWP|x86.ActiveCfg = DebugUWP|Win32
+ {8BDA439C-6358-45FB-9994-2FF083BABE06}.DebugUWP|x86.Build.0 = DebugUWP|Win32
+ {8BDA439C-6358-45FB-9994-2FF083BABE06}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64
+ {8BDA439C-6358-45FB-9994-2FF083BABE06}.ReleaseUWP|ARM64.Build.0 = ReleaseUWP|ARM64
+ {8BDA439C-6358-45FB-9994-2FF083BABE06}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64
+ {8BDA439C-6358-45FB-9994-2FF083BABE06}.ReleaseUWP|x64.Build.0 = ReleaseUWP|x64
+ {8BDA439C-6358-45FB-9994-2FF083BABE06}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32
+ {8BDA439C-6358-45FB-9994-2FF083BABE06}.ReleaseUWP|x86.Build.0 = ReleaseUWP|Win32
+ {7FF9FDB9-D504-47DB-A16A-B08071999620}.DebugUWP|ARM64.ActiveCfg = DebugUWP|ARM64
+ {7FF9FDB9-D504-47DB-A16A-B08071999620}.DebugUWP|ARM64.Build.0 = DebugUWP|ARM64
+ {7FF9FDB9-D504-47DB-A16A-B08071999620}.DebugUWP|x64.ActiveCfg = DebugUWP|x64
+ {7FF9FDB9-D504-47DB-A16A-B08071999620}.DebugUWP|x64.Build.0 = DebugUWP|x64
+ {7FF9FDB9-D504-47DB-A16A-B08071999620}.DebugUWP|x86.ActiveCfg = DebugUWP|Win32
+ {7FF9FDB9-D504-47DB-A16A-B08071999620}.DebugUWP|x86.Build.0 = DebugUWP|Win32
+ {7FF9FDB9-D504-47DB-A16A-B08071999620}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64
+ {7FF9FDB9-D504-47DB-A16A-B08071999620}.ReleaseUWP|ARM64.Build.0 = ReleaseUWP|ARM64
+ {7FF9FDB9-D504-47DB-A16A-B08071999620}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64
+ {7FF9FDB9-D504-47DB-A16A-B08071999620}.ReleaseUWP|x64.Build.0 = ReleaseUWP|x64
+ {7FF9FDB9-D504-47DB-A16A-B08071999620}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32
+ {7FF9FDB9-D504-47DB-A16A-B08071999620}.ReleaseUWP|x86.Build.0 = ReleaseUWP|Win32
+ {425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.DebugUWP|ARM64.ActiveCfg = DebugUWP|ARM64
+ {425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.DebugUWP|ARM64.Build.0 = DebugUWP|ARM64
+ {425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.DebugUWP|x64.ActiveCfg = DebugUWP|x64
+ {425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.DebugUWP|x64.Build.0 = DebugUWP|x64
+ {425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.DebugUWP|x86.ActiveCfg = DebugUWP|Win32
+ {425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.DebugUWP|x86.Build.0 = DebugUWP|Win32
+ {425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64
+ {425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.ReleaseUWP|ARM64.Build.0 = ReleaseUWP|ARM64
+ {425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64
+ {425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.ReleaseUWP|x64.Build.0 = ReleaseUWP|x64
+ {425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32
+ {425D6C99-D1C8-43C2-B8AC-4D7B1D941017}.ReleaseUWP|x86.Build.0 = ReleaseUWP|Win32
+ {97CBD3CB-CBC7-4D52-ABDE-F0AE7B794A5D}.DebugUWP|ARM64.ActiveCfg = DebugUWP|ARM64
+ {97CBD3CB-CBC7-4D52-ABDE-F0AE7B794A5D}.DebugUWP|ARM64.Build.0 = DebugUWP|ARM64
+ {97CBD3CB-CBC7-4D52-ABDE-F0AE7B794A5D}.DebugUWP|x64.ActiveCfg = DebugUWP|x64
+ {97CBD3CB-CBC7-4D52-ABDE-F0AE7B794A5D}.DebugUWP|x64.Build.0 = DebugUWP|x64
+ {97CBD3CB-CBC7-4D52-ABDE-F0AE7B794A5D}.DebugUWP|x86.ActiveCfg = DebugUWP|Win32
+ {97CBD3CB-CBC7-4D52-ABDE-F0AE7B794A5D}.DebugUWP|x86.Build.0 = DebugUWP|Win32
+ {97CBD3CB-CBC7-4D52-ABDE-F0AE7B794A5D}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64
+ {97CBD3CB-CBC7-4D52-ABDE-F0AE7B794A5D}.ReleaseUWP|ARM64.Build.0 = ReleaseUWP|ARM64
+ {97CBD3CB-CBC7-4D52-ABDE-F0AE7B794A5D}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64
+ {97CBD3CB-CBC7-4D52-ABDE-F0AE7B794A5D}.ReleaseUWP|x64.Build.0 = ReleaseUWP|x64
+ {97CBD3CB-CBC7-4D52-ABDE-F0AE7B794A5D}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32
+ {97CBD3CB-CBC7-4D52-ABDE-F0AE7B794A5D}.ReleaseUWP|x86.Build.0 = ReleaseUWP|Win32
+ {DD944834-7899-4C1C-A4C1-064B5009D239}.DebugUWP|ARM64.ActiveCfg = DebugUWP|ARM64
+ {DD944834-7899-4C1C-A4C1-064B5009D239}.DebugUWP|ARM64.Build.0 = DebugUWP|ARM64
+ {DD944834-7899-4C1C-A4C1-064B5009D239}.DebugUWP|x64.ActiveCfg = DebugUWP|x64
+ {DD944834-7899-4C1C-A4C1-064B5009D239}.DebugUWP|x64.Build.0 = DebugUWP|x64
+ {DD944834-7899-4C1C-A4C1-064B5009D239}.DebugUWP|x86.ActiveCfg = DebugUWP|Win32
+ {DD944834-7899-4C1C-A4C1-064B5009D239}.DebugUWP|x86.Build.0 = DebugUWP|Win32
+ {DD944834-7899-4C1C-A4C1-064B5009D239}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64
+ {DD944834-7899-4C1C-A4C1-064B5009D239}.ReleaseUWP|ARM64.Build.0 = ReleaseUWP|ARM64
+ {DD944834-7899-4C1C-A4C1-064B5009D239}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64
+ {DD944834-7899-4C1C-A4C1-064B5009D239}.ReleaseUWP|x64.Build.0 = ReleaseUWP|x64
+ {DD944834-7899-4C1C-A4C1-064B5009D239}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32
+ {DD944834-7899-4C1C-A4C1-064B5009D239}.ReleaseUWP|x86.Build.0 = ReleaseUWP|Win32
+ {6245DEC8-D2DA-47EE-A373-CBD6FCF3ECE6}.DebugUWP|ARM64.ActiveCfg = DebugUWP|ARM64
+ {6245DEC8-D2DA-47EE-A373-CBD6FCF3ECE6}.DebugUWP|ARM64.Build.0 = DebugUWP|ARM64
+ {6245DEC8-D2DA-47EE-A373-CBD6FCF3ECE6}.DebugUWP|x64.ActiveCfg = DebugUWP|x64
+ {6245DEC8-D2DA-47EE-A373-CBD6FCF3ECE6}.DebugUWP|x64.Build.0 = DebugUWP|x64
+ {6245DEC8-D2DA-47EE-A373-CBD6FCF3ECE6}.DebugUWP|x86.ActiveCfg = DebugUWP|Win32
+ {6245DEC8-D2DA-47EE-A373-CBD6FCF3ECE6}.DebugUWP|x86.Build.0 = DebugUWP|Win32
+ {6245DEC8-D2DA-47EE-A373-CBD6FCF3ECE6}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64
+ {6245DEC8-D2DA-47EE-A373-CBD6FCF3ECE6}.ReleaseUWP|ARM64.Build.0 = ReleaseUWP|ARM64
+ {6245DEC8-D2DA-47EE-A373-CBD6FCF3ECE6}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64
+ {6245DEC8-D2DA-47EE-A373-CBD6FCF3ECE6}.ReleaseUWP|x64.Build.0 = ReleaseUWP|x64
+ {6245DEC8-D2DA-47EE-A373-CBD6FCF3ECE6}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32
+ {6245DEC8-D2DA-47EE-A373-CBD6FCF3ECE6}.ReleaseUWP|x86.Build.0 = ReleaseUWP|Win32
+ {09553C96-9F39-49BF-8AE6-7ACBD07C410C}.DebugUWP|ARM64.ActiveCfg = DebugUWP|ARM64
+ {09553C96-9F39-49BF-8AE6-7ACBD07C410C}.DebugUWP|ARM64.Build.0 = DebugUWP|ARM64
+ {09553C96-9F39-49BF-8AE6-7ACBD07C410C}.DebugUWP|x64.ActiveCfg = DebugUWP|x64
+ {09553C96-9F39-49BF-8AE6-7ACBD07C410C}.DebugUWP|x64.Build.0 = DebugUWP|x64
+ {09553C96-9F39-49BF-8AE6-7ACBD07C410C}.DebugUWP|x86.ActiveCfg = DebugUWP|Win32
+ {09553C96-9F39-49BF-8AE6-7ACBD07C410C}.DebugUWP|x86.Build.0 = DebugUWP|Win32
+ {09553C96-9F39-49BF-8AE6-7ACBD07C410C}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64
+ {09553C96-9F39-49BF-8AE6-7ACBD07C410C}.ReleaseUWP|ARM64.Build.0 = ReleaseUWP|ARM64
+ {09553C96-9F39-49BF-8AE6-7ACBD07C410C}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64
+ {09553C96-9F39-49BF-8AE6-7ACBD07C410C}.ReleaseUWP|x64.Build.0 = ReleaseUWP|x64
+ {09553C96-9F39-49BF-8AE6-7ACBD07C410C}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32
+ {09553C96-9F39-49BF-8AE6-7ACBD07C410C}.ReleaseUWP|x86.Build.0 = ReleaseUWP|Win32
+ {075CED82-6A20-46DF-94C7-9624AC9DDBEB}.DebugUWP|ARM64.ActiveCfg = DebugUWP|ARM64
+ {075CED82-6A20-46DF-94C7-9624AC9DDBEB}.DebugUWP|ARM64.Build.0 = DebugUWP|ARM64
+ {075CED82-6A20-46DF-94C7-9624AC9DDBEB}.DebugUWP|x64.ActiveCfg = DebugUWP|x64
+ {075CED82-6A20-46DF-94C7-9624AC9DDBEB}.DebugUWP|x64.Build.0 = DebugUWP|x64
+ {075CED82-6A20-46DF-94C7-9624AC9DDBEB}.DebugUWP|x86.ActiveCfg = DebugUWP|Win32
+ {075CED82-6A20-46DF-94C7-9624AC9DDBEB}.DebugUWP|x86.Build.0 = DebugUWP|Win32
+ {075CED82-6A20-46DF-94C7-9624AC9DDBEB}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64
+ {075CED82-6A20-46DF-94C7-9624AC9DDBEB}.ReleaseUWP|ARM64.Build.0 = ReleaseUWP|ARM64
+ {075CED82-6A20-46DF-94C7-9624AC9DDBEB}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64
+ {075CED82-6A20-46DF-94C7-9624AC9DDBEB}.ReleaseUWP|x64.Build.0 = ReleaseUWP|x64
+ {075CED82-6A20-46DF-94C7-9624AC9DDBEB}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32
+ {075CED82-6A20-46DF-94C7-9624AC9DDBEB}.ReleaseUWP|x86.Build.0 = ReleaseUWP|Win32
+ {7F909E29-4808-4BD9-A60C-56C51A3AAEC2}.DebugUWP|ARM64.ActiveCfg = DebugUWP|ARM64
+ {7F909E29-4808-4BD9-A60C-56C51A3AAEC2}.DebugUWP|ARM64.Build.0 = DebugUWP|ARM64
+ {7F909E29-4808-4BD9-A60C-56C51A3AAEC2}.DebugUWP|x64.ActiveCfg = DebugUWP|x64
+ {7F909E29-4808-4BD9-A60C-56C51A3AAEC2}.DebugUWP|x64.Build.0 = DebugUWP|x64
+ {7F909E29-4808-4BD9-A60C-56C51A3AAEC2}.DebugUWP|x86.ActiveCfg = DebugUWP|Win32
+ {7F909E29-4808-4BD9-A60C-56C51A3AAEC2}.DebugUWP|x86.Build.0 = DebugUWP|Win32
+ {7F909E29-4808-4BD9-A60C-56C51A3AAEC2}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64
+ {7F909E29-4808-4BD9-A60C-56C51A3AAEC2}.ReleaseUWP|ARM64.Build.0 = ReleaseUWP|ARM64
+ {7F909E29-4808-4BD9-A60C-56C51A3AAEC2}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64
+ {7F909E29-4808-4BD9-A60C-56C51A3AAEC2}.ReleaseUWP|x64.Build.0 = ReleaseUWP|x64
+ {7F909E29-4808-4BD9-A60C-56C51A3AAEC2}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32
+ {7F909E29-4808-4BD9-A60C-56C51A3AAEC2}.ReleaseUWP|x86.Build.0 = ReleaseUWP|Win32
+ {9C8DDEB0-2B8F-4F5F-BA86-127CDF27F035}.DebugUWP|ARM64.ActiveCfg = DebugUWP|ARM64
+ {9C8DDEB0-2B8F-4F5F-BA86-127CDF27F035}.DebugUWP|ARM64.Build.0 = DebugUWP|ARM64
+ {9C8DDEB0-2B8F-4F5F-BA86-127CDF27F035}.DebugUWP|x64.ActiveCfg = DebugUWP|x64
+ {9C8DDEB0-2B8F-4F5F-BA86-127CDF27F035}.DebugUWP|x64.Build.0 = DebugUWP|x64
+ {9C8DDEB0-2B8F-4F5F-BA86-127CDF27F035}.DebugUWP|x86.ActiveCfg = DebugUWP|Win32
+ {9C8DDEB0-2B8F-4F5F-BA86-127CDF27F035}.DebugUWP|x86.Build.0 = DebugUWP|Win32
+ {9C8DDEB0-2B8F-4F5F-BA86-127CDF27F035}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64
+ {9C8DDEB0-2B8F-4F5F-BA86-127CDF27F035}.ReleaseUWP|ARM64.Build.0 = ReleaseUWP|ARM64
+ {9C8DDEB0-2B8F-4F5F-BA86-127CDF27F035}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64
+ {9C8DDEB0-2B8F-4F5F-BA86-127CDF27F035}.ReleaseUWP|x64.Build.0 = ReleaseUWP|x64
+ {9C8DDEB0-2B8F-4F5F-BA86-127CDF27F035}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32
+ {9C8DDEB0-2B8F-4F5F-BA86-127CDF27F035}.ReleaseUWP|x86.Build.0 = ReleaseUWP|Win32
+ {8906836E-F06E-46E8-B11A-74E5E8C7B8FB}.DebugUWP|ARM64.ActiveCfg = DebugUWP|ARM64
+ {8906836E-F06E-46E8-B11A-74E5E8C7B8FB}.DebugUWP|ARM64.Build.0 = DebugUWP|ARM64
+ {8906836E-F06E-46E8-B11A-74E5E8C7B8FB}.DebugUWP|x64.ActiveCfg = DebugUWP|x64
+ {8906836E-F06E-46E8-B11A-74E5E8C7B8FB}.DebugUWP|x86.ActiveCfg = DebugUWP|Win32
+ {8906836E-F06E-46E8-B11A-74E5E8C7B8FB}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64
+ {8906836E-F06E-46E8-B11A-74E5E8C7B8FB}.ReleaseUWP|ARM64.Build.0 = ReleaseUWP|ARM64
+ {8906836E-F06E-46E8-B11A-74E5E8C7B8FB}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64
+ {8906836E-F06E-46E8-B11A-74E5E8C7B8FB}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32
+ {39F0ADFF-3A84-470D-9CF0-CA49E164F2F3}.DebugUWP|ARM64.ActiveCfg = DebugUWP|ARM64
+ {39F0ADFF-3A84-470D-9CF0-CA49E164F2F3}.DebugUWP|ARM64.Build.0 = DebugUWP|ARM64
+ {39F0ADFF-3A84-470D-9CF0-CA49E164F2F3}.DebugUWP|x64.ActiveCfg = DebugUWP|x64
+ {39F0ADFF-3A84-470D-9CF0-CA49E164F2F3}.DebugUWP|x64.Build.0 = DebugUWP|x64
+ {39F0ADFF-3A84-470D-9CF0-CA49E164F2F3}.DebugUWP|x86.ActiveCfg = DebugUWP|Win32
+ {39F0ADFF-3A84-470D-9CF0-CA49E164F2F3}.DebugUWP|x86.Build.0 = DebugUWP|Win32
+ {39F0ADFF-3A84-470D-9CF0-CA49E164F2F3}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64
+ {39F0ADFF-3A84-470D-9CF0-CA49E164F2F3}.ReleaseUWP|ARM64.Build.0 = ReleaseUWP|ARM64
+ {39F0ADFF-3A84-470D-9CF0-CA49E164F2F3}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64
+ {39F0ADFF-3A84-470D-9CF0-CA49E164F2F3}.ReleaseUWP|x64.Build.0 = ReleaseUWP|x64
+ {39F0ADFF-3A84-470D-9CF0-CA49E164F2F3}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32
+ {39F0ADFF-3A84-470D-9CF0-CA49E164F2F3}.ReleaseUWP|x86.Build.0 = ReleaseUWP|Win32
+ {4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.DebugUWP|ARM64.ActiveCfg = DebugUWP|ARM64
+ {4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.DebugUWP|ARM64.Build.0 = DebugUWP|ARM64
+ {4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.DebugUWP|x64.ActiveCfg = DebugUWP|x64
+ {4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.DebugUWP|x64.Build.0 = DebugUWP|x64
+ {4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.DebugUWP|x86.ActiveCfg = DebugUWP|Win32
+ {4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.DebugUWP|x86.Build.0 = DebugUWP|Win32
+ {4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64
+ {4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.ReleaseUWP|ARM64.Build.0 = ReleaseUWP|ARM64
+ {4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64
+ {4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.ReleaseUWP|x64.Build.0 = ReleaseUWP|x64
+ {4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32
+ {4BA0A6D4-3AE1-42B2-9347-096FD023FF64}.ReleaseUWP|x86.Build.0 = ReleaseUWP|Win32
+ {E2A6CEA9-9537-4C61-B637-81F1F17EF638}.DebugUWP|ARM64.ActiveCfg = DebugUWP|ARM64
+ {E2A6CEA9-9537-4C61-B637-81F1F17EF638}.DebugUWP|ARM64.Build.0 = DebugUWP|ARM64
+ {E2A6CEA9-9537-4C61-B637-81F1F17EF638}.DebugUWP|ARM64.Deploy.0 = DebugUWP|ARM64
+ {E2A6CEA9-9537-4C61-B637-81F1F17EF638}.DebugUWP|x64.ActiveCfg = DebugUWP|x64
+ {E2A6CEA9-9537-4C61-B637-81F1F17EF638}.DebugUWP|x64.Build.0 = DebugUWP|x64
+ {E2A6CEA9-9537-4C61-B637-81F1F17EF638}.DebugUWP|x64.Deploy.0 = DebugUWP|x64
+ {E2A6CEA9-9537-4C61-B637-81F1F17EF638}.DebugUWP|x86.ActiveCfg = DebugUWP|Win32
+ {E2A6CEA9-9537-4C61-B637-81F1F17EF638}.DebugUWP|x86.Build.0 = DebugUWP|Win32
+ {E2A6CEA9-9537-4C61-B637-81F1F17EF638}.DebugUWP|x86.Deploy.0 = DebugUWP|Win32
+ {E2A6CEA9-9537-4C61-B637-81F1F17EF638}.ReleaseUWP|ARM64.ActiveCfg = ReleaseUWP|ARM64
+ {E2A6CEA9-9537-4C61-B637-81F1F17EF638}.ReleaseUWP|ARM64.Build.0 = ReleaseUWP|ARM64
+ {E2A6CEA9-9537-4C61-B637-81F1F17EF638}.ReleaseUWP|ARM64.Deploy.0 = ReleaseUWP|ARM64
+ {E2A6CEA9-9537-4C61-B637-81F1F17EF638}.ReleaseUWP|x64.ActiveCfg = ReleaseUWP|x64
+ {E2A6CEA9-9537-4C61-B637-81F1F17EF638}.ReleaseUWP|x64.Build.0 = ReleaseUWP|x64
+ {E2A6CEA9-9537-4C61-B637-81F1F17EF638}.ReleaseUWP|x64.Deploy.0 = ReleaseUWP|x64
+ {E2A6CEA9-9537-4C61-B637-81F1F17EF638}.ReleaseUWP|x86.ActiveCfg = ReleaseUWP|Win32
+ {E2A6CEA9-9537-4C61-B637-81F1F17EF638}.ReleaseUWP|x86.Build.0 = ReleaseUWP|Win32
+ {E2A6CEA9-9537-4C61-B637-81F1F17EF638}.ReleaseUWP|x86.Deploy.0 = ReleaseUWP|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {43540154-9E1E-409C-834F-B84BE5621388} = {BA490C0E-497D-4634-A21E-E65012006385}
+ {BB08260F-6FBC-46AF-8924-090EE71360C6} = {BA490C0E-497D-4634-A21E-E65012006385}
+ {ED601289-AC1A-46B8-A8ED-17DB9EB73423} = {BA490C0E-497D-4634-A21E-E65012006385}
+ {3773F4CC-614E-4028-8595-22E08CA649E3} = {BA490C0E-497D-4634-A21E-E65012006385}
+ {933118A9-68C5-47B4-B151-B03C93961623} = {BA490C0E-497D-4634-A21E-E65012006385}
+ {8BDA439C-6358-45FB-9994-2FF083BABE06} = {BA490C0E-497D-4634-A21E-E65012006385}
+ {7FF9FDB9-D504-47DB-A16A-B08071999620} = {BA490C0E-497D-4634-A21E-E65012006385}
+ {425D6C99-D1C8-43C2-B8AC-4D7B1D941017} = {BA490C0E-497D-4634-A21E-E65012006385}
+ {97CBD3CB-CBC7-4D52-ABDE-F0AE7B794A5D} = {BA490C0E-497D-4634-A21E-E65012006385}
+ {DD944834-7899-4C1C-A4C1-064B5009D239} = {BA490C0E-497D-4634-A21E-E65012006385}
+ {09553C96-9F39-49BF-8AE6-7ACBD07C410C} = {BA490C0E-497D-4634-A21E-E65012006385}
+ {7F909E29-4808-4BD9-A60C-56C51A3AAEC2} = {BA490C0E-497D-4634-A21E-E65012006385}
+ {9C8DDEB0-2B8F-4F5F-BA86-127CDF27F035} = {BA490C0E-497D-4634-A21E-E65012006385}
+ {8906836E-F06E-46E8-B11A-74E5E8C7B8FB} = {BA490C0E-497D-4634-A21E-E65012006385}
+ {39F0ADFF-3A84-470D-9CF0-CA49E164F2F3} = {BA490C0E-497D-4634-A21E-E65012006385}
+ {4BA0A6D4-3AE1-42B2-9347-096FD023FF64} = {BA490C0E-497D-4634-A21E-E65012006385}
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {26E40B32-7C1D-48D0-95F4-1A500E054028}
+ EndGlobalSection
+EndGlobal
diff --git a/src/duckstation-uwp/.gitignore b/src/duckstation-uwp/.gitignore
new file mode 100644
index 000000000..2297123c5
--- /dev/null
+++ b/src/duckstation-uwp/.gitignore
@@ -0,0 +1,6 @@
+database/
+inputprofiles/
+resources/
+shaders/
+BundleArtifacts/
+duckstation-uwp.pfx
\ No newline at end of file
diff --git a/src/duckstation-uwp/Assets/LargeTile.scale-100.png b/src/duckstation-uwp/Assets/LargeTile.scale-100.png
new file mode 100644
index 000000000..4b0ef4b94
Binary files /dev/null and b/src/duckstation-uwp/Assets/LargeTile.scale-100.png differ
diff --git a/src/duckstation-uwp/Assets/LargeTile.scale-125.png b/src/duckstation-uwp/Assets/LargeTile.scale-125.png
new file mode 100644
index 000000000..45cf55b1e
Binary files /dev/null and b/src/duckstation-uwp/Assets/LargeTile.scale-125.png differ
diff --git a/src/duckstation-uwp/Assets/LargeTile.scale-150.png b/src/duckstation-uwp/Assets/LargeTile.scale-150.png
new file mode 100644
index 000000000..014868e37
Binary files /dev/null and b/src/duckstation-uwp/Assets/LargeTile.scale-150.png differ
diff --git a/src/duckstation-uwp/Assets/LargeTile.scale-200.png b/src/duckstation-uwp/Assets/LargeTile.scale-200.png
new file mode 100644
index 000000000..2d481044d
Binary files /dev/null and b/src/duckstation-uwp/Assets/LargeTile.scale-200.png differ
diff --git a/src/duckstation-uwp/Assets/LargeTile.scale-400.png b/src/duckstation-uwp/Assets/LargeTile.scale-400.png
new file mode 100644
index 000000000..1e095e886
Binary files /dev/null and b/src/duckstation-uwp/Assets/LargeTile.scale-400.png differ
diff --git a/src/duckstation-uwp/Assets/LockScreenLogo.scale-200.png b/src/duckstation-uwp/Assets/LockScreenLogo.scale-200.png
new file mode 100644
index 000000000..735f57adb
Binary files /dev/null and b/src/duckstation-uwp/Assets/LockScreenLogo.scale-200.png differ
diff --git a/src/duckstation-uwp/Assets/SmallTile.scale-100.png b/src/duckstation-uwp/Assets/SmallTile.scale-100.png
new file mode 100644
index 000000000..22154a005
Binary files /dev/null and b/src/duckstation-uwp/Assets/SmallTile.scale-100.png differ
diff --git a/src/duckstation-uwp/Assets/SmallTile.scale-125.png b/src/duckstation-uwp/Assets/SmallTile.scale-125.png
new file mode 100644
index 000000000..a9692405e
Binary files /dev/null and b/src/duckstation-uwp/Assets/SmallTile.scale-125.png differ
diff --git a/src/duckstation-uwp/Assets/SmallTile.scale-150.png b/src/duckstation-uwp/Assets/SmallTile.scale-150.png
new file mode 100644
index 000000000..eb5b166e5
Binary files /dev/null and b/src/duckstation-uwp/Assets/SmallTile.scale-150.png differ
diff --git a/src/duckstation-uwp/Assets/SmallTile.scale-200.png b/src/duckstation-uwp/Assets/SmallTile.scale-200.png
new file mode 100644
index 000000000..2712512e8
Binary files /dev/null and b/src/duckstation-uwp/Assets/SmallTile.scale-200.png differ
diff --git a/src/duckstation-uwp/Assets/SmallTile.scale-400.png b/src/duckstation-uwp/Assets/SmallTile.scale-400.png
new file mode 100644
index 000000000..3570a150c
Binary files /dev/null and b/src/duckstation-uwp/Assets/SmallTile.scale-400.png differ
diff --git a/src/duckstation-uwp/Assets/SplashScreen.scale-100.png b/src/duckstation-uwp/Assets/SplashScreen.scale-100.png
new file mode 100644
index 000000000..6231d0d2d
Binary files /dev/null and b/src/duckstation-uwp/Assets/SplashScreen.scale-100.png differ
diff --git a/src/duckstation-uwp/Assets/SplashScreen.scale-125.png b/src/duckstation-uwp/Assets/SplashScreen.scale-125.png
new file mode 100644
index 000000000..d75cd027f
Binary files /dev/null and b/src/duckstation-uwp/Assets/SplashScreen.scale-125.png differ
diff --git a/src/duckstation-uwp/Assets/SplashScreen.scale-150.png b/src/duckstation-uwp/Assets/SplashScreen.scale-150.png
new file mode 100644
index 000000000..76cb3e102
Binary files /dev/null and b/src/duckstation-uwp/Assets/SplashScreen.scale-150.png differ
diff --git a/src/duckstation-uwp/Assets/SplashScreen.scale-200.png b/src/duckstation-uwp/Assets/SplashScreen.scale-200.png
new file mode 100644
index 000000000..1008aca35
Binary files /dev/null and b/src/duckstation-uwp/Assets/SplashScreen.scale-200.png differ
diff --git a/src/duckstation-uwp/Assets/SplashScreen.scale-400.png b/src/duckstation-uwp/Assets/SplashScreen.scale-400.png
new file mode 100644
index 000000000..645c6bb6a
Binary files /dev/null and b/src/duckstation-uwp/Assets/SplashScreen.scale-400.png differ
diff --git a/src/duckstation-uwp/Assets/Square150x150Logo.scale-100.png b/src/duckstation-uwp/Assets/Square150x150Logo.scale-100.png
new file mode 100644
index 000000000..6d132a875
Binary files /dev/null and b/src/duckstation-uwp/Assets/Square150x150Logo.scale-100.png differ
diff --git a/src/duckstation-uwp/Assets/Square150x150Logo.scale-125.png b/src/duckstation-uwp/Assets/Square150x150Logo.scale-125.png
new file mode 100644
index 000000000..f05e4604c
Binary files /dev/null and b/src/duckstation-uwp/Assets/Square150x150Logo.scale-125.png differ
diff --git a/src/duckstation-uwp/Assets/Square150x150Logo.scale-150.png b/src/duckstation-uwp/Assets/Square150x150Logo.scale-150.png
new file mode 100644
index 000000000..cd2cac9a0
Binary files /dev/null and b/src/duckstation-uwp/Assets/Square150x150Logo.scale-150.png differ
diff --git a/src/duckstation-uwp/Assets/Square150x150Logo.scale-200.png b/src/duckstation-uwp/Assets/Square150x150Logo.scale-200.png
new file mode 100644
index 000000000..863e4ef91
Binary files /dev/null and b/src/duckstation-uwp/Assets/Square150x150Logo.scale-200.png differ
diff --git a/src/duckstation-uwp/Assets/Square150x150Logo.scale-400.png b/src/duckstation-uwp/Assets/Square150x150Logo.scale-400.png
new file mode 100644
index 000000000..045913a3c
Binary files /dev/null and b/src/duckstation-uwp/Assets/Square150x150Logo.scale-400.png differ
diff --git a/src/duckstation-uwp/Assets/Square44x44Logo.altform-lightunplated_targetsize-16.png b/src/duckstation-uwp/Assets/Square44x44Logo.altform-lightunplated_targetsize-16.png
new file mode 100644
index 000000000..db57efd60
Binary files /dev/null and b/src/duckstation-uwp/Assets/Square44x44Logo.altform-lightunplated_targetsize-16.png differ
diff --git a/src/duckstation-uwp/Assets/Square44x44Logo.altform-lightunplated_targetsize-24.png b/src/duckstation-uwp/Assets/Square44x44Logo.altform-lightunplated_targetsize-24.png
new file mode 100644
index 000000000..5cf25729b
Binary files /dev/null and b/src/duckstation-uwp/Assets/Square44x44Logo.altform-lightunplated_targetsize-24.png differ
diff --git a/src/duckstation-uwp/Assets/Square44x44Logo.altform-lightunplated_targetsize-256.png b/src/duckstation-uwp/Assets/Square44x44Logo.altform-lightunplated_targetsize-256.png
new file mode 100644
index 000000000..4d1f4620f
Binary files /dev/null and b/src/duckstation-uwp/Assets/Square44x44Logo.altform-lightunplated_targetsize-256.png differ
diff --git a/src/duckstation-uwp/Assets/Square44x44Logo.altform-lightunplated_targetsize-32.png b/src/duckstation-uwp/Assets/Square44x44Logo.altform-lightunplated_targetsize-32.png
new file mode 100644
index 000000000..137ac4497
Binary files /dev/null and b/src/duckstation-uwp/Assets/Square44x44Logo.altform-lightunplated_targetsize-32.png differ
diff --git a/src/duckstation-uwp/Assets/Square44x44Logo.altform-lightunplated_targetsize-48.png b/src/duckstation-uwp/Assets/Square44x44Logo.altform-lightunplated_targetsize-48.png
new file mode 100644
index 000000000..6374d0219
Binary files /dev/null and b/src/duckstation-uwp/Assets/Square44x44Logo.altform-lightunplated_targetsize-48.png differ
diff --git a/src/duckstation-uwp/Assets/Square44x44Logo.altform-unplated_targetsize-16.png b/src/duckstation-uwp/Assets/Square44x44Logo.altform-unplated_targetsize-16.png
new file mode 100644
index 000000000..db57efd60
Binary files /dev/null and b/src/duckstation-uwp/Assets/Square44x44Logo.altform-unplated_targetsize-16.png differ
diff --git a/src/duckstation-uwp/Assets/Square44x44Logo.altform-unplated_targetsize-256.png b/src/duckstation-uwp/Assets/Square44x44Logo.altform-unplated_targetsize-256.png
new file mode 100644
index 000000000..4d1f4620f
Binary files /dev/null and b/src/duckstation-uwp/Assets/Square44x44Logo.altform-unplated_targetsize-256.png differ
diff --git a/src/duckstation-uwp/Assets/Square44x44Logo.altform-unplated_targetsize-32.png b/src/duckstation-uwp/Assets/Square44x44Logo.altform-unplated_targetsize-32.png
new file mode 100644
index 000000000..137ac4497
Binary files /dev/null and b/src/duckstation-uwp/Assets/Square44x44Logo.altform-unplated_targetsize-32.png differ
diff --git a/src/duckstation-uwp/Assets/Square44x44Logo.altform-unplated_targetsize-48.png b/src/duckstation-uwp/Assets/Square44x44Logo.altform-unplated_targetsize-48.png
new file mode 100644
index 000000000..6374d0219
Binary files /dev/null and b/src/duckstation-uwp/Assets/Square44x44Logo.altform-unplated_targetsize-48.png differ
diff --git a/src/duckstation-uwp/Assets/Square44x44Logo.scale-100.png b/src/duckstation-uwp/Assets/Square44x44Logo.scale-100.png
new file mode 100644
index 000000000..44b92a911
Binary files /dev/null and b/src/duckstation-uwp/Assets/Square44x44Logo.scale-100.png differ
diff --git a/src/duckstation-uwp/Assets/Square44x44Logo.scale-125.png b/src/duckstation-uwp/Assets/Square44x44Logo.scale-125.png
new file mode 100644
index 000000000..3890bbfd5
Binary files /dev/null and b/src/duckstation-uwp/Assets/Square44x44Logo.scale-125.png differ
diff --git a/src/duckstation-uwp/Assets/Square44x44Logo.scale-150.png b/src/duckstation-uwp/Assets/Square44x44Logo.scale-150.png
new file mode 100644
index 000000000..9a99b0af1
Binary files /dev/null and b/src/duckstation-uwp/Assets/Square44x44Logo.scale-150.png differ
diff --git a/src/duckstation-uwp/Assets/Square44x44Logo.scale-200.png b/src/duckstation-uwp/Assets/Square44x44Logo.scale-200.png
new file mode 100644
index 000000000..95ae49964
Binary files /dev/null and b/src/duckstation-uwp/Assets/Square44x44Logo.scale-200.png differ
diff --git a/src/duckstation-uwp/Assets/Square44x44Logo.scale-400.png b/src/duckstation-uwp/Assets/Square44x44Logo.scale-400.png
new file mode 100644
index 000000000..b84abd2fe
Binary files /dev/null and b/src/duckstation-uwp/Assets/Square44x44Logo.scale-400.png differ
diff --git a/src/duckstation-uwp/Assets/Square44x44Logo.targetsize-16.png b/src/duckstation-uwp/Assets/Square44x44Logo.targetsize-16.png
new file mode 100644
index 000000000..78927eb6d
Binary files /dev/null and b/src/duckstation-uwp/Assets/Square44x44Logo.targetsize-16.png differ
diff --git a/src/duckstation-uwp/Assets/Square44x44Logo.targetsize-24.png b/src/duckstation-uwp/Assets/Square44x44Logo.targetsize-24.png
new file mode 100644
index 000000000..82ed7fa0c
Binary files /dev/null and b/src/duckstation-uwp/Assets/Square44x44Logo.targetsize-24.png differ
diff --git a/src/duckstation-uwp/Assets/Square44x44Logo.targetsize-24_altform-unplated.png b/src/duckstation-uwp/Assets/Square44x44Logo.targetsize-24_altform-unplated.png
new file mode 100644
index 000000000..26eb22fb4
Binary files /dev/null and b/src/duckstation-uwp/Assets/Square44x44Logo.targetsize-24_altform-unplated.png differ
diff --git a/src/duckstation-uwp/Assets/Square44x44Logo.targetsize-256.png b/src/duckstation-uwp/Assets/Square44x44Logo.targetsize-256.png
new file mode 100644
index 000000000..db333e184
Binary files /dev/null and b/src/duckstation-uwp/Assets/Square44x44Logo.targetsize-256.png differ
diff --git a/src/duckstation-uwp/Assets/Square44x44Logo.targetsize-32.png b/src/duckstation-uwp/Assets/Square44x44Logo.targetsize-32.png
new file mode 100644
index 000000000..89a192373
Binary files /dev/null and b/src/duckstation-uwp/Assets/Square44x44Logo.targetsize-32.png differ
diff --git a/src/duckstation-uwp/Assets/Square44x44Logo.targetsize-48.png b/src/duckstation-uwp/Assets/Square44x44Logo.targetsize-48.png
new file mode 100644
index 000000000..75d0a3ab5
Binary files /dev/null and b/src/duckstation-uwp/Assets/Square44x44Logo.targetsize-48.png differ
diff --git a/src/duckstation-uwp/Assets/StoreLogo.backup.png b/src/duckstation-uwp/Assets/StoreLogo.backup.png
new file mode 100644
index 000000000..7385b56c0
Binary files /dev/null and b/src/duckstation-uwp/Assets/StoreLogo.backup.png differ
diff --git a/src/duckstation-uwp/Assets/StoreLogo.scale-100.png b/src/duckstation-uwp/Assets/StoreLogo.scale-100.png
new file mode 100644
index 000000000..e2a5aba4c
Binary files /dev/null and b/src/duckstation-uwp/Assets/StoreLogo.scale-100.png differ
diff --git a/src/duckstation-uwp/Assets/StoreLogo.scale-125.png b/src/duckstation-uwp/Assets/StoreLogo.scale-125.png
new file mode 100644
index 000000000..d8120d319
Binary files /dev/null and b/src/duckstation-uwp/Assets/StoreLogo.scale-125.png differ
diff --git a/src/duckstation-uwp/Assets/StoreLogo.scale-150.png b/src/duckstation-uwp/Assets/StoreLogo.scale-150.png
new file mode 100644
index 000000000..252be5560
Binary files /dev/null and b/src/duckstation-uwp/Assets/StoreLogo.scale-150.png differ
diff --git a/src/duckstation-uwp/Assets/StoreLogo.scale-200.png b/src/duckstation-uwp/Assets/StoreLogo.scale-200.png
new file mode 100644
index 000000000..30ad00de0
Binary files /dev/null and b/src/duckstation-uwp/Assets/StoreLogo.scale-200.png differ
diff --git a/src/duckstation-uwp/Assets/StoreLogo.scale-400.png b/src/duckstation-uwp/Assets/StoreLogo.scale-400.png
new file mode 100644
index 000000000..2f9adfad7
Binary files /dev/null and b/src/duckstation-uwp/Assets/StoreLogo.scale-400.png differ
diff --git a/src/duckstation-uwp/Assets/Wide310x150Logo.scale-200.png b/src/duckstation-uwp/Assets/Wide310x150Logo.scale-200.png
new file mode 100644
index 000000000..288995b39
Binary files /dev/null and b/src/duckstation-uwp/Assets/Wide310x150Logo.scale-200.png differ
diff --git a/src/duckstation-uwp/Assets/WideTile.scale-100.png b/src/duckstation-uwp/Assets/WideTile.scale-100.png
new file mode 100644
index 000000000..11fbe3620
Binary files /dev/null and b/src/duckstation-uwp/Assets/WideTile.scale-100.png differ
diff --git a/src/duckstation-uwp/Assets/WideTile.scale-125.png b/src/duckstation-uwp/Assets/WideTile.scale-125.png
new file mode 100644
index 000000000..53fb67842
Binary files /dev/null and b/src/duckstation-uwp/Assets/WideTile.scale-125.png differ
diff --git a/src/duckstation-uwp/Assets/WideTile.scale-150.png b/src/duckstation-uwp/Assets/WideTile.scale-150.png
new file mode 100644
index 000000000..d87729e47
Binary files /dev/null and b/src/duckstation-uwp/Assets/WideTile.scale-150.png differ
diff --git a/src/duckstation-uwp/Assets/WideTile.scale-200.png b/src/duckstation-uwp/Assets/WideTile.scale-200.png
new file mode 100644
index 000000000..6231d0d2d
Binary files /dev/null and b/src/duckstation-uwp/Assets/WideTile.scale-200.png differ
diff --git a/src/duckstation-uwp/Assets/WideTile.scale-400.png b/src/duckstation-uwp/Assets/WideTile.scale-400.png
new file mode 100644
index 000000000..1008aca35
Binary files /dev/null and b/src/duckstation-uwp/Assets/WideTile.scale-400.png differ
diff --git a/src/duckstation-uwp/Assets/duck_128.png b/src/duckstation-uwp/Assets/duck_128.png
new file mode 100644
index 000000000..bc6655bbd
Binary files /dev/null and b/src/duckstation-uwp/Assets/duck_128.png differ
diff --git a/src/duckstation-uwp/Package.appxmanifest b/src/duckstation-uwp/Package.appxmanifest
new file mode 100644
index 000000000..7982fce24
--- /dev/null
+++ b/src/duckstation-uwp/Package.appxmanifest
@@ -0,0 +1,52 @@
+
+
+
+
+
+ DuckStation
+ Stenzek
+ Assets\StoreLogo.png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ .cue
+ .chd
+ .ecm
+ .iso
+ .mds
+ .psexe
+ .psf
+ .minipsf
+ .m3u
+
+ DuckStation Disc Image
+ Assets\duck_128.png
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/duckstation-uwp/PropertySheet.props b/src/duckstation-uwp/PropertySheet.props
new file mode 100644
index 000000000..e34141b01
--- /dev/null
+++ b/src/duckstation-uwp/PropertySheet.props
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/duckstation-uwp/duckstation-uwp.vcxproj b/src/duckstation-uwp/duckstation-uwp.vcxproj
new file mode 100644
index 000000000..6af60b175
--- /dev/null
+++ b/src/duckstation-uwp/duckstation-uwp.vcxproj
@@ -0,0 +1,211 @@
+
+
+
+
+ true
+ false
+ true
+ {e2a6cea9-9537-4c61-b637-81f1f17ef638}
+ duckstation-uwp
+ DuckStationUWP
+ en-US
+ 15.0
+ true
+ Windows Store
+ 10.0
+ 10.0.19041.0
+ 10.0.17134.0
+ false
+ true
+ false
+
+
+ $(SolutionDir)build\$(Configuration)-$(Platform)\$(ProjectName)\
+ $(SolutionDir)build\$(Configuration)-$(Platform)\$(ProjectName)\
+ false
+ $(ProjectName)
+ False
+ True
+ duckstation-uwp.pfx
+ SHA256
+ False
+ False
+ True
+ Always
+ x64
+ 0
+
+
+
+
+
+
+
+
+
+ Level4
+ %(AdditionalOptions) /bigobj
+
+
+ WIN32_LEAN_AND_MEAN;WINRT_LEAN_AND_MEAN;%(PreprocessorDefinitions)
+
+
+ false
+
+
+
+
+
+ Designer
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+ true
+
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ false
+
+
+
+
+
+
+
+
+
+ $(RootBuildDir)frontend-common\frontend-common.lib;%(AdditionalDependencies)
+
+
+
+
diff --git a/src/duckstation-uwp/duckstation-uwp.vcxproj.filters b/src/duckstation-uwp/duckstation-uwp.vcxproj.filters
new file mode 100644
index 000000000..149abe69f
--- /dev/null
+++ b/src/duckstation-uwp/duckstation-uwp.vcxproj.filters
@@ -0,0 +1,304 @@
+
+
+
+
+
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Data\resources
+
+
+ Data\resources
+
+
+ Data\resources
+
+
+ Data\resources
+
+
+ Data\resources
+
+
+ Data\resources
+
+
+ Data\resources
+
+
+ Data\resources
+
+
+ Data\resources
+
+
+ Data\resources
+
+
+ Data\resources
+
+
+ Data\resources
+
+
+ Data\resources
+
+
+ Data\resources
+
+
+
+
+
+
+
+ {db9086fe-bacc-4437-8272-1aa6642082db}
+
+
+ {fa7724ab-a364-49f2-9cdb-11307aa3f63e}
+
+
+ {8eda719e-58c6-484f-b00f-90ee69cd6cb5}
+
+
+ {1d471d6d-942e-4e06-9b74-36c5620c9d43}
+
+
+ {bf7c6843-57df-4e82-bf4e-7ffea724e92d}
+
+
+ {26b9c7e0-8acd-44be-848e-7da8e32238fa}
+
+
+ {1c1f164b-4184-422c-8d95-9c4cbb6a21eb}
+
+
+
+
+
+
+ Data\database
+
+
+ Data\database
+
+
+ Data\shaders
+
+
+ Data\shaders
+
+
+ Data\shaders
+
+
+ Data\shaders
+
+
+ Data\shaders\dolphinfx
+
+
+ Data\shaders\dolphinfx
+
+
+ Data\shaders\dolphinfx
+
+
+ Data\inputprofiles
+
+
+ Data\inputprofiles
+
+
+ Data\inputprofiles
+
+
+ Data\inputprofiles
+
+
+ Data\inputprofiles
+
+
+
+
+
+
+
+
+
+ Data\resources
+
+
+
+
+ Data\database
+
+
+ Data\database
+
+
+
+
+ Data\database
+
+
+
\ No newline at end of file
diff --git a/src/duckstation-uwp/packages.config b/src/duckstation-uwp/packages.config
new file mode 100644
index 000000000..6d1e442a5
--- /dev/null
+++ b/src/duckstation-uwp/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/src/duckstation-uwp/uwp_host_interface.cpp b/src/duckstation-uwp/uwp_host_interface.cpp
new file mode 100644
index 000000000..1de20d6c5
--- /dev/null
+++ b/src/duckstation-uwp/uwp_host_interface.cpp
@@ -0,0 +1,753 @@
+#include "uwp_host_interface.h"
+#include "common/assert.h"
+#include "common/byte_stream.h"
+#include "common/file_system.h"
+#include "common/log.h"
+#include "common/string_util.h"
+#include "core/controller.h"
+#include "core/gpu.h"
+#include "core/host_display.h"
+#include "core/system.h"
+#include "frontend-common/controller_interface.h"
+#include "frontend-common/d3d11_host_display.h"
+#include "frontend-common/d3d12_host_display.h"
+#include "frontend-common/fullscreen_ui.h"
+#include "frontend-common/icon.h"
+#include "frontend-common/imgui_styles.h"
+#include "frontend-common/ini_settings_interface.h"
+#include "imgui.h"
+#include "imgui_internal.h"
+#include "imgui_stdlib.h"
+#include "uwp_key_map.h"
+#include
+#include
+Log_SetChannel(UWPHostInterface);
+
+#include
+#include
+#include
+#include
+#include
+
+static bool IsRunningOnXbox()
+{
+ const auto version_info = winrt::Windows::System::Profile::AnalyticsInfo::VersionInfo();
+ const auto device_family = version_info.DeviceFamily();
+ return (device_family == L"Windows.Xbox");
+}
+
+UWPHostInterface::UWPHostInterface() = default;
+
+UWPHostInterface::~UWPHostInterface() = default;
+
+winrt::Windows::ApplicationModel::Core::IFrameworkView UWPHostInterface::CreateView()
+{
+ return *this;
+}
+
+void UWPHostInterface::Initialize(const winrt::Windows::ApplicationModel::Core::CoreApplicationView& a)
+{
+ winrt::Windows::ApplicationModel::Core::CoreApplication::Suspending({this, &UWPHostInterface::OnSuspending});
+ winrt::Windows::ApplicationModel::Core::CoreApplication::Resuming({this, &UWPHostInterface::OnResuming});
+}
+
+void UWPHostInterface::Load(const winrt::hstring&) {}
+
+void UWPHostInterface::Uninitialize() {}
+
+const char* UWPHostInterface::GetFrontendName() const
+{
+ return "DuckStation UWP Frontend";
+}
+
+bool UWPHostInterface::Initialize()
+{
+ Log::SetDebugOutputParams(true, nullptr, LOGLEVEL_DEBUG);
+ if (!SetDirectories())
+ return false;
+
+ m_settings_interface = std::make_unique(GetSettingsFileName());
+ m_flags.force_fullscreen_ui = true;
+ m_fullscreen_ui_enabled = true;
+
+ if (!CommonHostInterface::Initialize())
+ return false;
+
+ SetImGuiKeyMap();
+
+ const bool start_fullscreen = m_flags.start_fullscreen || g_settings.start_fullscreen;
+ if (!CreateDisplay(start_fullscreen))
+ {
+ Log_ErrorPrintf("Failed to create host display");
+ return false;
+ }
+
+ return true;
+}
+
+void UWPHostInterface::Shutdown()
+{
+ DestroyDisplay();
+
+ CommonHostInterface::Shutdown();
+}
+
+void UWPHostInterface::SetDefaultSettings(SettingsInterface& si)
+{
+ CommonHostInterface::SetDefaultSettings(si);
+
+ si.SetStringValue("CPU", "FastmemMode", "LUT");
+ si.SetStringValue("Main", "ControllerBackend", "XInput");
+ si.AddToStringList("GameList", "RecursivePaths", GetUserDirectoryRelativePath("games").c_str());
+
+ if (IsRunningOnXbox())
+ SetDefaultSettingsForXbox(si);
+}
+
+bool UWPHostInterface::CreateDisplay(bool fullscreen)
+{
+ Assert(!m_display);
+
+ m_appview = winrt::Windows::UI::ViewManagement::ApplicationView::GetForCurrentView();
+ m_appview.PreferredLaunchWindowingMode(
+ fullscreen ? winrt::Windows::UI::ViewManagement::ApplicationViewWindowingMode::FullScreen :
+ winrt::Windows::UI::ViewManagement::ApplicationViewWindowingMode::Auto);
+
+ m_window.Activate();
+
+ const auto di = winrt::Windows::Graphics::Display::DisplayInformation::GetForCurrentView();
+ const auto hdi = winrt::Windows::Graphics::Display::Core::HdmiDisplayInformation::GetForCurrentView();
+ const s32 resolution_scale = static_cast(di.ResolutionScale());
+
+ WindowInfo wi;
+ wi.type = WindowInfo::Type::WinRT;
+ wi.window_handle = winrt::get_unknown(m_window);
+ wi.surface_scale = static_cast(resolution_scale) / 100.0f;
+ wi.surface_width = static_cast(m_window.Bounds().Width * wi.surface_scale);
+ wi.surface_height = static_cast(m_window.Bounds().Height * wi.surface_scale);
+ if (hdi)
+ {
+ try
+ {
+ const auto dm = hdi.GetCurrentDisplayMode();
+ const u32 hdmi_width = dm.ResolutionWidthInRawPixels();
+ const u32 hdmi_height = dm.ResolutionHeightInRawPixels();
+ wi.surface_refresh_rate = static_cast(dm.RefreshRate());
+ Log_InfoPrintf("HDMI mode: %ux%u @ %.2f hz", hdmi_width, hdmi_height, wi.surface_refresh_rate);
+
+ // If we're running on Xbox, use the HDMI mode instead of the CoreWindow size.
+ // In UWP, the CoreWindow is always 1920x1080, even when running at 4K.
+ if (IsRunningOnXbox())
+ {
+ GAMING_DEVICE_MODEL_INFORMATION gdinfo = {};
+ if (SUCCEEDED(GetGamingDeviceModelInformation(&gdinfo)) && gdinfo.vendorId == GAMING_DEVICE_VENDOR_ID_MICROSOFT)
+ {
+ if (gdinfo.deviceId != GAMING_DEVICE_DEVICE_ID_XBOX_ONE)
+ {
+ Log_InfoPrintf("Overriding core window size %ux%u with HDMI size %ux%u", wi.surface_width,
+ wi.surface_height, hdmi_width, hdmi_height);
+ wi.surface_scale *= static_cast(hdmi_width) / static_cast(wi.surface_width);
+ wi.surface_width = hdmi_width;
+ wi.surface_height = hdmi_height;
+ }
+ }
+ }
+ }
+ catch (const winrt::hresult_error&)
+ {
+ }
+ }
+
+ if (g_settings.gpu_renderer == GPURenderer::HardwareD3D12)
+ m_display = std::make_unique();
+ else
+ m_display = std::make_unique();
+
+ if (!m_display->CreateRenderDevice(wi, g_settings.gpu_adapter, g_settings.gpu_use_debug_device,
+ g_settings.gpu_threaded_presentation) ||
+ !m_display->InitializeRenderDevice(GetShaderCacheBasePath(), g_settings.gpu_use_debug_device,
+ g_settings.gpu_threaded_presentation) ||
+ !CreateHostDisplayResources())
+ {
+ m_display->DestroyRenderDevice();
+ m_display.reset();
+ ReportError("Failed to create/initialize display render device");
+ return false;
+ }
+
+ if (!CreateHostDisplayResources())
+ Log_WarningPrint("Failed to create host display resources");
+
+ Log_InfoPrintf("Host display initialized at %ux%u resolution", m_display->GetWindowWidth(),
+ m_display->GetWindowHeight());
+ return true;
+}
+
+void UWPHostInterface::DestroyDisplay()
+{
+ ReleaseHostDisplayResources();
+
+ if (m_display)
+ m_display->DestroyRenderDevice();
+
+ m_display.reset();
+}
+
+bool UWPHostInterface::AcquireHostDisplay()
+{
+ return true;
+}
+
+void UWPHostInterface::ReleaseHostDisplay()
+{
+ // restore vsync, since we don't want to burn cycles at the menu
+ m_display->SetVSync(true);
+}
+
+void UWPHostInterface::PollAndUpdate()
+{
+ CommonHostInterface::PollAndUpdate();
+
+ ImGuiIO& io = ImGui::GetIO();
+ if (m_text_input_requested != io.WantTextInput)
+ {
+ const bool activate = io.WantTextInput;
+ Log_InfoPrintf("%s input pane...", activate ? "showing" : "hiding");
+
+ m_text_input_requested = activate;
+ m_dispatcher.RunAsync(winrt::Windows::UI::Core::CoreDispatcherPriority::Normal, [this, activate]() {
+ const auto input_pane = winrt::Windows::UI::ViewManagement::InputPane::GetForCurrentView();
+ if (input_pane)
+ {
+ if (activate)
+ input_pane.TryShow();
+ else
+ input_pane.TryHide();
+ }
+ });
+ }
+}
+
+void UWPHostInterface::RequestExit()
+{
+ m_shutdown_flag.store(true);
+ m_dispatcher.RunAsync(winrt::Windows::UI::Core::CoreDispatcherPriority::Normal,
+ [this]() { winrt::Windows::ApplicationModel::Core::CoreApplication::Exit(); });
+}
+
+void UWPHostInterface::Run()
+{
+ if (!Initialize())
+ {
+ Shutdown();
+ return;
+ }
+
+ m_emulation_thread = std::thread(&UWPHostInterface::EmulationThreadEntryPoint, this);
+
+ m_dispatcher.ProcessEvents(winrt::Windows::UI::Core::CoreProcessEventsOption::ProcessUntilQuit);
+ m_shutdown_flag.store(true);
+ m_emulation_thread.join();
+}
+
+void UWPHostInterface::EmulationThreadEntryPoint()
+{
+ if (m_fullscreen_ui_enabled)
+ {
+ FullscreenUI::SetDebugMenuAllowed(true);
+ FullscreenUI::QueueGameListRefresh();
+ }
+
+ // process events to pick up controllers before updating input map
+ PollAndUpdate();
+ UpdateInputMap();
+
+ if (m_was_running_on_suspend && ShouldSaveResumeState())
+ ResumeSystemFromMostRecentState();
+
+ while (!m_shutdown_flag.load())
+ {
+ RunCallbacks();
+ PollAndUpdate();
+
+ ImGui::NewFrame();
+
+ if (System::IsRunning())
+ {
+ if (m_display_all_frames)
+ System::RunFrame();
+ else
+ System::RunFrames();
+
+ UpdateControllerMetaState();
+ if (m_frame_step_request)
+ {
+ m_frame_step_request = false;
+ PauseSystem(true);
+ }
+ }
+
+ // rendering
+ {
+ DrawImGuiWindows();
+ ImGui::Render();
+ ImGui::EndFrame();
+
+ m_display->Render();
+
+ if (System::IsRunning())
+ {
+ System::UpdatePerformanceCounters();
+
+ if (m_throttler_enabled)
+ System::Throttle();
+ }
+ }
+ }
+
+ // Save state on exit so it can be resumed
+ if (!System::IsShutdown())
+ PowerOffSystem(ShouldSaveResumeState());
+}
+
+void UWPHostInterface::ReportMessage(const char* message)
+{
+ Log_InfoPrint(message);
+ AddOSDMessage(message, 10.0f);
+}
+
+void UWPHostInterface::ReportError(const char* message)
+{
+ Log_ErrorPrint(message);
+
+ if (!m_display)
+ return;
+
+ const bool was_in_frame = GImGui->FrameCount != GImGui->FrameCountEnded;
+ if (was_in_frame)
+ ImGui::EndFrame();
+
+ bool done = false;
+ while (!done)
+ {
+ RunCallbacks();
+ PollAndUpdate();
+ if (m_fullscreen_ui_enabled)
+ FullscreenUI::SetImGuiNavInputs();
+
+ ImGui::NewFrame();
+ done = FullscreenUI::DrawErrorWindow(message);
+ ImGui::EndFrame();
+ m_display->Render();
+ }
+
+ if (was_in_frame)
+ ImGui::NewFrame();
+}
+
+bool UWPHostInterface::ConfirmMessage(const char* message)
+{
+ Log_InfoPrintf("Confirm: %s", message);
+
+ if (!m_display)
+ return true;
+
+ const bool was_in_frame = GImGui->FrameCount != GImGui->FrameCountEnded;
+ if (was_in_frame)
+ ImGui::EndFrame();
+
+ bool done = false;
+ bool result = true;
+ while (!done)
+ {
+ RunCallbacks();
+ PollAndUpdate();
+ if (m_fullscreen_ui_enabled)
+ FullscreenUI::SetImGuiNavInputs();
+
+ ImGui::NewFrame();
+ done = FullscreenUI::DrawConfirmWindow(message, &result);
+ ImGui::EndFrame();
+ m_display->Render();
+ }
+
+ if (was_in_frame)
+ ImGui::NewFrame();
+
+ return result;
+}
+
+void UWPHostInterface::RunLater(std::function callback)
+{
+ std::unique_lock lock(m_queued_callbacks_lock);
+ m_queued_callbacks.push_back(std::move(callback));
+}
+
+bool UWPHostInterface::IsFullscreen() const
+{
+ return m_appview.IsFullScreenMode();
+}
+
+bool UWPHostInterface::SetFullscreen(bool enabled)
+{
+ m_dispatcher.RunAsync(winrt::Windows::UI::Core::CoreDispatcherPriority::Normal, [this, enabled]() {
+ if (enabled)
+ m_appview.TryEnterFullScreenMode();
+ else
+ m_appview.ExitFullScreenMode();
+ });
+
+ return true;
+}
+
+void UWPHostInterface::RunCallbacks()
+{
+ std::unique_lock lock(m_queued_callbacks_lock);
+
+ while (!m_queued_callbacks.empty())
+ {
+ auto callback = std::move(m_queued_callbacks.front());
+ m_queued_callbacks.pop_front();
+ lock.unlock();
+ callback();
+ lock.lock();
+ }
+}
+
+void UWPHostInterface::SetWindow(const winrt::Windows::UI::Core::CoreWindow& window)
+{
+ m_window = window;
+ m_dispatcher = m_window.Dispatcher();
+
+ window.Closed({this, &UWPHostInterface::OnClosed});
+ window.SizeChanged({this, &UWPHostInterface::OnSizeChanged});
+ window.KeyDown({this, &UWPHostInterface::OnKeyDown});
+ window.KeyUp({this, &UWPHostInterface::OnKeyUp});
+ window.CharacterReceived({this, &UWPHostInterface::OnCharacterReceived});
+ window.PointerPressed({this, &UWPHostInterface::OnPointerPressed});
+ window.PointerReleased({this, &UWPHostInterface::OnPointerPressed});
+ window.PointerMoved({this, &UWPHostInterface::OnPointerMoved});
+ window.PointerWheelChanged({this, &UWPHostInterface::OnPointerWheelChanged});
+}
+
+bool UWPHostInterface::SetDirectories()
+{
+ const auto install_location = winrt::Windows::ApplicationModel::Package::Current().InstalledLocation();
+ m_program_directory = StringUtil::WideStringToUTF8String(install_location.Path());
+ if (m_program_directory.empty())
+ {
+ Log_ErrorPrintf("Failed to get install location");
+ return false;
+ }
+
+ Log_InfoPrintf("Program directory: %s", m_program_directory.c_str());
+
+ const auto local_location = winrt::Windows::Storage::ApplicationData::Current().LocalFolder();
+ m_user_directory = StringUtil::WideStringToUTF8String(local_location.Path());
+ if (m_user_directory.empty())
+ {
+ Log_ErrorPrintf("Failed to get user directory");
+ return false;
+ }
+
+ Log_InfoPrintf("User directory: %s", m_user_directory.c_str());
+ return true;
+}
+
+void UWPHostInterface::OnSuspending(const IInspectable&,
+ const winrt::Windows::ApplicationModel::SuspendingEventArgs& args)
+{
+ if (IsEmulationThreadRunning())
+ {
+ RunLater([this]() {
+ if (ShouldSaveResumeState())
+ SaveResumeSaveState();
+
+ m_was_running_on_suspend.store(System::IsRunning());
+ PauseSystem(true);
+ m_suspend_sync_event.Signal();
+ });
+
+ m_suspend_sync_event.Wait();
+ }
+}
+
+void UWPHostInterface::OnResuming(const IInspectable&, const IInspectable&)
+{
+ if (IsEmulationThreadRunning())
+ {
+ if (m_was_running_on_suspend.load())
+ RunLater([this]() { PauseSystem(false); });
+ }
+ else
+ {
+ RunLater([this]() {
+ if (ShouldSaveResumeState())
+ ResumeSystemFromMostRecentState();
+ });
+ }
+}
+
+void UWPHostInterface::OnClosed(const IInspectable&, const winrt::Windows::UI::Core::CoreWindowEventArgs& args)
+{
+ if (IsEmulationThreadRunning())
+ {
+ m_shutdown_flag.store(true);
+ m_emulation_thread.join();
+ }
+ args.Handled(true);
+}
+
+void UWPHostInterface::OnSizeChanged(const IInspectable&,
+ const winrt::Windows::UI::Core::WindowSizeChangedEventArgs& args)
+{
+ const auto size = args.Size();
+ const s32 width = static_cast(size.Width * m_display->GetWindowScale());
+ const s32 height = static_cast(size.Height * m_display->GetWindowScale());
+ if (IsEmulationThreadRunning())
+ {
+ RunLater([this, width, height]() {
+ m_display->ResizeRenderWindow(width, height);
+ OnHostDisplayResized();
+ });
+ }
+
+ args.Handled(true);
+}
+
+void UWPHostInterface::OnKeyDown(const IInspectable&, const winrt::Windows::UI::Core::KeyEventArgs& args)
+{
+ const auto status = args.KeyStatus();
+ if (!status.WasKeyDown && !status.IsKeyReleased && IsEmulationThreadRunning())
+ {
+ const HostKeyCode code = static_cast(args.VirtualKey());
+ RunLater([this, code]() {
+ ImGuiIO& io = ImGui::GetIO();
+ if (code < countof(io.KeysDown))
+ io.KeysDown[code] = true;
+
+ if (!io.WantCaptureKeyboard)
+ HandleHostKeyEvent(code, 0, true);
+ });
+ }
+
+ args.Handled(true);
+}
+
+void UWPHostInterface::OnKeyUp(const IInspectable&, const winrt::Windows::UI::Core::KeyEventArgs& args)
+{
+ const auto status = args.KeyStatus();
+ if (status.WasKeyDown && status.IsKeyReleased && IsEmulationThreadRunning())
+ {
+ const HostKeyCode code = static_cast(args.VirtualKey());
+ RunLater([this, code]() {
+ ImGuiIO& io = ImGui::GetIO();
+ if (code < countof(io.KeysDown))
+ io.KeysDown[code] = false;
+
+ if (!io.WantCaptureKeyboard)
+ HandleHostKeyEvent(code, 0, false);
+ });
+ }
+
+ args.Handled(true);
+}
+
+void UWPHostInterface::OnCharacterReceived(const IInspectable&,
+ const winrt::Windows::UI::Core::CharacterReceivedEventArgs& args)
+{
+ if (IsEmulationThreadRunning())
+ {
+ const u32 code = args.KeyCode();
+ RunLater([this, code]() { ImGui::GetIO().AddInputCharacter(code); });
+ }
+
+ args.Handled(true);
+}
+
+void UWPHostInterface::OnPointerPressed(const IInspectable&, const winrt::Windows::UI::Core::PointerEventArgs& args)
+{
+ const auto pointer = args.CurrentPoint();
+ if (pointer.PointerDevice().PointerDeviceType() == winrt::Windows::Devices::Input::PointerDeviceType::Mouse)
+ UpdateMouseButtonState(pointer);
+
+ args.Handled(true);
+}
+
+void UWPHostInterface::OnPointerReleased(const IInspectable&, const winrt::Windows::UI::Core::PointerEventArgs& args)
+{
+ const auto pointer = args.CurrentPoint();
+ if (pointer.PointerDevice().PointerDeviceType() == winrt::Windows::Devices::Input::PointerDeviceType::Mouse)
+ UpdateMouseButtonState(pointer);
+
+ args.Handled(true);
+}
+
+void UWPHostInterface::OnPointerMoved(const IInspectable&, const winrt::Windows::UI::Core::PointerEventArgs& args)
+{
+ const auto pointer = args.CurrentPoint();
+ if (pointer.PointerDevice().PointerDeviceType() == winrt::Windows::Devices::Input::PointerDeviceType::Mouse)
+ {
+ const auto pos = pointer.Position();
+ const float x = pos.X * m_display->GetWindowScale();
+ const float y = pos.Y * m_display->GetWindowScale();
+
+ if (IsEmulationThreadRunning())
+ {
+ RunLater([this, x, y]() {
+ m_display->SetMousePosition(static_cast(x), static_cast(y));
+
+ if (ImGui::GetCurrentContext())
+ {
+ ImGuiIO& io = ImGui::GetIO();
+ io.MousePos.x = x;
+ io.MousePos.y = y;
+ }
+ });
+ }
+
+ UpdateMouseButtonState(pointer);
+ }
+
+ args.Handled(true);
+}
+
+void UWPHostInterface::OnPointerWheelChanged(const IInspectable&,
+ const winrt::Windows::UI::Core::PointerEventArgs& args)
+{
+ const auto pointer = args.CurrentPoint();
+ const auto properties = pointer.Properties();
+ const s32 delta = properties.MouseWheelDelta();
+ const bool horizontal = properties.IsHorizontalMouseWheel();
+
+ if (IsEmulationThreadRunning())
+ {
+ RunLater([this, delta, horizontal]() {
+ if (ImGui::GetCurrentContext())
+ {
+ ImGuiIO& io = ImGui::GetIO();
+ const float dw = static_cast(std::clamp(delta, -1, 1));
+ if (horizontal)
+ io.MouseWheelH = dw;
+ else
+ io.MouseWheel = dw;
+ }
+ });
+ }
+
+ args.Handled(true);
+}
+
+void UWPHostInterface::UpdateMouseButtonState(const winrt::Windows::UI::Input::PointerPoint& point)
+{
+ const auto properties = point.Properties();
+ const bool states[3] = {properties.IsLeftButtonPressed(), properties.IsRightButtonPressed(),
+ properties.IsMiddleButtonPressed()};
+
+ if (IsEmulationThreadRunning())
+ {
+ RunLater([this, states]() {
+ if (!ImGui::GetCurrentContext())
+ return;
+
+ ImGuiIO& io = ImGui::GetIO();
+ for (u32 i = 0; i < countof(states); i++)
+ {
+ if (io.MouseDown[i] == states[i])
+ continue;
+
+ io.MouseDown[i] = states[i];
+ HandleHostMouseEvent(static_cast(i), states[i]);
+ }
+ });
+ }
+}
+
+std::optional UWPHostInterface::GetHostKeyCode(const std::string_view key_code) const
+{
+ for (const auto& it : s_key_map)
+ {
+ if (key_code.compare(it.second) == 0)
+ return static_cast(it.first);
+ }
+
+ return std::nullopt;
+}
+
+const char* UWPHostInterface::GetKeyCodeName(int key_code)
+{
+ const auto it = s_key_map.find(key_code);
+ return (it != s_key_map.end()) ? it->second : nullptr;
+}
+
+void UWPHostInterface::SetImGuiKeyMap()
+{
+ using namespace winrt::Windows::System;
+
+ ImGuiIO& io = ImGui::GetIO();
+ io.KeyMap[ImGuiKey_Tab] = static_cast(VirtualKey::Tab);
+ io.KeyMap[ImGuiKey_LeftArrow] = static_cast(VirtualKey::Left);
+ io.KeyMap[ImGuiKey_RightArrow] = static_cast(VirtualKey::Right);
+ io.KeyMap[ImGuiKey_UpArrow] = static_cast(VirtualKey::Up);
+ io.KeyMap[ImGuiKey_DownArrow] = static_cast(VirtualKey::Down);
+ io.KeyMap[ImGuiKey_PageUp] = static_cast(VirtualKey::PageUp);
+ io.KeyMap[ImGuiKey_PageDown] = static_cast(VirtualKey::PageDown);
+ io.KeyMap[ImGuiKey_Home] = static_cast(VirtualKey::Home);
+ io.KeyMap[ImGuiKey_End] = static_cast(VirtualKey::End);
+ io.KeyMap[ImGuiKey_Insert] = static_cast(VirtualKey::Insert);
+ io.KeyMap[ImGuiKey_Delete] = static_cast(VirtualKey::Delete);
+ io.KeyMap[ImGuiKey_Backspace] = static_cast(VirtualKey::Back);
+ io.KeyMap[ImGuiKey_Space] = static_cast(VirtualKey::Space);
+ io.KeyMap[ImGuiKey_Enter] = static_cast(VirtualKey::Enter);
+ io.KeyMap[ImGuiKey_Escape] = static_cast(VirtualKey::Escape);
+ io.KeyMap[ImGuiKey_A] = static_cast(VirtualKey::A);
+ io.KeyMap[ImGuiKey_C] = static_cast(VirtualKey::C);
+ io.KeyMap[ImGuiKey_V] = static_cast(VirtualKey::V);
+ io.KeyMap[ImGuiKey_X] = static_cast(VirtualKey::X);
+ io.KeyMap[ImGuiKey_Y] = static_cast(VirtualKey::Y);
+ io.KeyMap[ImGuiKey_Z] = static_cast(VirtualKey::Z);
+}
+
+void UWPHostInterface::SetDefaultSettingsForXbox(SettingsInterface& si)
+{
+ si.SetStringValue("GPU", "Renderer", "D3D12");
+
+ si.SetBoolValue("Main", "SyncToHostRefreshRate", true);
+ si.SetBoolValue("Display", "VSync", true);
+ si.SetBoolValue("Display", "DisplayAllFrames", true);
+ si.SetFloatValue("Display", "MaxFPS", 60.0f);
+
+ // Set up an analog controller in port 1.
+ si.SetStringValue("Controller1", "Type", "AnalogController");
+ si.SetStringValue("Controller1", "ButtonUp", "Controller0/Button11");
+ si.SetStringValue("Controller1", "ButtonDown", "Controller0/Button12");
+ si.SetStringValue("Controller1", "ButtonLeft", "Controller0/Button13");
+ si.SetStringValue("Controller1", "ButtonRight", "Controller0/Button14");
+ si.SetStringValue("Controller1", "ButtonStart", "Controller0/Button6");
+ si.SetStringValue("Controller1", "ButtonTriangle", "Controller0/Button3");
+ si.SetStringValue("Controller1", "ButtonCross", "Controller0/Button0");
+ si.SetStringValue("Controller1", "ButtonCircle", "Controller0/Button1");
+ si.SetStringValue("Controller1", "ButtonSquare", "Controller0/Button2");
+ si.SetStringValue("Controller1", "ButtonL1", "Controller0/Button9");
+ si.SetStringValue("Controller1", "ButtonL2", "Controller0/+Axis4");
+ si.SetStringValue("Controller1", "ButtonR1", "Controller0/Button10");
+ si.SetStringValue("Controller1", "ButtonR2", "Controller0/+Axis5");
+ si.SetStringValue("Controller1", "ButtonL3", "Controller0/Button7");
+ si.SetStringValue("Controller1", "ButtonR3", "Controller0/Button8");
+ si.SetStringValue("Controller1", "AxisLeftX", "Controller0/Axis0");
+ si.SetStringValue("Controller1", "AxisLeftY", "Controller0/Axis1");
+ si.SetStringValue("Controller1", "AxisRightX", "Controller0/Axis2");
+ si.SetStringValue("Controller1", "AxisRightY", "Controller0/Axis3");
+ si.SetStringValue("Controller1", "Rumble", "Controller0");
+ si.SetStringValue("Controller1", "ForceAnalogOnReset", "true");
+ si.SetStringValue("Controller1", "AnalogDPadInDigitalMode", "true");
+
+ // Repurpose the select button to open the menu.
+ // Not ideal, but all we can do until we have chords.
+ si.SetStringValue("Hotkeys", "OpenQuickMenu", "Controller0/Button4");
+}
+
+int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int)
+{
+ winrt::Windows::ApplicationModel::Core::CoreApplication::Run(winrt::make());
+}
diff --git a/src/duckstation-uwp/uwp_host_interface.h b/src/duckstation-uwp/uwp_host_interface.h
new file mode 100644
index 000000000..a0c2fc04b
--- /dev/null
+++ b/src/duckstation-uwp/uwp_host_interface.h
@@ -0,0 +1,117 @@
+#pragma once
+#include "common/event.h"
+#include "common/window_info.h"
+#include "common/windows_headers.h"
+#include "core/host_display.h"
+#include "core/host_interface.h"
+#include "frontend-common/common_host_interface.h"
+#include
+#include
+#include
+#include
+#include