Compare commits

..

38 Commits

Author SHA1 Message Date
muemart
aec3b28547 Use static functions instead of lambdas 2018-01-16 16:49:48 -05:00
muemart
5d5f1dfb68 Add translation support for button labels 2018-01-16 16:49:41 -05:00
muemart
f4f64cc197 Add button labels for sdl joystick mappings 2018-01-16 16:49:29 -05:00
bunnei
f10a7081e3 Merge pull request #48 from spycrab/cmake_python
CMake: Override PYTHON environment variable for libunicorn
2018-01-16 15:20:01 -05:00
spycrab
33778e4984 CMake: Override PYTHON environment variable for libunicorn 2018-01-16 20:05:05 +01:00
bunnei
c2e4666579 Update README.md to include AppVeyor build status. 2018-01-16 12:24:15 -05:00
bunnei
f53dc4c9d6 Merge pull request #31 from jroweboy/fix-deploy
Build/Deploy Updates to Setup Nightly Builds
2018-01-16 11:56:14 -05:00
James Rowe
2d7a85f7af Build: Automagically handle unicorn
On MSVC if unicorn isn't found, fallback to bundled unicorn
On everything else, fallback to building unicorn in externals

Also fixes loading unicorn in msvc
2018-01-16 09:39:07 -07:00
N00byKing
8b097aa17e Implement Pull #3333 from citra: citra_qt: Pause emulation on CoreError (#39) 2018-01-16 11:32:27 -05:00
bunnei
d818791866 Merge pull request #24 from nkatz565/nk-inputs
Adding meumart's Citra SDL Joystick support. Citra PR #3116
2018-01-16 10:13:39 -05:00
bunnei
3b28d382d0 Merge pull request #38 from goaaats/citra_merges
Merge citra-emu PR#3001 by Styleoshin(citra-qt : Adding fullscreen mode)
2018-01-16 10:00:24 -05:00
goaaats
8cdc1be0df Merge citra-emu PR#3159 by FearlessTobi(citra-qt : Fix a bug in our fullscreen implementation) 2018-01-16 15:59:30 +01:00
goaaats
f473780c52 Merge citra-emu PR#3001 by Styleoshin(citra-qt : Adding fullscreen mode) 2018-01-16 15:50:33 +01:00
James Rowe
b5b0d4e7c3 Build: Update Appveyor and Travis secret keys
The keys are github auth_tokens and are assigned to yuzubot for the
yuzu-nightly repository to allow Appveyor and Travis to upload releases
2018-01-16 01:20:11 -07:00
James Rowe
e026b66bbb Build: Add unicorn as a submodule and build it if needed
Adds a cmake custom target that will build unicorn on first compile and
uses this in the build scripts as well. Updates Appveyor and Travis
build scripts to work with the new unicorn build, and updates the paths
to all of the different artifacts.
2018-01-16 01:15:52 -07:00
Flame Sage
713c1ed203 Merge pull request #25 from chris062689/master
Updated Discord link to match website.
2018-01-15 20:35:26 -05:00
Flame Sage
21f5161ad8 Updated Discord link to match website. 2018-01-16 01:35:04 +00:00
muemart
eaff98dbb3 Adding meumart's Citra SDL Joystick support. Citra PR #3116 2018-01-15 20:02:30 -05:00
bunnei
20a745aa71 Merge pull request #23 from Simonx22/cmake_rename
CMakeList.txt: rename CITRA to YUZU
2018-01-15 17:48:02 -05:00
bunnei
6f904bb622 nso: Load subsdk4 if available. 2018-01-15 17:18:24 -05:00
Simonx22
e9cf161917 rename CITRA to YUZU 2018-01-15 23:05:20 +01:00
bunnei
1a3b3e9100 pctl: Clang format. 2018-01-15 15:16:06 -05:00
bunnei
1148e2ce7b pctl: GetService should return an IParentalControlService interface. 2018-01-15 15:10:18 -05:00
bunnei
5bc14ab0de applet_oe: Stub SetFocusHandlingMode, GetCurrentFocusState, SetTerminateResult. 2018-01-15 14:41:06 -05:00
bunnei
8e2f62c6a5 settings: Fix button mappings array to have correct entries. 2018-01-15 13:09:14 -05:00
bunnei
67c8b671d2 Merge pull request #17 from spycrab/bindir
CMake: Output binaries to bin/
2018-01-15 12:56:58 -05:00
bunnei
054d3e5fc3 Merge pull request #20 from Andrix44/fixes
Various fixes
2018-01-15 12:56:16 -05:00
bunnei
325f72aceb Merge pull request #16 from shinyquagsire23/hid-sharedmem-impl-start
HID Sharedmem Impl Start
2018-01-15 12:54:54 -05:00
unknown
a4f5ccbf0a Clanggit rebase -i fixes 2018-01-15 18:20:53 +01:00
unknown
8d968780c1 Clang format 2018-01-15 17:55:16 +01:00
unknown
58ee23f16d Change default log level to info 2018-01-15 17:15:10 +01:00
unknown
27960d8c2c Update the internal resolution settings 2018-01-15 16:59:02 +01:00
unknown
af6e0faf0a Fix some warnings 2018-01-15 16:24:29 +01:00
spycrab
8a440faa69 CMake: Output binaries to bin/ 2018-01-15 13:47:38 +01:00
bunnei
22347e8844 Merge pull request #15 from bsaleil/master
vi: Add IManagerDisplayService::CloseDisplay function
2018-01-15 02:56:53 -05:00
bsaleil
af1ca87be1 vi: Add IManagerDisplayService::CloseDisplay function 2018-01-15 01:29:00 -05:00
bunnei
2678dbfbe6 Merge pull request #13 from hpr/fno-new-ttp-matching
Fix build for gcc c++17 / boost.icl incompatibility
2018-01-15 00:22:06 -05:00
Harry Prevor
554cc9488f fixed build for gcc c++17 / boost.icl incompatibility 2018-01-14 21:48:01 -05:00
34 changed files with 915 additions and 448 deletions

3
.gitmodules vendored
View File

@@ -19,3 +19,6 @@
[submodule "lz4"]
path = externals/lz4
url = http://github.com/lz4/lz4.git
[submodule "unicorn"]
path = externals/unicorn
url = https://github.com/yuzu-emu/unicorn

View File

@@ -32,7 +32,7 @@ matrix:
deploy:
provider: releases
api_key:
secure: Mck15DIWaJdxDiS3aYVlM9N3G6y8VKUI1rnwII7/iolfm1s94U+tgvbheZDmT7SSbFyaGaYO/E8HrV/uZR9Vvs7ev20sHsTN1u60OTWfDIIyHs9SqjhcGbtq95m9/dMFschOYqTOR+gAs5BsxjuoeAotHdhpQEwvkO2oo5oR0zhGy45gjFnVvtcxT/IfpZBIpVgcK3aLb9zT6ekcJbSiPmEB15iLq3xXd0nFUNtEZdX3D6Veye4n5jB6n72qN8JVoKvPZAwaC2K0pZxpcGJaXDchLsw1q+4eCvdz6UJfUemeQ/uMAmjfeQ3wrzYGXe3nCM3WmX5wosCsB0mw4zYatzl3si6CZ1W+0GkV4Rwlx03dfp7v3EeFhTsXYCaXqhwuLZnWOLUik8t9vaSoFUx4nUIRwfO9kAMUJQSpLuHNO2nT01s3GxvqxzczuLQ9he5nGSi0RRodUzDwek1qUp6I4uV3gRHKz4B07YIc1i2fK88NLXjyQ0uLVZ+7Oq1+kgDp6+N7vvXXZ5qZ17tdaysSbKEE0Y8zsoXw7Rk1tPN19vrCS+TSpomNMyQyne1k+I5iZ/qkxPTLAS5qI6Utc2dL3GJdxWRAEfGNO9AIX3GV/jmmKfdcvwGsCYP8hxqs5vLYfgacw3D8NLf1941lQUwavC17jm9EV9g5G3Pn1Cp516E=
secure: IuTT8DjxzNgOtaEsyOpz1JaSmtDtHSsWZnJKmSBwXAzgP2ZU4Ja3/q0z5PwbC5Ql7kuFahuYTE5oi7lbJBuu2P3y1Wj2zvFozGUkA3JUvEXDNOPS9QTJ1EYd6O+wenZoj7d/Pn+ZeIgyEafnnZsGBb8lMQnV9MfIHgYlZQ5EyF3n4XikT2h1UbDBYx74ciXZIxFEulx68kDr9Q4/U+zIYQmYv2N+lgXSLDkFrCJ046gRcujPYGPqE6jVw0kKni80CTTpuDF5prU8yIBeiffjkJ3Qx1a17G07eZ4r83P4XUOlaHbRBmA/8ywZvLF2Gep3wGKfSFgMWbPxBJk5ZSYcOOAgMsEcg0+gBK9gLTwO4pbmc2GvqP21yRQBzgtbFoEtAHLu5lVPBkZU7kZuRMJtRdqvFIwOLhpnRS8IknFOD5vjtaFiNdGWaK9ePdsGvplijnXcPafkumakc4+eVEiXb6/KzdX1zXdur5tuUPFytm0Oy6IJcGIf8FHXGvUlmWsnPzwfusij9JgeQOP+uegc9PdBfL+h7L5rk+ilELt3cXD5K7wgov/4hkl5istNJ2bm0IioIstWss8QQQTkyscGoeh/oXmUpOL4FdsTvsWhDR3QKeq8nSzgDkqLe0iSbplQGnC7o7ytNbldmxJvf3nylwglA8w3HlqLHtZLkUOcuQ0=
file_glob: true
file: "artifacts/*"
skip_cleanup: true

