Add NoGUI frontend based on old SDL frontend + fullscreen UI

This commit is contained in:
Connor McLaughlin 2021-01-30 21:55:24 +10:00
parent 61e4e6f140
commit cae5bc1712
19 changed files with 2403 additions and 40 deletions

View file

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.8)
cmake_minimum_required(VERSION 3.10)
project(duckstation C CXX)
message("CMake Version: ${CMAKE_VERSION}")
@ -19,6 +19,7 @@ set(CMAKE_OSX_DEPLOYMENT_TARGET "10.14.0" CACHE STRING "")
# Global options.
if(NOT ANDROID)
option(BUILD_SDL_FRONTEND "Build the SDL frontend" ON)
option(BUILD_NOGUI_FRONTEND "Build the NoGUI frontend" ON)
option(BUILD_QT_FRONTEND "Build the Qt frontend" ON)
option(ENABLE_DISCORD_PRESENCE "Build with Discord Rich Presence support" ON)
option(USE_SDL2 "Link with SDL2 for controller support" ON)
@ -46,6 +47,10 @@ if(ANDROID)
message(WARNING "Building for Android, disabling SDL frontend")
set(BUILD_SDL_FRONTEND OFF)
endif()
if(BUILD_NOGUI_FRONTEND)
message(WARNING "Building for Android, disabling NoGUI frontend")
set(BUILD_QT_FRONTEND OFF)
endif()
if(BUILD_QT_FRONTEND)
message(WARNING "Building for Android, disabling Qt frontend")
set(BUILD_QT_FRONTEND OFF)
@ -137,18 +142,14 @@ if(MSVC)
# Enable LTO/LTCG on Release builds.
if(${CMAKE_BUILD_TYPE} STREQUAL "Release")
if (${CMAKE_VERSION} VERSION_LESS "3.9.0")
message(WARNING "CMake version is less than 3.9.0, we can't enable LTCG/IPO. This will make the build slightly slower, consider updating your CMake version.")
cmake_policy(SET CMP0069 NEW)
include(CheckIPOSupported)
check_ipo_supported(RESULT IPO_IS_SUPPORTED)
if(IPO_IS_SUPPORTED)
message(STATUS "Enabling LTCG/IPO.")
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON)
else()
cmake_policy(SET CMP0069 NEW)
include(CheckIPOSupported)
check_ipo_supported(RESULT IPO_IS_SUPPORTED)
if(IPO_IS_SUPPORTED)
message(STATUS "Enabling LTCG/IPO.")
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON)
else()
message(WARNING "LTCG/IPO is not supported, this will make the build slightly slower.")
endif()
message(WARNING "LTCG/IPO is not supported, this will make the build slightly slower.")
endif()
endif()
endif()

View file

