From d5aa47478895386a59f59a650d7391e3598e6739 Mon Sep 17 00:00:00 2001 From: JamePeng Date: Thu, 14 Jul 2016 18:26:43 +0800 Subject: [PATCH 01/11] Correct APT::0x00550040 and APT::0x00560000 function --- src/core/hle/service/apt/apt.cpp | 15 +++++++++------ src/core/hle/service/apt/apt.h | 26 ++++++++++++++++---------- src/core/hle/service/apt/apt_a.cpp | 4 ++-- src/core/hle/service/apt/apt_s.cpp | 4 ++-- src/core/hle/service/apt/apt_u.cpp | 4 ++-- 5 files changed, 31 insertions(+), 22 deletions(-) diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp index 1e54a53dd..14d661b38 100644 --- a/src/core/hle/service/apt/apt.cpp +++ b/src/core/hle/service/apt/apt.cpp @@ -37,6 +37,8 @@ static u32 cpu_percent; ///< CPU time available to the running application // APT::CheckNew3DSApp will check this unknown_ns_state_field to determine processing mode static u8 unknown_ns_state_field; +static ScreencapPostPermission screen_capture_post_permission; + /// Parameter data to be returned in the next call to Glance/ReceiveParameter static MessageParameter next_parameter; @@ -382,23 +384,23 @@ void StartLibraryApplet(Service::Interface* self) { cmd_buff[1] = applet->Start(parameter).raw; } -void SetNSStateField(Service::Interface* self) { +void SetScreenCapPostPermission(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); - unknown_ns_state_field = cmd_buff[1]; + screen_capture_post_permission = static_cast(cmd_buff[1] & 0xF); cmd_buff[0] = IPC::MakeHeader(0x55, 1, 0); cmd_buff[1] = RESULT_SUCCESS.raw; - LOG_WARNING(Service_APT, "(STUBBED) unknown_ns_state_field=%u", unknown_ns_state_field); + LOG_WARNING(Service_APT, "(STUBBED) screen_capture_post_permission=%u", screen_capture_post_permission); } -void GetNSStateField(Service::Interface* self) { +void GetScreenCapPostPermission(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[0] = IPC::MakeHeader(0x56, 2, 0); cmd_buff[1] = RESULT_SUCCESS.raw; - cmd_buff[8] = unknown_ns_state_field; - LOG_WARNING(Service_APT, "(STUBBED) unknown_ns_state_field=%u", unknown_ns_state_field); + cmd_buff[2] = static_cast(screen_capture_post_permission); + LOG_WARNING(Service_APT, "(STUBBED) screen_capture_post_permission=%u", screen_capture_post_permission); } void GetAppletInfo(Service::Interface* self) { @@ -493,6 +495,7 @@ void Init() { cpu_percent = 0; unknown_ns_state_field = 0; + screen_capture_post_permission = ScreencapPostPermission::CleanThePermission; // TODO(JamePeng): verify the initial value // TODO(bunnei): Check if these are created in Initialize or on APT process startup. notification_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "APT_U:Notification"); diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h index 53cee4867..077a6a316 100644 --- a/src/core/hle/service/apt/apt.h +++ b/src/core/hle/service/apt/apt.h @@ -94,6 +94,13 @@ enum class StartupArgumentType : u32 { OtherMedia = 2, }; +enum class ScreencapPostPermission : u32 { + CleanThePermission = 0, //TODO(JamePeng): verify what "zero" means + NoExplicitSetting = 1, + EnableScreenshotPostingToMiiverse = 2, + DisableScreenshotPostingToMiiverse = 3 +}; + /// Send a parameter to the currently-running application, which will read it via ReceiveParameter void SendParameter(const MessageParameter& parameter); @@ -383,25 +390,24 @@ void StartLibraryApplet(Service::Interface* self); void GetStartupArgument(Service::Interface* self); /** - * APT::SetNSStateField service function + * APT::SetScreenCapPostPermission service function * Inputs: - * 1 : u8 NS state field + * 0 : Header Code[0x00550040] + * 1 : u8 The screenshot posting permission * Outputs: * 1 : Result of function, 0 on success, otherwise error code - * Note: - * This writes the input u8 to a NS state field. */ -void SetNSStateField(Service::Interface* self); +void SetScreenCapPostPermission(Service::Interface* self); /** - * APT::GetNSStateField service function + * APT::GetScreenCapPostPermission service function + * Inputs: + * 0 : Header Code[0x00560000] * Outputs: * 1 : Result of function, 0 on success, otherwise error code - * 8 : u8 NS state field - * Note: - * This returns a u8 NS state field(which can be set by cmd 0x00550040), at cmdreply+8. + * 2 : u8 The screenshot posting permission */ -void GetNSStateField(Service::Interface* self); +void GetScreenCapPostPermission(Service::Interface* self); /** * APT::CheckNew3DSApp service function diff --git a/src/core/hle/service/apt/apt_a.cpp b/src/core/hle/service/apt/apt_a.cpp index 223c0a8bd..6c44c491c 100644 --- a/src/core/hle/service/apt/apt_a.cpp +++ b/src/core/hle/service/apt/apt_a.cpp @@ -33,8 +33,8 @@ const Interface::FunctionInfo FunctionTable[] = { {0x004F0080, SetAppCpuTimeLimit, "SetAppCpuTimeLimit"}, {0x00500040, GetAppCpuTimeLimit, "GetAppCpuTimeLimit"}, {0x00510080, GetStartupArgument, "GetStartupArgument"}, - {0x00550040, SetNSStateField, "SetNSStateField?"}, - {0x00560000, GetNSStateField, "GetNSStateField?"}, + {0x00550040, SetScreenCapPostPermission, "SetScreenCapPostPermission"}, + {0x00560000, GetScreenCapPostPermission, "GetScreenCapPostPermission"}, {0x01010000, CheckNew3DSApp, "CheckNew3DSApp"}, {0x01020000, CheckNew3DS, "CheckNew3DS"} }; diff --git a/src/core/hle/service/apt/apt_s.cpp b/src/core/hle/service/apt/apt_s.cpp index f5c52fa3d..c70f2201f 100644 --- a/src/core/hle/service/apt/apt_s.cpp +++ b/src/core/hle/service/apt/apt_s.cpp @@ -92,8 +92,8 @@ const Interface::FunctionInfo FunctionTable[] = { {0x00510080, GetStartupArgument, "GetStartupArgument"}, {0x00520104, nullptr, "Wrap1"}, {0x00530104, nullptr, "Unwrap1"}, - {0x00550040, SetNSStateField, "SetNSStateField?" }, - {0x00560000, GetNSStateField, "GetNSStateField?" }, + {0x00550040, SetScreenCapPostPermission, "SetScreenCapPostPermission"}, + {0x00560000, GetScreenCapPostPermission, "GetScreenCapPostPermission"}, {0x00580002, nullptr, "GetProgramID"}, {0x01010000, CheckNew3DSApp, "CheckNew3DSApp"}, {0x01020000, CheckNew3DS, "CheckNew3DS"} diff --git a/src/core/hle/service/apt/apt_u.cpp b/src/core/hle/service/apt/apt_u.cpp index 0e60bd34f..7bb804ffa 100644 --- a/src/core/hle/service/apt/apt_u.cpp +++ b/src/core/hle/service/apt/apt_u.cpp @@ -92,8 +92,8 @@ const Interface::FunctionInfo FunctionTable[] = { {0x00510080, GetStartupArgument, "GetStartupArgument"}, {0x00520104, nullptr, "Wrap1"}, {0x00530104, nullptr, "Unwrap1"}, - {0x00550040, SetNSStateField, "SetNSStateField?"}, - {0x00560000, GetNSStateField, "GetNSStateField?"}, + {0x00550040, SetScreenCapPostPermission, "SetScreenCapPostPermission"}, + {0x00560000, GetScreenCapPostPermission, "GetScreenCapPostPermission"}, {0x00580002, nullptr, "GetProgramID"}, {0x01010000, CheckNew3DSApp, "CheckNew3DSApp"}, {0x01020000, CheckNew3DS, "CheckNew3DS"} From c7125f37aa5325f84d615eaf3b8fa2e67eb7d800 Mon Sep 17 00:00:00 2001 From: Lectem Date: Thu, 21 Jul 2016 10:28:52 +0200 Subject: [PATCH 02/11] Fixes SDL2.dll copy to bindir on windows --- externals/cmake-modules/FindSDL2.cmake | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/externals/cmake-modules/FindSDL2.cmake b/externals/cmake-modules/FindSDL2.cmake index 9b8daa0d1..22ce752c5 100644 --- a/externals/cmake-modules/FindSDL2.cmake +++ b/externals/cmake-modules/FindSDL2.cmake @@ -3,6 +3,7 @@ # SDL2_LIBRARY, the name of the library to link against # SDL2_FOUND, if false, do not try to link to SDL2 # SDL2_INCLUDE_DIR, where to find SDL.h +# SDL2_DLL_DIR, where to find SDL2.dll if it exists # # This module responds to the the flag: # SDL2_BUILDING_LIBRARY @@ -149,6 +150,14 @@ FIND_LIBRARY(SDL2_LIBRARY_TEMP ) IF(SDL2_LIBRARY_TEMP) + if(MSVC) + get_filename_component(SDL2_DLL_DIR_TEMP ${SDL2_LIBRARY_TEMP} DIRECTORY) + if(EXISTS ${SDL2_DLL_DIR_TEMP}/SDL2.dll) + set(SDL2_DLL_DIR ${SDL2_DLL_DIR_TEMP}) + unset(SDL2_DLL_DIR_TEMP) + endif() + endif() + FIND_PATH(SDL2_INCLUDE_DIR SDL.h HINTS $ENV{SDL2DIR} From 78b97ee36433121b12d67d465f043cd7d75ec7ee Mon Sep 17 00:00:00 2001 From: Dale Whinham Date: Thu, 21 Jul 2016 21:33:54 +0100 Subject: [PATCH 03/11] CMake: Fix Info.plist template for citra_qt/OSX The Info.plist template incorrectly uses parentheses instead of curly braces, which means that building the .app bundle using regular 'make' results in the variable not being replaced, and hence the app bundle won't start because the executable name is incorrect. This commit fixes this issue. --- src/citra_qt/Info.plist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/citra_qt/Info.plist b/src/citra_qt/Info.plist index 4c89e128b..7d46b39d1 100644 --- a/src/citra_qt/Info.plist +++ b/src/citra_qt/Info.plist @@ -5,7 +5,7 @@ CFBundleDevelopmentRegion English CFBundleExecutable - $(EXECUTABLE_NAME) + ${EXECUTABLE_NAME} CFBundleGetInfoString CFBundleIconFile From 00c34e4df73add0f3eda53a71ea23125ac343971 Mon Sep 17 00:00:00 2001 From: wwylele Date: Wed, 20 Jul 2016 20:20:01 +0800 Subject: [PATCH 04/11] HLE: implement system time --- src/core/hle/shared_page.cpp | 57 ++++++++++++++++++++++++++++++++++++ src/core/hle/shared_page.h | 5 ++-- 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/src/core/hle/shared_page.cpp b/src/core/hle/shared_page.cpp index 2a1caeaac..4d9272923 100644 --- a/src/core/hle/shared_page.cpp +++ b/src/core/hle/shared_page.cpp @@ -2,8 +2,11 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include #include +#include +#include "core/core_timing.h" #include "core/hle/shared_page.h" //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -12,6 +15,57 @@ namespace SharedPage { SharedPageDef shared_page; +static int update_time_event; + +/// Gets system time in 3DS format. The epoch is Jan 1900, and the unit is millisecond. +static u64 GetSystemTime() { + auto now = std::chrono::system_clock::now(); + + // 3DS system does't allow user to set a time before Jan 1 2000, + // so we use it as an auxiliary epoch to calculate the console time. + std::tm epoch_tm; + epoch_tm.tm_sec = 0; + epoch_tm.tm_min = 0; + epoch_tm.tm_hour = 0; + epoch_tm.tm_mday = 1; + epoch_tm.tm_mon = 0; + epoch_tm.tm_year = 100; + epoch_tm.tm_isdst = 0; + auto epoch = std::chrono::system_clock::from_time_t(std::mktime(&epoch_tm)); + + // 3DS console time uses Jan 1 1900 as internal epoch, + // so we use the milliseconds between 1900 and 2000 as base console time + u64 console_time = 3155673600000ULL; + + // Only when system time is after 2000, we set it as 3DS system time + if (now > epoch) { + console_time += std::chrono::duration_cast(now - epoch).count(); + } + + // If the system time is in daylight saving, we give an additional hour to console time + std::time_t now_time_t = std::chrono::system_clock::to_time_t(now); + std::tm* now_tm = std::localtime(&now_time_t); + if (now_tm && now_tm->tm_isdst > 0) + console_time += 60 * 60 * 1000; + + return console_time; +} + +static void UpdateTimeCallback(u64 userdata, int cycles_late) { + DateTime& date_time = shared_page.date_time_counter % 2 ? + shared_page.date_time_0 : shared_page.date_time_1; + + date_time.date_time = GetSystemTime(); + date_time.update_tick = CoreTiming::GetTicks(); + date_time.tick_to_second_coefficient = g_clock_rate_arm11; + date_time.tick_offset = 0; + + ++shared_page.date_time_counter; + + // system time is updated hourly + CoreTiming::ScheduleEvent(msToCycles(60 * 60 * 1000) - cycles_late, update_time_event); +} + void Init() { std::memset(&shared_page, 0, sizeof(shared_page)); @@ -19,6 +73,9 @@ void Init() { // Some games wait until this value becomes 0x1, before asking running_hw shared_page.unknown_value = 0x1; + + update_time_event = CoreTiming::RegisterEvent("SharedPage::UpdateTimeCallback", UpdateTimeCallback); + CoreTiming::ScheduleEvent(0, update_time_event); } } // namespace diff --git a/src/core/hle/shared_page.h b/src/core/hle/shared_page.h index 35a07c685..cd9246726 100644 --- a/src/core/hle/shared_page.h +++ b/src/core/hle/shared_page.h @@ -25,13 +25,14 @@ namespace SharedPage { struct DateTime { u64_le date_time; // 0 u64_le update_tick; // 8 - INSERT_PADDING_BYTES(0x20 - 0x10); // 10 + u64_le tick_to_second_coefficient; // 10 + u64_le tick_offset; // 18 }; static_assert(sizeof(DateTime) == 0x20, "Datetime size is wrong"); struct SharedPageDef { // Most of these names are taken from the 3dbrew page linked above. - u32_le date_time_selector; // 0 + u32_le date_time_counter; // 0 u8 running_hw; // 4 /// "Microcontroller hardware info" u8 mcu_hw_info; // 5 From d63a76f4ce47962d7f191f3d4911c12344c4d249 Mon Sep 17 00:00:00 2001 From: wwylele Date: Wed, 20 Jul 2016 20:49:01 +0800 Subject: [PATCH 05/11] CoreTiming: avoid overflow --- src/core/core_timing.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/core_timing.h b/src/core/core_timing.h index 64f5b06d9..3d8a7d0c0 100644 --- a/src/core/core_timing.h +++ b/src/core/core_timing.h @@ -26,7 +26,7 @@ extern int g_clock_rate_arm11; inline s64 msToCycles(int ms) { - return g_clock_rate_arm11 / 1000 * ms; + return (s64)g_clock_rate_arm11 / 1000 * ms; } inline s64 msToCycles(float ms) { From e09e6837208a5cda81c0eee233f301433201cb8b Mon Sep 17 00:00:00 2001 From: Emmanuel Gil Peyrot Date: Sat, 23 Jul 2016 17:10:32 +0100 Subject: [PATCH 06/11] =?UTF-8?q?Remove=20the=20-msse4.1=20on=20=C2=ACMSVC?= =?UTF-8?q?.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This option makes the generated binary crash with an illegal instruction when the target CPU doesn’t support the SSE4.1 extension (see #1968), with no noticeable performance increase compared to a generic build. --- CMakeLists.txt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9a436b981..779eb8e50 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,11 +66,6 @@ message(STATUS "Target architecture: ${ARCHITECTURE}") if (NOT MSVC) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1y -Wno-attributes") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") - - if (ARCHITECTURE_x86_64) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse4.1") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse4.1") - endif() else() # Silence "deprecation" warnings add_definitions(/D_CRT_SECURE_NO_WARNINGS /D_CRT_NONSTDC_NO_DEPRECATE /D_SCL_SECURE_NO_WARNINGS) From 7331b790217f9a3e86e5668cb134bd8f073ff289 Mon Sep 17 00:00:00 2001 From: Alexandre LittleWhite Laurent Date: Sat, 23 Jul 2016 19:37:12 +0200 Subject: [PATCH 07/11] Protection against a resize of size 0 --- src/common/emu_window.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/common/emu_window.cpp b/src/common/emu_window.cpp index 08270dd88..fd728c109 100644 --- a/src/common/emu_window.cpp +++ b/src/common/emu_window.cpp @@ -51,7 +51,6 @@ static bool IsWithinTouchscreen(const EmuWindow::FramebufferLayout& layout, unsi } std::tuple EmuWindow::ClipToTouchScreen(unsigned new_x, unsigned new_y) { - new_x = std::max(new_x, framebuffer_layout.bottom_screen.left); new_x = std::min(new_x, framebuffer_layout.bottom_screen.right-1); @@ -92,9 +91,9 @@ void EmuWindow::TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y) { } EmuWindow::FramebufferLayout EmuWindow::FramebufferLayout::DefaultScreenLayout(unsigned width, unsigned height) { - - ASSERT(width > 0); - ASSERT(height > 0); + // When hiding the widget, the function receives a size of 0 + if (width == 0) width = 1; + if (height == 0) height = 1; EmuWindow::FramebufferLayout res = { width, height, {}, {} }; From f8f67221334dc6c81755961e2cdd8b14ad0441ce Mon Sep 17 00:00:00 2001 From: Andy Tran Date: Tue, 26 Jul 2016 11:08:06 +1000 Subject: [PATCH 08/11] Travis Build: OS X Startup Crash Fix (#1962) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Travis: Mac OS X Build Fix Addresses the issue of the nightly builds crashing on OS X. In short, the changes needed were to rename the references within the binaries in order to make the app “self-contained”. * Travis: Mac OS X Terminal Launches citra with a terminal (instead of going straight for the QT application, skipping the debugging terminal). * Travis: Clean Up Lines * Travis: Fix of EOL Issue * Travis: Merge Fixes from Build Branch * Travis: Forward OS X Arguments * Travis: Forward OS X Arg x2 The issue is, is that sure “open citra-qt.app —args test” works, but drag and drop doesn’t! * Travis: Something needed to be escaped --- .travis-upload.sh | 91 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/.travis-upload.sh b/.travis-upload.sh index 1ad8f5e5e..7838bf079 100755 --- a/.travis-upload.sh +++ b/.travis-upload.sh @@ -23,6 +23,97 @@ if [ "$TRAVIS_BRANCH" = "master" ]; then # move SDL2 libs into folder for deployment dylibbundler -b -x "${REV_NAME}/citra" -cd -d "${REV_NAME}/libs" -p "@executable_path/libs/" + + # Make the changes to make the citra-qt app standalone (i.e. not dependent on the current brew installation). + # To do this, the absolute references to each and every QT framework must be re-written to point to the local frameworks + # (in the Contents/Frameworks folder). + # The "install_name_tool" is used to do so. + + # Coreutils is a hack to coerce Homebrew to point to the absolute Cellar path (symlink dereferenced). i.e: + # ls -l /usr/local/opt/qt5:: /usr/local/opt/qt5 -> ../Cellar/qt5/5.6.1-1 + # grealpath ../Cellar/qt5/5.6.1-1:: /usr/local/Cellar/qt5/5.6.1-1 + brew install coreutils + + REV_NAME_ALT=$REV_NAME/ + # grealpath is located in coreutils, there is no "realpath" for OS X :( + QT_BREWS_PATH=$(grealpath "$(brew --prefix qt5)") + BREW_PATH=$(brew --prefix) + QT_VERSION_NUM=5 + + $BREW_PATH/opt/qt5/bin/macdeployqt "${REV_NAME_ALT}citra-qt.app" \ + -executable="${REV_NAME_ALT}citra-qt.app/Contents/MacOS/citra-qt" + + # These are the files that macdeployqt packed into Contents/Frameworks/ - we don't want those, so we replace them. + declare -a macos_libs=("QtCore" "QtWidgets" "QtGui" "QtOpenGL" "QtPrintSupport") + + for macos_lib in "${macos_libs[@]}" + do + SC_FRAMEWORK_PART=$macos_lib.framework/Versions/$QT_VERSION_NUM/$macos_lib + # Replace macdeployqt versions of the Frameworks with our own (from /usr/local/opt/qt5/lib/) + cp "$BREW_PATH/opt/qt5/lib/$SC_FRAMEWORK_PART" "${REV_NAME_ALT}citra-qt.app/Contents/Frameworks/$SC_FRAMEWORK_PART" + + # Replace references within the embedded Framework files with "internal" versions. + for macos_lib2 in "${macos_libs[@]}" + do + # Since brew references both the non-symlinked and symlink paths of QT5, it needs to be duplicated. + # /usr/local/Cellar/qt5/5.6.1-1/lib and /usr/local/opt/qt5/lib both resolve to the same files. + # So the two lines below are effectively duplicates when resolved as a path, but as strings, they aren't. + RM_FRAMEWORK_PART=$macos_lib2.framework/Versions/$QT_VERSION_NUM/$macos_lib2 + install_name_tool -change \ + $QT_BREWS_PATH/lib/$RM_FRAMEWORK_PART \ + @executable_path/../Frameworks/$RM_FRAMEWORK_PART \ + "${REV_NAME_ALT}citra-qt.app/Contents/Frameworks/$SC_FRAMEWORK_PART" + install_name_tool -change \ + "$BREW_PATH/opt/qt5/lib/$RM_FRAMEWORK_PART" \ + @executable_path/../Frameworks/$RM_FRAMEWORK_PART \ + "${REV_NAME_ALT}citra-qt.app/Contents/Frameworks/$SC_FRAMEWORK_PART" + done + done + + # Handles `This application failed to start because it could not find or load the Qt platform plugin "cocoa"` + # Which manifests itself as: + # "Exception Type: EXC_CRASH (SIGABRT) | Exception Codes: 0x0000000000000000, 0x0000000000000000 | Exception Note: EXC_CORPSE_NOTIFY" + # There may be more dylibs needed to be fixed... + declare -a macos_plugins=("Plugins/platforms/libqcocoa.dylib") + + for macos_lib in "${macos_plugins[@]}" + do + install_name_tool -id @executable_path/../$macos_lib "${REV_NAME_ALT}citra-qt.app/Contents/$macos_lib" + for macos_lib2 in "${macos_libs[@]}" + do + RM_FRAMEWORK_PART=$macos_lib2.framework/Versions/$QT_VERSION_NUM/$macos_lib2 + install_name_tool -change \ + $QT_BREWS_PATH/lib/$RM_FRAMEWORK_PART \ + @executable_path/../Frameworks/$RM_FRAMEWORK_PART \ + "${REV_NAME_ALT}citra-qt.app/Contents/$macos_lib" + install_name_tool -change \ + "$BREW_PATH/opt/qt5/lib/$RM_FRAMEWORK_PART" \ + @executable_path/../Frameworks/$RM_FRAMEWORK_PART \ + "${REV_NAME_ALT}citra-qt.app/Contents/$macos_lib" + done + done + + for macos_lib in "${macos_libs[@]}" + do + # Debugging info for Travis-CI + otool -L "${REV_NAME_ALT}citra-qt.app/Contents/Frameworks/$macos_lib.framework/Versions/$QT_VERSION_NUM/$macos_lib" + done + + # Make the citra-qt.app application launch a debugging terminal. + # Store away the actual binary + mv ${REV_NAME_ALT}citra-qt.app/Contents/MacOS/citra-qt ${REV_NAME_ALT}citra-qt.app/Contents/MacOS/citra-qt-bin + + cat > ${REV_NAME_ALT}citra-qt.app/Contents/MacOS/citra-qt < Date: Sun, 17 Jul 2016 11:55:52 +0100 Subject: [PATCH 09/11] dyncom: Fix translation of thumb REVSH --- src/core/arm/dyncom/arm_dyncom_thumb.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/core/arm/dyncom/arm_dyncom_thumb.cpp b/src/core/arm/dyncom/arm_dyncom_thumb.cpp index 29272fd5d..3576370d1 100644 --- a/src/core/arm/dyncom/arm_dyncom_thumb.cpp +++ b/src/core/arm/dyncom/arm_dyncom_thumb.cpp @@ -2,6 +2,8 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include + // We can provide simple Thumb simulation by decoding the Thumb instruction into its corresponding // ARM instruction, and using the existing ARM simulator. @@ -293,15 +295,22 @@ ThumbDecodeStatus TranslateThumbInstruction(u32 addr, u32 instr, u32* ainstr, u3 | (BIT(tinstr, 4) << 18); // enable bit } } else if ((tinstr & 0x0F00) == 0x0a00) { - static const u32 subset[3] = { + static const u32 subset[4] = { 0xE6BF0F30, // REV 0xE6BF0FB0, // REV16 + 0, // undefined 0xE6FF0FB0, // REVSH }; - *ainstr = subset[BITS(tinstr, 6, 7)] // base - | (BITS(tinstr, 0, 2) << 12) // Rd - | BITS(tinstr, 3, 5); // Rm + size_t subset_index = BITS(tinstr, 6, 7); + + if (subset_index == 2) { + valid = ThumbDecodeStatus::UNDEFINED; + } else { + *ainstr = subset[subset_index] // base + | (BITS(tinstr, 0, 2) << 12) // Rd + | BITS(tinstr, 3, 5); // Rm + } } else { static const u32 subset[4] = { 0xE92D0000, // STMDB sp!,{rlist} From 9a9e9dc375163090394e212a11e6f58379dc9a90 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Thu, 28 Jul 2016 21:47:31 +0200 Subject: [PATCH 10/11] Instead of segfaulting, log an error to remind the user to dump the shared font file --- src/core/hle/service/apt/apt.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp index 1e54a53dd..0c623d45f 100644 --- a/src/core/hle/service/apt/apt.cpp +++ b/src/core/hle/service/apt/apt.cpp @@ -70,6 +70,13 @@ void Initialize(Service::Interface* self) { void GetSharedFont(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); + if (!shared_font_mem) { + LOG_ERROR(Service_APT, "shared font file missing - go dump it from your 3ds"); + cmd_buff[0] = IPC::MakeHeader(0x44, 2, 2); + cmd_buff[1] = -1; // TODO: Find the right error code + return; + } + // The shared font has to be relocated to the new address before being passed to the application. VAddr target_address = Memory::PhysicalToVirtualAddress(shared_font_mem->linear_heap_phys_address); // The shared font dumped by 3dsutils (https://github.com/citra-emu/3dsutils) uses this address as base, From e91327c86a863b9419fd3695b2400a52336ec3b5 Mon Sep 17 00:00:00 2001 From: Anon Date: Fri, 29 Jul 2016 07:45:49 -0500 Subject: [PATCH 11/11] Input GUI: Add tab to remap controls (#1900) --- src/citra_qt/CMakeLists.txt | 3 + src/citra_qt/config.cpp | 9 +- src/citra_qt/config.h | 6 +- src/citra_qt/configure.ui | 8 +- src/citra_qt/configure_dialog.cpp | 1 + src/citra_qt/configure_input.cpp | 149 ++++++++ src/citra_qt/configure_input.h | 63 ++++ src/citra_qt/configure_input.ui | 593 ++++++++++++++++++++++++++++++ src/citra_qt/main.cpp | 1 + 9 files changed, 825 insertions(+), 8 deletions(-) create mode 100644 src/citra_qt/configure_input.cpp create mode 100644 src/citra_qt/configure_input.h create mode 100644 src/citra_qt/configure_input.ui diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt index 017b43871..4402ad995 100644 --- a/src/citra_qt/CMakeLists.txt +++ b/src/citra_qt/CMakeLists.txt @@ -23,6 +23,7 @@ set(SRCS configure_dialog.cpp configure_general.cpp configure_system.cpp + configure_input.cpp game_list.cpp hotkeys.cpp main.cpp @@ -54,6 +55,7 @@ set(HEADERS configure_dialog.h configure_general.h configure_system.h + configure_input.h game_list.h game_list_p.h hotkeys.h @@ -72,6 +74,7 @@ set(UIS configure_debug.ui configure_general.ui configure_system.ui + configure_input.ui hotkeys.ui main.ui ) diff --git a/src/citra_qt/config.cpp b/src/citra_qt/config.cpp index ba7edaff9..0e5f285c0 100644 --- a/src/citra_qt/config.cpp +++ b/src/citra_qt/config.cpp @@ -3,14 +3,11 @@ // Refer to the license.txt file included. #include -#include -#include #include "citra_qt/config.h" #include "citra_qt/ui_settings.h" #include "common/file_util.h" -#include "core/settings.h" Config::Config() { // TODO: Don't hardcode the path; let the frontend decide where to put the config files. @@ -21,7 +18,7 @@ Config::Config() { Reload(); } -static const std::array defaults = { +const std::array Config::defaults = { // directly mapped keys Qt::Key_A, Qt::Key_S, Qt::Key_Z, Qt::Key_X, Qt::Key_Q, Qt::Key_W, Qt::Key_1, Qt::Key_2, @@ -109,7 +106,7 @@ void Config::ReadValues() { UISettings::values.shortcuts.emplace_back( UISettings::Shortcut(group + "/" + hotkey, UISettings::ContextualShortcut(qt_config->value("KeySeq").toString(), - qt_config->value("Context").toInt()))); + qt_config->value("Context").toInt()))); qt_config->endGroup(); } @@ -191,7 +188,7 @@ void Config::SaveValues() { qt_config->endGroup(); qt_config->beginGroup("Shortcuts"); - for (auto shortcut : UISettings::values.shortcuts ) { + for (auto shortcut : UISettings::values.shortcuts) { qt_config->setValue(shortcut.first + "/KeySeq", shortcut.second.first); qt_config->setValue(shortcut.first + "/Context", shortcut.second.second); } diff --git a/src/citra_qt/config.h b/src/citra_qt/config.h index dd0b2ef0b..0cbdb707f 100644 --- a/src/citra_qt/config.h +++ b/src/citra_qt/config.h @@ -1,10 +1,13 @@ -// Copyright 2014 Citra Emulator Project +// Copyright 2014 Citra Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #pragma once #include +#include + +#include "core/settings.h" class QSettings; @@ -20,4 +23,5 @@ public: void Reload(); void Save(); + static const std::array defaults; }; diff --git a/src/citra_qt/configure.ui b/src/citra_qt/configure.ui index 4a9c52650..15fe17323 100644 --- a/src/citra_qt/configure.ui +++ b/src/citra_qt/configure.ui @@ -29,7 +29,7 @@ System - + Input @@ -80,6 +80,12 @@
configure_debug.h
1 + + ConfigureInput + QWidget +
configure_input.h
+ 1 +
diff --git a/src/citra_qt/configure_dialog.cpp b/src/citra_qt/configure_dialog.cpp index 77c266d01..459fac4bb 100644 --- a/src/citra_qt/configure_dialog.cpp +++ b/src/citra_qt/configure_dialog.cpp @@ -30,6 +30,7 @@ void ConfigureDialog::setConfiguration() { void ConfigureDialog::applyConfiguration() { ui->generalTab->applyConfiguration(); ui->systemTab->applyConfiguration(); + ui->inputTab->applyConfiguration(); ui->audioTab->applyConfiguration(); ui->debugTab->applyConfiguration(); } diff --git a/src/citra_qt/configure_input.cpp b/src/citra_qt/configure_input.cpp new file mode 100644 index 000000000..9c7a67174 --- /dev/null +++ b/src/citra_qt/configure_input.cpp @@ -0,0 +1,149 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include +#include + +#include "citra_qt/configure_input.h" + +ConfigureInput::ConfigureInput(QWidget* parent) : QWidget(parent), ui(std::make_unique()) { + ui->setupUi(this); + + // Initialize mapping of input enum to UI button. + input_mapping = { + { std::make_pair(Settings::NativeInput::Values::A, ui->buttonA) }, + { std::make_pair(Settings::NativeInput::Values::B, ui->buttonB) }, + { std::make_pair(Settings::NativeInput::Values::X, ui->buttonX) }, + { std::make_pair(Settings::NativeInput::Values::Y, ui->buttonY) }, + { std::make_pair(Settings::NativeInput::Values::L, ui->buttonL) }, + { std::make_pair(Settings::NativeInput::Values::R, ui->buttonR) }, + { std::make_pair(Settings::NativeInput::Values::ZL, ui->buttonZL) }, + { std::make_pair(Settings::NativeInput::Values::ZR, ui->buttonZR) }, + { std::make_pair(Settings::NativeInput::Values::START, ui->buttonStart) }, + { std::make_pair(Settings::NativeInput::Values::SELECT, ui->buttonSelect) }, + { std::make_pair(Settings::NativeInput::Values::HOME, ui->buttonHome) }, + { std::make_pair(Settings::NativeInput::Values::DUP, ui->buttonDpadUp) }, + { std::make_pair(Settings::NativeInput::Values::DDOWN, ui->buttonDpadDown) }, + { std::make_pair(Settings::NativeInput::Values::DLEFT, ui->buttonDpadLeft) }, + { std::make_pair(Settings::NativeInput::Values::DRIGHT, ui->buttonDpadRight) }, + { std::make_pair(Settings::NativeInput::Values::CUP, ui->buttonCStickUp) }, + { std::make_pair(Settings::NativeInput::Values::CDOWN, ui->buttonCStickDown) }, + { std::make_pair(Settings::NativeInput::Values::CLEFT, ui->buttonCStickLeft) }, + { std::make_pair(Settings::NativeInput::Values::CRIGHT, ui->buttonCStickRight) }, + { std::make_pair(Settings::NativeInput::Values::CIRCLE_UP, ui->buttonCircleUp) }, + { std::make_pair(Settings::NativeInput::Values::CIRCLE_DOWN, ui->buttonCircleDown) }, + { std::make_pair(Settings::NativeInput::Values::CIRCLE_LEFT, ui->buttonCircleLeft) }, + { std::make_pair(Settings::NativeInput::Values::CIRCLE_RIGHT, ui->buttonCircleRight) }, + { std::make_pair(Settings::NativeInput::Values::CIRCLE_MODIFIER, ui->buttonCircleMod) }, + }; + + // Attach handle click method to each button click. + for (const auto& entry : input_mapping) { + connect(entry.second, SIGNAL(released()), this, SLOT(handleClick())); + } + connect(ui->buttonRestoreDefaults, SIGNAL(released()), this, SLOT(restoreDefaults())); + setFocusPolicy(Qt::ClickFocus); + timer = new QTimer(this); + timer->setSingleShot(true); + connect(timer, &QTimer::timeout, this, [&]() { key_pressed = Qt::Key_Escape; setKey(); }); + this->setConfiguration(); +} + +void ConfigureInput::handleClick() { + QPushButton* sender = qobject_cast(QObject::sender()); + previous_mapping = sender->text(); + sender->setText(tr("[waiting]")); + sender->setFocus(); + grabKeyboard(); + grabMouse(); + changing_button = sender; + timer->start(5000); //Cancel after 5 seconds +} + +void ConfigureInput::applyConfiguration() { + for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) { + int value = getKeyValue(input_mapping[Settings::NativeInput::Values(i)]->text()); + Settings::values.input_mappings[Settings::NativeInput::All[i]] = value; + } + Settings::Apply(); +} + +void ConfigureInput::setConfiguration() { + for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) { + QString keyValue = getKeyName(Settings::values.input_mappings[i]); + input_mapping[Settings::NativeInput::Values(i)]->setText(keyValue); + } +} + +void ConfigureInput::keyPressEvent(QKeyEvent* event) { + if (!changing_button) + return; + if (!event || event->key() == Qt::Key_unknown) + return; + key_pressed = event->key(); + timer->stop(); + setKey(); +} + +void ConfigureInput::setKey() { + const QString key_value = getKeyName(key_pressed); + if (key_pressed == Qt::Key_Escape) + changing_button->setText(previous_mapping); + else + changing_button->setText(key_value); + removeDuplicates(key_value); + key_pressed = Qt::Key_unknown; + releaseKeyboard(); + releaseMouse(); + changing_button = nullptr; + previous_mapping = nullptr; +} + +QString ConfigureInput::getKeyName(int key_code) const { + if (key_code == Qt::Key_Shift) + return tr("Shift"); + if (key_code == Qt::Key_Control) + return tr("Ctrl"); + if (key_code == Qt::Key_Alt) + return tr("Alt"); + if (key_code == Qt::Key_Meta) + return ""; + if (key_code == -1) + return ""; + + return QKeySequence(key_code).toString(); +} + +Qt::Key ConfigureInput::getKeyValue(const QString& text) const { + if (text == "Shift") + return Qt::Key_Shift; + if (text == "Ctrl") + return Qt::Key_Control; + if (text == "Alt") + return Qt::Key_Alt; + if (text == "Meta") + return Qt::Key_unknown; + if (text == "") + return Qt::Key_unknown; + + return Qt::Key(QKeySequence(text)[0]); +} + +void ConfigureInput::removeDuplicates(const QString& newValue) { + for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) { + if (changing_button != input_mapping[Settings::NativeInput::Values(i)]) { + const QString oldValue = input_mapping[Settings::NativeInput::Values(i)]->text(); + if (newValue == oldValue) + input_mapping[Settings::NativeInput::Values(i)]->setText(""); + } + } +} + +void ConfigureInput::restoreDefaults() { + for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) { + const QString keyValue = getKeyName(Config::defaults[i].toInt()); + input_mapping[Settings::NativeInput::Values(i)]->setText(keyValue); + } +} diff --git a/src/citra_qt/configure_input.h b/src/citra_qt/configure_input.h new file mode 100644 index 000000000..fe8ea5580 --- /dev/null +++ b/src/citra_qt/configure_input.h @@ -0,0 +1,63 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include + +#include "citra_qt/config.h" +#include "core/settings.h" +#include "ui_configure_input.h" + +class QPushButton; +class QString; +class QTimer; + +namespace Ui { + class ConfigureInput; +} + +class ConfigureInput : public QWidget { + Q_OBJECT + +public: + explicit ConfigureInput(QWidget* parent = nullptr); + + /// Save all button configurations to settings file + void applyConfiguration(); + +private: + std::unique_ptr ui; + std::map input_mapping; + int key_pressed; + QPushButton* changing_button = nullptr; ///< button currently waiting for key press. + QString previous_mapping; + QTimer* timer; + + /// Load configuration settings into button text + void setConfiguration(); + + /// Check all inputs for duplicate keys. Clears out any other button with the same value as this button's new value. + void removeDuplicates(const QString& newValue); + + /// Handle key press event for input tab when a button is 'waiting'. + void keyPressEvent(QKeyEvent* event) override; + + /// Convert key ASCII value to its' letter/name + QString getKeyName(int key_code) const; + + /// Convert letter/name of key to its ASCII value. + Qt::Key getKeyValue(const QString& text) const; + + /// Set button text to name of key pressed. + void setKey(); + +private slots: + /// Event handler for all button released() event. + void handleClick(); + + /// Restore all buttons to their default values. + void restoreDefaults(); +}; diff --git a/src/citra_qt/configure_input.ui b/src/citra_qt/configure_input.ui new file mode 100644 index 000000000..a040d4df4 --- /dev/null +++ b/src/citra_qt/configure_input.ui @@ -0,0 +1,593 @@ + + + ConfigureInput + + + + 0 + 0 + 370 + 534 + + + + ConfigureInput + + + + + + + + Face Buttons + + + false + + + false + + + + + + + + A: + + + + + + + + + + + + + + + + + + B: + + + + + + + + + + + + + + + + + + X: + + + + + + + + + + + + + + + + + + Y: + + + + + + + + + + + + + + + + + + + Directional Pad + + + false + + + false + + + + + + + + Up: + + + + + + + + + + + + + + + + + + Down: + + + + + + + + + + + + + + + + + + Left: + + + + + + + + + + + + + + + + + + Right: + + + + + + + + + + + + + + + + + + + Shoulder Buttons + + + false + + + false + + + + + + + + L: + + + + + + + + + + + + + + + + + + R: + + + + + + + + + + + + + + + + + + ZL: + + + + + + + + + + + + + + + + + + ZR: + + + + + + + + + + + + + + + + + + + + Circle Pad + + + false + + + false + + + + + + + + Left: + + + + + + + + + + + + + + + + + + Right: + + + + + + + + + + + + + + + + + + Up: + + + + + + + + + + + + + + + + + + Down: + + + + + + + + + + + + + + + + + + + C-Stick + + + false + + + false + + + + + + + + Left: + + + + + + + + + + + + + + + + + + Right: + + + + + + + + + + + + + + + + + + Up: + + + + + + + + + + + + + + + + + + Down: + + + + + + + + + + + + + + + + + + + Misc. + + + false + + + false + + + + + + + + Start: + + + + + + + + + + + + + + + + + + Select: + + + + + + + + + + + + + + + + + + Home: + + + + + + + + + + + + + + + + + + Circle Mod: + + + + + + + + + + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 0 + 0 + + + + Qt::LeftToRight + + + Restore Defaults + + + + + + + + + + diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 6fe5d7a3f..68a936087 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -513,6 +513,7 @@ void GMainWindow::OnConfigure() { if (result == QDialog::Accepted) { configureDialog.applyConfiguration(); + render_window->ReloadSetKeymaps(); config->Save(); } }