View File

@@ -1,22 +1,16 @@
#!/bin/bash -ex
apt-get update
apt-get install -y build-essential git libcurl4-openssl-dev libqt5opengl5-dev libsdl2-dev libssl-dev python qtbase5-dev wget
apt-get install -y build-essential git libqt5opengl5-dev libsdl2-dev libssl-dev python qtbase5-dev wget
# Get a recent version of CMake
wget https://cmake.org/files/v3.10/cmake-3.10.1-Linux-x86_64.sh
sh cmake-3.10.1-Linux-x86_64.sh --exclude-subdir --prefix=/ --skip-license
mkdir /unicorn
cd /unicorn
git clone https://github.com/yuzu-emu/unicorn .
UNICORN_ARCHS=aarch64 ./make.sh
./make.sh install
cd /yuzu
mkdir build && cd build
cmake .. -DUSE_SYSTEM_CURL=ON -DCMAKE_BUILD_TYPE=Release
cmake .. -DYUZU_BUILD_UNICORN=ON -DCMAKE_BUILD_TYPE=Release
make -j4
ctest -VV -C Release

View File

@@ -8,7 +8,7 @@ COMPRESSION_FLAGS="-cJvf"
mkdir "$REV_NAME"
cp build/src/yuzu_cmd/yuzu-cmd "$REV_NAME"
cp build/src/yuzu/yuzu "$REV_NAME"
cp build/bin/yuzu-cmd "$REV_NAME"
cp build/bin/yuzu "$REV_NAME"
. .travis/common/post-upload.sh

View File

@@ -8,7 +8,7 @@ export UNICORNDIR=$(pwd)/externals/unicorn
mkdir build && cd build
cmake --version
cmake .. -DUSE_SYSTEM_CURL=ON -DCMAKE_OSX_ARCHITECTURES="x86_64;x86_64h" -DCMAKE_BUILD_TYPE=Release
cmake .. -DYUZU_BUILD_UNICORN=ON -DCMAKE_OSX_ARCHITECTURES="x86_64;x86_64h" -DCMAKE_BUILD_TYPE=Release
make -j4
ctest -VV -C Release

View File

@@ -2,9 +2,3 @@
brew update
brew install dylibbundler p7zip qt5 sdl2
mkdir externals/unicorn
pushd externals/unicorn
git clone https://github.com/yuzu-emu/unicorn .
UNICORN_ARCHS=aarch64 ./make.sh macos-universal-no
popd

View File

@@ -8,8 +8,8 @@ COMPRESSION_FLAGS="-czvf"
mkdir "$REV_NAME"
cp build/src/yuzu_cmd/yuzu-cmd "$REV_NAME"
cp -r build/src/yuzu/yuzu.app "$REV_NAME"
cp build/bin/yuzu-cmd "$REV_NAME"
cp -r build/bin/yuzu.app "$REV_NAME"
# move qt libs into app bundle for deployment
$(brew --prefix)/opt/qt5/bin/macdeployqt "${REV_NAME}/yuzu.app"

View File