@ -37,8 +37,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libFLAC", "dep\libFLAC\libF
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lzma", "dep\lzma\lzma.vcxproj", "{DD944834-7899-4C1C-A4C1-064B5009D239}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "duckstation-sdl", "src\duckstation-sdl\duckstation-sdl.vcxproj", "{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "frontend-common", "src\frontend-common\frontend-common.vcxproj", "{6245DEC8-D2DA-47EE-A373-CBD6FCF3ECE6}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xxhash", "dep\xxhash\xxhash.vcxproj", "{09553C96-9F39-49BF-8AE6-7ACBD07C410C}"
@ -61,6 +59,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vixl", "dep\vixl\vixl.vcxpr
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libsamplerate", "dep\libsamplerate\libsamplerate.vcxproj", "{39F0ADFF-3A84-470D-9CF0-CA49E164F2F3}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "duckstation-nogui", "src\duckstation-nogui\duckstation-nogui.vcxproj", "{0A172B2E-DC67-49FC-A4C1-975F93C586C4}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "duckstation-sdl", "src\duckstation-sdl\duckstation-sdl.vcxproj", "{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM64 = Debug|ARM64
@ -461,30 +463,6 @@ Global
{DD944834-7899-4C1C-A4C1-064B5009D239}.ReleaseLTCG|x64.Build.0 = ReleaseLTCG|x64
{DD944834-7899-4C1C-A4C1-064B5009D239}.ReleaseLTCG|x86.ActiveCfg = ReleaseLTCG|Win32
{DD944834-7899-4C1C-A4C1-064B5009D239}.ReleaseLTCG|x86.Build.0 = ReleaseLTCG|Win32
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.Debug|ARM64.ActiveCfg = Debug|ARM64
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.Debug|ARM64.Build.0 = Debug|ARM64
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.Debug|x64.ActiveCfg = Debug|x64
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.Debug|x64.Build.0 = Debug|x64
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.Debug|x86.ActiveCfg = Debug|Win32
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.Debug|x86.Build.0 = Debug|Win32
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.DebugFast|ARM64.ActiveCfg = DebugFast|ARM64
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.DebugFast|ARM64.Build.0 = DebugFast|ARM64
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.DebugFast|x64.ActiveCfg = DebugFast|x64
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.DebugFast|x64.Build.0 = DebugFast|x64
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.DebugFast|x86.ActiveCfg = DebugFast|Win32
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.DebugFast|x86.Build.0 = DebugFast|Win32
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.Release|ARM64.ActiveCfg = Release|ARM64
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.Release|ARM64.Build.0 = Release|ARM64
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.Release|x64.ActiveCfg = Release|x64
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.Release|x64.Build.0 = Release|x64
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.Release|x86.ActiveCfg = Release|Win32
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.Release|x86.Build.0 = Release|Win32
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.ReleaseLTCG|ARM64.ActiveCfg = ReleaseLTCG|ARM64
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.ReleaseLTCG|ARM64.Build.0 = ReleaseLTCG|ARM64
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.ReleaseLTCG|x64.ActiveCfg = ReleaseLTCG|x64
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.ReleaseLTCG|x64.Build.0 = ReleaseLTCG|x64
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.ReleaseLTCG|x86.ActiveCfg = ReleaseLTCG|Win32
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.ReleaseLTCG|x86.Build.0 = ReleaseLTCG|Win32
{6245DEC8-D2DA-47EE-A373-CBD6FCF3ECE6}.Debug|ARM64.ActiveCfg = Debug|ARM64
{6245DEC8-D2DA-47EE-A373-CBD6FCF3ECE6}.Debug|ARM64.Build.0 = Debug|ARM64
{6245DEC8-D2DA-47EE-A373-CBD6FCF3ECE6}.Debug|x64.ActiveCfg = Debug|x64
@ -741,6 +719,54 @@ Global
{39F0ADFF-3A84-470D-9CF0-CA49E164F2F3}.ReleaseLTCG|x64.Build.0 = ReleaseLTCG|x64
{39F0ADFF-3A84-470D-9CF0-CA49E164F2F3}.ReleaseLTCG|x86.ActiveCfg = ReleaseLTCG|Win32
{39F0ADFF-3A84-470D-9CF0-CA49E164F2F3}.ReleaseLTCG|x86.Build.0 = ReleaseLTCG|Win32
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Debug|ARM64.ActiveCfg = Debug|ARM64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Debug|ARM64.Build.0 = Debug|ARM64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Debug|x64.ActiveCfg = Debug|x64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Debug|x64.Build.0 = Debug|x64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Debug|x86.ActiveCfg = Debug|Win32
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Debug|x86.Build.0 = Debug|Win32
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.DebugFast|ARM64.ActiveCfg = DebugFast|ARM64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.DebugFast|ARM64.Build.0 = DebugFast|ARM64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.DebugFast|x64.ActiveCfg = DebugFast|x64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.DebugFast|x64.Build.0 = DebugFast|x64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.DebugFast|x86.ActiveCfg = DebugFast|Win32
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.DebugFast|x86.Build.0 = DebugFast|Win32
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Release|ARM64.ActiveCfg = Release|ARM64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Release|ARM64.Build.0 = Release|ARM64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Release|x64.ActiveCfg = Release|x64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Release|x64.Build.0 = Release|x64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Release|x86.ActiveCfg = Release|Win32
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.Release|x86.Build.0 = Release|Win32
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.ReleaseLTCG|ARM64.ActiveCfg = ReleaseLTCG|ARM64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.ReleaseLTCG|ARM64.Build.0 = ReleaseLTCG|ARM64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.ReleaseLTCG|x64.ActiveCfg = ReleaseLTCG|x64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.ReleaseLTCG|x64.Build.0 = ReleaseLTCG|x64
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.ReleaseLTCG|x86.ActiveCfg = ReleaseLTCG|Win32
{0A172B2E-DC67-49FC-A4C1-975F93C586C4}.ReleaseLTCG|x86.Build.0 = ReleaseLTCG|Win32
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.Debug|ARM64.ActiveCfg = Debug|ARM64
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.Debug|ARM64.Build.0 = Debug|ARM64
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.Debug|x64.ActiveCfg = Debug|x64
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.Debug|x64.Build.0 = Debug|x64
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.Debug|x86.ActiveCfg = Debug|Win32
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.Debug|x86.Build.0 = Debug|Win32
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.DebugFast|ARM64.ActiveCfg = DebugFast|ARM64
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.DebugFast|ARM64.Build.0 = DebugFast|ARM64
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.DebugFast|x64.ActiveCfg = DebugFast|x64
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.DebugFast|x64.Build.0 = DebugFast|x64
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.DebugFast|x86.ActiveCfg = DebugFast|Win32
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.DebugFast|x86.Build.0 = DebugFast|Win32
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.Release|ARM64.ActiveCfg = Release|ARM64
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.Release|ARM64.Build.0 = Release|ARM64
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.Release|x64.ActiveCfg = Release|x64
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.Release|x64.Build.0 = Release|x64
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.Release|x86.ActiveCfg = Release|Win32
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.Release|x86.Build.0 = Release|Win32
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.ReleaseLTCG|ARM64.ActiveCfg = ReleaseLTCG|ARM64
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.ReleaseLTCG|ARM64.Build.0 = ReleaseLTCG|ARM64
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.ReleaseLTCG|x64.ActiveCfg = ReleaseLTCG|x64
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.ReleaseLTCG|x64.Build.0 = ReleaseLTCG|x64
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.ReleaseLTCG|x86.ActiveCfg = ReleaseLTCG|Win32
{DAA8F93D-9C17-4DE2-BD0B-57891E0FF0D9}.ReleaseLTCG|x86.Build.0 = ReleaseLTCG|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View file

@ -9,8 +9,10 @@ if(WIN32)
add_subdirectory(updater)
endif()
if(ANDROID OR BUILD_SDL_FRONTEND OR BUILD_QT_FRONTEND)
add_subdirectory(frontend-common)
add_subdirectory(frontend-common)
if(BUILD_NOGUI_FRONTEND)
add_subdirectory(duckstation-nogui)
endif()
if(BUILD_SDL_FRONTEND)

View file

@ -0,0 +1,25 @@
add_executable(duckstation-nogui
imgui_impl_sdl.cpp
imgui_impl_sdl.h
main.cpp
sdl_host_interface.cpp
sdl_host_interface.h
sdl_key_names.h
sdl_util.cpp
sdl_util.h
)
target_include_directories(duckstation-nogui PRIVATE ${SDL2_INCLUDE_DIRS})
target_link_libraries(duckstation-nogui PRIVATE core common imgui nativefiledialog glad frontend-common scmversion vulkan-loader ${SDL2_LIBRARIES})
if(WIN32)
target_sources(duckstation-nogui PRIVATE
duckstation-nogui.manifest
)
# We want a Windows subsystem application not console.
set_target_properties(duckstation-nogui PROPERTIES
WIN32_EXECUTABLE TRUE
DEBUG_POSTFIX "-debug")
endif()

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<asmv3:application>
<asmv3:windowsSettings>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
</asmv3:windowsSettings>
</asmv3:application>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
</application>
</compatibility>
</assembly>

View file

@ -0,0 +1,110 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (Australia) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS
#pragma code_page(1252)
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,0,1
PRODUCTVERSION 1,0,0,1
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x40004L
FILETYPE 0x1L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "0c0904b0"
BEGIN
VALUE "CompanyName", "https://github.com/stenzek/duckstation"
VALUE "FileDescription", "DuckStation PS1 Emulator"
VALUE "FileVersion", "1.0.0.1"
VALUE "InternalName", "duckstation-nogui.exe"
VALUE "LegalCopyright", "Copyright (C) 2020 Stenzek and collaborators"
VALUE "OriginalFilename", "duckstation-nogui.exe"
VALUE "ProductName", "DuckStation NoGUI Frontend"
VALUE "ProductVersion", "1.0.0.1"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0xc09, 1200
END
END
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_ICON1 ICON "duckstation-nogui.ico"
#endif // English (Australia) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View file

@ -0,0 +1,586 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="DebugFast|ARM64">
<Configuration>DebugFast</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="DebugFast|Win32">
<Configuration>DebugFast</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="DebugFast|x64">
<Configuration>DebugFast</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|ARM64">
<Configuration>Debug</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="ReleaseLTCG|ARM64">
<Configuration>ReleaseLTCG</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="ReleaseLTCG|Win32">
<Configuration>ReleaseLTCG</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="ReleaseLTCG|x64">
<Configuration>ReleaseLTCG</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM64">
<Configuration>Release</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\dep\imgui\imgui.vcxproj">
<Project>{bb08260f-6fbc-46af-8924-090ee71360c6}</Project>
</ProjectReference>
<ProjectReference Include="..\common\common.vcxproj">
<Project>{ee054e08-3799-4a59-a422-18259c105ffd}</Project>
</ProjectReference>
<ProjectReference Include="..\core\core.vcxproj">
<Project>{868b98c8-65a1-494b-8346-250a73a48c0a}</Project>
</ProjectReference>
<ProjectReference Include="..\frontend-common\frontend-common.vcxproj">
<Project>{6245dec8-d2da-47ee-a373-cbd6fcf3ece6}</Project>
</ProjectReference>
<ProjectReference Include="..\scmversion\scmversion.vcxproj">
<Project>{075ced82-6a20-46df-94c7-9624ac9ddbeb}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ClCompile Include="imgui_impl_sdl.cpp" />
<ClCompile Include="sdl_host_interface.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="sdl_util.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="imgui_impl_sdl.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="sdl_host_interface.h" />
<ClInclude Include="sdl_key_names.h" />
<ClInclude Include="sdl_util.h" />
</ItemGroup>
<ItemGroup>
<Manifest Include="duckstation-nogui.manifest" />
</ItemGroup>
<ItemGroup>
<Image Include="duckstation-nogui.ico" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="duckstation-nogui.rc" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{0A172B2E-DC67-49FC-A4C1-975F93C586C4}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>duckstation-nogui</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<ImportGroup Label="ExtensionSettings">
<Import Project="..\..\dep\msvc\vsprops\SDL2Compile.props" />
</ImportGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|ARM64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>NotSet</CharacterSet>
<SpectreMitigation>false</SpectreMitigation>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>NotSet</CharacterSet>
<SpectreMitigation>false</SpectreMitigation>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>NotSet</CharacterSet>
<SpectreMitigation>false</SpectreMitigation>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>NotSet</CharacterSet>
<SpectreMitigation>false</SpectreMitigation>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>NotSet</CharacterSet>
<SpectreMitigation>false</SpectreMitigation>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|ARM64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>NotSet</CharacterSet>
<SpectreMitigation>false</SpectreMitigation>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|ARM64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|ARM64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)bin\$(Platform)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</IntDir>
<TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IntDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</IntDir>
<TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)bin\$(Platform)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<IntDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</IntDir>
<TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)bin\$(Platform)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)bin\$(Platform)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</IntDir>
<TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'">
<IntDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</IntDir>
<TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)bin\$(Platform)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|ARM64'">
<IntDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</IntDir>
<TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)bin\$(Platform)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>$(SolutionDir)bin\$(Platform)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</IntDir>
<TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)bin\$(Platform)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</IntDir>
<TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IntDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</IntDir>
<TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>
<OutDir>$(SolutionDir)bin\$(Platform)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
<IntDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</IntDir>
<TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>
<OutDir>$(SolutionDir)bin\$(Platform)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|x64'">
<IntDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</IntDir>
<TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)bin\$(Platform)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|ARM64'">
<IntDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</IntDir>
<TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)bin\$(Platform)\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WITH_DISCORD_PRESENCE=1;WITH_SDL2=1;WITH_IMGUI=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include;$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<MinimalRebuild>false</MinimalRebuild>
<LanguageStandard>stdcpp17</LanguageStandard>
<ConformanceMode>true</ConformanceMode>
<AdditionalOptions>/Zo /utf-8 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>SDL2.lib;SDL2main.lib;dxgi.lib;d3d11.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WITH_DISCORD_PRESENCE=1;WITH_SDL2=1;WITH_IMGUI=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include;$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<MinimalRebuild>false</MinimalRebuild>
<LanguageStandard>stdcpp17</LanguageStandard>
<ConformanceMode>true</ConformanceMode>
<AdditionalOptions>/Zo /utf-8 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>SDL2.lib;SDL2main.lib;dxgi.lib;d3d11.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WITH_DISCORD_PRESENCE=1;WITH_SDL2=1;WITH_IMGUI=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include;$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<MinimalRebuild>false</MinimalRebuild>
<LanguageStandard>stdcpp17</LanguageStandard>
<ConformanceMode>true</ConformanceMode>
<AdditionalOptions>/Zo /utf-8 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>SDL2.lib;SDL2main.lib;dxgi.lib;d3d11.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WITH_DISCORD_PRESENCE=1;WITH_SDL2=1;WITH_IMGUI=1;_ITERATOR_DEBUG_LEVEL=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUGFAST;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include;$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<MinimalRebuild>false</MinimalRebuild>
<LanguageStandard>stdcpp17</LanguageStandard>
<SupportJustMyCode>false</SupportJustMyCode>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<ConformanceMode>true</ConformanceMode>
<AdditionalOptions>/Zo /utf-8 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>SDL2.lib;SDL2main.lib;dxgi.lib;d3d11.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WITH_DISCORD_PRESENCE=1;WITH_SDL2=1;WITH_IMGUI=1;_ITERATOR_DEBUG_LEVEL=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUGFAST;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include;$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<MinimalRebuild>false</MinimalRebuild>
<LanguageStandard>stdcpp17</LanguageStandard>
<SupportJustMyCode>false</SupportJustMyCode>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<ConformanceMode>true</ConformanceMode>
<AdditionalOptions>/Zo /utf-8 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>SDL2.lib;SDL2main.lib;dxgi.lib;d3d11.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|ARM64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WITH_DISCORD_PRESENCE=1;WITH_SDL2=1;WITH_IMGUI=1;_ITERATOR_DEBUG_LEVEL=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUGFAST;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include;$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<MinimalRebuild>false</MinimalRebuild>
<LanguageStandard>stdcpp17</LanguageStandard>
<SupportJustMyCode>false</SupportJustMyCode>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<ConformanceMode>true</ConformanceMode>
<AdditionalOptions>/Zo /utf-8 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>SDL2.lib;SDL2main.lib;dxgi.lib;d3d11.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WITH_DISCORD_PRESENCE=1;WITH_SDL2=1;WITH_IMGUI=1;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include;$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<WholeProgramOptimization>false</WholeProgramOptimization>
<LanguageStandard>stdcpp17</LanguageStandard>
<ConformanceMode>true</ConformanceMode>
<AdditionalOptions>/Zo /utf-8 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>SDL2.lib;SDL2main.lib;dxgi.lib;d3d11.lib;%(AdditionalDependencies)</AdditionalDependencies>
<LinkTimeCodeGeneration>Default</LinkTimeCodeGeneration>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|Win32'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WITH_DISCORD_PRESENCE=1;WITH_SDL2=1;WITH_IMGUI=1;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include;$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<WholeProgramOptimization>true</WholeProgramOptimization>
<LanguageStandard>stdcpp17</LanguageStandard>
<OmitFramePointers>true</OmitFramePointers>
<ConformanceMode>true</ConformanceMode>
<AdditionalOptions>/Zo /utf-8 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>SDL2.lib;SDL2main.lib;dxgi.lib;d3d11.lib;%(AdditionalDependencies)</AdditionalDependencies>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WITH_DISCORD_PRESENCE=1;WITH_SDL2=1;WITH_IMGUI=1;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include;$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<WholeProgramOptimization>false</WholeProgramOptimization>
<LanguageStandard>stdcpp17</LanguageStandard>
<ConformanceMode>true</ConformanceMode>
<AdditionalOptions>/Zo /utf-8 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>SDL2.lib;SDL2main.lib;dxgi.lib;d3d11.lib;%(AdditionalDependencies)</AdditionalDependencies>
<LinkTimeCodeGeneration>Default</LinkTimeCodeGeneration>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WITH_DISCORD_PRESENCE=1;WITH_SDL2=1;WITH_IMGUI=1;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include;$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<WholeProgramOptimization>false</WholeProgramOptimization>
<LanguageStandard>stdcpp17</LanguageStandard>
<ConformanceMode>true</ConformanceMode>
<AdditionalOptions>/Zo /utf-8 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>SDL2.lib;SDL2main.lib;dxgi.lib;d3d11.lib;%(AdditionalDependencies)</AdditionalDependencies>
<LinkTimeCodeGeneration>Default</LinkTimeCodeGeneration>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|x64'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WITH_DISCORD_PRESENCE=1;WITH_SDL2=1;WITH_IMGUI=1;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include;$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<WholeProgramOptimization>true</WholeProgramOptimization>
<LanguageStandard>stdcpp17</LanguageStandard>
<OmitFramePointers>true</OmitFramePointers>
<ConformanceMode>true</ConformanceMode>
<AdditionalOptions>/Zo /utf-8 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>SDL2.lib;SDL2main.lib;dxgi.lib;d3d11.lib;%(AdditionalDependencies)</AdditionalDependencies>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|ARM64'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WITH_DISCORD_PRESENCE=1;WITH_SDL2=1;WITH_IMGUI=1;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)dep\msvc\include;$(SolutionDir)dep\msvc\include\SDL;$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\simpleini\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<WholeProgramOptimization>true</WholeProgramOptimization>
<LanguageStandard>stdcpp17</LanguageStandard>
<OmitFramePointers>true</OmitFramePointers>
<ConformanceMode>true</ConformanceMode>
<AdditionalOptions>/Zo /utf-8 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>SDL2.lib;SDL2main.lib;dxgi.lib;d3d11.lib;%(AdditionalDependencies)</AdditionalDependencies>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View file

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="main.cpp" />
<ClCompile Include="sdl_host_interface.cpp" />
<ClCompile Include="imgui_impl_sdl.cpp" />
<ClCompile Include="sdl_util.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="sdl_host_interface.h" />
<ClInclude Include="imgui_impl_sdl.h" />
<ClInclude Include="sdl_key_names.h" />
<ClInclude Include="resource.h" />
<ClInclude Include="sdl_util.h" />
</ItemGroup>
<ItemGroup>
<Manifest Include="duckstation-sdl.manifest" />
</ItemGroup>
<ItemGroup>
<Image Include="duckstation-sdl.ico" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="duckstation-sdl.rc" />
</ItemGroup>
</Project>

View file

@ -0,0 +1,260 @@
// dear imgui: Platform Binding for SDL2
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
// (Info: SDL2 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.)
// (Requires: SDL 2.0. Prefer SDL 2.0.4+ for full feature support.)
// Implemented features:
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
// [X] Platform: Clipboard support.
// [X] Platform: Keyboard arrays indexed using SDL_SCANCODE_* codes, e.g. ImGui::IsKeyPressed(SDL_SCANCODE_SPACE).
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
// [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
// Missing features:
// [ ] Platform: SDL2 handling of IME under Windows appears to be broken and it explicitly disable the regular Windows IME. You can restore Windows IME by compiling SDL with SDL_DISABLE_WINDOWS_IME.
// [ ] Platform: Multi-viewport + Minimized windows seems to break mouse wheel events (at least under Windows).
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
// https://github.com/ocornut/imgui
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2019-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 2019-07-21: Inputs: Added mapping for ImGuiKey_KeyPadEnter.
// 2019-04-23: Inputs: Added support for SDL_GameController (if ImGuiConfigFlags_NavEnableGamepad is set by user application).
// 2019-03-12: Misc: Preserve DisplayFramebufferScale when main window is minimized.
// 2018-12-21: Inputs: Workaround for Android/iOS which don't seem to handle focus related calls.
// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
// 2018-11-14: Changed the signature of ImGui_ImplSDL2_ProcessEvent() to take a 'const SDL_Event*'.
// 2018-08-01: Inputs: Workaround for Emscripten which doesn't seem to handle focus related calls.
// 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor.
// 2018-06-08: Misc: Extracted imgui_impl_sdl.cpp/.h away from the old combined SDL2+OpenGL/Vulkan examples.
// 2018-06-08: Misc: ImGui_ImplSDL2_InitForOpenGL() now takes a SDL_GLContext parameter.
// 2018-05-09: Misc: Fixed clipboard paste memory leak (we didn't call SDL_FreeMemory on the data returned by SDL_GetClipboardText).
// 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors flag + honor ImGuiConfigFlags_NoMouseCursorChange flag.
// 2018-02-16: Inputs: Added support for mouse cursors, honoring ImGui::GetMouseCursor() value.
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
// 2018-02-05: Misc: Using SDL_GetPerformanceCounter() instead of SDL_GetTicks() to be able to handle very high framerate (1000+ FPS).
// 2018-02-05: Inputs: Keyboard mapping is using scancodes everywhere instead of a confusing mixture of keycodes and scancodes.
// 2018-01-20: Inputs: Added Horizontal Mouse Wheel support.
// 2018-01-19: Inputs: When available (SDL 2.0.4+) using SDL_CaptureMouse() to retrieve coordinates outside of client area when dragging. Otherwise (SDL 2.0.3 and before) testing for SDL_WINDOW_INPUT_FOCUS instead of SDL_WINDOW_MOUSE_FOCUS.
// 2018-01-18: Inputs: Added mapping for ImGuiKey_Insert.
// 2017-08-25: Inputs: MousePos set to -FLT_MAX,-FLT_MAX when mouse is unavailable/missing (instead of -1,-1).
// 2016-10-15: Misc: Added a void* user_data parameter to Clipboard function handlers.
#include "imgui.h"
#include "imgui_impl_sdl.h"
// SDL
// (the multi-viewports feature requires SDL features supported from SDL 2.0.4+. SDL 2.0.5+ is highly recommended)
#include <SDL.h>
#include <SDL_syswm.h>
#if defined(__APPLE__)
#include "TargetConditionals.h"
#endif
#define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE SDL_VERSION_ATLEAST(2,0,4)
#define SDL_HAS_WINDOW_ALPHA SDL_VERSION_ATLEAST(2,0,5)
#define SDL_HAS_ALWAYS_ON_TOP SDL_VERSION_ATLEAST(2,0,5)
#define SDL_HAS_USABLE_DISPLAY_BOUNDS SDL_VERSION_ATLEAST(2,0,5)
#define SDL_HAS_PER_MONITOR_DPI SDL_VERSION_ATLEAST(2,0,4)
#define SDL_HAS_VULKAN SDL_VERSION_ATLEAST(2,0,6)
#define SDL_HAS_MOUSE_FOCUS_CLICKTHROUGH SDL_VERSION_ATLEAST(2,0,5)
#if !SDL_HAS_VULKAN
static const Uint32 SDL_WINDOW_VULKAN = 0x10000000;
#endif
// Data
static SDL_Window* g_Window = NULL;
static Uint64 g_Time = 0;
static bool g_MousePressed[3] = { false, false, false };
static SDL_Cursor* g_MouseCursors[ImGuiMouseCursor_COUNT] = {};
static char* g_ClipboardTextData = NULL;
static const char* ImGui_ImplSDL2_GetClipboardText(void*)
{
if (g_ClipboardTextData)
SDL_free(g_ClipboardTextData);
g_ClipboardTextData = SDL_GetClipboardText();
return g_ClipboardTextData;
}
static void ImGui_ImplSDL2_SetClipboardText(void*, const char* text)
{
SDL_SetClipboardText(text);
}
// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application.
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application.
// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
// If you have multiple SDL events and some of them are not meant to be used by dear imgui, you may need to filter events based on their windowID field.
bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event)
{
ImGuiIO& io = ImGui::GetIO();
switch (event->type)
{
case SDL_MOUSEWHEEL:
{
if (event->wheel.x > 0) io.MouseWheelH += 1;
if (event->wheel.x < 0) io.MouseWheelH -= 1;
if (event->wheel.y > 0) io.MouseWheel += 1;
if (event->wheel.y < 0) io.MouseWheel -= 1;
return true;
}
case SDL_MOUSEBUTTONDOWN:
{
if (event->button.button == SDL_BUTTON_LEFT) g_MousePressed[0] = true;
if (event->button.button == SDL_BUTTON_RIGHT) g_MousePressed[1] = true;
if (event->button.button == SDL_BUTTON_MIDDLE) g_MousePressed[2] = true;
return true;
}
case SDL_TEXTINPUT:
{
io.AddInputCharactersUTF8(event->text.text);
return true;
}
case SDL_KEYDOWN:
case SDL_KEYUP:
{
int key = event->key.keysym.scancode;
IM_ASSERT(key >= 0 && key < IM_ARRAYSIZE(io.KeysDown));
io.KeysDown[key] = (event->type == SDL_KEYDOWN);
io.KeyShift = ((SDL_GetModState() & KMOD_SHIFT) != 0);
io.KeyCtrl = ((SDL_GetModState() & KMOD_CTRL) != 0);
io.KeyAlt = ((SDL_GetModState() & KMOD_ALT) != 0);
io.KeySuper = ((SDL_GetModState() & KMOD_GUI) != 0);
return true;
}
}
return false;
}
bool ImGui_ImplSDL2_Init(SDL_Window* window)
{
g_Window = window;
// Setup back-end capabilities flags
ImGuiIO& io = ImGui::GetIO();
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; // We can honor GetMouseCursor() values (optional)
io.BackendPlatformName = "imgui_impl_sdl";
// Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array.
io.KeyMap[ImGuiKey_Tab] = SDL_SCANCODE_TAB;
io.KeyMap[ImGuiKey_LeftArrow] = SDL_SCANCODE_LEFT;
io.KeyMap[ImGuiKey_RightArrow] = SDL_SCANCODE_RIGHT;
io.KeyMap[ImGuiKey_UpArrow] = SDL_SCANCODE_UP;
io.KeyMap[ImGuiKey_DownArrow] = SDL_SCANCODE_DOWN;
io.KeyMap[ImGuiKey_PageUp] = SDL_SCANCODE_PAGEUP;
io.KeyMap[ImGuiKey_PageDown] = SDL_SCANCODE_PAGEDOWN;
io.KeyMap[ImGuiKey_Home] = SDL_SCANCODE_HOME;
io.KeyMap[ImGuiKey_End] = SDL_SCANCODE_END;
io.KeyMap[ImGuiKey_Insert] = SDL_SCANCODE_INSERT;
io.KeyMap[ImGuiKey_Delete] = SDL_SCANCODE_DELETE;
io.KeyMap[ImGuiKey_Backspace] = SDL_SCANCODE_BACKSPACE;
io.KeyMap[ImGuiKey_Space] = SDL_SCANCODE_SPACE;
io.KeyMap[ImGuiKey_Enter] = SDL_SCANCODE_RETURN;
io.KeyMap[ImGuiKey_Escape] = SDL_SCANCODE_ESCAPE;
io.KeyMap[ImGuiKey_KeyPadEnter] = SDL_SCANCODE_RETURN2;
io.KeyMap[ImGuiKey_A] = SDL_SCANCODE_A;
io.KeyMap[ImGuiKey_C] = SDL_SCANCODE_C;
io.KeyMap[ImGuiKey_V] = SDL_SCANCODE_V;
io.KeyMap[ImGuiKey_X] = SDL_SCANCODE_X;
io.KeyMap[ImGuiKey_Y] = SDL_SCANCODE_Y;
io.KeyMap[ImGuiKey_Z] = SDL_SCANCODE_Z;
io.SetClipboardTextFn = ImGui_ImplSDL2_SetClipboardText;
io.GetClipboardTextFn = ImGui_ImplSDL2_GetClipboardText;
io.ClipboardUserData = NULL;
g_MouseCursors[ImGuiMouseCursor_Arrow] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW);
g_MouseCursors[ImGuiMouseCursor_TextInput] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_IBEAM);
g_MouseCursors[ImGuiMouseCursor_ResizeAll] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEALL);
g_MouseCursors[ImGuiMouseCursor_ResizeNS] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENS);
g_MouseCursors[ImGuiMouseCursor_ResizeEW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZEWE);
g_MouseCursors[ImGuiMouseCursor_ResizeNESW] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENESW);
g_MouseCursors[ImGuiMouseCursor_ResizeNWSE] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_SIZENWSE);
g_MouseCursors[ImGuiMouseCursor_Hand] = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND);
return true;
}
void ImGui_ImplSDL2_Shutdown()
{
g_Window = NULL;
// Destroy last known clipboard data
if (g_ClipboardTextData)
SDL_free(g_ClipboardTextData);
g_ClipboardTextData = NULL;
// Destroy SDL mouse cursors
for (ImGuiMouseCursor cursor_n = 0; cursor_n < ImGuiMouseCursor_COUNT; cursor_n++)
SDL_FreeCursor(g_MouseCursors[cursor_n]);
memset(g_MouseCursors, 0, sizeof(g_MouseCursors));
}
// This code is incredibly messy because some of the functions we need for full viewport support are not available in SDL < 2.0.4.
static void ImGui_ImplSDL2_UpdateMousePosAndButtons()
{
ImGuiIO& io = ImGui::GetIO();
// [1]
// Only when requested by io.WantSetMousePos: set OS mouse pos from Dear ImGui mouse pos.
// (rarely used, mostly when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
if (io.WantSetMousePos)
{
SDL_WarpMouseInWindow(g_Window, (int)io.MousePos.x, (int)io.MousePos.y);
}
else
{
io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
}
// [2]
// Set Dear ImGui mouse pos from OS mouse pos + get buttons. (this is the common behavior)
int mouse_x_local, mouse_y_local;
Uint32 mouse_buttons = SDL_GetMouseState(&mouse_x_local, &mouse_y_local);
io.MouseDown[0] = g_MousePressed[0] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_LEFT)) != 0; // If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
io.MouseDown[1] = g_MousePressed[1] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_RIGHT)) != 0;
io.MouseDown[2] = g_MousePressed[2] || (mouse_buttons & SDL_BUTTON(SDL_BUTTON_MIDDLE)) != 0;
g_MousePressed[0] = g_MousePressed[1] = g_MousePressed[2] = false;
// SDL 2.0.3 and before: single-viewport only
if (SDL_GetWindowFlags(g_Window) & SDL_WINDOW_INPUT_FOCUS)
io.MousePos = ImVec2((float)mouse_x_local, (float)mouse_y_local);
}
static void ImGui_ImplSDL2_UpdateMouseCursor()
{
ImGuiIO& io = ImGui::GetIO();
if (io.ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange)
return;
ImGuiMouseCursor imgui_cursor = ImGui::GetMouseCursor();
if (io.MouseDrawCursor || imgui_cursor == ImGuiMouseCursor_None)
{
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
SDL_ShowCursor(SDL_FALSE);
}
else
{
// Show OS mouse cursor
SDL_SetCursor(g_MouseCursors[imgui_cursor] ? g_MouseCursors[imgui_cursor] : g_MouseCursors[ImGuiMouseCursor_Arrow]);
SDL_ShowCursor(SDL_TRUE);
}
}
void ImGui_ImplSDL2_NewFrame()
{
ImGuiIO& io = ImGui::GetIO();
// Setup time step (we don't use SDL_GetTicks() because it is using millisecond resolution)
static Uint64 frequency = SDL_GetPerformanceFrequency();
Uint64 current_time = SDL_GetPerformanceCounter();
io.DeltaTime = g_Time > 0 ? (float)((double)(current_time - g_Time) / frequency) : (float)(1.0f / 60.0f);
g_Time = current_time;
ImGui_ImplSDL2_UpdateMousePosAndButtons();
ImGui_ImplSDL2_UpdateMouseCursor();
}