@@ -7,12 +7,10 @@ include(DownloadExternals)
project(yuzu)
option(ENABLE_SDL2 "Enable the SDL2 frontend" ON)
option(CITRA_USE_BUNDLED_SDL2 "Download bundled SDL2 binaries" OFF)
option(YUZU_USE_BUNDLED_SDL2 "Download bundled SDL2 binaries" OFF)
option(ENABLE_QT "Enable the Qt frontend" ON)
option(CITRA_USE_BUNDLED_QT "Download bundled Qt binaries" OFF)
option(YUZU_USE_BUNDLED_UNICORN "Download bundled Unicorn binaries" OFF)
option(YUZU_USE_BUNDLED_QT "Download bundled Qt binaries" OFF)
if(NOT EXISTS ${CMAKE_SOURCE_DIR}/.git/hooks/pre-commit)
message(STATUS "Copying pre-commit hook")
@@ -29,7 +27,7 @@ function(check_submodules_present)
foreach(module ${gitmodules})
string(REGEX REPLACE "path *= *" "" module ${module})
if (NOT EXISTS "${CMAKE_SOURCE_DIR}/${module}/.git")
message(SEND_ERROR "Git submodule ${module} not found."
message(FATAL_ERROR "Git submodule ${module} not found. "
"Please run: git submodule update --init --recursive")
endif()
endforeach()
@@ -166,17 +164,20 @@ if (NOT Boost_FOUND)
find_package(Boost QUIET REQUIRED)
endif()
# Output binaries to bin/
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
# Prefer the -pthread flag on Linux.
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
if (ENABLE_SDL2)
if (CITRA_USE_BUNDLED_SDL2)
if (YUZU_USE_BUNDLED_SDL2)
# Detect toolchain and platform
if (MSVC14 AND ARCHITECTURE_x86_64)
set(SDL2_VER "SDL2-2.0.5")
else()
message(FATAL_ERROR "No bundled SDL2 binaries for your toolchain. Disable CITRA_USE_BUNDLED_SDL2 and provide your own.")
message(FATAL_ERROR "No bundled SDL2 binaries for your toolchain. Disable YUZU_USE_BUNDLED_SDL2 and provide your own.")
endif()
if (DEFINED SDL2_VER)
@@ -201,42 +202,73 @@ else()
set(SDL2_FOUND NO)
endif()
if (YUZU_USE_BUNDLED_UNICORN)
# Detect toolchain and platform
if (MSVC14 AND ARCHITECTURE_x86_64)
set(UNICORN_VER "unicorn-yuzu")
# If unicorn isn't found, msvc -> download bundled unicorn; everyone else -> build external
find_package(Unicorn QUIET)
if (NOT UNICORN_FOUND)
if (MSVC)
message(STATUS "unicorn not found, falling back to bundled")
# Detect toolchain and platform
if (MSVC14 AND ARCHITECTURE_x86_64)
set(UNICORN_VER "unicorn-yuzu")
else()
message(FATAL_ERROR "No bundled Unicorn binaries for your toolchain. Disable YUZU_USE_BUNDLED_UNICORN and provide your own.")
endif()
if (DEFINED UNICORN_VER)
download_bundled_external("unicorn/" ${UNICORN_VER} UNICORN_PREFIX)
endif()
if (DEFINED UNICORN_VER)
download_bundled_external("unicorn/" ${UNICORN_VER} UNICORN_PREFIX)
endif()
set(UNICORN_FOUND YES)
set(LIBUNICORN_INCLUDE_DIR "${UNICORN_PREFIX}/include" CACHE PATH "Path to Unicorn headers" FORCE)
set(LIBUNICORN_LIBRARY "${UNICORN_PREFIX}/lib/x64/unicorn_dynload.lib" CACHE PATH "Path to Unicorn library" FORCE)
set(UNICORN_DLL_DIR "${UNICORN_PREFIX}/lib/x64/" CACHE PATH "Path to unicorn.dll" FORCE)
else()
message(FATAL_ERROR "No bundled Unicorn binaries for your toolchain. Disable YUZU_USE_BUNDLED_UNICORN and provide your own.")
endif()
message(STATUS "unicorn not found, falling back to externals")
if (MINGW)
set(UNICORN_LIB_NAME "unicorn.a")
else()
set(UNICORN_LIB_NAME "libunicorn.a")
endif()
if (DEFINED UNICORN_VER)
download_bundled_external("unicorn/" ${UNICORN_VER} UNICORN_PREFIX)
endif()
set(UNICORN_FOUND YES)
set(UNICORN_PREFIX ${CMAKE_SOURCE_DIR}/externals/unicorn)
set(LIBUNICORN_LIBRARY "${UNICORN_PREFIX}/${UNICORN_LIB_NAME}" CACHE PATH "Path to Unicorn library" FORCE)
set(LIBUNICORN_INCLUDE_DIR "${UNICORN_PREFIX}/include" CACHE PATH "Path to Unicorn headers" FORCE)
set(UNICORN_DLL_DIR "${UNICORN_PREFIX}/" CACHE PATH "Path to unicorn dynamic library" FORCE)
if (DEFINED UNICORN_VER)
download_bundled_external("unicorn/" ${UNICORN_VER} UNICORN_PREFIX)
endif()
find_package(PythonInterp 2.7 REQUIRED)
set(UNICORN_FOUND YES)
set(LIBUNICORN_INCLUDE_DIR "${UNICORN_PREFIX}/include" CACHE PATH "Path to Unicorn headers")
set(LIBUNICORN_LIBRARY "${UNICORN_PREFIX}/lib/x64/unicorn_dynload.lib" CACHE PATH "Path to Unicorn library")
set(UNICORN_DLL_DIR "${UNICORN_PREFIX}/lib/x64/" CACHE PATH "Path to unicorn.dll")
else()
find_package(Unicorn REQUIRED)
add_custom_command(OUTPUT ${LIBUNICORN_LIBRARY}
COMMAND ${CMAKE_COMMAND} -E env UNICORN_ARCHS="aarch64" PYTHON="${PYTHON_EXECUTABLE}" /bin/sh make.sh
WORKING_DIRECTORY ${UNICORN_PREFIX}
)
# ALL makes this custom target build every time
# but it won't actually build if LIBUNICORN_LIBRARY is up to date
add_custom_target(unicorn-build ALL
DEPENDS ${LIBUNICORN_LIBRARY}
)
unset(UNICORN_LIB_NAME)
endif()
endif()
if (UNICORN_FOUND)
add_library(unicorn INTERFACE)
target_link_libraries(unicorn INTERFACE "${LIBUNICORN_LIBRARY}")
target_include_directories(unicorn INTERFACE "${LIBUNICORN_INCLUDE_DIR}")
else()
message(FATAL_ERROR "Could not find or build unicorn which is required.")
endif()
if (ENABLE_QT)
if (CITRA_USE_BUNDLED_QT)
if (YUZU_USE_BUNDLED_QT)
if (MSVC14 AND ARCHITECTURE_x86_64)
set(QT_VER qt-5.7-msvc2015_64)
else()
message(FATAL_ERROR "No bundled Qt binaries for your toolchain. Disable CITRA_USE_BUNDLED_QT and provide your own.")
message(FATAL_ERROR "No bundled Qt binaries for your toolchain. Disable YUZU_USE_BUNDLED_QT and provide your own.")
endif()
if (DEFINED QT_VER)

View File

@@ -1,6 +1,7 @@
yuzu emulator
=============
[![Travis CI Build Status](https://travis-ci.org/yuzu-emu/yuzu.svg?branch=master)](https://travis-ci.org/yuzu-emu/yuzu)
[![AppVeyor CI Build Status](https://ci.appveyor.com/api/projects/status/77k97svb2usreu68?svg=true)](https://ci.appveyor.com/project/bunnei/yuzu)
yuzu is an experimental open-source emulator for the Nintendo Switch from the creators of [Citra](https://citra-emu.org/).
@@ -12,7 +13,7 @@ yuzu is licensed under the GPLv2 (or any later version). Refer to the license.tx
Check out our [website](https://yuzu-emu.org/)!
For development discussion, please join us on [Discord](https://discord.gg/VXqngT3).
For development discussion, please join us on [Discord](https://discord.gg/XQV6dn9).
### Development

View File

@@ -28,7 +28,6 @@ install:
if ($env:BUILD_TYPE -eq 'mingw') {
$dependencies = "mingw64/mingw-w64-x86_64-cmake",
"mingw64/mingw-w64-x86_64-qt5",
"mingw64/mingw-w64-x86_64-curl",
"mingw64/mingw-w64-x86_64-SDL2"
# redirect err to null to prevent warnings from becoming errors
# workaround to prevent pacman from failing due to cyclical dependencies
@@ -42,9 +41,9 @@ before_build:
- ps: |
if ($env:BUILD_TYPE -eq 'msvc') {
# redirect stderr and change the exit code to prevent powershell from cancelling the build if cmake prints a warning
cmd /C 'cmake -G "Visual Studio 15 2017 Win64" -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_SDL2=1 -DYUZU_USE_BUNDLED_UNICORN=1 -DCMAKE_USE_OPENSSL=0 .. 2>&1 && exit 0'
cmd /C 'cmake -G "Visual Studio 15 2017 Win64" -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_SDL2=1 -DYUZU_USE_BUNDLED_UNICORN=1 .. 2>&1 && exit 0'
} else {
C:\msys64\usr\bin\bash.exe -lc "cmake -G 'MSYS Makefiles' -DUSE_SYSTEM_CURL=1 -DYUZU_USE_BUNDLED_CURL=1 -DCMAKE_BUILD_TYPE=Release .. 2>&1"
C:\msys64\usr\bin\bash.exe -lc "cmake -G 'MSYS Makefiles' -DYUZU_BUILD_UNICORN=1 -DCMAKE_BUILD_TYPE=Release .. 2>&1"
}
- cd ..
@@ -81,11 +80,12 @@ after_build:
$env:BUILD_SYMBOLS = $MSVC_BUILD_PDB
$env:BUILD_UPDATE = $MSVC_SEVENZIP
7z a -tzip $MSVC_BUILD_PDB .\msvc_build\bin\release\*.pdb
rm .\msvc_build\bin\release\*.pdb
mkdir pdb
Get-ChildItem ".\msvc_build\bin\" -Recurse -Filter "*.pdb" | Copy-Item -destination .\pdb
7z a -tzip $MSVC_BUILD_PDB .\pdb\*.pdb
mkdir $RELEASE_DIST
Copy-Item .\msvc_build\bin\release\* -Destination $RELEASE_DIST -Recurse
Get-ChildItem ".\msvc_build\bin\" -Recurse -Filter "yuzu*.exe" | Copy-Item -destination $RELEASE_DIST
Copy-Item .\license.txt -Destination $RELEASE_DIST
Copy-Item .\README.md -Destination $RELEASE_DIST
7z a -tzip $MSVC_BUILD_ZIP $RELEASE_DIST\*
@@ -104,16 +104,14 @@ after_build:
$env:BUILD_UPDATE = $MINGW_SEVENZIP
$CMAKE_SOURCE_DIR = "$env:APPVEYOR_BUILD_FOLDER"
$CMAKE_BINARY_DIR = "$CMAKE_SOURCE_DIR/mingw_build"
$CMAKE_BINARY_DIR = "$CMAKE_SOURCE_DIR/mingw_build/bin"
$RELEASE_DIST = $RELEASE_DIST + "-mingw"
mkdir $RELEASE_DIST
mkdir $RELEASE_DIST/platforms
# copy the compiled binaries and other release files to the release folder
Get-ChildItem "$CMAKE_BINARY_DIR" -Recurse -Filter "yuzu*.exe" | Copy-Item -destination $RELEASE_DIST
# copy the libcurl dll
Get-ChildItem "$CMAKE_BINARY_DIR" -Recurse -Filter "libcurl.dll" | Copy-Item -destination $RELEASE_DIST
Get-ChildItem "$CMAKE_BINARY_DIR" -Filter "yuzu*.exe" | Copy-Item -destination $RELEASE_DIST
Copy-Item -path "$CMAKE_SOURCE_DIR/license.txt" -destination $RELEASE_DIST
Copy-Item -path "$CMAKE_SOURCE_DIR/README.md" -destination $RELEASE_DIST
# copy all the dll dependencies to the release folder
@@ -122,7 +120,7 @@ after_build:
# QT dll dependencies
"libbz2-*.dll","libicudt*.dll","libicuin*.dll","libicuuc*.dll","libffi-*.dll",
"libfreetype-*.dll","libglib-*.dll","libgobject-*.dll","libgraphite2.dll","libiconv-*.dll",
"libharfbuzz-*.dll","libintl-*.dll","libpcre-*.dll","libpcre16-*.dll","libpng16-*.dll",
"libharfbuzz-*.dll","libintl-*.dll","libpcre-*.dll","libpcre2-16-*.dll","libpcre16-*.dll","libpng16-*.dll",
# Runtime/Other dependencies
"libgcc_s_seh-*.dll","libstdc++-*.dll","libwinpthread-*.dll","SDL2.dll","zlib1.dll"
foreach ($file in $MingwDLLs) {
@@ -165,7 +163,7 @@ deploy:
provider: GitHub
release: $(appveyor_repo_tag_name)
auth_token:
secure: "dbpsMC/MgPKWFNJCXpQl4cR8FYhepkPLjgNp/pRMktZ8oLKTqPYErfreaIxb/4P1"
secure: "argb6oi2TYLB4wDy+HoCC8PuGAmsnocSk12CQ5614XAPO+NVPndlkLv1utnDFfg2"
artifact: update,build
draft: false
prerelease: false

View File

@@ -1991,7 +1991,7 @@ const char* MicroProfileUIMenuGroups(int nIndex, bool* bSelected)
else
{
nIndex = nIndex-1;
if(nIndex < UI.GroupMenuCount)
if(static_cast<uint32_t>(nIndex) < UI.GroupMenuCount)
{
MicroProfileGroupMenuItem& Item = UI.GroupMenu[nIndex];
static char buffer[MICROPROFILE_NAME_MAX_LEN+32];
@@ -2134,7 +2134,7 @@ const char* MicroProfileUIMenuCustom(int nIndex, bool* bSelected)
case 1: return "--";
default:
nIndex -= 2;
if(nIndex < UI.nCustomCount)
if(static_cast<uint32_t>(nIndex) < UI.nCustomCount)
{
return UI.Custom[nIndex].pName;
}
@@ -2184,7 +2184,7 @@ void MicroProfileUIClickGroups(int nIndex)
else
{
nIndex -= 1;
if(nIndex < UI.GroupMenuCount)
if(static_cast<uint32_t>(nIndex) < UI.GroupMenuCount)
{
MicroProfileGroupMenuItem& Item = UI.GroupMenu[nIndex];
if(Item.nIsCategory)

1
externals/unicorn vendored Submodule

Submodule externals/unicorn added at 73f4573535

View File

@@ -11,7 +11,7 @@
#include "core/hle/kernel/svc.h"
// Load Unicorn DLL once on Windows using RAII
#ifdef _WIN32
#ifdef _MSC_VER
#include <unicorn_dynload.h>
struct LoadDll {
private:

View File

@@ -52,7 +52,23 @@ public:
class ISelfController final : public ServiceFramework<ISelfController> {
public:
ISelfController() : ServiceFramework("ISelfController") {}
ISelfController() : ServiceFramework("ISelfController") {
static const FunctionInfo functions[] = {
{13, &ISelfController::SetFocusHandlingMode, "SetFocusHandlingMode"},
};
RegisterHandlers(functions);
}
private:
void SetFocusHandlingMode(Kernel::HLERequestContext& ctx) {
// Takes 3 input u8s with each field located immediately after the previous u8, these are
// bool flags. No output.
IPC::RequestBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
LOG_WARNING(Service, "(STUBBED) called");
}
};
class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> {
@@ -61,6 +77,7 @@ public:
static const FunctionInfo functions[] = {
{0, &ICommonStateGetter::GetEventHandle, "GetEventHandle"},
{1, &ICommonStateGetter::ReceiveMessage, "ReceiveMessage"},
{9, &ICommonStateGetter::GetCurrentFocusState, "GetCurrentFocusState"},
};
RegisterHandlers(functions);
@@ -86,12 +103,39 @@ private:
LOG_WARNING(Service, "(STUBBED) called");
}
void GetCurrentFocusState(Kernel::HLERequestContext& ctx) {
IPC::RequestBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(1); // 1: In focus, 2/3: Out of focus(running in "background")
LOG_WARNING(Service, "(STUBBED) called");
}
Kernel::SharedPtr<Kernel::Event> event;
};
class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> {
public:
IApplicationFunctions() : ServiceFramework("IApplicationFunctions") {}
IApplicationFunctions() : ServiceFramework("IApplicationFunctions") {
static const FunctionInfo functions[] = {
{22, &IApplicationFunctions::SetTerminateResult, "SetTerminateResult"},
};
RegisterHandlers(functions);
}
private:
void SetTerminateResult(Kernel::HLERequestContext& ctx) {
// Takes an input u32 Result, no output.
// For example, in some cases official apps use this with error 0x2A2 then uses svcBreak.
IPC::RequestParser rp{ctx};
u32 result = rp.Pop<u32>();
IPC::RequestBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
LOG_WARNING(Service, "(STUBBED) called, result=0x%08X", result);
}
};
class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> {
@@ -120,48 +164,56 @@ private:
IPC::RequestBuilder rb{ctx, 2, 0, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IAudioController>();
LOG_DEBUG(Service, "called");
}
void GetDisplayController(Kernel::HLERequestContext& ctx) {
IPC::RequestBuilder rb{ctx, 2, 0, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IDisplayController>();
LOG_DEBUG(Service, "called");
}
void GetDebugFunctions(Kernel::HLERequestContext& ctx) {
IPC::RequestBuilder rb{ctx, 2, 0, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IDebugFunctions>();
LOG_DEBUG(Service, "called");
}
void GetWindowController(Kernel::HLERequestContext& ctx) {
IPC::RequestBuilder rb{ctx, 2, 0, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IWindowController>();
LOG_DEBUG(Service, "called");
}
void GetSelfController(Kernel::HLERequestContext& ctx) {
IPC::RequestBuilder rb{ctx, 2, 0, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISelfController>();
LOG_DEBUG(Service, "called");
}
void GetCommonStateGetter(Kernel::HLERequestContext& ctx) {
IPC::RequestBuilder rb{ctx, 2, 0, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ICommonStateGetter>();
LOG_DEBUG(Service, "called");
}
void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) {
IPC::RequestBuilder rb{ctx, 2, 0, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ILibraryAppletCreator>();
LOG_DEBUG(Service, "called");
}
void GetApplicationFunctions(Kernel::HLERequestContext& ctx) {
IPC::RequestBuilder rb{ctx, 2, 0, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IApplicationFunctions>();
LOG_DEBUG(Service, "called");
}
};
@@ -169,6 +221,7 @@ void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) {
IPC::RequestBuilder rb{ctx, 2, 0, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IApplicationProxy>();
LOG_DEBUG(Service, "called");
}
AppletOE::AppletOE() : ServiceFramework("appletOE") {

View File

@@ -9,11 +9,16 @@
namespace Service {
namespace PCTL {
class IParentalControlService final : public ServiceFramework<IParentalControlService> {
public:
IParentalControlService() : ServiceFramework("IParentalControlService") {}
};
void PCTL_A::GetService(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called");
IPC::RequestBuilder rb{ctx, 2};
IPC::RequestBuilder rb{ctx, 2, 0, 0, 1};
rb.Push(RESULT_SUCCESS);
// TODO(Subv): This should return an IParentalControlService interface.
rb.PushIpcInterface<IParentalControlService>();
LOG_DEBUG(Service, "called");
}
PCTL_A::PCTL_A() : ServiceFramework("pctl:a") {

View File

@@ -494,6 +494,7 @@ public:
IManagerDisplayService(std::shared_ptr<NVFlinger> nv_flinger)
: ServiceFramework("IManagerDisplayService"), nv_flinger(std::move(nv_flinger)) {
static const FunctionInfo functions[] = {
{1020, &IManagerDisplayService::CloseDisplay, "CloseDisplay"},
{1102, nullptr, "GetDisplayResolution"},
{2010, &IManagerDisplayService::CreateManagedLayer, "CreateManagedLayer"},
{6000, &IManagerDisplayService::AddToLayerStack, "AddToLayerStack"},
@@ -503,6 +504,15 @@ public:
~IManagerDisplayService() = default;
private:
void CloseDisplay(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called");
IPC::RequestParser rp{ctx};
u64 display = rp.Pop<u64>();
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0, 0, 0);
rb.Push(RESULT_SUCCESS);
}
void CreateManagedLayer(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called");
IPC::RequestParser rp{ctx};

View File

@@ -157,7 +157,7 @@ ResultStatus AppLoader_NSO::Load(Kernel::SharedPtr<Kernel::Process>& process) {
// Load NSO modules
VAddr next_load_addr{Memory::PROCESS_IMAGE_VADDR};
for (const auto& module : {"rtld", "sdk", "subsdk0", "subsdk1", "subsdk2", "subsdk3"}) {
for (const auto& module : {"rtld", "sdk", "subsdk0", "subsdk1", "subsdk2", "subsdk3", "subsdk4"}) {
const std::string path = filepath.substr(0, filepath.find_last_of("/\\")) + "/" + module;
const VAddr load_addr = next_load_addr;
next_load_addr = LoadNso(path, load_addr);

View File

@@ -79,11 +79,16 @@ static const std::array<const char*, NumButtons> mapping = {{
"button_lstick_up",
"button_lstick_right",
"button_lstick_down",
"button_rstick_left",
"button_rstick_up",
"button_rstick_right",
"button_rstick_down",
"button_sl",
"button_sr",
"button_home",
"button_screenshot",
}};
} // namespace NativeButton
namespace NativeAnalog {
@@ -95,8 +100,7 @@ enum Values {
};
static const std::array<const char*, NumAnalogs> mapping = {{
"lstick",
"rstick",
"lstick", "rstick",
}};
} // namespace NativeAnalog

View File

@@ -71,4 +71,15 @@ std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left,
return circle_pad_param.Serialize();
}
namespace Polling {
std::vector<std::unique_ptr<DevicePoller>> GetPollers(DeviceType type) {
#ifdef HAVE_SDL2
return SDL::Polling::GetPollers(type);
#else
return {};
#endif
}
} // namespace Polling
} // namespace InputCommon

View File

@@ -4,7 +4,13 @@
#pragma once
#include <memory>
#include <string>
#include <vector>
namespace Common {
class ParamPackage;
}
namespace InputCommon {
@@ -31,4 +37,30 @@ std::string GenerateKeyboardParam(int key_code);
std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left, int key_right,
int key_modifier, float modifier_scale);
namespace Polling {
enum class DeviceType { Button, Analog };
/**
* A class that can be used to get inputs from an input device like controllers without having to
* poll the device's status yourself
*/
class DevicePoller {
public:
virtual ~DevicePoller() = default;
/// Setup and start polling for inputs, should be called before GetNextInput
virtual void Start() = 0;
/// Stop polling
virtual void Stop() = 0;
/**
* Every call to this function returns the next input recorded since calling Start
* @return A ParamPackage of the recorded input, which can be used to create an InputDevice.
* If there has been no input, the package is empty
*/
virtual Common::ParamPackage GetNextInput() = 0;
};
// Get all DevicePoller from all backends for a specific device type
std::vector<std::unique_ptr<DevicePoller>> GetPollers(DeviceType type);
} // namespace Polling
} // namespace InputCommon

View File

@@ -3,13 +3,15 @@
// Refer to the license.txt file included.
#include <cmath>
#include <memory>
#include <string>
#include <tuple>
#include <unordered_map>
#include <utility>
#include <SDL.h>
#include "common/logging/log.h"
#include "common/math_util.h"
#include "common/param_package.h"
#include "input_common/main.h"
#include "input_common/sdl/sdl.h"
namespace InputCommon {
@@ -69,6 +71,10 @@ public:
return (SDL_JoystickGetHat(joystick.get(), hat) & direction) != 0;
}
SDL_JoystickID GetJoystickID() const {
return SDL_JoystickInstanceID(joystick.get());
}
private:
std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> joystick;
};
@@ -247,5 +253,180 @@ void Shutdown() {
}
}
/**
* This function converts a joystick ID used in SDL events to the device index. This is necessary
* because Citra opens joysticks using their indices, not their IDs.
*/
static int JoystickIDToDeviceIndex(SDL_JoystickID id) {
int num_joysticks = SDL_NumJoysticks();
for (int i = 0; i < num_joysticks; i++) {
auto joystick = GetJoystick(i);
if (joystick->GetJoystickID() == id) {
return i;
}
}
return -1;
}
Common::ParamPackage SDLEventToButtonParamPackage(const SDL_Event& event) {
Common::ParamPackage params({{"engine", "sdl"}});
switch (event.type) {
case SDL_JOYAXISMOTION:
params.Set("joystick", JoystickIDToDeviceIndex(event.jaxis.which));
params.Set("axis", event.jaxis.axis);
if (event.jaxis.value > 0) {
params.Set("direction", "+");
params.Set("threshold", "0.5");
} else {
params.Set("direction", "-");
params.Set("threshold", "-0.5");
}
break;
case SDL_JOYBUTTONUP:
params.Set("joystick", JoystickIDToDeviceIndex(event.jbutton.which));
params.Set("button", event.jbutton.button);
break;
case SDL_JOYHATMOTION:
params.Set("joystick", JoystickIDToDeviceIndex(event.jhat.which));
params.Set("hat", event.jhat.hat);
switch (event.jhat.value) {
case SDL_HAT_UP:
params.Set("direction", "up");
break;
case SDL_HAT_DOWN:
params.Set("direction", "down");
break;
case SDL_HAT_LEFT:
params.Set("direction", "left");
break;
case SDL_HAT_RIGHT:
params.Set("direction", "right");
break;
default:
return {};
}
break;
}
return params;
}
namespace Polling {
class SDLPoller : public InputCommon::Polling::DevicePoller {
public:
SDLPoller() = default;
~SDLPoller() = default;
void Start() override {
// SDL joysticks must be opened, otherwise they don't generate events
SDL_JoystickUpdate();
int num_joysticks = SDL_NumJoysticks();
for (int i = 0; i < num_joysticks; i++) {
joysticks_opened.emplace_back(GetJoystick(i));
}
// Empty event queue to get rid of old events. citra-qt doesn't use the queue
SDL_Event dummy;
while (SDL_PollEvent(&dummy)) {
}
}
void Stop() override {
joysticks_opened.clear();
}
private:
std::vector<std::shared_ptr<SDLJoystick>> joysticks_opened;
};
class SDLButtonPoller final : public SDLPoller {
public:
SDLButtonPoller() = default;
~SDLButtonPoller() = default;
Common::ParamPackage GetNextInput() override {
SDL_Event event;
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_JOYAXISMOTION:
if (std::abs(event.jaxis.value / 32767.0) < 0.5) {
break;
}
case SDL_JOYBUTTONUP:
case SDL_JOYHATMOTION:
return SDLEventToButtonParamPackage(event);
}
}
return {};
}
};
class SDLAnalogPoller final : public SDLPoller {
public:
SDLAnalogPoller() = default;
~SDLAnalogPoller() = default;
void Start() override {
SDLPoller::Start();
// Reset stored axes
analog_xaxis = -1;
analog_yaxis = -1;
analog_axes_joystick = -1;
}
Common::ParamPackage GetNextInput() override {
SDL_Event event;
while (SDL_PollEvent(&event)) {
if (event.type != SDL_JOYAXISMOTION || std::abs(event.jaxis.value / 32767.0) < 0.5) {
continue;
}
// An analog device needs two axes, so we need to store the axis for later and wait for
// a second SDL event. The axes also must be from the same joystick.
int axis = event.jaxis.axis;
if (analog_xaxis == -1) {
analog_xaxis = axis;
analog_axes_joystick = event.jaxis.which;
} else if (analog_yaxis == -1 && analog_xaxis != axis &&
analog_axes_joystick == event.jaxis.which) {
analog_yaxis = axis;
}
}
Common::ParamPackage params;
if (analog_xaxis != -1 && analog_yaxis != -1) {
params.Set("engine", "sdl");
params.Set("joystick", JoystickIDToDeviceIndex(analog_axes_joystick));
params.Set("axis_x", analog_xaxis);
params.Set("axis_y", analog_yaxis);
analog_xaxis = -1;
analog_yaxis = -1;
analog_axes_joystick = -1;
return params;
}
return params;
}
private:
int analog_xaxis = -1;
int analog_yaxis = -1;
SDL_JoystickID analog_axes_joystick = -1;
};
std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> GetPollers(
InputCommon::Polling::DeviceType type) {
std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> pollers;
switch (type) {
case InputCommon::Polling::DeviceType::Analog:
pollers.push_back(std::make_unique<SDLAnalogPoller>());
break;
case InputCommon::Polling::DeviceType::Button:
pollers.push_back(std::make_unique<SDLButtonPoller>());
break;
}
return std::move(pollers);
}
} // namespace Polling
} // namespace SDL
} // namespace InputCommon

View File

@@ -4,8 +4,21 @@
#pragma once
#include <memory>
#include <vector>
#include "core/frontend/input.h"
union SDL_Event;
namespace Common {
class ParamPackage;
}
namespace InputCommon {
namespace Polling {
class DevicePoller;
enum class DeviceType;
} // namespace Polling
} // namespace InputCommon
namespace InputCommon {
namespace SDL {
@@ -15,5 +28,15 @@ void Init();
/// Unresisters SDL device factories and shut them down.
void Shutdown();
/// Creates a ParamPackage from an SDL_Event that can directly be used to create a ButtonDevice
Common::ParamPackage SDLEventToButtonParamPackage(const SDL_Event& event);
namespace Polling {
/// Get all DevicePoller that use the SDL backend for a specific device type
std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> GetPollers(
InputCommon::Polling::DeviceType type);
} // namespace Polling
} // namespace SDL
} // namespace InputCommon

View File

@@ -40,6 +40,7 @@ void EmuThread::run() {
Core::System::ResultStatus result = Core::System::GetInstance().RunLoop();
if (result != Core::System::ResultStatus::Success) {
this->SetRunning(false);
emit ErrorThrown(result, Core::System::GetInstance().GetStatusDetails());
}

View File

@@ -8,7 +8,6 @@
#include "yuzu/configuration/config.h"
#include "yuzu/ui_settings.h"
Config::Config() {
// TODO: Don't hardcode the path; let the frontend decide where to put the config files.
qt_config_loc = FileUtil::GetUserPath(D_CONFIG_IDX) + "qt-config.ini";
@@ -88,7 +87,7 @@ void Config::ReadValues() {
qt_config->endGroup();
qt_config->beginGroup("Miscellaneous");
Settings::values.log_filter = qt_config->value("log_filter", "*:Trace").toString().toStdString();
Settings::values.log_filter = qt_config->value("log_filter", "*:Info").toString().toStdString();
qt_config->endGroup();
qt_config->beginGroup("Debugging");
@@ -138,6 +137,7 @@ void Config::ReadValues() {
qt_config->endGroup();
UISettings::values.single_window_mode = qt_config->value("singleWindowMode", true).toBool();
UISettings::values.fullscreen = qt_config->value("fullscreen", false).toBool();
UISettings::values.display_titlebar = qt_config->value("displayTitleBars", true).toBool();
UISettings::values.show_filter_bar = qt_config->value("showFilterBar", true).toBool();
UISettings::values.show_status_bar = qt_config->value("showStatusBar", true).toBool();
@@ -217,6 +217,7 @@ void Config::SaveValues() {
qt_config->endGroup();
qt_config->setValue("singleWindowMode", UISettings::values.single_window_mode);
qt_config->setValue("fullscreen", UISettings::values.fullscreen);
qt_config->setValue("displayTitleBars", UISettings::values.display_titlebar);
qt_config->setValue("showFilterBar", UISettings::values.show_filter_bar);
qt_config->setValue("showStatusBar", UISettings::values.show_status_bar);

View File

@@ -7,7 +7,6 @@
#include "ui_configure_graphics.h"
#include "yuzu/configuration/configure_graphics.h"
ConfigureGraphics::ConfigureGraphics(QWidget* parent)
: QWidget(parent), ui(new Ui::ConfigureGraphics) {
@@ -23,12 +22,6 @@ enum class Resolution : int {
Scale2x,
Scale3x,
Scale4x,
Scale5x,
Scale6x,
Scale7x,
Scale8x,
Scale9x,
Scale10x,
};
float ToResolutionFactor(Resolution option) {
@@ -43,18 +36,6 @@ float ToResolutionFactor(Resolution option) {
return 3.f;
case Resolution::Scale4x:
return 4.f;
case Resolution::Scale5x:
return 5.f;
case Resolution::Scale6x:
return 6.f;
case Resolution::Scale7x:
return 7.f;
case Resolution::Scale8x:
return 8.f;
case Resolution::Scale9x:
return 9.f;
case Resolution::Scale10x:
return 10.f;
}
return 0.f;
}
@@ -70,18 +51,6 @@ Resolution FromResolutionFactor(float factor) {
return Resolution::Scale3x;
} else if (factor == 4.f) {
return Resolution::Scale4x;
} else if (factor == 5.f) {
return Resolution::Scale5x;
} else if (factor == 6.f) {
return Resolution::Scale6x;
} else if (factor == 7.f) {
return Resolution::Scale7x;
} else if (factor == 8.f) {
return Resolution::Scale8x;
} else if (factor == 9.f) {
return Resolution::Scale9x;
} else if (factor == 10.f) {
return Resolution::Scale10x;
}
return Resolution::Auto;
}

View File

@@ -34,7 +34,7 @@
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Internal Resolution:</string>
<string>Internal Resolution:(Currently does nothing.)</string>
</property>
</widget>
</item>
@@ -47,52 +47,22 @@
</item>
<item>
<property name="text">
<string>Native (400x240)</string>
<string>Native (1280x720)</string>
</property>
</item>
<item>
<property name="text">
<string>2x Native (800x480)</string>
<string>2x Native (2560x1440)</string>
</property>
</item>
<item>
<property name="text">
<string>3x Native (1200x720)</string>
<string>3x Native (3840x2160)</string>
</property>
</item>
<item>
<property name="text">
<string>4x Native (1600x960)</string>
</property>
</item>
<item>
<property name="text">
<string>5x Native (2000x1200)</string>
</property>
</item>
<item>
<property name="text">
<string>6x Native (2400x1440)</string>
</property>
</item>
<item>
<property name="text">
<string>7x Native (2800x1680)</string>
</property>
</item>
<item>
<property name="text">
<string>8x Native (3200x1920)</string>
</property>
</item>
<item>
<property name="text">
<string>9x Native (3600x2160)</string>
</property>
</item>
<item>
<property name="text">
<string>10x Native (4000x2400)</string>
<string>4x Native (5120x2880)</string>
</property>
</item>
</widget>

View File

@@ -5,13 +5,13 @@
#include <algorithm>
#include <memory>
#include <utility>
#include <QMessageBox>
#include <QTimer>
#include "common/param_package.h"
#include "input_common/main.h"
#include "yuzu/configuration/config.h"
#include "yuzu/configuration/configure_input.h"
const std::array<std::string, ConfigureInput::ANALOG_SUB_BUTTONS_NUM>
ConfigureInput::analog_sub_buttons{{
"up", "down", "left", "right", "modifier",
@@ -32,23 +32,65 @@ static QString getKeyName(int key_code) {
}
}
static void SetButtonKey(int key, Common::ParamPackage& button_param) {
button_param = Common::ParamPackage{InputCommon::GenerateKeyboardParam(key)};
}
static void SetAnalogKey(int key, Common::ParamPackage& analog_param,
const std::string& button_name) {
static void SetAnalogButton(const Common::ParamPackage& input_param,
Common::ParamPackage& analog_param, const std::string& button_name) {
if (analog_param.Get("engine", "") != "analog_from_button") {
analog_param = {
{"engine", "analog_from_button"}, {"modifier_scale", "0.5"},
};
}
analog_param.Set(button_name, InputCommon::GenerateKeyboardParam(key));
analog_param.Set(button_name, input_param.Serialize());
}
static QString ButtonToText(const Common::ParamPackage& param) {
if (!param.Has("engine")) {
return QObject::tr("[not set]");
} else if (param.Get("engine", "") == "keyboard") {
return getKeyName(param.Get("code", 0));
} else if (param.Get("engine", "") == "sdl") {
QString text = QString(QObject::tr("Joystick %1")).arg(param.Get("joystick", "").c_str());
if (param.Has("hat")) {
text += QString(QObject::tr(" Hat %1 %2"))
.arg(param.Get("hat", "").c_str(), param.Get("direction", "").c_str());
}
if (param.Has("axis")) {
text += QString(QObject::tr(" Axis %1%2"))
.arg(param.Get("axis", "").c_str(), param.Get("direction", "").c_str());
}
if (param.Has("button")) {
text += QString(QObject::tr(" Button %1")).arg(param.Get("button", "").c_str());
}
return text;
} else {
return QObject::tr("[unknown]");
}
};
static QString AnalogToText(const Common::ParamPackage& param, const std::string& dir) {
if (!param.Has("engine")) {
return QObject::tr("[not set]");
} else if (param.Get("engine", "") == "analog_from_button") {
return ButtonToText(Common::ParamPackage{param.Get(dir, "")});
} else if (param.Get("engine", "") == "sdl") {
if (dir == "modifier") {
return QString(QObject::tr("[unused]"));
}
QString text = QString(QObject::tr("Joystick %1")).arg(param.Get("joystick", "").c_str());
if (dir == "left" || dir == "right") {
text += QString(QObject::tr(" Axis %1")).arg(param.Get("axis_x", "").c_str());
} else if (dir == "up" || dir == "down") {
text += QString(QObject::tr(" Axis %1")).arg(param.Get("axis_y", "").c_str());
}
return text;
} else {
return QObject::tr("[unknown]");
}
};
ConfigureInput::ConfigureInput(QWidget* parent)
: QWidget(parent), ui(std::make_unique<Ui::ConfigureInput>()),
timer(std::make_unique<QTimer>()) {
timeout_timer(std::make_unique<QTimer>()), poll_timer(std::make_unique<QTimer>()) {
ui->setupUi(this);
setFocusPolicy(Qt::ClickFocus);
@@ -63,7 +105,7 @@ ConfigureInput::ConfigureInput(QWidget* parent)
ui->buttonSL, ui->buttonSR, ui->buttonHome, ui->buttonScreenshot,
};
analog_map = {{
analog_map_buttons = {{
{
ui->buttonLStickUp, ui->buttonLStickDown, ui->buttonLStickLeft, ui->buttonLStickRight,
ui->buttonLStickMod,
@@ -74,35 +116,57 @@ ConfigureInput::ConfigureInput(QWidget* parent)
},
}};
analog_map_stick = {ui->buttonLStickAnalog, ui->buttonRStickAnalog};
for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) {
if (button_map[button_id])
connect(button_map[button_id], &QPushButton::released, [=]() {
handleClick(button_map[button_id],
[=](int key) { SetButtonKey(key, buttons_param[button_id]); });
handleClick(
button_map[button_id],
[=](const Common::ParamPackage& params) { buttons_param[button_id] = params; },
InputCommon::Polling::DeviceType::Button);
});
}
for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) {
for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) {
if (analog_map[analog_id][sub_button_id] != nullptr) {
connect(analog_map[analog_id][sub_button_id], &QPushButton::released, [=]() {
handleClick(analog_map[analog_id][sub_button_id], [=](int key) {
SetAnalogKey(key, analogs_param[analog_id],
analog_sub_buttons[sub_button_id]);
});
});
if (analog_map_buttons[analog_id][sub_button_id] != nullptr) {
connect(analog_map_buttons[analog_id][sub_button_id], &QPushButton::released,
[=]() {
handleClick(analog_map_buttons[analog_id][sub_button_id],
[=](const Common::ParamPackage& params) {
SetAnalogButton(params, analogs_param[analog_id],
analog_sub_buttons[sub_button_id]);
},
InputCommon::Polling::DeviceType::Button);
});
}
}
connect(analog_map_stick[analog_id], &QPushButton::released, [=]() {
QMessageBox::information(
this, "Information",
"After pressing OK, first move your joystick horizontally, and then vertically.");
handleClick(
analog_map_stick[analog_id],
[=](const Common::ParamPackage& params) { analogs_param[analog_id] = params; },
InputCommon::Polling::DeviceType::Analog);
});
}
connect(ui->buttonRestoreDefaults, &QPushButton::released, [this]() { restoreDefaults(); });
timer->setSingleShot(true);
connect(timer.get(), &QTimer::timeout, [this]() {
releaseKeyboard();
releaseMouse();
key_setter = boost::none;
updateButtonLabels();
timeout_timer->setSingleShot(true);
connect(timeout_timer.get(), &QTimer::timeout, [this]() { setPollingResult({}, true); });
connect(poll_timer.get(), &QTimer::timeout, [this]() {
Common::ParamPackage params;
for (auto& poller : device_pollers) {
params = poller->GetNextInput();
if (params.Has("engine")) {
setPollingResult(params, false);
return;
}
}
});
this->loadConfiguration();
@@ -132,13 +196,15 @@ void ConfigureInput::loadConfiguration() {
void ConfigureInput::restoreDefaults() {
for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) {
SetButtonKey(Config::default_buttons[button_id], buttons_param[button_id]);
buttons_param[button_id] = Common::ParamPackage{
InputCommon::GenerateKeyboardParam(Config::default_buttons[button_id])};
}
for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) {
for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) {
SetAnalogKey(Config::default_analogs[analog_id][sub_button_id],
analogs_param[analog_id], analog_sub_buttons[sub_button_id]);
Common::ParamPackage params{InputCommon::GenerateKeyboardParam(
Config::default_analogs[analog_id][sub_button_id])};
SetAnalogButton(params, analogs_param[analog_id], analog_sub_buttons[sub_button_id]);
}
}
updateButtonLabels();
@@ -146,59 +212,73 @@ void ConfigureInput::restoreDefaults() {
}
void ConfigureInput::updateButtonLabels() {
QString non_keyboard(tr("[non-keyboard]"));
auto KeyToText = [&non_keyboard](const Common::ParamPackage& param) {
if (param.Get("engine", "") != "keyboard") {
return non_keyboard;
} else {
return getKeyName(param.Get("code", 0));
}
};
for (int button = 0; button < Settings::NativeButton::NumButtons; button++) {
button_map[button]->setText(KeyToText(buttons_param[button]));
button_map[button]->setText(ButtonToText(buttons_param[button]));
}
for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) {
if (analogs_param[analog_id].Get("engine", "") != "analog_from_button") {
for (QPushButton* button : analog_map[analog_id]) {
if (button)
button->setText(non_keyboard);
}
} else {
for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) {
Common::ParamPackage param(
analogs_param[analog_id].Get(analog_sub_buttons[sub_button_id], ""));
if (analog_map[analog_id][sub_button_id])
analog_map[analog_id][sub_button_id]->setText(KeyToText(param));
for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; sub_button_id++) {
if (analog_map_buttons[analog_id][sub_button_id]) {
analog_map_buttons[analog_id][sub_button_id]->setText(
AnalogToText(analogs_param[analog_id], analog_sub_buttons[sub_button_id]));
}
}
analog_map_stick[analog_id]->setText(tr("Set Analog Stick"));
}
}
void ConfigureInput::handleClick(QPushButton* button, std::function<void(int)> new_key_setter) {
void ConfigureInput::handleClick(QPushButton* button,
std::function<void(const Common::ParamPackage&)> new_input_setter,
InputCommon::Polling::DeviceType type) {
button->setText(tr("[press key]"));
button->setFocus();
key_setter = new_key_setter;
input_setter = new_input_setter;
device_pollers = InputCommon::Polling::GetPollers(type);
// Keyboard keys can only be used as button devices
want_keyboard_keys = type == InputCommon::Polling::DeviceType::Button;
for (auto& poller : device_pollers) {
poller->Start();
}
grabKeyboard();
grabMouse();
timer->start(5000); // Cancel after 5 seconds
timeout_timer->start(5000); // Cancel after 5 seconds
poll_timer->start(200); // Check for new inputs every 200ms
}
void ConfigureInput::setPollingResult(const Common::ParamPackage& params, bool abort) {
releaseKeyboard();
releaseMouse();
timeout_timer->stop();
poll_timer->stop();
for (auto& poller : device_pollers) {
poller->Stop();
}
if (!abort) {
(*input_setter)(params);
}
updateButtonLabels();
input_setter = boost::none;
}
void ConfigureInput::keyPressEvent(QKeyEvent* event) {
releaseKeyboard();
releaseMouse();
if (!key_setter || !event)
if (!input_setter || !event)
return;
if (event->key() != Qt::Key_Escape)
(*key_setter)(event->key());
updateButtonLabels();
key_setter = boost::none;
timer->stop();
if (event->key() != Qt::Key_Escape) {
if (want_keyboard_keys) {
setPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->key())},
false);
} else {
// Escape key wasn't pressed and we don't want any keyboard keys, so don't stop polling
return;
}
}
setPollingResult({}, true);
}

View File

@@ -8,11 +8,13 @@
#include <functional>
#include <memory>
#include <string>
#include <unordered_map>
#include <QKeyEvent>
#include <QWidget>
#include <boost/optional.hpp>
#include "common/param_package.h"
#include "core/settings.h"
#include "input_common/main.h"
#include "ui_configure_input.h"
class QPushButton;
@@ -35,10 +37,11 @@ public:
private:
std::unique_ptr<Ui::ConfigureInput> ui;
std::unique_ptr<QTimer> timer;
std::unique_ptr<QTimer> timeout_timer;
std::unique_ptr<QTimer> poll_timer;
/// This will be the the setting function when an input is awaiting configuration.
boost::optional<std::function<void(int)>> key_setter;
boost::optional<std::function<void(const Common::ParamPackage&)>> input_setter;
std::array<Common::ParamPackage, Settings::NativeButton::NumButtons> buttons_param;
std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs> analogs_param;
@@ -48,13 +51,23 @@ private:
/// Each button input is represented by a QPushButton.
std::array<QPushButton*, Settings::NativeButton::NumButtons> button_map;
/// Each analog input is represented by five QPushButtons which represents up, down, left, right
/// and modifier
/// A group of five QPushButtons represent one analog input. The buttons each represent up,
/// down, left, right, and modifier, respectively.
std::array<std::array<QPushButton*, ANALOG_SUB_BUTTONS_NUM>, Settings::NativeAnalog::NumAnalogs>
analog_map;
analog_map_buttons;
/// Analog inputs are also represented each with a single button, used to configure with an
/// actual analog stick
std::array<QPushButton*, Settings::NativeAnalog::NumAnalogs> analog_map_stick;
static const std::array<std::string, ANALOG_SUB_BUTTONS_NUM> analog_sub_buttons;
std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> device_pollers;
/// A flag to indicate if keyboard keys are okay when configuring an input. If this is false,
/// keyboard events are ignored.
bool want_keyboard_keys = false;
/// Load configuration settings.
void loadConfiguration();
/// Restore all buttons to their default values.
@@ -63,7 +76,13 @@ private:
void updateButtonLabels();
/// Called when the button was pressed.
void handleClick(QPushButton* button, std::function<void(int)> new_key_setter);
void handleClick(QPushButton* button,
std::function<void(const Common::ParamPackage&)> new_input_setter,
InputCommon::Polling::DeviceType type);
/// Finish polling and configure input using the input_setter
void setPollingResult(const Common::ParamPackage& params, bool abort);
/// Handle key press events.
void keyPressEvent(QKeyEvent* event) override;
};

View File

@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>343</width>
<height>665</height>
<height>677</height>
</rect>
</property>
<property name="windowTitle">
@@ -16,6 +16,107 @@
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<layout class="QGridLayout" name="gridLayout_7">
<item row="3" column="1">
<widget class="QGroupBox" name="faceButtons_6">
<property name="title">
<string>Misc.</string>
</property>
<property name="flat">
<bool>false</bool>
</property>
<property name="checkable">
<bool>false</bool>
</property>
<layout class="QGridLayout" name="gridLayout_6">
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout_25">
<item>
<widget class="QLabel" name="label_29">
<property name="text">
<string>Plus:</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonPlus">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="1">
<layout class="QVBoxLayout" name="verticalLayout_26">
<item>
<widget class="QLabel" name="label_30">
<property name="text">
<string>Minus:</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonMinus">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<layout class="QVBoxLayout" name="verticalLayout_27">
<item>
<widget class="QLabel" name="label_31">
<property name="text">
<string>Home:</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonHome">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="1">
<layout class="QVBoxLayout" name="verticalLayout_28">
<item>
<widget class="QLabel" name="label_11">
<property name="text">
<string>Screen
Capture:</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonScreenshot">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item row="0" column="0">
<widget class="QGroupBox" name="faceButtons">
<property name="title">
@@ -190,107 +291,6 @@
</layout>
</widget>
</item>
<item row="3" column="1">
<widget class="QGroupBox" name="faceButtons_6">
<property name="title">
<string>Misc.</string>
</property>
<property name="flat">
<bool>false</bool>
</property>
<property name="checkable">
<bool>false</bool>
</property>
<layout class="QGridLayout" name="gridLayout_6">
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout_25">
<item>
<widget class="QLabel" name="label_29">
<property name="text">
<string>Plus:</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonPlus">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="1">
<layout class="QVBoxLayout" name="verticalLayout_26">
<item>
<widget class="QLabel" name="label_30">
<property name="text">
<string>Minus:</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonMinus">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<layout class="QVBoxLayout" name="verticalLayout_27">
<item>
<widget class="QLabel" name="label_31">
<property name="text">
<string>Home:</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonHome">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="1">
<layout class="QVBoxLayout" name="verticalLayout_28">
<item>
<widget class="QLabel" name="label_11">
<property name="text">
<string>Screen
Capture:</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonScreenshot">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item row="3" column="0">
<widget class="QGroupBox" name="faceButtons_3">
<property name="title">
@@ -414,129 +414,6 @@ Capture:</string>
</layout>
</widget>
</item>
<item row="1" column="0">
<widget class="QGroupBox" name="faceButtons_4">
<property name="title">
<string>Left Stick</string>
</property>
<property name="flat">
<bool>false</bool>
</property>
<property name="checkable">
<bool>false</bool>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout_17">
<item>
<widget class="QLabel" name="label_21">
<property name="text">
<string>Left:</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonLStickLeft">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="1">
<layout class="QVBoxLayout" name="verticalLayout_18">
<item>
<widget class="QLabel" name="label_23">
<property name="text">
<string>Right:</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonLStickRight">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<layout class="QVBoxLayout" name="verticalLayout_19">
<item>
<widget class="QLabel" name="label_24">
<property name="text">
<string>Up:</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonLStickUp">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="1">
<layout class="QVBoxLayout" name="verticalLayout_20">
<item>
<widget class="QLabel" name="label_22">
<property name="text">
<string>Down:</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonLStickDown">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="0">
<layout class="QVBoxLayout" name="verticalLayout_7" stretch="0,0">
<item>
<widget class="QLabel" name="label_6">
<property name="text">
<string>Pressed:</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonLStick">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="1">
<layout class="QVBoxLayout" name="verticalLayout_31">
<item>
<widget class="QLabel" name="label_9">
<property name="text">
<string>Modifier:</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonLStickMod">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item row="1" column="1">
<widget class="QGroupBox" name="faceButtons_5">
<property name="title">
@@ -588,8 +465,33 @@ Capture:</string>
</item>
</layout>
</item>
<item row="3" column="0" colspan="2">
<widget class="QPushButton" name="buttonRStickAnalog">
<property name="text">
<string>Set Analog Stick</string>
</property>
</widget>
</item>
<item row="1" column="0">
<layout class="QVBoxLayout" name="verticalLayout_23">
<layout class="QVBoxLayout" name="verticalLayout_21">
<item>
<widget class="QLabel" name="label_25">
<property name="text">
<string>Left:</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonRStickLeft">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout_25">
<item>
<widget class="QLabel" name="label_28">
<property name="text">
@@ -606,17 +508,17 @@ Capture:</string>
</item>
</layout>
</item>
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout_21">
<item row="2" column="0">
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QLabel" name="label_25">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Left:</string>
<string>Pressed:</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonRStickLeft">
<widget class="QPushButton" name="buttonRStick">
<property name="text">
<string/>
</property>
@@ -642,17 +544,129 @@ Capture:</string>
</item>
</layout>
</item>
<item row="2" column="0">
<layout class="QVBoxLayout" name="verticalLayout_6">
</layout>
</widget>
</item>
<item row="1" column="0">
<widget class="QGroupBox" name="faceButtons_4">
<property name="title">
<string>Left Stick</string>
</property>
<property name="flat">
<bool>false</bool>
</property>
<property name="checkable">
<bool>false</bool>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<item row="1" column="1">
<layout class="QVBoxLayout" name="verticalLayout_20">
<item>
<widget class="QLabel" name="label_5">
<widget class="QLabel" name="label_22">
<property name="text">
<string>Down:</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonLStickDown">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item row="4" column="0" colspan="2">
<widget class="QPushButton" name="buttonLStickAnalog">
<property name="text">
<string>Set Analog Stick</string>
</property>
</widget>
</item>
<item row="0" column="1">
<layout class="QVBoxLayout" name="verticalLayout_18">
<item>
<widget class="QLabel" name="label_23">
<property name="text">
<string>Right:</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonLStickRight">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="0">
<layout class="QVBoxLayout" name="verticalLayout_17">
<item>
<widget class="QLabel" name="label_21">
<property name="text">
<string>Left:</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonLStickLeft">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<layout class="QVBoxLayout" name="verticalLayout_19">
<item>
<widget class="QLabel" name="label_24">
<property name="text">
<string>Up:</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonLStickUp">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item row="3" column="0">
<layout class="QVBoxLayout" name="verticalLayout_31">
<item>
<widget class="QLabel" name="label_9">
<property name="text">
<string>Modifier:</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonLStickMod">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item row="3" column="1">
<layout class="QVBoxLayout" name="verticalLayout_7" stretch="0,0">
<item>
<widget class="QLabel" name="label_6">
<property name="text">
<string>Pressed:</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonRStick">
<widget class="QPushButton" name="buttonLStick">
<property name="text">
<string/>
</property>

View File

@@ -185,12 +185,24 @@ void GMainWindow::InitializeRecentFileMenuActions() {
void GMainWindow::InitializeHotkeys() {
RegisterHotkey("Main Window", "Load File", QKeySequence::Open);
RegisterHotkey("Main Window", "Start Emulation");
RegisterHotkey( "Main Window", "Fullscreen", QKeySequence::FullScreen );
RegisterHotkey( "Main Window", "Exit Fullscreen", QKeySequence::Cancel, Qt::ApplicationShortcut );
LoadHotkeys();
connect(GetHotkey("Main Window", "Load File", this), SIGNAL(activated()), this,
SLOT(OnMenuLoadFile()));
connect(GetHotkey("Main Window", "Start Emulation", this), SIGNAL(activated()), this,
SLOT(OnStartGame()));
connect(GetHotkey("Main Window", "Fullscreen", render_window), &QShortcut::activated,
ui.action_Fullscreen, &QAction::trigger);
connect(GetHotkey("Main Window", "Fullscreen", render_window), &QShortcut::activatedAmbiguously,
ui.action_Fullscreen, &QAction::trigger);
connect(GetHotkey("Main Window", "Exit Fullscreen", this), &QShortcut::activated, this, [&] {
if (emulation_running) {
ui.action_Fullscreen->setChecked(false);
ToggleFullscreen();
}
});
}
void GMainWindow::SetDefaultUIGeometry() {
@@ -219,6 +231,8 @@ void GMainWindow::RestoreUIState() {
ui.action_Single_Window_Mode->setChecked(UISettings::values.single_window_mode);
ToggleWindowMode();
ui.action_Fullscreen->setChecked(UISettings::values.fullscreen);
ui.action_Display_Dock_Widget_Headers->setChecked(UISettings::values.display_titlebar);
OnDisplayTitleBars(ui.action_Display_Dock_Widget_Headers->isChecked());
@@ -263,6 +277,10 @@ void GMainWindow::ConnectMenuEvents() {
connect(ui.action_Show_Filter_Bar, &QAction::triggered, this, &GMainWindow::OnToggleFilterBar);
connect(ui.action_Show_Status_Bar, &QAction::triggered, statusBar(), &QStatusBar::setVisible);
// Fullscreen
ui.action_Fullscreen->setShortcut(GetHotkey("Main Window", "Fullscreen", this)->key());
connect(ui.action_Fullscreen, &QAction::triggered, this, &GMainWindow::ToggleFullscreen);
// Help
connect(ui.action_About, &QAction::triggered, this, &GMainWindow::OnAbout);
}
@@ -402,6 +420,9 @@ void GMainWindow::BootGame(const QString& filename) {
render_window->setFocus();
emulation_running = true;
if (ui.action_Fullscreen->isChecked()) {
ShowFullscreen();
}
OnStartGame();
}
@@ -548,6 +569,41 @@ void GMainWindow::OnStopGame() {
ShutdownGame();
}
void GMainWindow::ToggleFullscreen() {
if (!emulation_running) {
return;
}
if (ui.action_Fullscreen->isChecked()) {
ShowFullscreen();
} else {
HideFullscreen();
}
}
void GMainWindow::ShowFullscreen() {
if (ui.action_Single_Window_Mode->isChecked()) {
UISettings::values.geometry = saveGeometry();
ui.menubar->hide();
statusBar()->hide();
showFullScreen();
} else {
UISettings::values.renderwindow_geometry = render_window->saveGeometry();
render_window->showFullScreen();
}
}
void GMainWindow::HideFullscreen() {
if (ui.action_Single_Window_Mode->isChecked()) {
statusBar()->setVisible(ui.action_Show_Status_Bar->isChecked());
ui.menubar->show();
showNormal();
restoreGeometry(UISettings::values.geometry);
} else {
render_window->showNormal();
render_window->restoreGeometry(UISettings::values.renderwindow_geometry);
}
}
void GMainWindow::ToggleWindowMode() {
if (ui.action_Single_Window_Mode->isChecked()) {
// Render in the main window...
@@ -670,6 +726,7 @@ void GMainWindow::OnCoreError(Core::System::ResultStatus result, std::string det
} else {
// Only show the message if the game is still running.
if (emu_thread) {
emu_thread->SetRunning(true);
message_label->setText(status_message);
message_label->setVisible(true);
}
@@ -700,6 +757,7 @@ void GMainWindow::closeEvent(QCloseEvent* event) {
UISettings::values.microprofile_visible = microProfileDialog->isVisible();
#endif
UISettings::values.single_window_mode = ui.action_Single_Window_Mode->isChecked();
UISettings::values.fullscreen = ui.action_Fullscreen->isChecked();
UISettings::values.display_titlebar = ui.action_Display_Dock_Widget_Headers->isChecked();
UISettings::values.show_filter_bar = ui.action_Show_Filter_Bar->isChecked();
UISettings::values.show_status_bar = ui.action_Show_Status_Bar->isChecked();

View File

@@ -127,6 +127,9 @@ private slots:
void OnAbout();
void OnToggleFilterBar();
void OnDisplayTitleBars(bool);
void ToggleFullscreen();
void ShowFullscreen();
void HideFullscreen();
void ToggleWindowMode();
void OnCoreError(Core::System::ResultStatus, std::string);

View File

@@ -83,6 +83,7 @@
<string>Debugging</string>
</property>
</widget>
<addaction name="action_Fullscreen"/>
<addaction name="action_Single_Window_Mode"/>
<addaction name="action_Display_Dock_Widget_Headers"/>
<addaction name="action_Show_Filter_Bar"/>
@@ -189,6 +190,14 @@
<string>Selects a folder to display in the game list</string>
</property>
</action>
</widget>
<action name="action_Fullscreen">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Fullscreen</string>
</property>
</action>
</widget>
<resources/>
</ui>

View File

@@ -27,6 +27,7 @@ struct Values {
bool microprofile_visible;
bool single_window_mode;
bool fullscreen;
bool display_titlebar;
bool show_filter_bar;
bool show_status_bar;

View File

@@ -90,8 +90,8 @@ use_hw_renderer =
use_shader_jit =
# Resolution scale factor
# 0: Auto (scales resolution to window size), 1: Native 3DS screen resolution, Otherwise a scale
# factor for the 3DS resolution
# 0: Auto (scales resolution to window size), 1: Native Switch screen resolution, Otherwise a scale
# factor for the Switch resolution
resolution_factor =
# Whether to enable V-Sync (caps the framerate at 60FPS) or not.