View file

@ -0,0 +1,28 @@
// dear imgui: Platform Binding for SDL2
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
// (Info: SDL2 is a cross-platform general purpose library for handling windows, inputs, graphics context creation, etc.)
// Implemented features:
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
// [X] Platform: Clipboard support.
// [X] Platform: Keyboard arrays indexed using SDL_SCANCODE_* codes, e.g. ImGui::IsKeyPressed(SDL_SCANCODE_SPACE).
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
// [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
// Missing features:
// [ ] Platform: SDL2 handling of IME under Windows appears to be broken and it explicitly disable the regular Windows IME. You can restore Windows IME by compiling SDL with SDL_DISABLE_WINDOWS_IME.
// [ ] Platform: Multi-viewport + Minimized windows seems to break mouse wheel events (at least under Windows).
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
// If you are new to dear imgui, read examples/README.txt and read the documentation at the top of imgui.cpp.
// https://github.com/ocornut/imgui
#pragma once
#include "imgui.h"
struct SDL_Window;
typedef union SDL_Event SDL_Event;
IMGUI_IMPL_API bool ImGui_ImplSDL2_Init(SDL_Window* window);
IMGUI_IMPL_API void ImGui_ImplSDL2_Shutdown();
IMGUI_IMPL_API void ImGui_ImplSDL2_NewFrame();
IMGUI_IMPL_API bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event);

View file

@ -0,0 +1,48 @@
#include "common/assert.h"
#include "common/log.h"
#include "core/system.h"
#include "frontend-common/sdl_initializer.h"
#include "sdl_host_interface.h"
#include <SDL.h>
#include <cstdio>
#include <cstdlib>
int main(int argc, char* argv[])
{
FrontendCommon::EnsureSDLInitialized();
std::unique_ptr<SDLHostInterface> host_interface = SDLHostInterface::Create();
std::unique_ptr<SystemBootParameters> boot_params;
if (!host_interface->ParseCommandLineParameters(argc, argv, &boot_params))
{
SDL_Quit();
return EXIT_FAILURE;
}
if (!host_interface->Initialize())
{
host_interface->Shutdown();
SDL_Quit();
return EXIT_FAILURE;
}
if (boot_params)
{
if (!host_interface->BootSystem(*boot_params) && host_interface->InBatchMode())
{
host_interface->Shutdown();
host_interface.reset();
SDL_Quit();
return EXIT_FAILURE;
}
boot_params.reset();
}
host_interface->Run();
host_interface->Shutdown();
host_interface.reset();
SDL_Quit();
return EXIT_SUCCESS;
}

View file

@ -0,0 +1,16 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by duckstation-sdl.rc
//
#define IDI_ICON1 102
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 103
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View file

@ -0,0 +1,661 @@
#include "sdl_host_interface.h"
#include "common/assert.h"
#include "common/byte_stream.h"
#include "common/file_system.h"
#include "common/image.h"
#include "common/log.h"
#include "common/string_util.h"
#include "core/gpu.h"
#include "core/host_display.h"
#include "core/system.h"
#include "frontend-common/fullscreen_ui.h"
#include "frontend-common/icon.h"
#include "frontend-common/imgui_fullscreen.h"
#include "frontend-common/imgui_styles.h"
#include "frontend-common/ini_settings_interface.h"
#include "frontend-common/opengl_host_display.h"
#include "frontend-common/sdl_audio_stream.h"
#include "frontend-common/sdl_controller_interface.h"
#include "frontend-common/vulkan_host_display.h"
#include "imgui.h"
#include "imgui_impl_sdl.h"
#include "imgui_stdlib.h"
#include "scmversion/scmversion.h"
#include "sdl_key_names.h"
#include "sdl_util.h"
#include <cinttypes>
#include <cmath>
Log_SetChannel(SDLHostInterface);
#ifdef WIN32
#include "frontend-common/d3d11_host_display.h"
#endif
SDLHostInterface::SDLHostInterface()
{
m_run_later_event_id = SDL_RegisterEvents(1);
}
SDLHostInterface::~SDLHostInterface() = default;
const char* SDLHostInterface::GetFrontendName() const
{
return "DuckStation NoGUI Frontend";
}
ALWAYS_INLINE static TinyString GetWindowTitle()
{
return TinyString::FromFormat("DuckStation %s (%s)", g_scm_tag_str, g_scm_branch_str);
}
bool SDLHostInterface::CreateSDLWindow()
{
static constexpr u32 DEFAULT_WINDOW_WIDTH = 1280;
static constexpr u32 DEFAULT_WINDOW_HEIGHT = 720;
// Create window.
const u32 window_flags = SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI;
u32 window_width = DEFAULT_WINDOW_WIDTH;
u32 window_height = DEFAULT_WINDOW_HEIGHT;
// macOS does DPI scaling differently..
#ifndef __APPLE__
{
// scale by default monitor's DPI
float scale = SDLUtil::GetDPIScaleFactor(nullptr);
window_width = static_cast<u32>(std::round(static_cast<float>(window_width) * scale));
window_height = static_cast<u32>(std::round(static_cast<float>(window_height) * scale));
}
#endif
m_window = SDL_CreateWindow(GetWindowTitle(), SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, window_width,
window_height, window_flags);
if (!m_window)
return false;
// Set window icon.
SDL_Surface* icon_surface =
SDL_CreateRGBSurfaceFrom(const_cast<unsigned int*>(WINDOW_ICON_DATA), WINDOW_ICON_WIDTH, WINDOW_ICON_HEIGHT, 32,
WINDOW_ICON_WIDTH * sizeof(u32), UINT32_C(0x000000FF), UINT32_C(0x0000FF00),
UINT32_C(0x00FF0000), UINT32_C(0xFF000000));
if (icon_surface)
{
SDL_SetWindowIcon(m_window, icon_surface);
SDL_FreeSurface(icon_surface);
}
if (m_fullscreen)
SDL_SetWindowFullscreen(m_window, SDL_WINDOW_FULLSCREEN_DESKTOP);
// Process events so that we have everything sorted out before creating a child window for the GL context (X11).
SDL_PumpEvents();
return true;
}
void SDLHostInterface::DestroySDLWindow()
{
SDL_DestroyWindow(m_window);
m_window = nullptr;
}
bool SDLHostInterface::CreateDisplay()
{
std::optional<WindowInfo> wi = SDLUtil::GetWindowInfoForSDLWindow(m_window);
if (!wi.has_value())
{
ReportError("Failed to get window info from SDL window");
return false;
}
switch (g_settings.gpu_renderer)
{
case GPURenderer::HardwareVulkan:
m_display = std::make_unique<FrontendCommon::VulkanHostDisplay>();
break;
case GPURenderer::HardwareOpenGL:
#ifndef WIN32
default:
#endif
m_display = std::make_unique<FrontendCommon::OpenGLHostDisplay>();
break;
#ifdef WIN32
case GPURenderer::HardwareD3D11:
default:
m_display = std::make_unique<FrontendCommon::D3D11HostDisplay>();
break;
#endif
}
Assert(m_display);
if (!m_display->CreateRenderDevice(wi.value(), 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))
{
ReportError("Failed to create/initialize display render device");
m_display.reset();
return false;
}
if (!ImGui_ImplSDL2_Init(m_window) || !m_display->CreateImGuiContext())
{
ReportError("Failed to initialize ImGui SDL2 wrapper");
ImGui_ImplSDL2_Shutdown();
m_display->DestroyRenderDevice();
m_display.reset();
return false;
}
if (!FullscreenUI::Initialize(this, m_settings_interface.get()) || !m_display->UpdateImGuiFontTexture())
{
ReportError("Failed to initialize fonts/fullscreen UI");
FullscreenUI::Shutdown();
m_display->DestroyImGuiContext();
ImGui_ImplSDL2_Shutdown();
m_display->DestroyRenderDevice();
m_display.reset();
return false;
}
m_fullscreen_ui_enabled = true;
return true;
}
void SDLHostInterface::DestroyDisplay()
{
FullscreenUI::Shutdown();
m_display->DestroyImGuiContext();
m_display->DestroyRenderDevice();
m_display.reset();
}
void SDLHostInterface::CreateImGuiContext()
{
const float framebuffer_scale = SDLUtil::GetDPIScaleFactor(m_window);
ImGui::CreateContext();
ImGui::GetIO().IniFilename = nullptr;
ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard | ImGuiConfigFlags_NavEnableGamepad;
ImGui::GetIO().DisplayFramebufferScale.x = framebuffer_scale;
ImGui::GetIO().DisplayFramebufferScale.y = framebuffer_scale;
ImGui::GetStyle().ScaleAllSizes(framebuffer_scale);
ImGui::StyleColorsDarker();
}
void SDLHostInterface::UpdateFramebufferScale()
{
ImGuiIO& io = ImGui::GetIO();
const float framebuffer_scale = SDLUtil::GetDPIScaleFactor(m_window);
if (framebuffer_scale != io.DisplayFramebufferScale.x)
{
io.DisplayFramebufferScale = ImVec2(framebuffer_scale, framebuffer_scale);
ImGui::GetStyle().ScaleAllSizes(framebuffer_scale);
}
if (ImGuiFullscreen::UpdateLayoutScale())
{
if (ImGuiFullscreen::UpdateFonts())
{
if (!m_display->UpdateImGuiFontTexture())
Panic("Failed to update font texture");
}
}
}
bool SDLHostInterface::AcquireHostDisplay()
{
// Handle renderer switch if required.
const HostDisplay::RenderAPI render_api = m_display->GetRenderAPI();
bool needs_switch = false;
switch (g_settings.gpu_renderer)
{
#ifdef WIN32
case GPURenderer::HardwareD3D11:
needs_switch = (render_api != HostDisplay::RenderAPI::D3D11);
break;
#endif
case GPURenderer::HardwareVulkan:
needs_switch = (render_api != HostDisplay::RenderAPI::Vulkan);
break;
case GPURenderer::HardwareOpenGL:
needs_switch = (render_api != HostDisplay::RenderAPI::OpenGL && render_api != HostDisplay::RenderAPI::OpenGLES);
break;
case GPURenderer::Software:
default:
needs_switch = false;
break;
}
if (needs_switch)
{
ImGui::EndFrame();
DestroyDisplay();
// We need to recreate the window, otherwise bad things happen...
DestroySDLWindow();
if (!CreateSDLWindow())
Panic("Failed to recreate SDL window on GPU renderer switch");
if (!CreateDisplay())
Panic("Failed to recreate display on GPU renderer switch");
ImGui::NewFrame();
}
if (!CreateHostDisplayResources())
return false;
return true;
}
void SDLHostInterface::ReleaseHostDisplay()
{
ReleaseHostDisplayResources();
// restore vsync, since we don't want to burn cycles at the menu
m_display->SetVSync(true);
}
std::optional<CommonHostInterface::HostKeyCode> SDLHostInterface::GetHostKeyCode(const std::string_view key_code) const
{
const std::optional<u32> code = SDLKeyNames::ParseKeyString(key_code);
if (!code)
return std::nullopt;
return static_cast<HostKeyCode>(*code);
}
void SDLHostInterface::UpdateInputMap()
{
CommonHostInterface::UpdateInputMap(*m_settings_interface.get());
}
void SDLHostInterface::OnSystemCreated()
{
CommonHostInterface::OnSystemCreated();
FullscreenUI::SystemCreated();
}
void SDLHostInterface::OnSystemPaused(bool paused)
{
CommonHostInterface::OnSystemPaused(paused);
FullscreenUI::SystemPaused(paused);
}
void SDLHostInterface::OnSystemDestroyed()
{
CommonHostInterface::OnSystemDestroyed();
ReportFormattedMessage("System shut down.");
FullscreenUI::SystemDestroyed();
}
void SDLHostInterface::OnRunningGameChanged()
{
CommonHostInterface::OnRunningGameChanged();
Settings old_settings(std::move(g_settings));
CommonHostInterface::LoadSettings(*m_settings_interface.get());
CommonHostInterface::ApplyGameSettings(true);
CommonHostInterface::FixIncompatibleSettings(true);
CheckForSettingsChanges(old_settings);
if (!System::GetRunningTitle().empty())
SDL_SetWindowTitle(m_window, System::GetRunningTitle().c_str());
else
SDL_SetWindowTitle(m_window, GetWindowTitle());
}
void SDLHostInterface::RequestExit()
{
m_quit_request = true;
}
void SDLHostInterface::RunLater(std::function<void()> callback)
{
SDL_Event ev = {};
ev.type = SDL_USEREVENT;
ev.user.code = m_run_later_event_id;
ev.user.data1 = new std::function<void()>(std::move(callback));
SDL_PushEvent(&ev);
}
void SDLHostInterface::ApplySettings(bool display_osd_messages)
{
Settings old_settings(std::move(g_settings));
CommonHostInterface::LoadSettings(*m_settings_interface.get());
CommonHostInterface::ApplyGameSettings(display_osd_messages);
CommonHostInterface::FixIncompatibleSettings(display_osd_messages);
CheckForSettingsChanges(old_settings);
}
bool SDLHostInterface::IsFullscreen() const
{
return m_fullscreen;
}
bool SDLHostInterface::SetFullscreen(bool enabled)
{
if (m_fullscreen == enabled)
return true;
SDL_SetWindowFullscreen(m_window, enabled ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
int window_width, window_height;
SDL_GetWindowSize(m_window, &window_width, &window_height);
m_display->ResizeRenderWindow(window_width, window_height);
if (!System::IsShutdown())
g_gpu->UpdateResolutionScale();
m_fullscreen = enabled;
return true;
}
std::unique_ptr<SDLHostInterface> SDLHostInterface::Create()
{
return std::make_unique<SDLHostInterface>();
}
bool SDLHostInterface::Initialize()
{
if (!CommonHostInterface::Initialize())
return false;
// Change to the user directory so that all default/relative paths in the config are after this.
if (!FileSystem::SetWorkingDirectory(m_user_directory.c_str()))
Log_ErrorPrintf("Failed to set working directory to '%s'", m_user_directory.c_str());
if (!CreateSDLWindow())
{
Log_ErrorPrintf("Failed to create SDL window");
return false;
}
CreateImGuiContext();
if (!CreateDisplay())
{
Log_ErrorPrintf("Failed to create host display");
return false;
}
// process events to pick up controllers before updating input map
ProcessEvents();
UpdateInputMap();
return true;
}
void SDLHostInterface::Shutdown()
{
DestroySystem();
CommonHostInterface::Shutdown();
if (m_display)
{
DestroyDisplay();
ImGui::DestroyContext();
}
if (m_window)
DestroySDLWindow();
}
std::string SDLHostInterface::GetStringSettingValue(const char* section, const char* key,
const char* default_value /*= ""*/)
{
return m_settings_interface->GetStringValue(section, key, default_value);
}
bool SDLHostInterface::GetBoolSettingValue(const char* section, const char* key, bool default_value /* = false */)
{
return m_settings_interface->GetBoolValue(section, key, default_value);
}
int SDLHostInterface::GetIntSettingValue(const char* section, const char* key, int default_value /* = 0 */)
{
return m_settings_interface->GetIntValue(section, key, default_value);
}
float SDLHostInterface::GetFloatSettingValue(const char* section, const char* key, float default_value /* = 0.0f */)
{
return m_settings_interface->GetFloatValue(section, key, default_value);
}
bool SDLHostInterface::RequestRenderWindowSize(s32 new_window_width, s32 new_window_height)
{
if (new_window_width <= 0 || new_window_height <= 0 || m_fullscreen)
return false;
// use imgui scale as the dpr
const float dpi_scale = ImGui::GetIO().DisplayFramebufferScale.x;
const s32 scaled_width =
std::max<s32>(static_cast<s32>(std::ceil(static_cast<float>(new_window_width) * dpi_scale)), 1);
const s32 scaled_height = std::max<s32>(
static_cast<s32>(std::ceil(static_cast<float>(new_window_height) * dpi_scale)) + m_display->GetDisplayTopMargin(),
1);
SDL_SetWindowSize(m_window, scaled_width, scaled_height);
s32 window_width, window_height;
SDL_GetWindowSize(m_window, &window_width, &window_height);
m_display->ResizeRenderWindow(window_width, window_height);
UpdateFramebufferScale();
if (!System::IsShutdown())
g_gpu->UpdateResolutionScale();
return true;
}
void SDLHostInterface::LoadSettings()
{
// Settings need to be loaded prior to creating the window for OpenGL bits.
m_settings_interface = std::make_unique<INISettingsInterface>(GetSettingsFileName());
CommonHostInterface::LoadSettings(*m_settings_interface.get());
CommonHostInterface::FixIncompatibleSettings(false);
}
void SDLHostInterface::ReportError(const char* message)
{
const bool was_fullscreen = IsFullscreen();
if (was_fullscreen)
SetFullscreen(false);
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "DuckStation", message, m_window);
if (was_fullscreen)
SetFullscreen(true);
}
void SDLHostInterface::ReportMessage(const char* message)
{
AddOSDMessage(message, 2.0f);
}
bool SDLHostInterface::ConfirmMessage(const char* message)
{
const bool was_fullscreen = IsFullscreen();
if (was_fullscreen)
SetFullscreen(false);
SDL_MessageBoxData mbd = {};
mbd.flags = SDL_MESSAGEBOX_INFORMATION;
mbd.window = m_window;
mbd.title = "DuckStation";
mbd.message = message;
mbd.numbuttons = 2;
// Why the heck these are reversed I have no idea...
SDL_MessageBoxButtonData buttons[2] = {};
buttons[1].flags = SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT;
buttons[1].buttonid = 0;
buttons[1].text = "Yes";
buttons[0].flags = SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT;
buttons[0].buttonid = 1;
buttons[0].text = "No";
mbd.buttons = buttons;
mbd.numbuttons = countof(buttons);
int button_id = 0;
SDL_ShowMessageBox(&mbd, &button_id);
const bool result = (button_id == 0);
if (was_fullscreen)
SetFullscreen(true);
return result;
}
void SDLHostInterface::HandleSDLEvent(const SDL_Event* event)
{
ImGui_ImplSDL2_ProcessEvent(event);
if (m_controller_interface &&
static_cast<SDLControllerInterface*>(m_controller_interface.get())->ProcessSDLEvent(event))
{
return;
}
switch (event->type)
{
case SDL_WINDOWEVENT:
{
if (event->window.event == SDL_WINDOWEVENT_RESIZED)
{
m_display->ResizeRenderWindow(event->window.data1, event->window.data2);
UpdateFramebufferScale();
if (!System::IsShutdown())
g_gpu->UpdateResolutionScale();
}
else if (event->window.event == SDL_WINDOWEVENT_MOVED)
{
UpdateFramebufferScale();
}
}
break;
case SDL_QUIT:
m_quit_request = true;
break;
case SDL_KEYDOWN:
case SDL_KEYUP:
{
if (!ImGui::GetIO().WantCaptureKeyboard && event->key.repeat == 0)
{
const HostKeyCode code = static_cast<HostKeyCode>(SDLKeyNames::KeyEventToInt(event));
const bool pressed = (event->type == SDL_KEYDOWN);
HandleHostKeyEvent(code, pressed);
}
}
break;
case SDL_MOUSEMOTION:
{
m_display->SetMousePosition(event->motion.x, event->motion.y);
}
break;
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
{
if (!ImGui::GetIO().WantCaptureMouse)
{
const s32 button = static_cast<s32>(ZeroExtend32(event->button.button));
const bool pressed = (event->type == SDL_MOUSEBUTTONDOWN);
HandleHostMouseEvent(button, pressed);
}
}
break;
case SDL_USEREVENT:
{
if (static_cast<u32>(event->user.code) == m_run_later_event_id)
{
std::function<void()>* callback = static_cast<std::function<void()>*>(event->user.data1);
Assert(callback);
(*callback)();
delete callback;
}
}
break;
}
}
void SDLHostInterface::PollAndUpdate()
{
ProcessEvents();
CommonHostInterface::PollAndUpdate();
}
void SDLHostInterface::ProcessEvents()
{
for (;;)
{
SDL_Event ev;
if (SDL_PollEvent(&ev))
HandleSDLEvent(&ev);
else
break;
}
}
void SDLHostInterface::Run()
{
while (!m_quit_request)
{
PollAndUpdate();
if (System::IsRunning())
{
if (m_display_all_frames)
System::RunFrame();
else
System::RunFrames();
UpdateControllerRumble();
if (m_frame_step_request)
{
m_frame_step_request = false;
PauseSystem(true);
}
}
// rendering
{
ImGui_ImplSDL2_NewFrame();
FullscreenUI::SetImGuiNavInputs();
ImGui::NewFrame();
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())
{
if (g_settings.save_state_on_exit)
SaveResumeSaveState();
DestroySystem();
}
}

View file

@ -0,0 +1,87 @@
#pragma once
#include "common/gl/program.h"
#include "common/gl/texture.h"
#include "core/host_display.h"
#include "core/host_interface.h"
#include "frontend-common/common_host_interface.h"
#include <SDL.h>
#include <array>
#include <deque>
#include <map>
#include <memory>
#include <mutex>
#include <string>
class AudioStream;
class INISettingsInterface;
struct GameListEntry;
class SDLHostInterface final : public CommonHostInterface
{
public:
SDLHostInterface();
~SDLHostInterface();
static std::unique_ptr<SDLHostInterface> Create();
const char* GetFrontendName() const override;
void ReportError(const char* message) override;
void ReportMessage(const char* message) override;
bool ConfirmMessage(const char* message) override;
bool Initialize() override;
void Shutdown() override;
std::string GetStringSettingValue(const char* section, const char* key, const char* default_value = "") override;
bool GetBoolSettingValue(const char* section, const char* key, bool default_value = false) override;
int GetIntSettingValue(const char* section, const char* key, int default_value = 0) override;
float GetFloatSettingValue(const char* section, const char* key, float default_value = 0.0f) override;
bool RequestRenderWindowSize(s32 new_window_width, s32 new_window_height) override;
bool IsFullscreen() const override;
bool SetFullscreen(bool enabled) override;
void RunLater(std::function<void()> callback) override;
void ApplySettings(bool display_osd_messages) override;
void Run();
protected:
void LoadSettings() override;
bool AcquireHostDisplay() override;
void ReleaseHostDisplay() override;
void OnSystemCreated() override;
void OnSystemPaused(bool paused) override;
void OnSystemDestroyed() override;
void OnRunningGameChanged() override;
void RequestExit() override;
void PollAndUpdate() override;
std::optional<HostKeyCode> GetHostKeyCode(const std::string_view key_code) const override;
void UpdateInputMap() override;
private:
bool CreateSDLWindow();
void DestroySDLWindow();
bool CreateDisplay();
void DestroyDisplay();
void CreateImGuiContext();
void UpdateFramebufferScale();
void HandleSDLEvent(const SDL_Event* event);
void ProcessEvents();
SDL_Window* m_window = nullptr;
std::unique_ptr<INISettingsInterface> m_settings_interface;
u32 m_run_later_event_id = 0;
bool m_fullscreen = false;
bool m_quit_request = false;
};

View file

@ -0,0 +1,353 @@
#pragma once
#include "common/string.h"
#include "common/types.h"
#include <SDL.h>
#include <array>
#include <cstring>
#include <map>
#include <optional>
#include <string_view>
namespace SDLKeyNames {
static const std::map<int, const char*> s_sdl_key_names = {{SDLK_RETURN, "Return"},
{SDLK_ESCAPE, "Escape"},
{SDLK_BACKSPACE, "Backspace"},
{SDLK_TAB, "Tab"},
{SDLK_SPACE, "Space"},
{SDLK_EXCLAIM, "Exclam"},
{SDLK_QUOTEDBL, "QuoteDbl"},
{SDLK_HASH, "Hash"},
{SDLK_PERCENT, "Percent"},
{SDLK_DOLLAR, "Dollar"},
{SDLK_AMPERSAND, "Ampersand"},
{SDLK_QUOTE, "Apostrophe"},
{SDLK_LEFTPAREN, "ParenLeft"},
{SDLK_RIGHTPAREN, "ParenRight"},
{SDLK_ASTERISK, "Asterisk"},
{SDLK_PLUS, "PLus"},
{SDLK_COMMA, "Comma"},
{SDLK_MINUS, "Minus"},
{SDLK_PERIOD, "Period"},
{SDLK_SLASH, "Slash"},
{SDLK_0, "0"},
{SDLK_1, "1"},
{SDLK_2, "2"},
{SDLK_3, "3"},
{SDLK_4, "4"},
{SDLK_5, "5"},
{SDLK_6, "6"},
{SDLK_7, "7"},
{SDLK_8, "8"},
{SDLK_9, "9"},
{SDLK_COLON, "Colon"},
{SDLK_SEMICOLON, "Semcolon"},
{SDLK_LESS, "Less"},
{SDLK_EQUALS, "Equal"},
{SDLK_GREATER, "Greater"},
{SDLK_QUESTION, "Question"},
{SDLK_AT, "AT"},
{SDLK_LEFTBRACKET, "BracketLeft"},
{SDLK_BACKSLASH, "Backslash"},
{SDLK_RIGHTBRACKET, "BracketRight"},
{SDLK_CARET, "Caret"},
{SDLK_UNDERSCORE, "Underscore"},
{SDLK_BACKQUOTE, "QuoteLeft"},
{SDLK_a, "A"},
{SDLK_b, "B"},
{SDLK_c, "C"},
{SDLK_d, "D"},
{SDLK_e, "E"},
{SDLK_f, "F"},
{SDLK_g, "G"},
{SDLK_h, "H"},
{SDLK_i, "I"},
{SDLK_j, "J"},
{SDLK_k, "K"},
{SDLK_l, "L"},
{SDLK_m, "M"},
{SDLK_n, "N"},
{SDLK_o, "O"},
{SDLK_p, "P"},
{SDLK_q, "Q"},
{SDLK_r, "R"},
{SDLK_s, "S"},
{SDLK_t, "T"},
{SDLK_u, "U"},
{SDLK_v, "V"},
{SDLK_w, "W"},
{SDLK_x, "X"},
{SDLK_y, "Y"},
{SDLK_z, "Z"},
{SDLK_CAPSLOCK, "CapsLock"},
{SDLK_F1, "F1"},
{SDLK_F2, "F2"},
{SDLK_F3, "F3"},
{SDLK_F4, "F4"},
{SDLK_F5, "F5"},
{SDLK_F6, "F6"},
{SDLK_F7, "F7"},
{SDLK_F8, "F8"},
{SDLK_F9, "F9"},
{SDLK_F10, "F10"},
{SDLK_F11, "F11"},
{SDLK_F12, "F12"},
{SDLK_PRINTSCREEN, "Print"},
{SDLK_SCROLLLOCK, "ScrollLock"},
{SDLK_PAUSE, "Pause"},
{SDLK_INSERT, "Insert"},
{SDLK_HOME, "Home"},
{SDLK_PAGEUP, "PageUp"},
{SDLK_DELETE, "Delete"},
{SDLK_END, "End"},
{SDLK_PAGEDOWN, "PageDown"},
{SDLK_RIGHT, "Right"},
{SDLK_LEFT, "Left"},
{SDLK_DOWN, "Down"},
{SDLK_UP, "Up"},
{SDLK_NUMLOCKCLEAR, "NumLock"},
{SDLK_KP_DIVIDE, "Keypad+Divide"},
{SDLK_KP_MULTIPLY, "Keypad+Multiply"},
{SDLK_KP_MINUS, "Keypad+Minus"},
{SDLK_KP_PLUS, "Keypad+Plus"},
{SDLK_KP_ENTER, "Keypad+Return"},
{SDLK_KP_1, "Keypad+1"},
{SDLK_KP_2, "Keypad+2"},
{SDLK_KP_3, "Keypad+3"},
{SDLK_KP_4, "Keypad+4"},
{SDLK_KP_5, "Keypad+5"},
{SDLK_KP_6, "Keypad+6"},
{SDLK_KP_7, "Keypad+7"},
{SDLK_KP_8, "Keypad+8"},
{SDLK_KP_9, "Keypad+9"},
{SDLK_KP_0, "Keypad+0"},
{SDLK_KP_PERIOD, "Keypad+Period"},
{SDLK_APPLICATION, "Application"},
{SDLK_POWER, "Power"},
{SDLK_KP_EQUALS, "Keypad+Equal"},
{SDLK_F13, "F13"},
{SDLK_F14, "F14"},
{SDLK_F15, "F15"},
{SDLK_F16, "F16"},
{SDLK_F17, "F17"},
{SDLK_F18, "F18"},
{SDLK_F19, "F19"},
{SDLK_F20, "F20"},
{SDLK_F21, "F21"},
{SDLK_F22, "F22"},
{SDLK_F23, "F23"},
{SDLK_F24, "F24"},
{SDLK_EXECUTE, "Execute"},
{SDLK_HELP, "Help"},
{SDLK_MENU, "Menu"},
{SDLK_SELECT, "Select"},
{SDLK_STOP, "Stop"},
{SDLK_AGAIN, "Again"},
{SDLK_UNDO, "Undo"},
{SDLK_CUT, "Cut"},
{SDLK_COPY, "Copy"},
{SDLK_PASTE, "Paste"},
{SDLK_FIND, "Find"},
{SDLK_MUTE, "Mute"},
{SDLK_VOLUMEUP, "VolumeUp"},
{SDLK_VOLUMEDOWN, "VolumeDown"},
{SDLK_KP_COMMA, "Keypad+Comma"},
{SDLK_KP_EQUALSAS400, "Keypad+EqualAS400"},
{SDLK_ALTERASE, "AltErase"},
{SDLK_SYSREQ, "SysReq"},
{SDLK_CANCEL, "Cancel"},
{SDLK_CLEAR, "Clear"},
{SDLK_PRIOR, "Prior"},
{SDLK_RETURN2, "Return2"},
{SDLK_SEPARATOR, "Separator"},
{SDLK_OUT, "Out"},
{SDLK_OPER, "Oper"},
{SDLK_CLEARAGAIN, "ClearAgain"},
{SDLK_CRSEL, "CrSel"},
{SDLK_EXSEL, "ExSel"},
{SDLK_KP_00, "Keypad+00"},
{SDLK_KP_000, "Keypad+000"},
{SDLK_THOUSANDSSEPARATOR, "ThousandsSeparator"},
{SDLK_DECIMALSEPARATOR, "DecimalSeparator"},
{SDLK_CURRENCYUNIT, "CurrencyUnit"},
{SDLK_CURRENCYSUBUNIT, "CurrencySubunit"},
{SDLK_KP_LEFTPAREN, "Keypad+ParenLeft"},
{SDLK_KP_RIGHTPAREN, "Keypad+ParenRight"},
{SDLK_KP_LEFTBRACE, "Keypad+LeftBrace"},
{SDLK_KP_RIGHTBRACE, "Keypad+RightBrace"},
{SDLK_KP_TAB, "Keypad+Tab"},
{SDLK_KP_BACKSPACE, "Keypad+Backspace"},
{SDLK_KP_A, "Keypad+A"},
{SDLK_KP_B, "Keypad+B"},
{SDLK_KP_C, "Keypad+C"},
{SDLK_KP_D, "Keypad+D"},
{SDLK_KP_E, "Keypad+E"},
{SDLK_KP_F, "Keypad+F"},
{SDLK_KP_XOR, "Keypad+XOR"},
{SDLK_KP_POWER, "Keypad+Power"},
{SDLK_KP_PERCENT, "Keypad+Percent"},
{SDLK_KP_LESS, "Keypad+Less"},
{SDLK_KP_GREATER, "Keypad+Greater"},
{SDLK_KP_AMPERSAND, "Keypad+Ampersand"},
{SDLK_KP_DBLAMPERSAND, "Keypad+AmpersandDbl"},
{SDLK_KP_VERTICALBAR, "Keypad+Bar"},
{SDLK_KP_DBLVERTICALBAR, "Keypad+BarDbl"},
{SDLK_KP_COLON, "Keypad+Colon"},
{SDLK_KP_HASH, "Keypad+Hash"},
{SDLK_KP_SPACE, "Keypad+Space"},
{SDLK_KP_AT, "Keypad+At"},
{SDLK_KP_EXCLAM, "Keypad+Exclam"},
{SDLK_KP_MEMSTORE, "Keypad+MemStore"},
{SDLK_KP_MEMRECALL, "Keypad+MemRecall"},
{SDLK_KP_MEMCLEAR, "Keypad+MemClear"},
{SDLK_KP_MEMADD, "Keypad+MemAdd"},
{SDLK_KP_MEMSUBTRACT, "Keypad+MemSubtract"},
{SDLK_KP_MEMMULTIPLY, "Keypad+MemMultiply"},
{SDLK_KP_MEMDIVIDE, "Keypad+MemDivide"},
{SDLK_KP_PLUSMINUS, "Keypad+PlusMinus"},
{SDLK_KP_CLEAR, "Keypad+Clear"},
{SDLK_KP_CLEARENTRY, "Keypad+ClearEntry"},
{SDLK_KP_BINARY, "Keypad+Binary"},
{SDLK_KP_OCTAL, "Keypad+Octal"},
{SDLK_KP_DECIMAL, "Keypad+Decimal"},
{SDLK_KP_HEXADECIMAL, "Keypad+Hexadecimal"},
{SDLK_LCTRL, "LeftControl"},
{SDLK_LSHIFT, "LeftShift"},
{SDLK_LALT, "LeftAlt"},
{SDLK_LGUI, "Super_L"},
{SDLK_RCTRL, "RightCtrl"},
{SDLK_RSHIFT, "RightShift"},
{SDLK_RALT, "RightAlt"},
{SDLK_RGUI, "RightSuper"},
{SDLK_MODE, "Mode"},
{SDLK_AUDIONEXT, "MediaNext"},
{SDLK_AUDIOPREV, "MediaPrevious"},
{SDLK_AUDIOSTOP, "MediaStop"},
{SDLK_AUDIOPLAY, "MediaPlay"},
{SDLK_AUDIOMUTE, "VolumeMute"},
{SDLK_MEDIASELECT, "MediaSelect"},
{SDLK_WWW, "WWW"},
{SDLK_MAIL, "Mail"},
{SDLK_CALCULATOR, "Calculator"},
{SDLK_COMPUTER, "Computer"},
{SDLK_AC_SEARCH, "Search"},
{SDLK_AC_HOME, "Home"},
{SDLK_AC_BACK, "Back"},
{SDLK_AC_FORWARD, "Forward"},
{SDLK_AC_STOP, "Stop"},
{SDLK_AC_REFRESH, "Refresh"},
{SDLK_AC_BOOKMARKS, "Bookmarks"},
{SDLK_BRIGHTNESSDOWN, "BrightnessDown"},
{SDLK_BRIGHTNESSUP, "BrightnessUp"},
{SDLK_DISPLAYSWITCH, "DisplaySwitch"},
{SDLK_KBDILLUMTOGGLE, "IllumToggle"},
{SDLK_KBDILLUMDOWN, "IllumDown"},
{SDLK_KBDILLUMUP, "IllumUp"},
{SDLK_EJECT, "Eject"},
{SDLK_SLEEP, "Sleep"},
{SDLK_APP1, "App1"},
{SDLK_APP2, "App2"},
{SDLK_AUDIOREWIND, "MediaRewind"},
{SDLK_AUDIOFASTFORWARD, "MediaFastForward"}};
struct SDLKeyModifierEntry
{
SDL_Keymod mod;
SDL_Keymod mod_mask;
SDL_Keycode key_left;
SDL_Keycode key_right;
const char* name;
};
static const std::array<SDLKeyModifierEntry, 4> s_sdl_key_modifiers = {
{{KMOD_LSHIFT, static_cast<SDL_Keymod>(KMOD_LSHIFT | KMOD_RSHIFT), SDLK_LSHIFT, SDLK_RSHIFT, "Shift"},
{KMOD_LCTRL, static_cast<SDL_Keymod>(KMOD_LCTRL | KMOD_LCTRL), SDLK_LCTRL, SDLK_RCTRL, "Control"},
{KMOD_LALT, static_cast<SDL_Keymod>(KMOD_LALT | KMOD_RALT), SDLK_LALT, SDLK_RALT, "Alt"},
{KMOD_LGUI, static_cast<SDL_Keymod>(KMOD_LGUI | KMOD_RGUI), SDLK_LGUI, SDLK_RGUI, "Meta"}}};
const char* GetKeyName(SDL_Keycode key)
{
const auto it = s_sdl_key_names.find(key);
return it == s_sdl_key_names.end() ? nullptr : it->second;
}
std::optional<SDL_Keycode> GetKeyCodeForName(const std::string_view key_name)
{
for (const auto& it : s_sdl_key_names)
{
if (key_name == it.second)
return it.first;
}
return std::nullopt;
}
u32 KeyEventToInt(const SDL_Event* event)
{
u32 code = static_cast<u32>(event->key.keysym.sym);
const SDL_Keymod mods = static_cast<SDL_Keymod>(event->key.keysym.mod);
if (mods & (KMOD_LSHIFT | KMOD_RSHIFT))
code |= static_cast<u32>(KMOD_LSHIFT) << 16;
if (mods & (KMOD_LCTRL | KMOD_RCTRL))
code |= static_cast<u32>(KMOD_LCTRL) << 16;
if (mods & (KMOD_LALT | KMOD_RALT))
code |= static_cast<u32>(KMOD_LALT) << 16;
if (mods & (KMOD_LGUI | KMOD_RGUI))
code |= static_cast<u32>(KMOD_LGUI) << 16;
return code;
}
bool KeyEventToString(const SDL_Event* event, String& out_string)
{
const SDL_Keycode key = event->key.keysym.sym;
const SDL_Keymod mods = static_cast<SDL_Keymod>(event->key.keysym.mod);
const char* key_name = GetKeyName(event->key.keysym.sym);
if (!key_name)
return false;
out_string.Clear();
for (const SDLKeyModifierEntry& mod : s_sdl_key_modifiers)
{
if (mods & mod.mod_mask && key != mod.key_left && key != mod.key_right)
{
out_string.AppendString(mod.name);
out_string.AppendCharacter('+');
}
}
out_string.AppendString(key_name);
return true;
}
std::optional<u32> ParseKeyString(const std::string_view key_str)
{
u32 modifiers = 0;
std::string_view::size_type pos = 0;
for (;;)
{
std::string_view::size_type plus_pos = key_str.find('+', pos);
if (plus_pos == std::string_view::npos)
break;
const std::string_view mod_part = key_str.substr(pos, plus_pos - pos);
for (const SDLKeyModifierEntry& mod : s_sdl_key_modifiers)
{
if (mod_part == mod.name)
{
modifiers |= static_cast<int>(mod.mod);
break;
}
}
pos = plus_pos + 1;
}
std::optional<SDL_Keycode> key_code = GetKeyCodeForName(key_str.substr(pos));
if (!key_code)
return std::nullopt;
return static_cast<u32>(key_code.value()) | (modifiers << 16);
}
} // namespace SDLKeyNames

View file

@ -0,0 +1,107 @@
#include "sdl_util.h"
#include "common/log.h"
#include <SDL_syswm.h>
Log_SetChannel(SDLUtil);
#ifdef __APPLE__
#include <objc/message.h>
struct NSView;
static NSView* GetContentViewFromWindow(NSWindow* window)
{
// window.contentView
return reinterpret_cast<NSView* (*)(id, SEL)>(objc_msgSend)(reinterpret_cast<id>(window), sel_getUid("contentView"));
}
#endif
namespace SDLUtil {
std::optional<WindowInfo> GetWindowInfoForSDLWindow(SDL_Window* window)
{
SDL_SysWMinfo syswm = {};
SDL_VERSION(&syswm.version);
if (!SDL_GetWindowWMInfo(window, &syswm))
{
Log_ErrorPrintf("SDL_GetWindowWMInfo failed");
return std::nullopt;
}
int window_width, window_height;
SDL_GetWindowSize(window, &window_width, &window_height);
WindowInfo wi;
wi.surface_width = static_cast<u32>(window_width);
wi.surface_height = static_cast<u32>(window_height);
wi.surface_scale = GetDPIScaleFactor(window);
wi.surface_format = WindowInfo::SurfaceFormat::RGB8;
switch (syswm.subsystem)
{
#ifdef SDL_VIDEO_DRIVER_WINDOWS
case SDL_SYSWM_WINDOWS:
wi.type = WindowInfo::Type::Win32;
wi.window_handle = syswm.info.win.window;
break;
#endif
#ifdef SDL_VIDEO_DRIVER_COCOA
case SDL_SYSWM_COCOA:
wi.type = WindowInfo::Type::MacOS;
wi.window_handle = GetContentViewFromWindow(syswm.info.cocoa.window);
break;
#endif
#ifdef SDL_VIDEO_DRIVER_X11
case SDL_SYSWM_X11:
wi.type = WindowInfo::Type::X11;
wi.window_handle = reinterpret_cast<void*>(static_cast<uintptr_t>(syswm.info.x11.window));
wi.display_connection = syswm.info.x11.display;
break;
#endif
#ifdef SDL_VIDEO_DRIVER_WAYLAND
case SDL_SYSWM_WAYLAND:
wi.type = WindowInfo::Type::Wayland;
wi.window_handle = syswm.info.wl.surface;
wi.display_connection = syswm.info.wl.display;
break;
#endif
default:
Log_ErrorPrintf("Unhandled syswm subsystem %u", static_cast<u32>(syswm.subsystem));
return std::nullopt;
}
return wi;
}
float GetDPIScaleFactor(SDL_Window* window)
{
#ifdef __APPLE__
static constexpr float DEFAULT_DPI = 72.0f;
#else
static constexpr float DEFAULT_DPI = 96.0f;
#endif
if (!window)
{
SDL_Window* dummy_window = SDL_CreateWindow("", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 1, 1,
SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_HIDDEN);
if (!dummy_window)
return 1.0f;
const float scale = GetDPIScaleFactor(dummy_window);
SDL_DestroyWindow(dummy_window);
return scale;
}
int display_index = SDL_GetWindowDisplayIndex(window);
float display_dpi = DEFAULT_DPI;
if (SDL_GetDisplayDPI(display_index, &display_dpi, nullptr, nullptr) != 0)
return 1.0f;
return display_dpi / DEFAULT_DPI;
}
} // namespace SDLUtil

View file

@ -0,0 +1,11 @@
#pragma once
#include "common/types.h"
#include "common/window_info.h"
#include <optional>
struct SDL_Window;
namespace SDLUtil {
std::optional<WindowInfo> GetWindowInfoForSDLWindow(SDL_Window* window);
float GetDPIScaleFactor(SDL_Window* window);
}